home *** CD-ROM | disk | FTP | other *** search
/ PC Loisirs 18 / cd.iso / sharewar / mikm202 / source / virtch32 / virtch32.c < prev   
Encoding:
C/C++ Source or Header  |  1995-09-18  |  9.6 KB  |  506 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <dos.h>
  5. #include <io.h>
  6. #include <malloc.h>
  7. #include <mem.h>
  8. #include "mdriver.h"
  9.  
  10. #include "vc.h"
  11.  
  12. char ampbuf[16384];
  13. WORD voltab[65][256];
  14. #define MAXTICKSIZE 1800                // max number of samples in temporary buffer
  15.  
  16. #define samples2bytes(x) (x<<samplesize[md_mode])
  17. #define bytes2samples(x) (x>>samplesize[md_mode])
  18.  
  19. WORD VC_TICKBUF[MAXTICKSIZE*2]; // tickbuffer
  20.  
  21. int samplesize[]={ 0,1,1,2 };
  22.  
  23. GHOLD *ghl;
  24.  
  25.  
  26.  
  27. void VC_MemSet(UWORD *buf,UWORD data,UWORD count)
  28. {
  29.     while(count--) *(buf++)=data;
  30. }
  31.  
  32.  
  33. void VC_Sample16To8Copy(UWORD *srce,BYTE *dest,UWORD count)
  34. {
  35.     while(count){
  36.         *dest=ampbuf[*srce];
  37.         dest++;
  38.         srce++;
  39.         count--;
  40.     }
  41. }
  42.  
  43.  
  44. UWORD VC_ResampleMixMono(UBYTE *srce,WORD *dest,WORD *volt,UWORD todo,ULONG incr,UWORD *itrr)
  45. {
  46.     register ULONG index=*itrr;
  47.  
  48.     while(todo){
  49.         *(dest++)+=volt[srce[index>>16]];
  50.         index+=incr;
  51.         todo--;
  52.     }
  53.     *itrr=(index&0xffff);
  54.     return (index>>16);
  55. }
  56.  
  57.  
  58. UWORD VC_ResampleMixStereo(UBYTE *srce,WORD *dest,WORD *lvolt,WORD *rvolt,UWORD todo,ULONG incr,UWORD *itrr)
  59. {
  60.     register ULONG index=*itrr;
  61.     register UBYTE sample;
  62.  
  63.     while(todo){
  64.         sample=srce[index>>16];
  65.         *(dest++)+=lvolt[sample];
  66.         *(dest++)+=rvolt[sample];
  67.         index+=incr;
  68.         todo--;
  69.     }
  70.     *itrr=(index&0xffff);
  71.     return (index>>16);
  72. }
  73.  
  74.  
  75. ULONG fraction2long(ULONG dividend,UWORD divisor)
  76. {
  77.     ULONG whole,part;
  78.  
  79.     whole=dividend/divisor;
  80.     part=((dividend%divisor)<<16)/divisor;
  81.  
  82.     return((whole<<16)|part);
  83. }
  84.  
  85.  
  86. /**************************************************
  87. ***************************************************
  88. ***************************************************
  89. **************************************************/
  90.  
  91.  
  92. #define MAXHANDLE 160           // should be enough for now
  93.  
  94. char *Samples[MAXHANDLE];
  95.  
  96.  
  97. BOOL LargeRead(char *buffer,ULONG size)
  98. {
  99.     int t;
  100.     ULONG todo;
  101.  
  102.     // No ems.. so do a normal, dull memory load..
  103.  
  104.     while(size){
  105.  
  106.         // how many bytes to load (in chunks of 8000) ?
  107.  
  108.         todo=(size>8000)?8000:size;
  109.  
  110.         // read data
  111.  
  112.         SL_Load(buffer,todo);
  113.  
  114.         // and update pointers..
  115.  
  116.         size-=todo;
  117.         buffer+=todo;
  118.     }
  119.     return 1;
  120. }
  121.  
  122.  
  123.  
  124. WORD VC_SampleLoad(FILE *fp,ULONG length,ULONG reppos,ULONG repend,UWORD flags)
  125. {
  126.     int handle,emshandle,t;
  127.  
  128.     SL_Init(fp,flags,(flags|SF_SIGNED)&~SF_16BITS);
  129.  
  130.     // Find empty slot to put sample address in
  131.  
  132.     for(handle=0;handle<MAXHANDLE;handle++){
  133.         if(Samples[handle]==NULL) break;
  134.     }
  135.  
  136.     if(handle==MAXHANDLE){
  137.         myerr=ERROR_OUT_OF_HANDLES;
  138.         return -1;
  139.     }
  140.  
  141.     if((Samples[handle]=malloc(length))==NULL){
  142.         myerr=ERROR_SAMPLE_TOO_BIG;
  143.         return -1;
  144.     }
  145.  
  146.     // read sample into buffer.
  147.  
  148.     LargeRead(Samples[handle],length);
  149.  
  150.     return handle;
  151. }
  152.  
  153.  
  154. void VC_SampleUnload(WORD handle)
  155. {
  156.     free(Samples[handle]);
  157.     Samples[handle]=NULL;
  158. }
  159.  
  160.  
  161. /**************************************************
  162. ***************************************************
  163. ***************************************************
  164. **************************************************/
  165.  
  166.  
  167.  
  168. ULONG VC_NewSampleAddress(char **s)
  169. {
  170.     ULONG avail2;
  171.  
  172.     if(ghl->flags&SF_LOOP){
  173.         if(ghl->current>=ghl->repend){
  174.             ghl->current=ghl->reppos;
  175.         }
  176.     }
  177.     else{
  178.         if(ghl->current>=ghl->size){
  179.             ghl->current=0;
  180.             ghl->active=0;
  181.             ghl->iter=0;
  182.             return 0;
  183.         }
  184.     }
  185.  
  186.     /* avail1 is the number of samples thats available before
  187.        segment wrap */
  188.  
  189.     *s=Samples[ghl->handle]+ghl->current;
  190.  
  191.     /* avail2 is the number of samples available before the end
  192.        of the sample, or before the end of the loop */
  193.  
  194.     if(ghl->flags&SF_LOOP){
  195.         avail2=(ghl->repend)-(ghl->current);
  196.     }
  197.     else{
  198.         avail2=(ghl->size)-(ghl->current);
  199.     }
  200.  
  201.     return(avail2);
  202. }
  203.  
  204.  
  205.  
  206. UWORD NewPredict(ULONG avail,UWORD todo,ULONG increment,UWORD iter)
  207. /*
  208.     The returnvalue is the number of times we can resample a sample so that:
  209.  
  210.         - the number of samples written doesn't exceed 'todo'
  211.         - the number of samples read doesn't exceed 'avail'
  212. */
  213. {
  214.     long tmp;
  215.     ULONG di=0;
  216.  
  217.     if(avail==0) return 0;
  218.     if(todo==0) return 0;
  219.  
  220.     tmp=(avail<<16)-iter;
  221.  
  222.     di=tmp/increment;
  223.     tmp-=(di*increment);
  224.  
  225.     while(tmp>0){
  226.         di++;
  227.         tmp-=increment;
  228.     }
  229.  
  230.     /* di is het aantal keren dat ik increment van avail:-iter
  231.        kan aftrekken zodat het resultaat <= 0 is */
  232.  
  233.     return( (di<todo) ? di : todo );
  234. }
  235.  
  236.  
  237.  
  238. void VC_AddChannelStereo(LONG *ptr,UWORD todo)
  239. /*
  240.     Mixes 'todo' stereo samples of the current channel to the tickbuffer.
  241. */
  242. {
  243.     ULONG avail;
  244.     UWORD done,needs;
  245.     char *s;
  246.  
  247.     while(todo>0){
  248.  
  249.         /* Vraag een far ptr op van het sampleadres
  250.            op byte offset ghl->current, en hoeveel samples
  251.            daarvan geldig zijn (VOORDAT segment overschrijding optreed) */
  252.  
  253.         avail=VC_NewSampleAddress(&s);
  254.  
  255.         /* Als de sample simpelweg niet beschikbaar is, of als
  256.            sample gestopt moet worden sample stilleggen en stoppen */
  257.  
  258.         if(!avail){
  259.             ghl->active=0;
  260.             break;
  261.         }
  262.  
  263.         /* we overschrijden wel het sampleeinde of segmentgrens, dus
  264.            we samplen eerst zoveel bytes als er beschikbaar zijn */
  265.  
  266.         done=NewPredict(avail,todo,ghl->increment,ghl->iter);
  267.  
  268.         // mix 'em:
  269.  
  270.         ghl->current+=VC_ResampleMixStereo(s,ptr,ghl->lvoltab,ghl->rvoltab,done,ghl->increment,&ghl->iter);
  271.  
  272.         todo-=done;
  273.         ptr+=done;
  274.     }
  275. }
  276.  
  277.  
  278.  
  279. void VC_AddChannelMono(WORD *ptr,UWORD todo)
  280. /*
  281.     Mixes 'todo' mono samples of the current channel to the tickbuffer.
  282. */
  283. {
  284.     UWORD avail,done,needs;
  285.     char *s;
  286.  
  287.     while(todo>0){
  288.  
  289.         /* Vraag een far ptr op van het sampleadres
  290.            op byte offset ghl->current, en hoeveel samples
  291.            daarvan geldig zijn (VOORDAT segment overschrijding optreed) */
  292.  
  293.         avail=VC_NewSampleAddress(&s);
  294.  
  295.         /* Als de sample simpelweg niet beschikbaar is, of als
  296.            sample gestopt moet worden sample stilleggen en stoppen */
  297.  
  298.         if(!avail){
  299.             ghl->active=0;
  300.             break;
  301.         }
  302.  
  303.         /* we overschrijden wel het sampleeinde of segmentgrens, dus
  304.            we samplen eerst zoveel bytes als er beschikbaar zijn */
  305.  
  306.         done=NewPredict(avail,todo,ghl->increment,ghl->iter);
  307.  
  308.         // mix 'em:
  309.  
  310.         ghl->current+=VC_ResampleMixMono(s,ptr,ghl->lvoltab,done,ghl->increment,&ghl->iter);
  311.  
  312.         todo-=done;
  313.         ptr+=done;
  314.     }
  315. }
  316.  
  317.  
  318.  
  319. void VC_FillTickStereo(WORD *buf,UWORD todo)
  320. /*
  321.     Fills 'buf' with 'todo' 16 bits stereo samples.
  322. */
  323. {
  324.     int t;
  325.  
  326.     // Dan voor ieder kanaal de tickbuffer vullen
  327.  
  328.     for(t=0;t<md_numchn;t++){
  329.         ghl=&ghld[t];
  330.  
  331.         if(ghl->active){
  332.             VC_AddChannelStereo((LONG *)buf,todo);
  333.         }
  334.     }
  335. }
  336.  
  337.  
  338.  
  339.  
  340. void VC_FillTickMono(WORD *buf,UWORD todo)
  341. /*
  342.     Fills 'buf' with 'todo' 16 bits mono samples.
  343. */
  344. {
  345.     int t;
  346.  
  347.     // Dan voor ieder kanaal de tickbuffer vullen
  348.  
  349.     for(t=0;t<md_numchn;t++){
  350.         ghl=&ghld[t];
  351.  
  352.         if(ghl->active){
  353.             VC_AddChannelMono(buf,todo);
  354.         }
  355.     }
  356. }
  357.  
  358.  
  359.  
  360.  
  361. void VC_FillTick(char *buf,UWORD todo)
  362. /*
  363.     Mixes 'todo' samples to 'buf'. todo has to be <= MAXTICKSIZE
  364. */
  365. {
  366.     switch(md_mode){
  367.  
  368.         case 0:         // mono, 8 bits
  369.             VC_MemSet(VC_TICKBUF,0x2000,todo);
  370.             VC_FillTickMono(VC_TICKBUF,todo);
  371.             VC_Sample16To8Copy(VC_TICKBUF,buf,todo);
  372.             break;
  373.  
  374.         case 1:         // stereo, 8 bits
  375.             VC_MemSet(VC_TICKBUF,0x2000,todo<<1);
  376.             VC_FillTickStereo(VC_TICKBUF,todo);
  377.             VC_Sample16To8Copy(VC_TICKBUF,buf,todo<<1);
  378.             break;
  379.  
  380.         case 2:         // mono,16 bits
  381.             VC_MemSet(buf,0x0000,todo);
  382.             VC_FillTickMono((WORD *)buf,todo);
  383.             break;
  384.  
  385.         case 3:         // stereo,16 bits
  386.             VC_MemSet(buf,0x0000,todo<<1);
  387.             VC_FillTickStereo((WORD *)buf,todo);
  388.             break;
  389.     }
  390. }
  391.  
  392.  
  393. void VC_WriteSamples(char *buf,UWORD todo)
  394. /*
  395.     Writes 'todo' mixed SAMPLES (!!) to 'buf'. When todo is bigger than the
  396.     number of samples that fit into VC_TICKBUF, the mixing operation is split
  397.     up into a number of smaller chunks.
  398. */
  399. {
  400.     int t;
  401.     UWORD part;
  402.  
  403.     // compute volume, frequency counter & panning parameters for each channel.
  404.  
  405.     for(t=0;t<md_numchn;t++){
  406.         WORD pan,vol,lvol,rvol;
  407.  
  408.         if(ghld[t].kick){
  409.             ghld[t].current=ghld[t].start;
  410.             ghld[t].iter=0;
  411.             ghld[t].active=1;
  412.             ghld[t].kick=0;
  413.         }
  414.  
  415.         ghld[t].increment=fraction2long(ghld[t].frq,md_mixfreq); // & 0xfffffffc;
  416.  
  417.         vol=ghld[t].vol;
  418.         pan=ghld[t].pan;
  419.  
  420.         if(md_mode & DMODE_STEREO){
  421.             lvol= ( vol * (255-pan) ) / 255;
  422.             rvol= ( vol * pan ) / 255;
  423.             ghld[t].lvoltab=voltab[lvol];
  424.             ghld[t].rvoltab=voltab[rvol];
  425.         }
  426.         else{
  427.             ghld[t].lvoltab=voltab[vol];
  428.         }
  429.     }
  430.  
  431.     // write 'part' samples to the buffer
  432.  
  433.     while(todo){
  434.         part=min(todo,MAXTICKSIZE);
  435.         VC_FillTick(buf,part);
  436.         buf+=bytes2samples(part);
  437.         todo-=part;
  438.     }
  439. }
  440.  
  441.  
  442.  
  443. UWORD VC_WriteBytes(char *buf,UWORD todo)
  444. /*
  445.     Writes 'todo' mixed BYTES (!!) to 'buf'. It returns the number of
  446.     BYTES actually written to 'buf' (which is rounded to number of samples
  447.     that fit into 'todo' bytes).
  448. */
  449. {
  450.     todo=bytes2samples(todo);
  451.     VC_WriteSamples(buf,todo);
  452.     return samples2bytes(todo);
  453. }
  454.  
  455.  
  456.  
  457. void VC_PlayStart(void)
  458. {
  459.     int t,c,maxvol,per256;
  460.     long q;
  461.     UWORD i;
  462.  
  463.     maxvol=256 / md_numchn;
  464.  
  465.     if(!(md_mode & DMODE_16BITS)) maxvol>>=2;
  466.  
  467.     for(c=0;c<=64;c++){
  468.         for(t=-128;t<128;t++) voltab[c][(UBYTE)t]=((long)(t*maxvol)*c)/64;
  469.     }
  470.  
  471.     /* I assume that each channel can be amplified to a 30% higher volume
  472.        than the original volume without noticable clipping..
  473.        and 30% = 76/256
  474.  
  475.        I use this amplification when doing 8-bit mixing so I get a decent
  476.        volume-level, even on 16-channel mods.. this is what OC calls
  477.        'autogain' I think, but I don't know if he uses the same 20% factor */
  478.  
  479.     per256=256+(76U*md_numchn);
  480.  
  481.     for(q=-8192;q<=8191;q++){
  482.  
  483.         c=(q*per256) >> 14;             // /(64*256);
  484.         if(c<-128) c=-128;
  485.         else if(c>127) c=127;
  486.  
  487.         ampbuf[q+8192]=c+128;
  488.     }
  489. }
  490.  
  491.  
  492. void VC_PlayStop(void)
  493. {
  494. }
  495.  
  496.  
  497. BOOL VC_Init(void)
  498. {
  499.     return 1;
  500. }
  501.  
  502.  
  503. void VC_Exit(void)
  504. {
  505. }
  506.