X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Foldmik%2Fsrc%2Fvirtch.c;fp=libs%2Foldmik%2Fsrc%2Fvirtch.c;h=8f7e35776350208eb29b41943b413390e14e7157;hp=0000000000000000000000000000000000000000;hb=77db1ca18d5446dcda9e524261399b63c2cd1813;hpb=a714b8c4811627d874934b0a0387b8cb27fc5921 diff --git a/libs/oldmik/src/virtch.c b/libs/oldmik/src/virtch.c new file mode 100644 index 0000000..8f7e357 --- /dev/null +++ b/libs/oldmik/src/virtch.c @@ -0,0 +1,852 @@ +/* + +Name: +VIRTCH.C + +Description: +All-c sample mixing routines, using a 32 bits mixing buffer + +Portability: +All systems - all compilers + +*/ +#include +#include +#include +#include +#include "mikmod.h" + +#define FRACBITS 11 +#define FRACMASK ((1L< sample has to be restarted */ + UBYTE active; /* =1 -> sample is playing */ + UWORD flags; /* 16/8 bits looping/one-shot */ + SWORD handle; /* identifies the sample */ + ULONG start; /* start index */ + ULONG size; /* samplesize */ + ULONG reppos; /* loop start */ + ULONG repend; /* loop end */ + ULONG frq; /* current frequency */ + UBYTE vol; /* current volume */ + UBYTE pan; /* current panning position */ + SLONG current; /* current index in the sample */ + SLONG increment; /* fixed-point increment value */ +#ifdef __WATCOMC__ + UWORD lvolsel; /* left volume table selector */ + UWORD rvolsel; /* right volume table selector */ +#else + SLONG lvolmul; /* left volume multiply */ + SLONG rvolmul; /* right volume multiply */ +#endif +} VINFO; + + +static VINFO vinf[32]; +static VINFO *vnf; + +static UWORD samplesthatfit; +static SLONG idxsize,idxlpos,idxlend,maxvol; + +static long per256; +static int ampshift; + + +#ifdef __WATCOMC__ + +static SLONG voltab[65][256]; +static UWORD volsel[65]; + +#ifdef __cplusplus +extern "C" { +#endif + +UWORD lvolsel,rvolsel; + +void AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo); +#pragma aux AsmStereoNormal \ + parm [esi] [edi] [ebx] [ecx] [edx] \ + modify [eax]; + + +void AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo); +#pragma aux AsmMonoNormal \ + parm [esi] [edi] [ebx] [ecx] [edx] \ + modify [eax]; + +#ifdef __cplusplus +} +#endif + +void freedescriptor(unsigned short selector); +#pragma aux freedescriptor = \ + "mov ax,0001h" \ + "int 31h" \ + parm [bx] \ + modify [ax]; + +unsigned short getalias(void); +#pragma aux getalias = \ + "mov ax,cs " \ + "mov bx,ax " \ + "mov ax,000ah" \ + "int 31h " \ + "jnc isok " \ + "xor ax,ax " \ + "isok: " \ + modify [bx] \ + value [ax]; + +void setbase(unsigned short selector,unsigned long offset); +#pragma aux setbase = \ + "mov ax,0007h" \ + "mov ecx,edx" \ + "ror ecx,16" \ + "int 31h" \ + parm [bx] [edx] \ + modify [ax ecx] ; + +void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift); +#pragma aux VC_Sample32To16Copy = \ +"again:" \ + "mov eax,[esi]" \ + "sar eax,cl" \ + "cmp eax,32767" \ + "jg toobig" \ + "cmp eax,-32768" \ + "jl toosmall" \ +"write:" \ + "mov [edi],ax" \ + "add esi,4" \ + "add edi,2" \ + "dec edx" \ + "jnz again" \ + "jmp ready" \ +"toobig:" \ + "mov eax,32767" \ + "jmp write" \ +"toosmall:" \ + "mov eax,-32768" \ + "jmp write" \ +"ready:" \ + parm [esi] [edi] [edx] [cl] \ + modify [eax] ; + + +void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift); +#pragma aux VC_Sample32To8Copy = \ +"again:" \ + "mov eax,[esi]" \ + "sar eax,cl" \ + "cmp eax,127" \ + "jg toobig" \ + "cmp eax,-128" \ + "jl toosmall" \ +"write:" \ + "add al,080h" \ + "mov [edi],al" \ + "add esi,4" \ + "inc edi" \ + "dec edx" \ + "jnz again" \ + "jmp ready" \ +"toobig:" \ + "mov eax,127" \ + "jmp write" \ +"toosmall:" \ + "mov eax,-128" \ + "jmp write" \ +"ready:" \ + parm [esi] [edi] [edx] [cl] \ + modify [eax] ; + + +#else + + +static SLONG lvolmul,rvolmul; + + +static void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift) +{ + SLONG c; + int shift=(24-ampshift); + + while(count--){ + c=*srce >> shift; + if(c>127) c=127; + else if(c<-128) c=-128; + *dest++=c+128; + srce++; + } +} + + +static void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift) +{ + SLONG c; + int shift=(16-ampshift); + + while(count--){ + c=*srce >> shift; + if(c>32767) c=32767; + else if(c<-32768) c=-32768; + *dest++=c; + srce++; + } +} + +#endif + + +static SLONG fraction2long(ULONG dividend,UWORD divisor) +/* + Converts the fraction 'dividend/divisor' into a fixed point longword. +*/ +{ + ULONG whole,part; + + whole=dividend/divisor; + part=((dividend%divisor)<>=1; + if(md_mode & DMODE_STEREO) bytes>>=1; + return bytes; +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +static SBYTE *Samples[MAXSAMPLEHANDLES]; + + +BOOL LargeRead(SBYTE *buffer,ULONG size) +{ + int t; + ULONG todo; + + while(size){ + /* how many bytes to load (in chunks of 8000) ? */ + + todo=(size>8000)?8000:size; + + /* read data */ + + SL_Load(buffer,todo); + /* and update pointers.. */ + + size-=todo; + buffer+=todo; + } + return 1; +} + + + +SWORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags) +{ + int handle; + ULONG t; + + SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS); + + /* Find empty slot to put sample address in */ + + for(handle=0;handle0){ + sample=srce[index>>FRACBITS]; + *(dest++)+=lvolmul*sample; + *(dest++)+=rvolmul*sample; + index+=increment; + todo--; + } +} + + +static void MixMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo) +{ + SBYTE sample; + + while(todo>0){ + sample=srce[index>>FRACBITS]; + *(dest++)+=lvolmul*sample; + index+=increment; + todo--; + } +} + + +static void MixStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo) +{ + SWORD sample,a,b; + + while(todo>0){ + a=srce[index>>FRACBITS]; + b=srce[1+(index>>FRACBITS)]; + sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS); + + *(dest++)+=lvolmul*sample; + *(dest++)+=rvolmul*sample; + index+=increment; + todo--; + } +} + + +static void MixMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo) +{ + SWORD sample,a,b; + + while(todo>0){ + a=srce[index>>FRACBITS]; + b=srce[1+(index>>FRACBITS)]; + sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS); + + *(dest++)+=lvolmul*sample; + + index+=increment; + todo--; + } +} + +#endif + + +static UWORD NewPredict(SLONG index,SLONG end,SLONG increment,UWORD todo) +/* + This functions returns the number of resamplings we can do so that: + + - it never accesses indexes bigger than index 'end' + - it doesn't do more than 'todo' resamplings +*/ +{ + SLONG di; + + di=(end-index)/increment; + index+=(di*increment); + + if(increment<0){ + while(index>=end){ + index+=increment; + di++; + } + } + else{ + while(index<=end){ + index+=increment; + di++; + } + } + return ((di0){ + + /* update the 'current' index so the sample loops, or + stops playing if it reached the end of the sample */ + + if(vnf->flags&SF_REVERSE){ + + /* The sample is playing in reverse */ + + if(vnf->flags&SF_LOOP){ + + /* the sample is looping, so check if + it reached the loopstart index */ + + if(vnf->currentflags&SF_BIDI){ + + /* sample is doing bidirectional loops, so 'bounce' + the current index against the idxlpos */ + + vnf->current=idxlpos+(idxlpos-vnf->current); + vnf->flags&=~SF_REVERSE; + vnf->increment=-vnf->increment; + } + else + /* normal backwards looping, so set the + current position to loopend index */ + + vnf->current=idxlend-(idxlpos-vnf->current); + } + } + else{ + + /* the sample is not looping, so check + if it reached index 0 */ + + if(vnf->current<0){ + + /* playing index reached 0, so stop + playing this sample */ + + vnf->current=0; + vnf->active=0; + break; + } + } + } + else{ + + /* The sample is playing forward */ + + if(vnf->flags&SF_LOOP){ + + /* the sample is looping, so check if + it reached the loopend index */ + + if(vnf->current>idxlend){ + if(vnf->flags&SF_BIDI){ + + /* sample is doing bidirectional loops, so 'bounce' + the current index against the idxlend */ + + vnf->flags|=SF_REVERSE; + vnf->increment=-vnf->increment; + vnf->current=idxlend-(vnf->current-idxlend); /* ?? */ + } + else + /* normal backwards looping, so set the + current position to loopend index */ + + vnf->current=idxlpos+(vnf->current-idxlend); + } + } + else{ + + /* sample is not looping, so check + if it reached the last position */ + + if(vnf->current>idxsize){ + + /* yes, so stop playing this sample */ + + vnf->current=0; + vnf->active=0; + break; + } + } + } + + /* Vraag een far ptr op van het sampleadres + op byte offset vnf->current, en hoeveel samples + daarvan geldig zijn (VOORDAT segment overschrijding optreed) */ + + if(!(s=Samples[vnf->handle])){ + vnf->current=0; + vnf->active=0; + break; + } + + if(vnf->flags & SF_REVERSE) + end = (vnf->flags & SF_LOOP) ? idxlpos : 0; + else + end = (vnf->flags & SF_LOOP) ? idxlend : idxsize; + + /* Als de sample simpelweg niet beschikbaar is, of als + sample gestopt moet worden sample stilleggen en stoppen */ + /* mix 'em: */ + + done=NewPredict(vnf->current,end,vnf->increment,todo); + + if(!done){ +/* printf("predict stopped it. current %ld, end %ld\n",vnf->current,end); +*/ vnf->active=0; + break; + } + + /* optimisation: don't mix anything if volume is zero */ + + if(vnf->vol){ +#ifdef __WATCOMC__ + if(md_mode & DMODE_STEREO) + AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done); +#else + SampleMix(s,ptr,vnf->current,vnf->increment,done); +#endif + } + vnf->current+=(vnf->increment*done); + + todo-=done; + ptr+=(md_mode & DMODE_STEREO) ? (done<<1) : done; + } +} + + + + +static void VC_FillTick(SBYTE *buf,UWORD todo) +/* + Mixes 'todo' samples to 'buf'.. The number of samples has + to fit into the tickbuffer. +*/ +{ + int t; + + /* clear the mixing buffer: */ + + memset(VC_TICKBUF,0,(md_mode & DMODE_STEREO) ? todo<<3 : todo<<2); + + for(t=0;tactive){ + idxsize=(vnf->size<reppos<repend<lvolsel; + rvolsel=vnf->rvolsel; +#else + lvolmul=vnf->lvolmul; + rvolmul=vnf->rvolmul; +#endif + VC_AddChannel(VC_TICKBUF,todo); + } + } + + if(md_mode & DMODE_16BITS) + VC_Sample32To16Copy(VC_TICKBUF,(SWORD *)buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,16-ampshift); + else + VC_Sample32To8Copy(VC_TICKBUF,buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,24-ampshift); +} + + + +static void VC_WritePortion(SBYTE *buf,UWORD todo) +/* + Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the + number of samples that fit into VC_TICKBUF, the mixing operation is split + up into a number of smaller chunks. +*/ +{ + UWORD part; + + /* write 'part' samples to the buffer */ + + while(todo){ + part=min(todo,samplesthatfit); + VC_FillTick(buf,part); + buf+=samples2bytes(part); + todo-=part; + } +} + + +static UWORD TICKLEFT; + + +void VC_WriteSamples(SBYTE *buf,UWORD todo) +{ + int t; + UWORD part; + + while(todo>0){ + + if(TICKLEFT==0){ + md_player(); + + TICKLEFT=(125L*md_mixfreq)/(50L*md_bpm); + + /* compute volume, frequency counter & panning parameters for each channel. */ + + for(t=0;t>=1; + TICKLEFT=0; +} + + +void VC_PlayStop(void) +{ +} + + +BOOL VC_Init(void) +{ + int t; + for(t=0;t<32;t++){ + vinf[t].current=0; + vinf[t].flags=0; + vinf[t].handle=0; + vinf[t].kick=0; + vinf[t].active=0; + vinf[t].frq=10000; + vinf[t].vol=0; + vinf[t].pan=(t&1)?0:255; + } + +#ifdef __WATCOMC__ + if(md_mode & DMODE_INTERP) md_mode&=~DMODE_INTERP; + + for(t=0;t<65;t++) volsel[t]=0; + + for(t=0;t<65;t++){ + if(!(volsel[t]=getalias())) return 0; + setbase(volsel[t],(ULONG)voltab[t]); + } +#endif + + return 1; +} + + +void VC_Exit(void) +{ +#ifdef __WATCOMC__ + int t; + for(t=0;t<65;t++){ + if(volsel[t]) freedescriptor(volsel[t]); + } +#endif +} + + +void VC_VoiceSetVolume(UBYTE voice,UBYTE vol) +{ + vinf[voice].vol=vol; +} + + +void VC_VoiceSetFrequency(UBYTE voice,ULONG frq) +{ + vinf[voice].frq=frq; +} + + +void VC_VoiceSetPanning(UBYTE voice,UBYTE pan) +{ + vinf[voice].pan=pan; +} + + +void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags) +{ + if(start>=size) return; + + if(flags&SF_LOOP){ + if(repend>size) repend=size; /* repend can't be bigger than size */ + } + + vinf[voice].flags=flags; + vinf[voice].handle=handle; + vinf[voice].start=start; + vinf[voice].size=size; + vinf[voice].reppos=reppos; + vinf[voice].repend=repend; + vinf[voice].kick=1; +}