--- /dev/null
+/* MikMod sound library\r
+ (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS\r
+ for complete list.\r
+\r
+ This library is free software; you can redistribute it and/or modify\r
+ it under the terms of the GNU Library General Public License as\r
+ published by the Free Software Foundation; either version 2 of\r
+ the License, or (at your option) any later version.\r
+ \r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU Library General Public License for more details.\r
+ \r
+ You should have received a copy of the GNU Library General Public\r
+ License along with this library; if not, write to the Free Software\r
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\r
+ 02111-1307, USA.\r
+*/\r
+\r
+/*==============================================================================\r
+\r
+ $Id: virtch_common.c,v 1.2 2004/02/13 13:31:54 raph Exp $\r
+\r
+ Common source parts between the two software mixers.\r
+ This file is probably the ugliest part of libmikmod...\r
+\r
+==============================================================================*/\r
+\r
+#ifndef _IN_VIRTCH_\r
+\r
+#include "mikmod_internals.h"\r
+\r
+extern BOOL VC1_Init(void);\r
+extern BOOL VC2_Init(void);\r
+static BOOL (*VC_Init_ptr)(void)=VC1_Init;\r
+extern void VC1_Exit(void);\r
+extern void VC2_Exit(void);\r
+static void (*VC_Exit_ptr)(void)=VC1_Exit;\r
+extern BOOL VC1_SetNumVoices(void);\r
+extern BOOL VC2_SetNumVoices(void);\r
+static BOOL (*VC_SetNumVoices_ptr)(void);\r
+extern ULONG VC1_SampleSpace(int);\r
+extern ULONG VC2_SampleSpace(int);\r
+static ULONG (*VC_SampleSpace_ptr)(int);\r
+extern ULONG VC1_SampleLength(int,SAMPLE*);\r
+extern ULONG VC2_SampleLength(int,SAMPLE*);\r
+static ULONG (*VC_SampleLength_ptr)(int,SAMPLE*);\r
+\r
+extern BOOL VC1_PlayStart(void);\r
+extern BOOL VC2_PlayStart(void);\r
+static BOOL (*VC_PlayStart_ptr)(void);\r
+extern void VC1_PlayStop(void);\r
+extern void VC2_PlayStop(void);\r
+static void (*VC_PlayStop_ptr)(void);\r
+\r
+extern SWORD VC1_SampleLoad(struct SAMPLOAD*,int);\r
+extern SWORD VC2_SampleLoad(struct SAMPLOAD*,int);\r
+static SWORD (*VC_SampleLoad_ptr)(struct SAMPLOAD*,int);\r
+extern void VC1_SampleUnload(SWORD);\r
+extern void VC2_SampleUnload(SWORD);\r
+static void (*VC_SampleUnload_ptr)(SWORD);\r
+\r
+extern ULONG VC1_WriteBytes(SBYTE*,ULONG);\r
+extern ULONG VC2_WriteBytes(SBYTE*,ULONG);\r
+static ULONG (*VC_WriteBytes_ptr)(SBYTE*,ULONG);\r
+extern ULONG VC1_SilenceBytes(SBYTE*,ULONG);\r
+extern ULONG VC2_SilenceBytes(SBYTE*,ULONG);\r
+static ULONG (*VC_SilenceBytes_ptr)(SBYTE*,ULONG);\r
+\r
+extern void VC1_VoiceSetVolume(UBYTE,UWORD);\r
+extern void VC2_VoiceSetVolume(UBYTE,UWORD);\r
+static void (*VC_VoiceSetVolume_ptr)(UBYTE,UWORD);\r
+extern UWORD VC1_VoiceGetVolume(UBYTE);\r
+extern UWORD VC2_VoiceGetVolume(UBYTE);\r
+static UWORD (*VC_VoiceGetVolume_ptr)(UBYTE);\r
+extern void VC1_VoiceSetFrequency(UBYTE,ULONG);\r
+extern void VC2_VoiceSetFrequency(UBYTE,ULONG);\r
+static void (*VC_VoiceSetFrequency_ptr)(UBYTE,ULONG);\r
+extern ULONG VC1_VoiceGetFrequency(UBYTE);\r
+extern ULONG VC2_VoiceGetFrequency(UBYTE);\r
+static ULONG (*VC_VoiceGetFrequency_ptr)(UBYTE);\r
+extern void VC1_VoiceSetPanning(UBYTE,ULONG);\r
+extern void VC2_VoiceSetPanning(UBYTE,ULONG);\r
+static void (*VC_VoiceSetPanning_ptr)(UBYTE,ULONG);\r
+extern ULONG VC1_VoiceGetPanning(UBYTE);\r
+extern ULONG VC2_VoiceGetPanning(UBYTE);\r
+static ULONG (*VC_VoiceGetPanning_ptr)(UBYTE);\r
+extern void VC1_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+extern void VC2_VoicePlay(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+static void (*VC_VoicePlay_ptr)(UBYTE,SWORD,ULONG,ULONG,ULONG,ULONG,UWORD);\r
+\r
+extern void VC1_VoiceStop(UBYTE);\r
+extern void VC2_VoiceStop(UBYTE);\r
+static void (*VC_VoiceStop_ptr)(UBYTE);\r
+extern BOOL VC1_VoiceStopped(UBYTE);\r
+extern BOOL VC2_VoiceStopped(UBYTE);\r
+static BOOL (*VC_VoiceStopped_ptr)(UBYTE);\r
+extern SLONG VC1_VoiceGetPosition(UBYTE);\r
+extern SLONG VC2_VoiceGetPosition(UBYTE);\r
+static SLONG (*VC_VoiceGetPosition_ptr)(UBYTE);\r
+extern ULONG VC1_VoiceRealVolume(UBYTE);\r
+extern ULONG VC2_VoiceRealVolume(UBYTE);\r
+static ULONG (*VC_VoiceRealVolume_ptr)(UBYTE);\r
+\r
+#if defined __STDC__ || defined _MSC_VER\r
+#define VC_PROC0(suffix) \\r
+MIKMODAPI void VC_##suffix (void) { VC_##suffix##_ptr(); }\r
+\r
+#define VC_FUNC0(suffix,ret) \\r
+MIKMODAPI ret VC_##suffix (void) { return VC_##suffix##_ptr(); }\r
+\r
+#define VC_PROC1(suffix,typ1) \\r
+MIKMODAPI void VC_##suffix (typ1 a) { VC_##suffix##_ptr(a); }\r
+\r
+#define VC_FUNC1(suffix,ret,typ1) \\r
+MIKMODAPI ret VC_##suffix (typ1 a) { return VC_##suffix##_ptr(a); }\r
+\r
+#define VC_PROC2(suffix,typ1,typ2) \\r
+MIKMODAPI void VC_##suffix (typ1 a,typ2 b) { VC_##suffix##_ptr(a,b); }\r
+\r
+#define VC_FUNC2(suffix,ret,typ1,typ2) \\r
+MIKMODAPI ret VC_##suffix (typ1 a,typ2 b) { return VC_##suffix##_ptr(a,b); }\r
+#else\r
+#define VC_PROC0(suffix) \\r
+MIKMODAPI void VC_/**/suffix (void) { VC_/**/suffix/**/_ptr(); }\r
+\r
+#define VC_FUNC0(suffix,ret) \\r
+MIKMODAPI ret VC_/**/suffix (void) { return VC_/**/suffix/**/_ptr(); }\r
+\r
+#define VC_PROC1(suffix,typ1) \\r
+MIKMODAPI void VC_/**/suffix (typ1 a) { VC_/**/suffix/**/_ptr(a); }\r
+\r
+#define VC_FUNC1(suffix,ret,typ1) \\r
+MIKMODAPI ret VC_/**/suffix (typ1 a) { return VC_/**/suffix/**/_ptr(a); }\r
+\r
+#define VC_PROC2(suffix,typ1,typ2) \\r
+MIKMODAPI void VC_/**/suffix (typ1 a,typ2 b) { VC_/**/suffix/**/_ptr(a,b); }\r
+\r
+#define VC_FUNC2(suffix,ret,typ1,typ2) \\r
+MIKMODAPI ret VC_/**/suffix (typ1 a,typ2 b) { return VC_/**/suffix/**/_ptr(a,b); }\r
+#endif\r
+\r
+VC_FUNC0(Init,BOOL)\r
+VC_PROC0(Exit)\r
+VC_FUNC0(SetNumVoices,BOOL)\r
+VC_FUNC1(SampleSpace,ULONG,int)\r
+VC_FUNC2(SampleLength,ULONG,int,SAMPLE*)\r
+VC_FUNC0(PlayStart,BOOL)\r
+VC_PROC0(PlayStop)\r
+VC_FUNC2(SampleLoad,SWORD,struct SAMPLOAD*,int)\r
+VC_PROC1(SampleUnload,SWORD)\r
+VC_FUNC2(WriteBytes,ULONG,SBYTE*,ULONG)\r
+VC_FUNC2(SilenceBytes,ULONG,SBYTE*,ULONG)\r
+VC_PROC2(VoiceSetVolume,UBYTE,UWORD)\r
+VC_FUNC1(VoiceGetVolume,UWORD,UBYTE)\r
+VC_PROC2(VoiceSetFrequency,UBYTE,ULONG)\r
+VC_FUNC1(VoiceGetFrequency,ULONG,UBYTE)\r
+VC_PROC2(VoiceSetPanning,UBYTE,ULONG)\r
+VC_FUNC1(VoiceGetPanning,ULONG,UBYTE)\r
+ \r
+void VC_VoicePlay(UBYTE a,SWORD b,ULONG c,ULONG d,ULONG e,ULONG f,UWORD g)\r
+{ VC_VoicePlay_ptr(a,b,c,d,e,f,g); }\r
+\r
+VC_PROC1(VoiceStop,UBYTE)\r
+VC_FUNC1(VoiceStopped,BOOL,UBYTE)\r
+VC_FUNC1(VoiceGetPosition,SLONG,UBYTE)\r
+VC_FUNC1(VoiceRealVolume,ULONG,UBYTE)\r
+ \r
+void VC_SetupPointers(void)\r
+{\r
+ if (md_mode&DMODE_HQMIXER) {\r
+ VC_Init_ptr=VC2_Init;\r
+ VC_Exit_ptr=VC2_Exit;\r
+ VC_SetNumVoices_ptr=VC2_SetNumVoices;\r
+ VC_SampleSpace_ptr=VC2_SampleSpace;\r
+ VC_SampleLength_ptr=VC2_SampleLength;\r
+ VC_PlayStart_ptr=VC2_PlayStart;\r
+ VC_PlayStop_ptr=VC2_PlayStop;\r
+ VC_SampleLoad_ptr=VC2_SampleLoad;\r
+ VC_SampleUnload_ptr=VC2_SampleUnload;\r
+ VC_WriteBytes_ptr=VC2_WriteBytes;\r
+ VC_SilenceBytes_ptr=VC2_SilenceBytes;\r
+ VC_VoiceSetVolume_ptr=VC2_VoiceSetVolume;\r
+ VC_VoiceGetVolume_ptr=VC2_VoiceGetVolume;\r
+ VC_VoiceSetFrequency_ptr=VC2_VoiceSetFrequency;\r
+ VC_VoiceGetFrequency_ptr=VC2_VoiceGetFrequency;\r
+ VC_VoiceSetPanning_ptr=VC2_VoiceSetPanning;\r
+ VC_VoiceGetPanning_ptr=VC2_VoiceGetPanning;\r
+ VC_VoicePlay_ptr=VC2_VoicePlay;\r
+ VC_VoiceStop_ptr=VC2_VoiceStop;\r
+ VC_VoiceStopped_ptr=VC2_VoiceStopped;\r
+ VC_VoiceGetPosition_ptr=VC2_VoiceGetPosition;\r
+ VC_VoiceRealVolume_ptr=VC2_VoiceRealVolume;\r
+ } else {\r
+ VC_Init_ptr=VC1_Init;\r
+ VC_Exit_ptr=VC1_Exit;\r
+ VC_SetNumVoices_ptr=VC1_SetNumVoices;\r
+ VC_SampleSpace_ptr=VC1_SampleSpace;\r
+ VC_SampleLength_ptr=VC1_SampleLength;\r
+ VC_PlayStart_ptr=VC1_PlayStart;\r
+ VC_PlayStop_ptr=VC1_PlayStop;\r
+ VC_SampleLoad_ptr=VC1_SampleLoad;\r
+ VC_SampleUnload_ptr=VC1_SampleUnload;\r
+ VC_WriteBytes_ptr=VC1_WriteBytes;\r
+ VC_SilenceBytes_ptr=VC1_SilenceBytes;\r
+ VC_VoiceSetVolume_ptr=VC1_VoiceSetVolume;\r
+ VC_VoiceGetVolume_ptr=VC1_VoiceGetVolume;\r
+ VC_VoiceSetFrequency_ptr=VC1_VoiceSetFrequency;\r
+ VC_VoiceGetFrequency_ptr=VC1_VoiceGetFrequency;\r
+ VC_VoiceSetPanning_ptr=VC1_VoiceSetPanning;\r
+ VC_VoiceGetPanning_ptr=VC1_VoiceGetPanning;\r
+ VC_VoicePlay_ptr=VC1_VoicePlay;\r
+ VC_VoiceStop_ptr=VC1_VoiceStop;\r
+ VC_VoiceStopped_ptr=VC1_VoiceStopped;\r
+ VC_VoiceGetPosition_ptr=VC1_VoiceGetPosition;\r
+ VC_VoiceRealVolume_ptr=VC1_VoiceRealVolume;\r
+ }\r
+}\r
+\r
+#else\r
+\r
+#ifndef _VIRTCH_COMMON_\r
+#define _VIRTCH_COMMON_\r
+\r
+static ULONG samples2bytes(ULONG samples)\r
+{\r
+ if(vc_mode & DMODE_FLOAT) samples <<= 2;\r
+ else if(vc_mode & DMODE_16BITS) samples <<= 1;\r
+ if(vc_mode & DMODE_STEREO) samples <<= 1;\r
+ return samples;\r
+}\r
+\r
+static ULONG bytes2samples(ULONG bytes)\r
+{\r
+ if(vc_mode & DMODE_FLOAT) bytes >>= 2;\r
+ else if(vc_mode & DMODE_16BITS) bytes >>= 1;\r
+ if(vc_mode & DMODE_STEREO) bytes >>= 1;\r
+ return bytes;\r
+}\r
+\r
+/* Fill the buffer with 'todo' bytes of silence (it depends on the mixing mode\r
+ how the buffer is filled) */\r
+ULONG VC1_SilenceBytes(SBYTE* buf,ULONG todo)\r
+{\r
+ todo=samples2bytes(bytes2samples(todo));\r
+\r
+ /* clear the buffer to zero (16 bits signed) or 0x80 (8 bits unsigned) */\r
+ if(vc_mode & DMODE_FLOAT)\r
+ memset(buf,0,todo);\r
+ else if(vc_mode & DMODE_16BITS)\r
+ memset(buf,0,todo);\r
+ else\r
+ memset(buf,0x80,todo);\r
+\r
+ return todo;\r
+}\r
+\r
+void VC1_WriteSamples(SBYTE*,ULONG);\r
+\r
+/* Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of SBYTES\r
+ actually written to 'buf' (which is rounded to number of samples that fit\r
+ into 'todo' bytes). */\r
+ULONG VC1_WriteBytes(SBYTE* buf,ULONG todo)\r
+{\r
+ if(!vc_softchn)\r
+ return VC1_SilenceBytes(buf,todo);\r
+\r
+ todo = bytes2samples(todo);\r
+ VC1_WriteSamples(buf,todo);\r
+\r
+ return samples2bytes(todo);\r
+}\r
+\r
+void VC1_Exit(void)\r
+{\r
+ if(vc_tickbuf) free(vc_tickbuf);\r
+ if(vinf) free(vinf);\r
+ if(Samples) free(Samples);\r
+\r
+ vc_tickbuf = NULL;\r
+ vinf = NULL;\r
+ Samples = NULL;\r
+ \r
+ VC_SetupPointers();\r
+}\r
+\r
+UWORD VC1_VoiceGetVolume(UBYTE voice)\r
+{\r
+ return vinf[voice].vol;\r
+}\r
+\r
+ULONG VC1_VoiceGetPanning(UBYTE voice)\r
+{\r
+ return vinf[voice].pan;\r
+}\r
+\r
+void VC1_VoiceSetFrequency(UBYTE voice,ULONG frq)\r
+{\r
+ vinf[voice].frq=frq;\r
+}\r
+\r
+ULONG VC1_VoiceGetFrequency(UBYTE voice)\r
+{\r
+ return vinf[voice].frq;\r
+}\r
+\r
+void VC1_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+ vinf[voice].flags = flags;\r
+ vinf[voice].handle = handle;\r
+ vinf[voice].start = start;\r
+ vinf[voice].size = size;\r
+ vinf[voice].reppos = reppos;\r
+ vinf[voice].repend = repend;\r
+ vinf[voice].kick = 1;\r
+}\r
+\r
+void VC1_VoiceStop(UBYTE voice)\r
+{\r
+ vinf[voice].active = 0;\r
+} \r
+\r
+BOOL VC1_VoiceStopped(UBYTE voice)\r
+{\r
+ return(vinf[voice].active==0);\r
+}\r
+\r
+SLONG VC1_VoiceGetPosition(UBYTE voice)\r
+{\r
+ return(vinf[voice].current>>FRACBITS);\r
+}\r
+\r
+void VC1_VoiceSetVolume(UBYTE voice,UWORD vol)\r
+{ \r
+ /* protect against clicks if volume variation is too high */\r
+ if(abs((int)vinf[voice].vol-(int)vol)>32)\r
+ vinf[voice].rampvol=CLICK_BUFFER;\r
+ vinf[voice].vol=vol;\r
+}\r
+\r
+void VC1_VoiceSetPanning(UBYTE voice,ULONG pan)\r
+{\r
+ /* protect against clicks if panning variation is too high */\r
+ if(abs((int)vinf[voice].pan-(int)pan)>48)\r
+ vinf[voice].rampvol=CLICK_BUFFER;\r
+ vinf[voice].pan=pan;\r
+}\r
+\r
+/*========== External mixer interface */\r
+\r
+void VC1_SampleUnload(SWORD handle)\r
+{\r
+ if (handle<MAXSAMPLEHANDLES) {\r
+ if (Samples[handle])\r
+ free(Samples[handle]);\r
+ Samples[handle]=NULL;\r
+ }\r
+}\r
+\r
+SWORD VC1_SampleLoad(struct SAMPLOAD* sload,int type)\r
+{\r
+ SAMPLE *s = sload->sample;\r
+ int handle;\r
+ ULONG t, length,loopstart,loopend;\r
+\r
+ if(type==MD_HARDWARE) return -1;\r
+\r
+ /* Find empty slot to put sample address in */\r
+ for(handle=0;handle<MAXSAMPLEHANDLES;handle++)\r
+ if(!Samples[handle]) break;\r
+\r
+ if(handle==MAXSAMPLEHANDLES) {\r
+ _mm_errno = MMERR_OUT_OF_HANDLES;\r
+ return -1;\r
+ }\r
+ \r
+ /* Reality check for loop settings */\r
+ if (s->loopend > s->length)\r
+ s->loopend = s->length;\r
+ if (s->loopstart >= s->loopend)\r
+ s->flags &= ~SF_LOOP;\r
+\r
+ length = s->length;\r
+ loopstart = s->loopstart;\r
+ loopend = s->loopend;\r
+\r
+ SL_SampleSigned(sload);\r
+ SL_Sample8to16(sload);\r
+\r
+ if(!(Samples[handle]=(SWORD*)_mm_malloc((length+20)<<1))) {\r
+ _mm_errno = MMERR_SAMPLE_TOO_BIG;\r
+ return -1;\r
+ }\r
+\r
+ /* read sample into buffer */\r
+ if (SL_Load(Samples[handle],sload,length))\r
+ return -1;\r
+\r
+ /* Unclick sample */\r
+ if(s->flags & SF_LOOP) {\r
+ if(s->flags & SF_BIDI)\r
+ for(t=0;t<16;t++)\r
+ Samples[handle][loopend+t]=Samples[handle][(loopend-t)-1];\r
+ else\r
+ for(t=0;t<16;t++)\r
+ Samples[handle][loopend+t]=Samples[handle][t+loopstart];\r
+ } else\r
+ for(t=0;t<16;t++)\r
+ Samples[handle][t+length]=0;\r
+\r
+ return handle;\r
+}\r
+\r
+ULONG VC1_SampleSpace(int type)\r
+{\r
+ (void)type;\r
+ return vc_memory;\r
+}\r
+\r
+ULONG VC1_SampleLength(int type,SAMPLE* s)\r
+{\r
+ (void)type;\r
+ if (!s) return 0;\r
+\r
+ return (s->length*((s->flags&SF_16BITS)?2:1))+16;\r
+}\r
+\r
+ULONG VC1_VoiceRealVolume(UBYTE voice)\r
+{\r
+ ULONG i,s,size;\r
+ int k,j;\r
+ SWORD *smp;\r
+ SLONG t;\r
+\r
+ t = vinf[voice].current>>FRACBITS;\r
+ if(!vinf[voice].active) return 0;\r
+\r
+ s = vinf[voice].handle;\r
+ size = vinf[voice].size;\r
+\r
+ i=64; t-=64; k=0; j=0;\r
+ if(i>size) i = size;\r
+ if(t<0) t = 0;\r
+ if(t+i > size) t = size-i;\r
+\r
+ i &= ~1; /* make sure it's EVEN. */\r
+\r
+ smp = &Samples[s][t];\r
+ for(;i;i--,smp++) {\r
+ if(k<*smp) k = *smp;\r
+ if(j>*smp) j = *smp;\r
+ }\r
+ return abs(k-j);\r
+}\r
+\r
+#endif\r
+\r
+#endif\r
+\r
+/* ex:set ts=4: */\r