--- /dev/null
+/*\r
+\r
+Name:\r
+VIRTCH.C\r
+\r
+Description:\r
+All-c sample mixing routines, using a 32 bits mixing buffer\r
+\r
+Portability:\r
+All systems - all compilers\r
+\r
+*/\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <malloc.h>\r
+#include "mikmod.h"\r
+\r
+#define FRACBITS 11\r
+#define FRACMASK ((1L<<FRACBITS)-1)\r
+\r
+#define TICKLSIZE 3600\r
+#define TICKWSIZE (TICKLSIZE*2)\r
+#define TICKBSIZE (TICKWSIZE*2)\r
+static SLONG VC_TICKBUF[TICKLSIZE];\r
+\r
+#ifndef min\r
+#define min(a,b) (((a)<(b)) ? (a) : (b))\r
+#endif\r
+\r
+typedef struct{\r
+ UBYTE kick; /* =1 -> sample has to be restarted */\r
+ UBYTE active; /* =1 -> sample is playing */\r
+ UWORD flags; /* 16/8 bits looping/one-shot */\r
+ SWORD handle; /* identifies the sample */\r
+ ULONG start; /* start index */\r
+ ULONG size; /* samplesize */\r
+ ULONG reppos; /* loop start */\r
+ ULONG repend; /* loop end */\r
+ ULONG frq; /* current frequency */\r
+ UBYTE vol; /* current volume */\r
+ UBYTE pan; /* current panning position */\r
+ SLONG current; /* current index in the sample */\r
+ SLONG increment; /* fixed-point increment value */\r
+#ifdef __WATCOMC__\r
+ UWORD lvolsel; /* left volume table selector */\r
+ UWORD rvolsel; /* right volume table selector */\r
+#else\r
+ SLONG lvolmul; /* left volume multiply */\r
+ SLONG rvolmul; /* right volume multiply */\r
+#endif\r
+} VINFO;\r
+\r
+\r
+static VINFO vinf[32];\r
+static VINFO *vnf;\r
+\r
+static UWORD samplesthatfit;\r
+static SLONG idxsize,idxlpos,idxlend,maxvol;\r
+\r
+static long per256;\r
+static int ampshift;\r
+\r
+\r
+#ifdef __WATCOMC__\r
+\r
+static SLONG voltab[65][256];\r
+static UWORD volsel[65];\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+UWORD lvolsel,rvolsel;\r
+\r
+void AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);\r
+#pragma aux AsmStereoNormal \\r
+ parm [esi] [edi] [ebx] [ecx] [edx] \\r
+ modify [eax];\r
+\r
+\r
+void AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);\r
+#pragma aux AsmMonoNormal \\r
+ parm [esi] [edi] [ebx] [ecx] [edx] \\r
+ modify [eax];\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+void freedescriptor(unsigned short selector);\r
+#pragma aux freedescriptor = \\r
+ "mov ax,0001h" \\r
+ "int 31h" \\r
+ parm [bx] \\r
+ modify [ax];\r
+\r
+unsigned short getalias(void);\r
+#pragma aux getalias = \\r
+ "mov ax,cs " \\r
+ "mov bx,ax " \\r
+ "mov ax,000ah" \\r
+ "int 31h " \\r
+ "jnc isok " \\r
+ "xor ax,ax " \\r
+ "isok: " \\r
+ modify [bx] \\r
+ value [ax];\r
+\r
+void setbase(unsigned short selector,unsigned long offset);\r
+#pragma aux setbase = \\r
+ "mov ax,0007h" \\r
+ "mov ecx,edx" \\r
+ "ror ecx,16" \\r
+ "int 31h" \\r
+ parm [bx] [edx] \\r
+ modify [ax ecx] ;\r
+\r
+void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift);\r
+#pragma aux VC_Sample32To16Copy = \\r
+"again:" \\r
+ "mov eax,[esi]" \\r
+ "sar eax,cl" \\r
+ "cmp eax,32767" \\r
+ "jg toobig" \\r
+ "cmp eax,-32768" \\r
+ "jl toosmall" \\r
+"write:" \\r
+ "mov [edi],ax" \\r
+ "add esi,4" \\r
+ "add edi,2" \\r
+ "dec edx" \\r
+ "jnz again" \\r
+ "jmp ready" \\r
+"toobig:" \\r
+ "mov eax,32767" \\r
+ "jmp write" \\r
+"toosmall:" \\r
+ "mov eax,-32768" \\r
+ "jmp write" \\r
+"ready:" \\r
+ parm [esi] [edi] [edx] [cl] \\r
+ modify [eax] ;\r
+\r
+\r
+void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift);\r
+#pragma aux VC_Sample32To8Copy = \\r
+"again:" \\r
+ "mov eax,[esi]" \\r
+ "sar eax,cl" \\r
+ "cmp eax,127" \\r
+ "jg toobig" \\r
+ "cmp eax,-128" \\r
+ "jl toosmall" \\r
+"write:" \\r
+ "add al,080h" \\r
+ "mov [edi],al" \\r
+ "add esi,4" \\r
+ "inc edi" \\r
+ "dec edx" \\r
+ "jnz again" \\r
+ "jmp ready" \\r
+"toobig:" \\r
+ "mov eax,127" \\r
+ "jmp write" \\r
+"toosmall:" \\r
+ "mov eax,-128" \\r
+ "jmp write" \\r
+"ready:" \\r
+ parm [esi] [edi] [edx] [cl] \\r
+ modify [eax] ;\r
+\r
+\r
+#else\r
+\r
+\r
+static SLONG lvolmul,rvolmul;\r
+\r
+\r
+static void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift)\r
+{\r
+ SLONG c;\r
+ int shift=(24-ampshift);\r
+\r
+ while(count--){\r
+ c=*srce >> shift;\r
+ if(c>127) c=127;\r
+ else if(c<-128) c=-128;\r
+ *dest++=c+128;\r
+ srce++;\r
+ }\r
+}\r
+\r
+\r
+static void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift)\r
+{\r
+ SLONG c;\r
+ int shift=(16-ampshift);\r
+\r
+ while(count--){\r
+ c=*srce >> shift;\r
+ if(c>32767) c=32767;\r
+ else if(c<-32768) c=-32768;\r
+ *dest++=c;\r
+ srce++;\r
+ }\r
+}\r
+\r
+#endif\r
+\r
+\r
+static SLONG fraction2long(ULONG dividend,UWORD divisor)\r
+/*\r
+ Converts the fraction 'dividend/divisor' into a fixed point longword.\r
+*/\r
+{\r
+ ULONG whole,part;\r
+\r
+ whole=dividend/divisor;\r
+ part=((dividend%divisor)<<FRACBITS)/divisor;\r
+\r
+ return((whole<<FRACBITS)|part);\r
+}\r
+\r
+\r
+static UWORD samples2bytes(UWORD samples)\r
+{\r
+ if(md_mode & DMODE_16BITS) samples<<=1;\r
+ if(md_mode & DMODE_STEREO) samples<<=1;\r
+ return samples;\r
+}\r
+\r
+\r
+static UWORD bytes2samples(UWORD bytes)\r
+{\r
+ if(md_mode & DMODE_16BITS) bytes>>=1;\r
+ if(md_mode & DMODE_STEREO) bytes>>=1;\r
+ return bytes;\r
+}\r
+\r
+\r
+/**************************************************\r
+***************************************************\r
+***************************************************\r
+**************************************************/\r
+\r
+\r
+static SBYTE *Samples[MAXSAMPLEHANDLES];\r
+\r
+\r
+BOOL LargeRead(SBYTE *buffer,ULONG size)\r
+{\r
+ int t;\r
+ ULONG todo;\r
+\r
+ while(size){\r
+ /* how many bytes to load (in chunks of 8000) ? */\r
+\r
+ todo=(size>8000)?8000:size;\r
+\r
+ /* read data */\r
+\r
+ SL_Load(buffer,todo);\r
+ /* and update pointers.. */\r
+\r
+ size-=todo;\r
+ buffer+=todo;\r
+ }\r
+ return 1;\r
+}\r
+\r
+\r
+\r
+SWORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+ int handle;\r
+ ULONG t;\r
+\r
+ SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS);\r
+\r
+ /* Find empty slot to put sample address in */\r
+\r
+ for(handle=0;handle<MAXSAMPLEHANDLES;handle++){\r
+ if(Samples[handle]==NULL) break;\r
+ }\r
+\r
+ if(handle==MAXSAMPLEHANDLES){\r
+ myerr=ERROR_OUT_OF_HANDLES;\r
+ return -1;\r
+ }\r
+\r
+ if((Samples[handle]=(SBYTE *)malloc(length+16))==NULL){\r
+ myerr=ERROR_SAMPLE_TOO_BIG;\r
+ return -1;\r
+ }\r
+\r
+ /* read sample into buffer. */\r
+ LargeRead(Samples[handle],length);\r
+\r
+ /* Unclick samples: */\r
+\r
+ if(flags & SF_LOOP){\r
+ if(flags & SF_BIDI)\r
+ for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][(repend-t)-1];\r
+ else\r
+ for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][t+reppos];\r
+ }\r
+ else{\r
+ for(t=0;t<16;t++) Samples[handle][t+length]=0;\r
+ }\r
+\r
+ return handle;\r
+}\r
+\r
+\r
+\r
+void VC_SampleUnload(SWORD handle)\r
+{\r
+ void *sampleadr=Samples[handle];\r
+\r
+ free(sampleadr);\r
+ Samples[handle]=NULL;\r
+}\r
+\r
+\r
+/**************************************************\r
+***************************************************\r
+***************************************************\r
+**************************************************/\r
+\r
+\r
+#ifndef __WATCOMC__\r
+\r
+\r
+static void (*SampleMix)(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo);\r
+\r
+\r
+static void MixStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+ SBYTE sample;\r
+\r
+ while(todo>0){\r
+ sample=srce[index>>FRACBITS];\r
+ *(dest++)+=lvolmul*sample;\r
+ *(dest++)+=rvolmul*sample;\r
+ index+=increment;\r
+ todo--;\r
+ }\r
+}\r
+\r
+\r
+static void MixMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+ SBYTE sample;\r
+\r
+ while(todo>0){\r
+ sample=srce[index>>FRACBITS];\r
+ *(dest++)+=lvolmul*sample;\r
+ index+=increment;\r
+ todo--;\r
+ }\r
+}\r
+\r
+\r
+static void MixStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+ SWORD sample,a,b;\r
+\r
+ while(todo>0){\r
+ a=srce[index>>FRACBITS];\r
+ b=srce[1+(index>>FRACBITS)];\r
+ sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);\r
+\r
+ *(dest++)+=lvolmul*sample;\r
+ *(dest++)+=rvolmul*sample;\r
+ index+=increment;\r
+ todo--;\r
+ }\r
+}\r
+\r
+\r
+static void MixMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)\r
+{\r
+ SWORD sample,a,b;\r
+\r
+ while(todo>0){\r
+ a=srce[index>>FRACBITS];\r
+ b=srce[1+(index>>FRACBITS)];\r
+ sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);\r
+\r
+ *(dest++)+=lvolmul*sample;\r
+\r
+ index+=increment;\r
+ todo--;\r
+ }\r
+}\r
+\r
+#endif\r
+\r
+\r
+static UWORD NewPredict(SLONG index,SLONG end,SLONG increment,UWORD todo)\r
+/*\r
+ This functions returns the number of resamplings we can do so that:\r
+\r
+ - it never accesses indexes bigger than index 'end'\r
+ - it doesn't do more than 'todo' resamplings\r
+*/\r
+{\r
+ SLONG di;\r
+\r
+ di=(end-index)/increment;\r
+ index+=(di*increment);\r
+\r
+ if(increment<0){\r
+ while(index>=end){\r
+ index+=increment;\r
+ di++;\r
+ }\r
+ }\r
+ else{\r
+ while(index<=end){\r
+ index+=increment;\r
+ di++;\r
+ }\r
+ }\r
+ return ((di<todo) ? di : todo);\r
+}\r
+\r
+\r
+static void VC_AddChannel(SLONG *ptr,UWORD todo)\r
+/*\r
+ Mixes 'todo' stereo or mono samples of the current channel to the tickbuffer.\r
+*/\r
+{\r
+ SLONG end;\r
+ UWORD done,needs;\r
+ SBYTE *s;\r
+\r
+ while(todo>0){\r
+\r
+ /* update the 'current' index so the sample loops, or\r
+ stops playing if it reached the end of the sample */\r
+\r
+ if(vnf->flags&SF_REVERSE){\r
+\r
+ /* The sample is playing in reverse */\r
+\r
+ if(vnf->flags&SF_LOOP){\r
+\r
+ /* the sample is looping, so check if\r
+ it reached the loopstart index */\r
+\r
+ if(vnf->current<idxlpos){\r
+ if(vnf->flags&SF_BIDI){\r
+\r
+ /* sample is doing bidirectional loops, so 'bounce'\r
+ the current index against the idxlpos */\r
+\r
+ vnf->current=idxlpos+(idxlpos-vnf->current);\r
+ vnf->flags&=~SF_REVERSE;\r
+ vnf->increment=-vnf->increment;\r
+ }\r
+ else\r
+ /* normal backwards looping, so set the\r
+ current position to loopend index */\r
+\r
+ vnf->current=idxlend-(idxlpos-vnf->current);\r
+ }\r
+ }\r
+ else{\r
+\r
+ /* the sample is not looping, so check\r
+ if it reached index 0 */\r
+\r
+ if(vnf->current<0){\r
+\r
+ /* playing index reached 0, so stop\r
+ playing this sample */\r
+\r
+ vnf->current=0;\r
+ vnf->active=0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else{\r
+\r
+ /* The sample is playing forward */\r
+\r
+ if(vnf->flags&SF_LOOP){\r
+\r
+ /* the sample is looping, so check if\r
+ it reached the loopend index */\r
+\r
+ if(vnf->current>idxlend){\r
+ if(vnf->flags&SF_BIDI){\r
+\r
+ /* sample is doing bidirectional loops, so 'bounce'\r
+ the current index against the idxlend */\r
+\r
+ vnf->flags|=SF_REVERSE;\r
+ vnf->increment=-vnf->increment;\r
+ vnf->current=idxlend-(vnf->current-idxlend); /* ?? */\r
+ }\r
+ else\r
+ /* normal backwards looping, so set the\r
+ current position to loopend index */\r
+\r
+ vnf->current=idxlpos+(vnf->current-idxlend);\r
+ }\r
+ }\r
+ else{\r
+\r
+ /* sample is not looping, so check\r
+ if it reached the last position */\r
+\r
+ if(vnf->current>idxsize){\r
+\r
+ /* yes, so stop playing this sample */\r
+\r
+ vnf->current=0;\r
+ vnf->active=0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Vraag een far ptr op van het sampleadres\r
+ op byte offset vnf->current, en hoeveel samples\r
+ daarvan geldig zijn (VOORDAT segment overschrijding optreed) */\r
+\r
+ if(!(s=Samples[vnf->handle])){\r
+ vnf->current=0;\r
+ vnf->active=0;\r
+ break;\r
+ }\r
+\r
+ if(vnf->flags & SF_REVERSE)\r
+ end = (vnf->flags & SF_LOOP) ? idxlpos : 0;\r
+ else\r
+ end = (vnf->flags & SF_LOOP) ? idxlend : idxsize;\r
+\r
+ /* Als de sample simpelweg niet beschikbaar is, of als\r
+ sample gestopt moet worden sample stilleggen en stoppen */\r
+ /* mix 'em: */\r
+\r
+ done=NewPredict(vnf->current,end,vnf->increment,todo);\r
+\r
+ if(!done){\r
+/* printf("predict stopped it. current %ld, end %ld\n",vnf->current,end);\r
+*/ vnf->active=0;\r
+ break;\r
+ }\r
+\r
+ /* optimisation: don't mix anything if volume is zero */\r
+\r
+ if(vnf->vol){\r
+#ifdef __WATCOMC__\r
+ if(md_mode & DMODE_STEREO)\r
+ AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done);\r
+ else\r
+ AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done);\r
+#else\r
+ SampleMix(s,ptr,vnf->current,vnf->increment,done);\r
+#endif\r
+ }\r
+ vnf->current+=(vnf->increment*done);\r
+\r
+ todo-=done;\r
+ ptr+=(md_mode & DMODE_STEREO) ? (done<<1) : done;\r
+ }\r
+}\r
+\r
+\r
+\r
+\r
+static void VC_FillTick(SBYTE *buf,UWORD todo)\r
+/*\r
+ Mixes 'todo' samples to 'buf'.. The number of samples has\r
+ to fit into the tickbuffer.\r
+*/\r
+{\r
+ int t;\r
+\r
+ /* clear the mixing buffer: */\r
+\r
+ memset(VC_TICKBUF,0,(md_mode & DMODE_STEREO) ? todo<<3 : todo<<2);\r
+\r
+ for(t=0;t<md_numchn;t++){\r
+ vnf=&vinf[t];\r
+\r
+ if(vnf->active){\r
+ idxsize=(vnf->size<<FRACBITS)-1;\r
+ idxlpos=vnf->reppos<<FRACBITS;\r
+ idxlend=(vnf->repend<<FRACBITS)-1;\r
+#ifdef __WATCOMC__\r
+ lvolsel=vnf->lvolsel;\r
+ rvolsel=vnf->rvolsel;\r
+#else\r
+ lvolmul=vnf->lvolmul;\r
+ rvolmul=vnf->rvolmul;\r
+#endif\r
+ VC_AddChannel(VC_TICKBUF,todo);\r
+ }\r
+ }\r
+\r
+ if(md_mode & DMODE_16BITS)\r
+ VC_Sample32To16Copy(VC_TICKBUF,(SWORD *)buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,16-ampshift);\r
+ else\r
+ VC_Sample32To8Copy(VC_TICKBUF,buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,24-ampshift);\r
+}\r
+\r
+\r
+\r
+static void VC_WritePortion(SBYTE *buf,UWORD todo)\r
+/*\r
+ Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the\r
+ number of samples that fit into VC_TICKBUF, the mixing operation is split\r
+ up into a number of smaller chunks.\r
+*/\r
+{\r
+ UWORD part;\r
+\r
+ /* write 'part' samples to the buffer */\r
+\r
+ while(todo){\r
+ part=min(todo,samplesthatfit);\r
+ VC_FillTick(buf,part);\r
+ buf+=samples2bytes(part);\r
+ todo-=part;\r
+ }\r
+}\r
+\r
+\r
+static UWORD TICKLEFT;\r
+\r
+\r
+void VC_WriteSamples(SBYTE *buf,UWORD todo)\r
+{\r
+ int t;\r
+ UWORD part;\r
+\r
+ while(todo>0){\r
+\r
+ if(TICKLEFT==0){\r
+ md_player();\r
+\r
+ TICKLEFT=(125L*md_mixfreq)/(50L*md_bpm);\r
+\r
+ /* compute volume, frequency counter & panning parameters for each channel. */\r
+\r
+ for(t=0;t<md_numchn;t++){\r
+ int pan,vol,lvol,rvol;\r
+\r
+ if(vinf[t].kick){\r
+ vinf[t].current=(vinf[t].start << FRACBITS);\r
+ vinf[t].active=1;\r
+ vinf[t].kick=0;\r
+ }\r
+\r
+ if(vinf[t].frq==0) vinf[t].active=0;\r
+\r
+ if(vinf[t].active){\r
+ vinf[t].increment=fraction2long(vinf[t].frq,md_mixfreq);\r
+\r
+ if(vinf[t].flags & SF_REVERSE) vinf[t].increment=-vinf[t].increment;\r
+\r
+ vol=vinf[t].vol;\r
+ pan=vinf[t].pan;\r
+\r
+#ifdef __WATCOMC__\r
+ if(md_mode & DMODE_STEREO){\r
+ lvol= ( vol * (255-pan) ) / 255;\r
+ rvol= ( vol * pan ) / 255;\r
+ vinf[t].lvolsel=volsel[lvol];\r
+ vinf[t].rvolsel=volsel[rvol];\r
+ }\r
+ else{\r
+ vinf[t].lvolsel=volsel[vol];\r
+ }\r
+#else\r
+ if(md_mode & DMODE_STEREO){\r
+ lvol= ( vol * (255-pan) ) / 255;\r
+ rvol= ( vol * pan ) / 255;\r
+ vinf[t].lvolmul=(maxvol*lvol)/64;\r
+ vinf[t].rvolmul=(maxvol*rvol)/64;\r
+ }\r
+ else{\r
+ vinf[t].lvolmul=(maxvol*vol)/64;\r
+ }\r
+#endif\r
+ }\r
+ }\r
+ }\r
+\r
+ part=min(TICKLEFT,todo);\r
+\r
+ VC_WritePortion(buf,part);\r
+\r
+ TICKLEFT-=part;\r
+ todo-=part;\r
+\r
+ buf+=samples2bytes(part);\r
+ }\r
+}\r
+\r
+\r
+UWORD VC_WriteBytes(SBYTE *buf,UWORD todo)\r
+/*\r
+ Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of\r
+ SBYTES actually written to 'buf' (which is rounded to number of samples\r
+ that fit into 'todo' bytes).\r
+*/\r
+{\r
+ todo=bytes2samples(todo);\r
+ VC_WriteSamples(buf,todo);\r
+ return samples2bytes(todo);\r
+}\r
+\r
+\r
+void VC_SilenceBytes(SBYTE *buf,UWORD todo)\r
+/*\r
+ Fill the buffer with 'todo' bytes of silence (it depends on the mixing\r
+ mode how the buffer is filled)\r
+*/\r
+{\r
+ /* clear the buffer to zero (16 bits\r
+ signed ) or 0x80 (8 bits unsigned) */\r
+\r
+ if(md_mode & DMODE_16BITS)\r
+ memset(buf,0,todo);\r
+ else\r
+ memset(buf,0x80,todo);\r
+}\r
+\r
+\r
+void VC_PlayStart(void)\r
+{\r
+ int t;\r
+\r
+ maxvol=16777216L / md_numchn;\r
+\r
+#ifdef __WATCOMC__\r
+ for(t=0;t<65;t++){\r
+ int c;\r
+ SLONG volmul=(maxvol*t)/64;\r
+ for(c=-128;c<128;c++){\r
+ voltab[t][(UBYTE)c]=(SLONG)c*volmul;\r
+ }\r
+ }\r
+#endif\r
+\r
+ /* instead of using a amplifying lookup table, I'm using a simple shift\r
+ amplify now.. amplifying doubles with every extra 4 channels, and also\r
+ doubles in stereo mode.. this seems to give similar volume levels\r
+ across the channel range */\r
+\r
+ ampshift=md_numchn/8;\r
+ if(md_mode & DMODE_STEREO) ampshift++;\r
+\r
+#ifndef __WATCOMC__\r
+ if(md_mode & DMODE_INTERP)\r
+ SampleMix=(md_mode & DMODE_STEREO) ? MixStereoInterp : MixMonoInterp;\r
+ else\r
+ SampleMix=(md_mode & DMODE_STEREO) ? MixStereoNormal : MixMonoNormal;\r
+#endif\r
+\r
+ samplesthatfit=TICKLSIZE;\r
+ if(md_mode & DMODE_STEREO) samplesthatfit>>=1;\r
+ TICKLEFT=0;\r
+}\r
+\r
+\r
+void VC_PlayStop(void)\r
+{\r
+}\r
+\r
+\r
+BOOL VC_Init(void)\r
+{\r
+ int t;\r
+ for(t=0;t<32;t++){\r
+ vinf[t].current=0;\r
+ vinf[t].flags=0;\r
+ vinf[t].handle=0;\r
+ vinf[t].kick=0;\r
+ vinf[t].active=0;\r
+ vinf[t].frq=10000;\r
+ vinf[t].vol=0;\r
+ vinf[t].pan=(t&1)?0:255;\r
+ }\r
+\r
+#ifdef __WATCOMC__\r
+ if(md_mode & DMODE_INTERP) md_mode&=~DMODE_INTERP;\r
+\r
+ for(t=0;t<65;t++) volsel[t]=0;\r
+\r
+ for(t=0;t<65;t++){\r
+ if(!(volsel[t]=getalias())) return 0;\r
+ setbase(volsel[t],(ULONG)voltab[t]);\r
+ }\r
+#endif\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+void VC_Exit(void)\r
+{\r
+#ifdef __WATCOMC__\r
+ int t;\r
+ for(t=0;t<65;t++){\r
+ if(volsel[t]) freedescriptor(volsel[t]);\r
+ }\r
+#endif\r
+}\r
+\r
+\r
+void VC_VoiceSetVolume(UBYTE voice,UBYTE vol)\r
+{\r
+ vinf[voice].vol=vol;\r
+}\r
+\r
+\r
+void VC_VoiceSetFrequency(UBYTE voice,ULONG frq)\r
+{\r
+ vinf[voice].frq=frq;\r
+}\r
+\r
+\r
+void VC_VoiceSetPanning(UBYTE voice,UBYTE pan)\r
+{\r
+ vinf[voice].pan=pan;\r
+}\r
+\r
+\r
+void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)\r
+{\r
+ if(start>=size) return;\r
+\r
+ if(flags&SF_LOOP){\r
+ if(repend>size) repend=size; /* repend can't be bigger than size */\r
+ }\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