Mercurial > ~darius > hgwebdir.cgi > mikmod
diff playercode/virtch.c @ 6:d14fd386d182
Initial entry of mikmod into the CVS tree.
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:09 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playercode/virtch.c Fri Jan 23 16:05:09 1998 +0000 @@ -0,0 +1,1226 @@ +/* + +Name: VIRTCH.C + +Description: + Sample mixing routines, using a 32 bits mixing buffer. + + Optional features include: + (a) 4-step reverb (for 16 bit output only) + (b) Interpolation of sample data during mixing + (c) Dolby Surround Sound + (d) Optimized assembly mixers for the Intel platform + (e) Optional high-speed or high-quality modes + +C Mixer Portability: + All Systems -- All compilers. + +Assembly Mixer Portability: + + MSDOS: BC(?) Watcom(y) DJGPP(y) + Win95: ? + Os2: ? + Linux: y + + (y) - yes + (n) - no (not possible or not useful) + (?) - may be possible, but not tested + +*/ + +#include <stddef.h> +#include <string.h> +#include "mikmod.h" + +// REVERBERATION : Larger numbers result in shorter reverb duration. +#define REVERBERATION 110000l + + +#ifdef __GNUC__ +#define __cdecl +#endif + +#ifdef __WATCOMC__ +#define inline +#endif + + +// for PC-assembly mixing +// ====================== +// +// Uncomment both lines below for assembly mixing under WATCOM or GCC for +// Linux. +// Note that there is no 16 bit mixers for assembly yet (C only), so +// defining __ASSEMBLY__ if not defining __FASTMIXER__ will lead to compiler +// errors. + +#define __FASTMIXER__ +//#define __ASSEMBLY__ + +#define FRACBITS 11 +#define FRACMASK ((1l<<FRACBITS)-1) + +#define TICKLSIZE 3600 +#define TICKWSIZE (TICKLSIZE*2) +#define TICKBSIZE (TICKWSIZE*2) + +#ifndef MIN +#define MIN(a,b) (((a)<(b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a,b) (((a)>(b))?(a):(b)) +#endif + + +typedef struct +{ BOOL active; + UWORD infmt; + UWORD flags; +#ifdef __FASTMIXER__ + UBYTE *buffer; +#else + UWORD *buffer; +#endif + ULONG size; + ULONG speed; + ULONG speedfactor; + SLONG current; + SLONG increment; + SLONG writepos; +} VSTREAM; + + +typedef struct +{ UBYTE kick; // =1 -> 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 + UWORD vol; // current volume + UWORD pan; // current panning position + SLONG current; // current index in the sample + SLONG increment; // fixed-point increment value +} VINFO; + + +#ifdef __FASTMIXER__ +static SBYTE **Samples; +#else +static SWORD **Samples; +#endif + +// Volume table for 8 bit sample mixing +#ifdef __FASTMIXER__ +static SLONG **voltab; +#endif + +static VINFO *vinf = NULL, *vnf; +static VSTREAM vstream; +static ULONG samplesthatfit; +static BOOL vc_stream = 0; +static int vc_memory, vc_softchn; +static SLONG idxsize,idxlpos,idxlend; +static SLONG TICKLEFT, *VC_TICKBUF = NULL; +static UWORD vc_mode; + + +// Reverb control variables +// ======================== + +static int RVc1, RVc2, RVc3, RVc4; +static ULONG RVRindex; + + +// For Mono or Left Channel + +static SLONG *RVbuf1 = NULL, *RVbuf2 = NULL, *RVbuf3 = NULL, + *RVbuf4 = NULL; + +// For Stereo only (Right Channel) +// Values start at 9 to leave room for expanding this to 8-step +// reverb in the future. + +static SLONG *RVbuf9 = NULL, *RVbuf10 = NULL, *RVbuf11 = NULL, + *RVbuf12 = NULL; + + +int bitshift; // Amplification shift (amount to decrease 32 bit mixing buffer by!) + +#ifdef __FASTMIXER__ +SLONG *lvoltab, *rvoltab; // Volume Table values for use by 8 bit mixers +#else +static SLONG lvolsel, rvolsel; // Volume Selectors for 16 bit mixers. +#endif + + + +// Define external Assembly Language Prototypes +// ============================================ + +#ifdef __ASSEMBLY__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __GNUC__ +#define __cdecl +#endif + +void __cdecl AsmStereoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmStereoSurround(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); +void __cdecl AsmMonoNormal(SBYTE *srce,SLONG *dest,SLONG index,SLONG increment,SLONG todo); + +#ifdef __cplusplus +}; +#endif + +#else + +#ifdef __FASTMIXER__ + +// ============================================================== +// 8 bit sample mixers! + +static SLONG MixStereoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + UBYTE sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = srce[index >> FRACBITS]; + index += increment; + sample2 = srce[index >> FRACBITS]; + index += increment; + sample3 = srce[index >> FRACBITS]; + index += increment; + sample4 = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvoltab[sample1]; + *dest++ += rvoltab[sample1]; + *dest++ += lvoltab[sample2]; + *dest++ += rvoltab[sample2]; + *dest++ += lvoltab[sample3]; + *dest++ += rvoltab[sample3]; + *dest++ += lvoltab[sample4]; + *dest++ += rvoltab[sample4]; + } + + for(; remain--; ) + { + sample1 = srce[index >> FRACBITS]; + index += increment; + *dest++ += lvoltab[sample1]; + *dest++ += rvoltab[sample1]; + } + + return index; +} + + +static SLONG MixStereoSurround(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SLONG sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample2 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample3 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + sample4 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + + *dest++ += sample1; + *dest++ -= sample1; + *dest++ += sample2; + *dest++ -= sample2; + *dest++ += sample3; + *dest++ -= sample3; + *dest++ += sample4; + *dest++ -= sample4; + } + + for(; remain--; ) + { sample1 = lvoltab[(UBYTE)srce[index >> FRACBITS]]; + index += increment; + *dest++ += sample1; + *dest++ -= sample1; + } + + return index; +} + + +static SLONG MixMonoNormal(SBYTE *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + UBYTE sample1, sample2, sample3, sample4; + int remain; + + remain = todo & 3; + + for(todo>>=2; todo; todo--) + { + sample1 = srce[index >> FRACBITS]; + index += increment; + sample2 = srce[index >> FRACBITS]; + index += increment; + sample3 = srce[index >> FRACBITS]; + index += increment; + sample4 = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvoltab[sample1]; + *dest++ += lvoltab[sample2]; + *dest++ += lvoltab[sample3]; + *dest++ += lvoltab[sample4]; + } + + for(; remain--;) + { sample1 = srce[index >> FRACBITS]; + index += increment; + *dest++ -= lvoltab[sample1]; + } + + return index; +} + +#else // not __FASTMIXER__ + +// ============================================================== +// 16 bit sample mixers! + +static SLONG MixStereoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ += rvolsel * sample; + } + + return index; +} + + +static SLONG MixStereoSurround(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, ULONG todo) +{ + SWORD sample; + + for (; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ -= lvolsel * sample; + } + + return index; +} + + +static SLONG MixMonoNormal(SWORD *srce, SLONG *dest, SLONG index, SLONG increment, SLONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { + sample = srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + } + + return index; +} + +#endif // __FASTMIXER__ +#endif // __ASSEMBLY__ + +static void (*MixReverb16)(SLONG *srce, SLONG count); + +static void MixReverb16_Normal(SLONG *srce, SLONG count) +{ + unsigned int speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4; + + ReverbPct = 63 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128l); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128l); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128l); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128l); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + + // Left Channel! + + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; + } +} + + +static void MixReverb16_Stereo(SLONG *srce, SLONG count) +{ + unsigned int speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4; + + ReverbPct = 63 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128l); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128l); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128l); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128l); + + // Compute the RIGHT CHANNEL echo buffers! + + speedup = srce[1] >> 3; + + RVbuf9[loc1] = speedup + ((ReverbPct * RVbuf9[loc1]) / 128l); + RVbuf10[loc2] = speedup + ((ReverbPct * RVbuf11[loc2]) / 128l); + RVbuf11[loc3] = speedup + ((ReverbPct * RVbuf12[loc3]) / 128l); + RVbuf12[loc4] = speedup + ((ReverbPct * RVbuf12[loc4]) / 128l); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + + // Left Channel! + + *srce++ += RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4]; + + // Right Channel! + + *srce++ += RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4]; + } +} + + +static void Mix32To16(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, x3, x4; + int remain; + + remain = count & 3; + + for(count>>=2; count; count--) + { x1 = *srce++ >> bitshift; + x2 = *srce++ >> bitshift; + x3 = *srce++ >> bitshift; + x4 = *srce++ >> bitshift; + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + x3 = (x3 > 32767) ? 32767 : (x3 < -32768) ? -32768 : x3; + x4 = (x4 > 32767) ? 32767 : (x4 < -32768) ? -32768 : x4; + *dste++ = x1; + *dste++ = x2; + *dste++ = x3; + *dste++ = x4; + } + + for(; remain; remain--) + { x1 = *srce++ >> bitshift; + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + *dste++ = x1; + } +} + + +static void Mix32To8(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2, x3, x4; + int remain; + + remain = count & 3; + + for(count>>=2; count; count--) + { x1 = *srce++ >> bitshift; + x2 = *srce++ >> bitshift; + x3 = *srce++ >> bitshift; + x4 = *srce++ >> bitshift; + + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; + x3 = (x3 > 127) ? 127 : (x3 < -128) ? -128 : x3; + x4 = (x4 > 127) ? 127 : (x4 < -128) ? -128 : x4; + + *dste++ = x1 + 128; + *dste++ = x2 + 128; + *dste++ = x3 + 128; + *dste++ = x4 + 128; + } + + for(; remain; remain--) + { x1 = *srce++ >> bitshift; + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + *dste++ = x1 + 128; + } +} + + +static ULONG samples2bytes(ULONG samples) +{ + if(vc_mode & DMODE_16BITS) samples <<= 1; + if(vc_mode & DMODE_STEREO) samples <<= 1; + return samples; +} + + +static ULONG bytes2samples(ULONG bytes) +{ + if(vc_mode & DMODE_16BITS) bytes >>= 1; + if(vc_mode & DMODE_STEREO) bytes >>= 1; + return bytes; +} + + +static void AddChannel(SLONG *ptr, SLONG todo) +{ + SLONG end, done; +#ifdef __FASTMIXER__ + SBYTE *s; +#else + SWORD *s; +#endif + + while(todo > 0) + { // 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) && (vnf->current < idxlpos)) + { + // the sample is looping, and it has + // reached the loopstart index + + if(vnf->flags & 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) && (vnf->current > idxlend)) + { + // the sample is looping, so check if + // it reached the loopend index + + 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; + } + } + } + + if(!(s=Samples[vnf->handle])) + { vnf->current = 0; + vnf->active = 0; + break; + } + + end = (vnf->flags & SF_REVERSE) ? + (vnf->flags & SF_LOOP) ? idxlpos : 0 : + (vnf->flags & SF_LOOP) ? idxlend : idxsize; + + done = MIN((end - vnf->current) / vnf->increment + 1, todo); + + if(!done) + { vnf->active = 0; + break; + } + + if(vnf->vol) + { +#ifdef __ASSEMBLY__ + if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + AsmStereoSurround(s,ptr,vnf->current,vnf->increment,done); + else + AsmStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + AsmMonoNormal(s,ptr,vnf->current,vnf->increment,done); + vnf->current += (vnf->increment*done); +#else + if(vc_mode & DMODE_STEREO) + if((vnf->pan == PAN_SURROUND) && (vc_mode & DMODE_SURROUND)) + vnf->current = MixStereoSurround(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixStereoNormal(s,ptr,vnf->current,vnf->increment,done); + else + vnf->current = MixMonoNormal(s,ptr,vnf->current,vnf->increment,done); +#endif + } + todo -= done; + ptr += (vc_mode & DMODE_STEREO) ? (done<<1) : done; + } +} + + +void VC_WriteSamples(SBYTE *buf, ULONG todo) +{ + int left, portion = 0, count; + SBYTE *buffer, *samplebuf; + int t; + int pan, vol; + int sampletodo; + + samplebuf = buf; + sampletodo = todo; + + while(todo) + { if(TICKLEFT==0) + { if(vc_mode & DMODE_SOFT_MUSIC) md_player(); + TICKLEFT = (md_mixfreq*125l) / (md_bpm*50L); + } + + left = MIN(TICKLEFT, todo); + + buffer = buf; + TICKLEFT -= left; + todo -= left; + + buf += samples2bytes(left); + + while(left) + { portion = MIN(left, samplesthatfit); + count = (vc_mode & DMODE_STEREO) ? (portion<<1) : portion; + + memset(VC_TICKBUF, 0, count<<2); + + for(t=0; t<vc_softchn; t++) + { vnf = &vinf[t]; + + if(vnf->kick) + { vnf->current = vnf->start << FRACBITS; + vnf->kick = 0; + vnf->active = 1; + } + + if(vnf->frq == 0) vnf->active = 0; + + if(vnf->active) + { vnf->increment = (vnf->frq<<FRACBITS) / md_mixfreq; + if(vnf->flags & SF_REVERSE) vnf->increment=-vnf->increment; + + vol = vnf->vol; pan = vnf->pan; + + if(vc_mode & DMODE_STEREO) + { if(pan != PAN_SURROUND) + { + #ifdef __FASTMIXER__ + lvoltab = voltab[(vol * (255-pan)) / 1024]; + rvoltab = voltab[(vol * pan) / 1024]; + #else + lvolsel = (vol * (255-pan)) >> 8; + rvolsel = (vol * pan) >> 8; + #endif + } else + { + #ifdef __FASTMIXER__ + lvoltab = voltab[(vol+1)>>3]; + #else + lvolsel = vol/2; + #endif + } + } else + { + #ifdef __FASTMIXER__ + lvoltab = voltab[(vol+1)>>2]; + #else + lvolsel = vol; + #endif + } + idxsize = (vnf->size) ? (vnf->size << FRACBITS)-1 : 0; + idxlend = (vnf->repend) ? (vnf->repend << FRACBITS)-1 : 0; + idxlpos = vnf->reppos << FRACBITS; + AddChannel(VC_TICKBUF, portion); + } + } + + if(md_reverb) MixReverb16(VC_TICKBUF, portion); + + if(vc_mode & DMODE_16BITS) + Mix32To16((SWORD *) buffer, VC_TICKBUF, count); + else + Mix32To8((SBYTE *) buffer, VC_TICKBUF, count); + + buffer += samples2bytes(portion); + left -= portion; + } + } +} + + +void VC_SilenceBytes(SBYTE *buf, ULONG todo) + +// Fill the buffer with 'todo' bytes of silence (it depends on the mixing +// mode how the buffer is filled) + +{ + // clear the buffer to zero (16 bits + // signed ) or 0x80 (8 bits unsigned) + + if(vc_mode & DMODE_16BITS) + memset(buf,0,todo); + else + memset(buf,0x80,todo); +} + + +ULONG VC_WriteBytes(SBYTE *buf, ULONG todo) + +// Writes 'todo' mixed SBYTES (!!) to 'buf'. It returns the number of +// SBYTES actually written to 'buf' (which is rounded to number of samples +// that fit into 'todo' bytes). + +{ + if(vc_softchn == 0) + { VC_SilenceBytes(buf,todo); + return todo; + } + + todo = bytes2samples(todo); + VC_WriteSamples(buf,todo); + + return samples2bytes(todo); +} + + +static UBYTE log2(ULONG x) +{ + UBYTE result = 0; + while (x>>=1) result++; + + return result; +} + + +BOOL VC_PlayStart(void) +{ + int t, numchn; + + numchn = md_softchn; + if(vc_stream) numchn++; + + if(numchn > 0) + { +#ifdef __FASTMIXER__ + int c; + SLONG maxvol, volmul; + + if(vc_stream) numchn++; + maxvol = 16777216L / (numchn+6); + + for(t=0; t<65; t++) + { volmul = (maxvol*t) / 64; + for(c=-128; c<128; c++) + voltab[t][(UBYTE)c] = (SLONG)c*volmul; + } + + bitshift = 16 - log2(numchn); +#else + bitshift = (log2(numchn)>>3) + 7; + +#endif + + if (!(vc_mode & DMODE_16BITS)) + bitshift += 8; + } + + samplesthatfit = TICKLSIZE; + if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; + TICKLEFT = 0; + + + RVc1 = (5000L * md_mixfreq) / REVERBERATION; + RVc2 = (5078L * md_mixfreq) / REVERBERATION; + RVc3 = (5313L * md_mixfreq) / REVERBERATION; + RVc4 = (5703L * md_mixfreq) / REVERBERATION; + + if((RVbuf1 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf2 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf3 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf4 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; + + if(vc_mode & DMODE_STEREO) + { if((RVbuf9 = (SLONG *)_mm_calloc((RVc1+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf10 = (SLONG *)_mm_calloc((RVc2+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf11 = (SLONG *)_mm_calloc((RVc3+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf12 = (SLONG *)_mm_calloc((RVc4+1),sizeof(SLONG))) == NULL) return 1; + } + + RVRindex = 0; + + return 0; +} + + +void VC_PlayStop(void) +{ + if(RVbuf1 != NULL) free(RVbuf1); + if(RVbuf2 != NULL) free(RVbuf2); + if(RVbuf3 != NULL) free(RVbuf3); + if(RVbuf4 != NULL) free(RVbuf4); + if(RVbuf9 != NULL) free(RVbuf9); + if(RVbuf10 != NULL) free(RVbuf10); + if(RVbuf11 != NULL) free(RVbuf11); + if(RVbuf12 != NULL) free(RVbuf12); + + RVbuf1 = NULL; RVbuf2 = NULL; RVbuf3 = NULL; RVbuf4 = NULL; + RVbuf9 = NULL; RVbuf10 = NULL; RVbuf11 = NULL; RVbuf12 = NULL; +} + + +BOOL VC_Init(void) +{ + +#ifdef __FASTMIXER__ + int t; + + _mm_errno = MMERR_INITIALIZING_MIXER; + if((voltab = (SLONG **)calloc(65,sizeof(SLONG *))) == NULL) return 1; + for(t=0; t<65; t++) + if((voltab[t] = (SLONG *)calloc(256,sizeof(SLONG))) == NULL) return 1; + + if((Samples = (SBYTE **)calloc(MAXSAMPLEHANDLES, sizeof(SBYTE *))) == NULL) return 1; +#else + _mm_errno = MMERR_INITIALIZING_MIXER; + if((Samples = (SWORD **)calloc(MAXSAMPLEHANDLES, sizeof(SWORD *))) == NULL) return 1; +#endif + + if(VC_TICKBUF==NULL) if((VC_TICKBUF=(SLONG *)malloc((TICKLSIZE+32) * sizeof(SLONG))) == NULL) return 1; + if(md_mode & DMODE_INTERP) md_mode &= ~DMODE_INTERP; + + MixReverb16 = (md_mode & DMODE_STEREO) ? MixReverb16_Stereo : MixReverb16_Normal; + vc_mode = md_mode; + + + _mm_errno = 0; + return 0; +} + + +void VC_Exit(void) +{ +#ifdef __FASTMIXER__ + int t; + if(voltab!=NULL) + { for(t=0; t<65; t++) if(voltab[t]!=NULL) free(voltab[t]); + free(voltab); voltab = NULL; + } +#endif + + //if(VC_TICKBUF!=NULL) free(VC_TICKBUF); + if(vinf!=NULL) free(vinf); + if(Samples!=NULL) free(Samples); + + //VC_TICKBUF = NULL; + vinf = NULL; + Samples = NULL; +} + + +BOOL VC_SetNumVoices(void) +{ + int t; + + if((vc_softchn = md_softchn) == 0) return 0; + + if(vinf!=NULL) free(vinf); + if((vinf = _mm_calloc(sizeof(VINFO),vc_softchn)) == NULL) return 1; + + for(t=0; t<vc_softchn; t++) + { vinf[t].frq = 10000; + vinf[t].pan = (t&1) ? 0 : 255; + } + + return 0; +} + + +void VC_VoiceSetVolume(UBYTE voice, UWORD vol) +{ + vinf[voice].vol = vol; +} + + +void VC_VoiceSetFrequency(UBYTE voice, ULONG frq) +{ + vinf[voice].frq = frq; +} + + +void VC_VoiceSetPanning(UBYTE voice, ULONG pan) +{ + vinf[voice].pan = pan; +} + + +void VC_VoicePlay(UBYTE voice, SWORD handle, ULONG start, ULONG size, ULONG reppos, ULONG repend, UWORD flags) +{ + 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; +} + + +void VC_VoiceStop(UBYTE voice) +{ + vinf[voice].active = 0; +} + + +BOOL VC_VoiceStopped(UBYTE voice) +{ + return(vinf[voice].active==0); +} + + +void VC_VoiceReleaseSustain(UBYTE voice) +{ + +} + + +SLONG VC_VoiceGetPosition(UBYTE voice) +{ + return(vinf[voice].current>>FRACBITS); +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +void VC_SampleUnload(SWORD handle) +{ + void *sampleadr = Samples[handle]; + + free(sampleadr); + Samples[handle] = NULL; +} + + +SWORD VC_SampleLoad(SAMPLOAD *sload, int type, FILE *fp) +{ + SAMPLE *s = sload->sample; + int handle; + ULONG t, length,loopstart,loopend; + + if(type==MD_HARDWARE) return -1; + + // Find empty slot to put sample address in + for(handle=0; handle<MAXSAMPLEHANDLES; handle++) + if(Samples[handle]==NULL) break; + + if(handle==MAXSAMPLEHANDLES) + { _mm_errno = MMERR_OUT_OF_HANDLES; + return -1; + } + + length = s->length; + loopstart = s->loopstart; + loopend = s->loopend; + + SL_SampleSigned(sload); + +#ifdef __FASTMIXER__ + SL_Sample16to8(sload); + if((Samples[handle]=(SBYTE *)malloc(length+16))==NULL) + { _mm_errno = MMERR_SAMPLE_TOO_BIG; + return -1; + } + // read sample into buffer. + SL_Load(Samples[handle],sload,length); +#else + SL_Sample8to16(sload); + if((Samples[handle]=(SWORD *)malloc((length+16)<<1))==NULL) + { _mm_errno = MMERR_SAMPLE_TOO_BIG; + return -1; + } + // read sample into buffer. + SL_Load(Samples[handle],sload,length); +#endif + + + // Unclick samples: + + if(s->flags & SF_LOOP) + { if(s->flags & SF_BIDI) + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][(loopend-t)-1]; + else + for(t=0; t<16; t++) Samples[handle][loopend+t] = Samples[handle][t+loopstart]; + } else + for(t=0; t<16; t++) Samples[handle][t+length] = 0; + + return handle; +} + + +ULONG VC_SampleSpace(int type) +{ + return vc_memory; +} + + +ULONG VC_SampleLength(int type, SAMPLE *s) +{ +#ifdef __FASTMIXER__ + return s->length + 16; +#else + return (s->length * ((s->flags&SF_16BITS) ? 2 : 1)) + 16; +#endif +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +ULONG VC_VoiceRealVolume(UBYTE voice) +{ + ULONG i,s,size; + int k,j; +#ifdef __FASTMIXER__ + SBYTE *smp; +#else + SWORD *smp; +#endif + SLONG t; + + t = vinf[voice].current>>FRACBITS; + if(vinf[voice].active==0) return 0; + + s = vinf[voice].handle; + size = vinf[voice].size; + + i=64; t-=64; k=0; j=0; + if(i>size) i = size; + if(t<0) t = 0; + if(t+i > size) t = size-i; + + i &= ~1; // make sure it's EVEN. + + smp = &Samples[s][t]; + for(; i; i--, smp++) + { if(k<*smp) k = *smp; + if(j>*smp) j = *smp; + } + +#ifdef __FASTMIXER__ + k = abs(k-j)<<8; +#else + k = abs(k-j); +#endif + + return k; +} + + +BOOL VC_StreamInit(ULONG speed, UWORD flags) + +// flags - Disk Format - SF_STEREO, SF_16BITS, etc. +// speed - speed at which to replay sample +// +// Returns - TRUE if init failed + +{ + ULONG tmp; + +#ifdef __FASTMIXER__ + tmp = stream_bufsize * speed * (((flags & SF_STEREO) && (vc_mode & DMODE_STEREO)) ? 2 : 1); +#else + tmp = stream_bufsize * speed * (((flags & SF_STEREO) && (vc_mode & DMODE_STEREO)) ? 2 : 1) + * ((flags & SF_16BITS) && (vc_mode & DMODE_16BITS)) ? 2 : 1; +#endif + if((flags & SF_STEREO) && (vc_mode & DMODE_STEREO)) tmp <<= 1; + + vstream.size = tmp; + if((vstream.buffer=_mm_calloc(vstream.size,1024)) == NULL) return 1; + + vstream.speed = speed; + vstream.speedfactor = (md_mixfreq / speed); + if(!((vstream.speedfactor==2) || (vstream.speedfactor==4))) + vstream.speedfactor = 1; + + vstream.infmt = flags; + vstream.flags = flags; +#ifdef __FASTMIXER__ + vstream.flags = flags &= ~SF_16BITS; +#else + vstream.flags = flags |= SF_16BITS; +#endif + if(!(vc_mode&DMODE_STEREO)) vstream.flags &= ~SF_STEREO; + + vstream.active = 0; + vstream.current = 0; + vstream.increment = 0; + + vc_stream = 1; + VC_PlayStart(); + + return 0; +} + + +void VC_StreamExit(void) +{ + vstream.active = 0; + if(vstream.buffer != NULL) free(vstream.buffer); + vstream.buffer = NULL; + vc_stream = 0; + VC_PlayStart(); +} + + +void VC_StreamSetSpeed(ULONG speed) +{ + vstream.speed = speed; + vstream.speedfactor = (md_mixfreq/speed); + if(!((vstream.speedfactor==2) || (vstream.speedfactor==4))) + vstream.speedfactor = 1; +} + + +SLONG VC_StreamGetPosition(void) +{ + return(vstream.current >> FRACBITS); +} + + +void VC_StreamStart(void) +{ + if(vstream.buffer!=NULL) vstream.active = 1; +} + + +void VC_StreamStop(void) +{ + vstream.active = 0; +} + + +void VC_StreamCommit(void *sample, ULONG size) + +// Read 'size' bytes from the specified buffer and commit them to +// the streaming audio buffer. + +{ + //ULONG last, curr; + //ULONG todo; + + if(vstream.buffer==NULL) return; + +} +