home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ELYVER10.ZIP / MIKXMAS.ZIP / source / virtch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-12  |  17.8 KB  |  853 lines

  1. /*
  2.  
  3. Name:
  4. VIRTCH.C
  5.  
  6. Description:
  7. All-c sample mixing routines, using a 32 bits mixing buffer
  8.  
  9. Portability:
  10. All systems - all compilers
  11.  
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <malloc.h>
  17. #include "mikmod.h"
  18.  
  19. #define FRACBITS 11
  20. #define FRACMASK ((1L<<FRACBITS)-1)
  21.  
  22. #define TICKLSIZE 3600
  23. #define TICKWSIZE (TICKLSIZE*2)
  24. #define TICKBSIZE (TICKWSIZE*2)
  25. static SLONG VC_TICKBUF[TICKLSIZE];
  26.  
  27. #ifndef min
  28. #define min(a,b) (((a)<(b)) ? (a) : (b))
  29. #endif
  30.  
  31. typedef struct{
  32.     UBYTE kick;                     /* =1 -> sample has to be restarted */
  33.     UBYTE active;                   /* =1 -> sample is playing */
  34.     UWORD flags;                    /* 16/8 bits looping/one-shot */
  35.     SWORD handle;                  /* identifies the sample */
  36.     ULONG start;                    /* start index */
  37.     ULONG size;                     /* samplesize */
  38.     ULONG reppos;                   /* loop start */
  39.     ULONG repend;                   /* loop end */
  40.     ULONG frq;                      /* current frequency */
  41.     UBYTE vol;                      /* current volume */
  42.     UBYTE pan;                        /* current panning position */
  43.     SLONG current;                  /* current index in the sample */
  44.     SLONG increment;                 /* fixed-point increment value */
  45. #ifdef __WATCOMC__
  46.     UWORD lvolsel;                    /* left volume table selector */
  47.     UWORD rvolsel;                    /* right volume table selector */
  48. #else
  49.     SLONG lvolmul;                    /* left volume multiply */
  50.     SLONG rvolmul;                    /* right volume multiply */
  51. #endif
  52. } VINFO;
  53.  
  54.  
  55. static VINFO vinf[32];
  56. static VINFO *vnf;
  57.  
  58. static UWORD samplesthatfit;
  59. static SLONG idxsize,idxlpos,idxlend,maxvol;
  60.  
  61. static long per256;
  62. static int ampshift;
  63.  
  64.  
  65. #ifdef __WATCOMC__
  66.  
  67. static SLONG voltab[65][256];
  68. static UWORD volsel[65];
  69.  
  70. #ifdef __cplusplus
  71. extern "C" {
  72. #endif
  73.  
  74. UWORD lvolsel,rvolsel;
  75.  
  76. void AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);
  77. #pragma aux AsmStereoNormal    \
  78.         parm [esi] [edi] [ebx] [ecx] [edx] \
  79.         modify [eax];
  80.  
  81.  
  82. void AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,ULONG todo);
  83. #pragma aux AsmMonoNormal     \
  84.         parm [esi] [edi] [ebx] [ecx] [edx] \
  85.         modify [eax];
  86.  
  87. #ifdef __cplusplus
  88. }
  89. #endif
  90.  
  91. void freedescriptor(unsigned short selector);
  92. #pragma aux freedescriptor =    \
  93.     "mov    ax,0001h"       \
  94.     "int    31h"            \
  95.     parm    [bx]            \
  96.     modify  [ax];
  97.  
  98. unsigned short getalias(void);
  99. #pragma aux getalias =          \
  100.     "mov    ax,cs   "       \
  101.     "mov    bx,ax   "       \
  102.     "mov    ax,000ah"       \
  103.     "int    31h     "       \
  104.     "jnc    isok    "       \
  105.     "xor    ax,ax   "       \
  106.     "isok:          "       \
  107.     modify  [bx]            \
  108.     value   [ax];
  109.  
  110. void setbase(unsigned short selector,unsigned long offset);
  111. #pragma aux setbase =           \
  112.     "mov    ax,0007h"       \
  113.     "mov    ecx,edx"        \
  114.     "ror    ecx,16"         \
  115.     "int    31h"            \
  116.     parm    [bx] [edx]      \
  117.     modify  [ax ecx] ;
  118.  
  119. void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift);
  120. #pragma aux VC_Sample32To16Copy =    \
  121. "again:"                    \
  122.     "mov   eax,[esi]"        \
  123.     "sar   eax,cl"          \
  124.     "cmp   eax,32767"        \
  125.     "jg    toobig"             \
  126.     "cmp   eax,-32768"        \
  127.     "jl    toosmall"        \
  128. "write:"                    \
  129.     "mov   [edi],ax"        \
  130.     "add   esi,4"           \
  131.     "add   edi,2"            \
  132.     "dec   edx"               \
  133.     "jnz   again"           \
  134.     "jmp   ready"            \
  135. "toobig:"                   \
  136.     "mov   eax,32767"        \
  137.     "jmp   write"            \
  138. "toosmall:"                 \
  139.     "mov   eax,-32768"        \
  140.     "jmp   write"            \
  141. "ready:"                    \
  142.     parm [esi] [edi] [edx] [cl]    \
  143.     modify [eax] ;
  144.  
  145.  
  146. void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift);
  147. #pragma aux VC_Sample32To8Copy =    \
  148. "again:"                       \
  149.     "mov   eax,[esi]"           \
  150.     "sar   eax,cl"          \
  151.     "cmp   eax,127"         \
  152.     "jg    toobig"             \
  153.     "cmp   eax,-128"        \
  154.     "jl    toosmall"        \
  155. "write:"                    \
  156.     "add   al,080h"         \
  157.     "mov   [edi],al"        \
  158.     "add   esi,4"           \
  159.     "inc   edi"             \
  160.     "dec   edx"             \
  161.     "jnz   again"            \
  162.     "jmp   ready"            \
  163. "toobig:"                   \
  164.     "mov   eax,127"         \
  165.     "jmp   write"            \
  166. "toosmall:"                 \
  167.     "mov   eax,-128"        \
  168.     "jmp   write"            \
  169. "ready:"                    \
  170.     parm [esi] [edi] [edx] [cl]    \
  171.     modify [eax] ;
  172.  
  173.  
  174. #else
  175.  
  176.  
  177. static SLONG lvolmul,rvolmul;
  178.  
  179.  
  180. static void VC_Sample32To8Copy(SLONG *srce,SBYTE *dest,ULONG count,UBYTE shift)
  181. {
  182.     SLONG c;
  183.     int shift=(24-ampshift);
  184.  
  185.     while(count--){
  186.         c=*srce >> shift;
  187.         if(c>127) c=127;
  188.         else if(c<-128) c=-128;
  189.         *dest++=c+128;
  190.         srce++;
  191.     }
  192. }
  193.  
  194.  
  195. static void VC_Sample32To16Copy(SLONG *srce,SWORD *dest,ULONG count,UBYTE shift)
  196. {
  197.     SLONG c;
  198.     int shift=(16-ampshift);
  199.  
  200.     while(count--){
  201.         c=*srce >> shift;
  202.         if(c>32767) c=32767;
  203.         else if(c<-32768) c=-32768;
  204.         *dest++=c;
  205.         srce++;
  206.     }
  207. }
  208.  
  209. #endif
  210.  
  211.  
  212. static SLONG fraction2long(ULONG dividend,UWORD divisor)
  213. /*
  214.     Converts the fraction 'dividend/divisor' into a fixed point longword.
  215. */
  216. {
  217.     ULONG whole,part;
  218.  
  219.     whole=dividend/divisor;
  220.     part=((dividend%divisor)<<FRACBITS)/divisor;
  221.  
  222.     return((whole<<FRACBITS)|part);
  223. }
  224.  
  225.  
  226. static UWORD samples2bytes(UWORD samples)
  227. {
  228.     if(md_mode & DMODE_16BITS) samples<<=1;
  229.     if(md_mode & DMODE_STEREO) samples<<=1;
  230.     return samples;
  231. }
  232.  
  233.  
  234. static UWORD bytes2samples(UWORD bytes)
  235. {
  236.     if(md_mode & DMODE_16BITS) bytes>>=1;
  237.     if(md_mode & DMODE_STEREO) bytes>>=1;
  238.     return bytes;
  239. }
  240.  
  241.  
  242. /**************************************************
  243. ***************************************************
  244. ***************************************************
  245. **************************************************/
  246.  
  247.  
  248. static SBYTE *Samples[MAXSAMPLEHANDLES];
  249.  
  250.  
  251. BOOL LargeRead(SBYTE *buffer,ULONG size)
  252. {
  253.     int t;
  254.     ULONG todo;
  255.  
  256.     while(size){
  257.         /* how many bytes to load (in chunks of 8000) ? */
  258.  
  259.         todo=(size>8000)?8000:size;
  260.  
  261.         /* read data */
  262.  
  263.         SL_Load(buffer,todo);
  264.         /* and update pointers.. */
  265.  
  266.         size-=todo;
  267.         buffer+=todo;
  268.     }
  269.     return 1;
  270. }
  271.  
  272.  
  273.  
  274. SWORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags)
  275. {
  276.     int handle;
  277.     ULONG t;
  278.  
  279.     SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS);
  280.  
  281.     /* Find empty slot to put sample address in */
  282.  
  283.     for(handle=0;handle<MAXSAMPLEHANDLES;handle++){
  284.         if(Samples[handle]==NULL) break;
  285.     }
  286.  
  287.     if(handle==MAXSAMPLEHANDLES){
  288.         myerr=ERROR_OUT_OF_HANDLES;
  289.         return -1;
  290.     }
  291.  
  292.         if((Samples[handle]=(SBYTE *)malloc(length+16))==NULL){
  293.         myerr=ERROR_SAMPLE_TOO_BIG;
  294.         return -1;
  295.     }
  296.  
  297.     /* read sample into buffer. */
  298.     LargeRead(Samples[handle],length);
  299.  
  300.     /* Unclick samples: */
  301.  
  302.     if(flags & SF_LOOP){
  303.         if(flags & SF_BIDI)
  304.             for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][(repend-t)-1];
  305.         else
  306.             for(t=0;t<16;t++) Samples[handle][repend+t]=Samples[handle][t+reppos];
  307.     }
  308.     else{
  309.         for(t=0;t<16;t++) Samples[handle][t+length]=0;
  310.     }
  311.  
  312.     return handle;
  313. }
  314.  
  315.  
  316.  
  317. void VC_SampleUnload(SWORD handle)
  318. {
  319.     void *sampleadr=Samples[handle];
  320.  
  321.     free(sampleadr);
  322.     Samples[handle]=NULL;
  323. }
  324.  
  325.  
  326. /**************************************************
  327. ***************************************************
  328. ***************************************************
  329. **************************************************/
  330.  
  331.  
  332. #ifndef __WATCOMC__
  333.  
  334.  
  335. static void (*SampleMix)(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo);
  336.  
  337.  
  338. static void MixStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  339. {
  340.     SBYTE sample;
  341.  
  342.     while(todo>0){
  343.         sample=srce[index>>FRACBITS];
  344.         *(dest++)+=lvolmul*sample;
  345.         *(dest++)+=rvolmul*sample;
  346.         index+=increment;
  347.         todo--;
  348.     }
  349. }
  350.  
  351.  
  352. static void MixMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  353. {
  354.     SBYTE sample;
  355.  
  356.     while(todo>0){
  357.         sample=srce[index>>FRACBITS];
  358.         *(dest++)+=lvolmul*sample;
  359.         index+=increment;
  360.         todo--;
  361.     }
  362. }
  363.  
  364.  
  365. static void MixStereoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  366. {
  367.     SWORD sample,a,b;
  368.  
  369.     while(todo>0){
  370.         a=srce[index>>FRACBITS];
  371.         b=srce[1+(index>>FRACBITS)];
  372.         sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);
  373.  
  374.         *(dest++)+=lvolmul*sample;
  375.         *(dest++)+=rvolmul*sample;
  376.         index+=increment;
  377.         todo--;
  378.     }
  379. }
  380.  
  381.  
  382. static void MixMonoInterp(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,UWORD todo)
  383. {
  384.     SWORD sample,a,b;
  385.  
  386.     while(todo>0){
  387.         a=srce[index>>FRACBITS];
  388.         b=srce[1+(index>>FRACBITS)];
  389.         sample=a+(((long)(b-a)*(index&FRACMASK))>>FRACBITS);
  390.  
  391.         *(dest++)+=lvolmul*sample;
  392.  
  393.         index+=increment;
  394.         todo--;
  395.     }
  396. }
  397.  
  398. #endif
  399.  
  400.  
  401. static UWORD NewPredict(SLONG index,SLONG end,SLONG increment,UWORD todo)
  402. /*
  403.     This functions returns the number of resamplings we can do so that:
  404.  
  405.         - it never accesses indexes bigger than index 'end'
  406.         - it doesn't do more than 'todo' resamplings
  407. */
  408. {
  409.     SLONG di;
  410.  
  411.     di=(end-index)/increment;
  412.     index+=(di*increment);
  413.  
  414.     if(increment<0){
  415.         while(index>=end){
  416.             index+=increment;
  417.             di++;
  418.         }
  419.     }
  420.     else{
  421.         while(index<=end){
  422.             index+=increment;
  423.             di++;
  424.         }
  425.     }
  426.     return ((di<todo) ? di : todo);
  427. }
  428.  
  429.  
  430. static void VC_AddChannel(SLONG *ptr,UWORD todo)
  431. /*
  432.     Mixes 'todo' stereo or mono samples of the current channel to the tickbuffer.
  433. */
  434. {
  435.     SLONG end;
  436.     UWORD done,needs;
  437.         SBYTE *s;
  438.  
  439.     while(todo>0){
  440.  
  441.         /* update the 'current' index so the sample loops, or
  442.            stops playing if it reached the end of the sample */
  443.  
  444.         if(vnf->flags&SF_REVERSE){
  445.  
  446.             /* The sample is playing in reverse */
  447.  
  448.                 if(vnf->flags&SF_LOOP){
  449.  
  450.                     /* the sample is looping, so check if
  451.                        it reached the loopstart index */
  452.  
  453.                     if(vnf->current<idxlpos){
  454.                     if(vnf->flags&SF_BIDI){
  455.  
  456.                         /* sample is doing bidirectional loops, so 'bounce'
  457.                             the current index against the idxlpos */
  458.  
  459.                         vnf->current=idxlpos+(idxlpos-vnf->current);
  460.                         vnf->flags&=~SF_REVERSE;
  461.                         vnf->increment=-vnf->increment;
  462.                     }
  463.                     else
  464.                         /* normal backwards looping, so set the
  465.                             current position to loopend index */
  466.  
  467.                             vnf->current=idxlend-(idxlpos-vnf->current);
  468.                     }
  469.                 }
  470.                 else{
  471.  
  472.                     /* the sample is not looping, so check
  473.                         if it reached index 0 */
  474.  
  475.                     if(vnf->current<0){
  476.  
  477.                         /* playing index reached 0, so stop
  478.                             playing this sample */
  479.  
  480.                         vnf->current=0;
  481.                         vnf->active=0;
  482.                         break;
  483.                     }
  484.                 }
  485.         }
  486.         else{
  487.  
  488.             /* The sample is playing forward */
  489.  
  490.                 if(vnf->flags&SF_LOOP){
  491.  
  492.                     /* the sample is looping, so check if
  493.                         it reached the loopend index */
  494.  
  495.                     if(vnf->current>idxlend){
  496.                         if(vnf->flags&SF_BIDI){
  497.  
  498.                         /* sample is doing bidirectional loops, so 'bounce'
  499.                             the current index against the idxlend */
  500.  
  501.                             vnf->flags|=SF_REVERSE;
  502.                             vnf->increment=-vnf->increment;
  503.                             vnf->current=idxlend-(vnf->current-idxlend); /* ?? */
  504.                         }
  505.                         else
  506.                         /* normal backwards looping, so set the
  507.                             current position to loopend index */
  508.  
  509.                             vnf->current=idxlpos+(vnf->current-idxlend);
  510.                     }
  511.                 }
  512.                 else{
  513.  
  514.                     /* sample is not looping, so check
  515.                         if it reached the last position */
  516.  
  517.                     if(vnf->current>idxsize){
  518.  
  519.                         /* yes, so stop playing this sample */
  520.  
  521.                         vnf->current=0;
  522.                         vnf->active=0;
  523.                         break;
  524.                     }
  525.                 }
  526.         }
  527.  
  528.         /* Vraag een far ptr op van het sampleadres
  529.             op byte offset vnf->current, en hoeveel samples
  530.             daarvan geldig zijn (VOORDAT segment overschrijding optreed) */
  531.  
  532.         if(!(s=Samples[vnf->handle])){
  533.             vnf->current=0;
  534.             vnf->active=0;
  535.             break;
  536.         }
  537.  
  538.         if(vnf->flags & SF_REVERSE)
  539.             end = (vnf->flags & SF_LOOP) ? idxlpos : 0;
  540.         else
  541.             end = (vnf->flags & SF_LOOP) ? idxlend : idxsize;
  542.  
  543.         /* Als de sample simpelweg niet beschikbaar is, of als
  544.             sample gestopt moet worden sample stilleggen en stoppen */
  545.         /* mix 'em: */
  546.  
  547.         done=NewPredict(vnf->current,end,vnf->increment,todo);
  548.  
  549.         if(!done){
  550. /*            printf("predict stopped it. current %ld, end %ld\n",vnf->current,end);
  551. */            vnf->active=0;
  552.             break;
  553.         }
  554.  
  555.         /* optimisation: don't mix anything if volume is zero */
  556.  
  557.         if(vnf->vol){
  558. #ifdef __WATCOMC__
  559.             if(md_mode & DMODE_STEREO)
  560.                 AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done);
  561.             else
  562.                 AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done);
  563. #else
  564.             SampleMix(s,ptr,vnf->current,vnf->increment,done);
  565. #endif
  566.         }
  567.         vnf->current+=(vnf->increment*done);
  568.  
  569.         todo-=done;
  570.         ptr+=(md_mode & DMODE_STEREO) ? (done<<1) : done;
  571.     }
  572. }
  573.  
  574.  
  575.  
  576.  
  577. static void VC_FillTick(SBYTE *buf,UWORD todo)
  578. /*
  579.     Mixes 'todo' samples to 'buf'.. The number of samples has
  580.     to fit into the tickbuffer.
  581. */
  582. {
  583.     int t;
  584.  
  585.     /* clear the mixing buffer: */
  586.  
  587.     memset(VC_TICKBUF,0,(md_mode & DMODE_STEREO) ? todo<<3 : todo<<2);
  588.  
  589.     for(t=0;t<md_numchn;t++){
  590.         vnf=&vinf[t];
  591.  
  592.         if(vnf->active){
  593.             idxsize=(vnf->size<<FRACBITS)-1;
  594.             idxlpos=vnf->reppos<<FRACBITS;
  595.             idxlend=(vnf->repend<<FRACBITS)-1;
  596. #ifdef __WATCOMC__
  597.                         lvolsel=vnf->lvolsel;
  598.                         rvolsel=vnf->rvolsel;
  599. #else
  600.             lvolmul=vnf->lvolmul;
  601.             rvolmul=vnf->rvolmul;
  602. #endif
  603.             VC_AddChannel(VC_TICKBUF,todo);
  604.         }
  605.     }
  606.  
  607.     if(md_mode & DMODE_16BITS)
  608.         VC_Sample32To16Copy(VC_TICKBUF,(SWORD *)buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,16-ampshift);
  609.     else
  610.         VC_Sample32To8Copy(VC_TICKBUF,buf,(md_mode & DMODE_STEREO) ? todo<<1 : todo,24-ampshift);
  611. }
  612.  
  613.  
  614.  
  615. static void VC_WritePortion(SBYTE *buf,UWORD todo)
  616. /*
  617.     Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the
  618.     number of samples that fit into VC_TICKBUF, the mixing operation is split
  619.     up into a number of smaller chunks.
  620. */
  621. {
  622.     UWORD part;
  623.  
  624.     /* write 'part' samples to the buffer */
  625.  
  626.     while(todo){
  627.         part=min(todo,samplesthatfit);
  628.         VC_FillTick(buf,part);
  629.         buf+=samples2bytes(part);
  630.         todo-=part;
  631.     }
  632. }
  633.  
  634.  
  635. static UWORD TICKLEFT;
  636.  
  637.  
  638. void VC_WriteSamples(SBYTE *buf,UWORD todo)
  639. {
  640.     int t;
  641.     UWORD part;
  642.  
  643.     while(todo>0){
  644.  
  645.         if(TICKLEFT==0){
  646.             md_player();
  647.  
  648.             TICKLEFT=(125L*md_mixfreq)/(50L*md_bpm);
  649.  
  650.             /* compute volume, frequency counter & panning parameters for each channel. */
  651.  
  652.             for(t=0;t<md_numchn;t++){
  653.                 int pan,vol,lvol,rvol;
  654.  
  655.                 if(vinf[t].kick){
  656.                     vinf[t].current=(vinf[t].start << FRACBITS);
  657.                     vinf[t].active=1;
  658.                     vinf[t].kick=0;
  659.                 }
  660.  
  661.                 if(vinf[t].frq==0) vinf[t].active=0;
  662.  
  663.                 if(vinf[t].active){
  664.                     vinf[t].increment=fraction2long(vinf[t].frq,md_mixfreq);
  665.  
  666.                     if(vinf[t].flags & SF_REVERSE) vinf[t].increment=-vinf[t].increment;
  667.  
  668.                     vol=vinf[t].vol;
  669.                     pan=vinf[t].pan;
  670.  
  671. #ifdef __WATCOMC__
  672.                     if(md_mode & DMODE_STEREO){
  673.                         lvol= ( vol * (255-pan) ) / 255;
  674.                         rvol= ( vol * pan ) / 255;
  675.                         vinf[t].lvolsel=volsel[lvol];
  676.                         vinf[t].rvolsel=volsel[rvol];
  677.                     }
  678.                     else{
  679.                         vinf[t].lvolsel=volsel[vol];
  680.                     }
  681. #else
  682.                     if(md_mode & DMODE_STEREO){
  683.                         lvol= ( vol * (255-pan) ) / 255;
  684.                         rvol= ( vol * pan ) / 255;
  685.                         vinf[t].lvolmul=(maxvol*lvol)/64;
  686.                         vinf[t].rvolmul=(maxvol*rvol)/64;
  687.                     }
  688.                     else{
  689.                         vinf[t].lvolmul=(maxvol*vol)/64;
  690.                     }
  691. #endif
  692.                 }
  693.             }
  694.         }
  695.  
  696.         part=min(TICKLEFT,todo);
  697.  
  698.         VC_WritePortion(buf,part);
  699.  
  700.         TICKLEFT-=part;
  701.         todo-=part;
  702.  
  703.         buf+=samples2bytes(part);
  704.     }
  705. }
  706.  
  707.  
  708. UWORD VC_WriteBytes(SBYTE *buf,UWORD todo)
  709. /*
  710.     Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of
  711.     SBYTES actually written to 'buf' (which is rounded to number of samples
  712.     that fit into 'todo' bytes).
  713. */
  714. {
  715.     todo=bytes2samples(todo);
  716.     VC_WriteSamples(buf,todo);
  717.     return samples2bytes(todo);
  718. }
  719.  
  720.  
  721. void VC_SilenceBytes(SBYTE *buf,UWORD todo)
  722. /*
  723.     Fill the buffer with 'todo' bytes of silence (it depends on the mixing
  724.     mode how the buffer is filled)
  725. */
  726. {
  727.     /* clear the buffer to zero (16 bits
  728.        signed ) or 0x80 (8 bits unsigned) */
  729.  
  730.     if(md_mode & DMODE_16BITS)
  731.         memset(buf,0,todo);
  732.     else
  733.         memset(buf,0x80,todo);
  734. }
  735.  
  736.  
  737. void VC_PlayStart(void)
  738. {
  739.     int t;
  740.  
  741.     maxvol=16777216L / md_numchn;
  742.  
  743. #ifdef __WATCOMC__
  744.     for(t=0;t<65;t++){
  745.         int c;
  746.         SLONG volmul=(maxvol*t)/64;
  747.         for(c=-128;c<128;c++){
  748.             voltab[t][(UBYTE)c]=(SLONG)c*volmul;
  749.         }
  750.     }
  751. #endif
  752.  
  753.     /* instead of using a amplifying lookup table, I'm using a simple shift
  754.        amplify now.. amplifying doubles with every extra 4 channels, and also
  755.        doubles in stereo mode.. this seems to give similar volume levels
  756.        across the channel range */
  757.  
  758.     ampshift=md_numchn/8;
  759.     if(md_mode & DMODE_STEREO) ampshift++;
  760.  
  761. #ifndef __WATCOMC__
  762.     if(md_mode & DMODE_INTERP)
  763.         SampleMix=(md_mode & DMODE_STEREO) ? MixStereoInterp : MixMonoInterp;
  764.     else
  765.         SampleMix=(md_mode & DMODE_STEREO) ? MixStereoNormal : MixMonoNormal;
  766. #endif
  767.  
  768.     samplesthatfit=TICKLSIZE;
  769.     if(md_mode & DMODE_STEREO) samplesthatfit>>=1;
  770.     TICKLEFT=0;
  771. }
  772.  
  773.  
  774. void VC_PlayStop(void)
  775. {
  776. }
  777.  
  778.  
  779. BOOL VC_Init(void)
  780. {
  781.     int t;
  782.     for(t=0;t<32;t++){
  783.         vinf[t].current=0;
  784.         vinf[t].flags=0;
  785.         vinf[t].handle=0;
  786.         vinf[t].kick=0;
  787.         vinf[t].active=0;
  788.         vinf[t].frq=10000;
  789.         vinf[t].vol=0;
  790.         vinf[t].pan=(t&1)?0:255;
  791.     }
  792.  
  793. #ifdef __WATCOMC__
  794.     if(md_mode & DMODE_INTERP) md_mode&=~DMODE_INTERP;
  795.  
  796.     for(t=0;t<65;t++) volsel[t]=0;
  797.  
  798.     for(t=0;t<65;t++){
  799.         if(!(volsel[t]=getalias())) return 0;
  800.         setbase(volsel[t],(ULONG)voltab[t]);
  801.     }
  802. #endif
  803.  
  804.     return 1;
  805. }
  806.  
  807.  
  808. void VC_Exit(void)
  809. {
  810. #ifdef __WATCOMC__
  811.     int t;
  812.     for(t=0;t<65;t++){
  813.         if(volsel[t]) freedescriptor(volsel[t]);
  814.     }
  815. #endif
  816. }
  817.  
  818.  
  819. void VC_VoiceSetVolume(UBYTE voice,UBYTE vol)
  820. {
  821.     vinf[voice].vol=vol;
  822. }
  823.  
  824.  
  825. void VC_VoiceSetFrequency(UBYTE voice,ULONG frq)
  826. {
  827.     vinf[voice].frq=frq;
  828. }
  829.  
  830.  
  831. void VC_VoiceSetPanning(UBYTE voice,UBYTE pan)
  832. {
  833.     vinf[voice].pan=pan;
  834. }
  835.  
  836.  
  837. void VC_VoicePlay(UBYTE voice,SWORD handle,ULONG start,ULONG size,ULONG reppos,ULONG repend,UWORD flags)
  838. {
  839.     if(start>=size) return;
  840.  
  841.     if(flags&SF_LOOP){
  842.         if(repend>size) repend=size;    /* repend can't be bigger than size */
  843.     }
  844.  
  845.     vinf[voice].flags=flags;
  846.     vinf[voice].handle=handle;
  847.     vinf[voice].start=start;
  848.     vinf[voice].size=size;
  849.     vinf[voice].reppos=reppos;
  850.     vinf[voice].repend=repend;
  851.     vinf[voice].kick=1;
  852. }
  853.