Mercurial > ~darius > hgwebdir.cgi > mikmod
diff playercode/virtch2.c @ 4:5d614bcc4287
Initial entry of mikmod into the CVS tree.
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:08 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/playercode/virtch2.c Fri Jan 23 16:05:08 1998 +0000 @@ -0,0 +1,927 @@ +/* + +Name: VIRTCH2.C + +Description: + All-c sample mixing routines, using a 32 bits mixing buffer, interpolation, + and sample smoothing [improves sound quality and removes clicks]. + + Future Additions: + Low-Pass filter to remove annoying staticy buzz. + + +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. +// Longer reverb durations can cause unwanted static and make the +// reverb sound more like an echo. + +#define REVERBERATION 28000l + +// SAMPLING_SHIFT : Specified the shift multiplier which controls by how +// much the mixing rate is multiplied while mixing. Higher values +// can improve quality by smoothing the soudn and reducing pops and +// clicks. Note, this is a shift value, so a value of 2 becomes a +// mixing-rate multiplier of 4, and a value of 3 = 8, etc. + +#define SAMPLING_SHIFT 2 +#define SAMPLING_FACTOR (SLONG)(1<<SAMPLING_SHIFT) + + +// FRACBITS : the number of bits per integer devoted to the fractional +// part of the number. This value HAS to be changed if the compiler +// does not support 64 bit integers. If 32 bit integers are used, +// FRACBITS _must_ be 9 or smaller. + +#define FRACBITS 28 +#define FRACMASK ((1l<<FRACBITS)-1) + +#define TICKLSIZE 4096 +#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 +{ 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 + SDOUBLE current; // current index in the sample + SDOUBLE increment; // fixed-point increment value +} VINFO; + + +static SWORD **Samples; + +static VINFO *vinf = NULL; +static VINFO *vnf; +static ULONG samplesthatfit; +static int vc_memory, vc_softchn; +static SDOUBLE idxsize,idxlpos,idxlend; +static SLONG TICKLEFT; +static SLONG *VC2_TICKBUF = NULL; +static UWORD vc_mode; +static int bitshift; // Amplification shift (amount to decrease 32 bit mixing buffer by!) +static SLONG lvolsel, rvolsel; // Volume factor .. range 0-255 + + +// Reverb control variables +// ======================== + +static int RVc1, RVc2, RVc3, RVc4, RVc5, RVc6, RVc7, RVc8; +static ULONG RVRindex; + +// For Mono or Left Channel +static SLONG *RVbuf1 = NULL, *RVbuf2 = NULL, *RVbuf3 = NULL, + *RVbuf4 = NULL, *RVbuf5 = NULL, *RVbuf6 = NULL, + *RVbuf7 = NULL, *RVbuf8 = NULL; + +// For Stereo only (Right Channel) +static SLONG *RVbuf9 = NULL, *RVbuf10 = NULL, *RVbuf11 = NULL, + *RVbuf12 = NULL, *RVbuf13 = NULL, *RVbuf14 = NULL, + *RVbuf15 = NULL, *RVbuf16 = NULL; + + +// ============================================================== +// 16 bit sample mixers! + +static SDOUBLE MixStereoNormal(SWORD *srce, SLONG *dest, SDOUBLE index, SDOUBLE increment, ULONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { sample = (index & FRACBITS) ? + (((srce[index >> FRACBITS] * (FRACBITS - (index & FRACBITS))) + + (srce[(index >> FRACBITS)+1] * (index & FRACBITS))) / FRACBITS) + : srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ += rvolsel * sample; + } + + return index; +} + + +static SDOUBLE MixStereoSurround(SWORD *srce, SLONG *dest, SDOUBLE index, SDOUBLE increment, ULONG todo) +{ + SWORD sample; + + for(dest--; todo; todo--) + { sample = (index & FRACBITS) ? + (((srce[index >> FRACBITS] * (FRACBITS - (index & FRACBITS))) + + (srce[(index >> FRACBITS)+1] * (index & FRACBITS))) / FRACBITS) + : srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + *dest++ -= lvolsel * sample; + } + + return index; +} + + +static SDOUBLE MixMonoNormal(SWORD *srce, SLONG *dest, SDOUBLE index, SDOUBLE increment, SLONG todo) +{ + SWORD sample; + + for(; todo; todo--) + { sample = (index & FRACBITS) ? + (((srce[index >> FRACBITS] * (FRACBITS - (index & FRACBITS))) + + (srce[(index >> FRACBITS)+1] * (index & FRACBITS))) / FRACBITS) + : srce[index >> FRACBITS]; + index += increment; + + *dest++ += lvolsel * sample; + } + + return index; +} + + +static void (*Mix32to16)(SWORD *dste, SLONG *srce, SLONG count); +static void (*Mix32to8)(SBYTE *dste, SLONG *srce, SLONG count); +static void (*MixReverb)(SLONG *srce, SLONG count); + + +static void MixReverb_Normal(SLONG *srce, SLONG count) +{ + SLONG speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4, + loc5, loc6, loc7, loc8; + + ReverbPct = 63 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + // Left Channel! + + *srce++ += (RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]); + } +} + + +static void MixReverb_Stereo(SLONG *srce, SLONG count) +{ + SLONG speedup; + int ReverbPct; + unsigned int loc1, loc2, loc3, loc4, + loc5, loc6, loc7, loc8; + + ReverbPct = 63 + (md_reverb*4); + + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + for(; count; count--) + { + // Compute the LEFT CHANNEL echo buffers! + + speedup = *srce >> 3; + + RVbuf1[loc1] = speedup + ((ReverbPct * RVbuf1[loc1]) / 128); + RVbuf2[loc2] = speedup + ((ReverbPct * RVbuf2[loc2]) / 128); + RVbuf3[loc3] = speedup + ((ReverbPct * RVbuf3[loc3]) / 128); + RVbuf4[loc4] = speedup + ((ReverbPct * RVbuf4[loc4]) / 128); + RVbuf5[loc5] = speedup + ((ReverbPct * RVbuf5[loc5]) / 128); + RVbuf6[loc6] = speedup + ((ReverbPct * RVbuf6[loc6]) / 128); + RVbuf7[loc7] = speedup + ((ReverbPct * RVbuf7[loc7]) / 128); + RVbuf8[loc8] = speedup + ((ReverbPct * RVbuf8[loc8]) / 128); + + // Compute the RIGHT CHANNEL echo buffers! + + speedup = srce[1] >> 3; + + RVbuf9[loc1] = speedup + ((ReverbPct * RVbuf9[loc1]) / 128); + RVbuf10[loc2] = speedup + ((ReverbPct * RVbuf11[loc2]) / 128); + RVbuf11[loc3] = speedup + ((ReverbPct * RVbuf12[loc3]) / 128); + RVbuf12[loc4] = speedup + ((ReverbPct * RVbuf12[loc4]) / 128); + RVbuf13[loc5] = speedup + ((ReverbPct * RVbuf13[loc5]) / 128); + RVbuf14[loc6] = speedup + ((ReverbPct * RVbuf14[loc6]) / 128); + RVbuf15[loc7] = speedup + ((ReverbPct * RVbuf15[loc7]) / 128); + RVbuf16[loc8] = speedup + ((ReverbPct * RVbuf16[loc8]) / 128); + + // Prepare to compute actual finalized data! + + RVRindex++; + loc1 = RVRindex % RVc1; + loc2 = RVRindex % RVc2; + loc3 = RVRindex % RVc3; + loc4 = RVRindex % RVc4; + loc5 = RVRindex % RVc5; + loc6 = RVRindex % RVc6; + loc7 = RVRindex % RVc7; + loc8 = RVRindex % RVc8; + + // Left Channel! + + *srce++ += (RVbuf1[loc1] - RVbuf2[loc2] + RVbuf3[loc3] - RVbuf4[loc4] + + RVbuf5[loc5] - RVbuf6[loc6] + RVbuf7[loc7] - RVbuf8[loc8]); + + // Right Channel! + + *srce++ += (RVbuf9[loc1] - RVbuf10[loc2] + RVbuf11[loc3] - RVbuf12[loc4] + + RVbuf13[loc5] - RVbuf14[loc6] + RVbuf15[loc7] - RVbuf16[loc8]); + } +} + + +static void Mix32To16_Normal(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, tmpx; + int i; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / bitshift; + x2 = *srce++ / bitshift; + + x1 = (x1 > 32767) ? 32767 : (x1 < -32768) ? -32768 : x1; + x2 = (x2 > 32767) ? 32767 : (x2 < -32768) ? -32768 : x2; + + tmpx += x1 + x2; + } + + *dste++ = tmpx / SAMPLING_FACTOR; + } +} + + +static void Mix32To16_Stereo(SWORD *dste, SLONG *srce, SLONG count) +{ + SLONG x1, x2, x3, x4, tmpx, tmpy; + int i; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = tmpy = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { 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; + + tmpx += x1 + x3; + tmpy += x2 + x4; + } + + *dste++ = tmpx / SAMPLING_FACTOR; + *dste++ = tmpy / SAMPLING_FACTOR; + } +} + + +static void Mix32To8_Normal(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2; + int i, tmpx; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { x1 = *srce++ / bitshift; + x2 = *srce++ / bitshift; + + x1 = (x1 > 127) ? 127 : (x1 < -128) ? -128 : x1; + x2 = (x2 > 127) ? 127 : (x2 < -128) ? -128 : x2; + + tmpx += x1 + x2; + } + + *dste++ = (tmpx / SAMPLING_FACTOR) + 128; + } +} + + +static void Mix32To8_Stereo(SBYTE *dste, SLONG *srce, SLONG count) +{ + int x1, x2, x3, x4; + int i, tmpx, tmpy; + + for(count/=SAMPLING_FACTOR; count; count--) + { tmpx = tmpy = 0; + + for(i=SAMPLING_FACTOR/2; i; i--) + { 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; + + tmpx += x1 + x3; + tmpy += x2 + x4; + } + + *dste++ = (tmpx / SAMPLING_FACTOR) + 128; + *dste++ = (tmpy / SAMPLING_FACTOR) + 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) +{ + SDOUBLE end; + SLONG done; + SWORD *s; + + 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) + { 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); + } + todo -= done; + ptr += (vc_mode & DMODE_STEREO) ? (done<<1) : done; + } +} + + +void VC2_WriteSamples(SBYTE *buf, ULONG todo) +{ + int left, portion = 0; + SBYTE *buffer; + int t; + int pan, vol; + + todo *= SAMPLING_FACTOR; + + while(todo) + { if(TICKLEFT==0) + { if(vc_mode & DMODE_SOFT_MUSIC) md_player(); + TICKLEFT = (md_mixfreq*125l*SAMPLING_FACTOR) / (md_bpm*50l); + TICKLEFT &= ~(SAMPLING_FACTOR-1); + } + + left = MIN(TICKLEFT, todo); + + buffer = buf; + TICKLEFT -= left; + todo -= left; + + buf += samples2bytes(left) / SAMPLING_FACTOR; + + while(left) + { portion = MIN(left, samplesthatfit); + memset(VC2_TICKBUF, 0, portion << ((vc_mode & DMODE_STEREO) ? 3 : 2)); + + for(t=0; t<vc_softchn; t++) + { vnf = &vinf[t]; + + if(vnf->kick) + { vnf->current = (SDOUBLE)(vnf->start) << FRACBITS; + vnf->kick = 0; + vnf->active = 1; + } + + if(vnf->frq == 0) vnf->active = 0; + + if(vnf->active) + { vnf->increment = ((SDOUBLE)(vnf->frq) << (FRACBITS-SAMPLING_SHIFT)) / (SDOUBLE)md_mixfreq; + if(vnf->flags & SF_REVERSE) vnf->increment=-vnf->increment; + + vol = vnf->vol; pan = vnf->pan; + + if((vc_mode & DMODE_STEREO) && (pan!=PAN_SURROUND)) + { lvolsel = (vol * (255-pan)) >> 8; + rvolsel = (vol * pan) >> 8; + } else + lvolsel = (vol*256l) / 480; + + idxsize = (vnf->size) ? ((SDOUBLE)(vnf->size) << FRACBITS)-1 : 0; + idxlend = (vnf->repend) ? ((SDOUBLE)(vnf->repend) << FRACBITS)-1 : 0; + idxlpos = (SDOUBLE)(vnf->reppos) << FRACBITS; + AddChannel(VC2_TICKBUF, portion); + } + } + + if(md_reverb) MixReverb(VC2_TICKBUF, portion); + + if(vc_mode & DMODE_16BITS) + Mix32to16((SWORD *) buffer, VC2_TICKBUF, portion); + else + Mix32to8((SBYTE *) buffer, VC2_TICKBUF, portion); + + buffer += samples2bytes(portion) / SAMPLING_FACTOR; + left -= portion; + } + } +} + + +void VC2_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 VC2_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) + { VC2_SilenceBytes(buf,todo); + return todo; + } + + todo = bytes2samples(todo); + VC2_WriteSamples(buf,todo); + + return samples2bytes(todo); +} + + +BOOL VC2_PlayStart(void) +{ + if(vc_softchn > 0) + { bitshift = vc_softchn + 257; + if(!(vc_mode & DMODE_16BITS)) + bitshift *= 256; + if(md_reverb) bitshift++; + } + + samplesthatfit = TICKLSIZE; + if(vc_mode & DMODE_STEREO) samplesthatfit >>= 1; + TICKLEFT = 0; + + /* Original Reverb Code! + The stuff I use avoids floating point (below). + + RVc1 = (SLONG)(500 * md_mixfreq) / 11000; + RVc2 = (SLONG)(507.8125 * md_mixfreq) / 11000; + RVc3 = (SLONG)(531.25 * md_mixfreq) / 11000; + RVc4 = (SLONG)(570.3125 * md_mixfreq) / 11000; + RVc5 = (SLONG)(625 * md_mixfreq) / 11000; + RVc6 = (SLONG)(695.3125 * md_mixfreq) / 11000; + RVc7 = (SLONG)(781.25 * md_mixfreq) / 11000; + RVc8 = (SLONG)(882.8125 * md_mixfreq) / 11000; + ReverbPct = 99 - (md_reverb*2); + */ + + RVc1 = (5000L * md_mixfreq) / REVERBERATION; + RVc2 = (5078L * md_mixfreq) / REVERBERATION; + RVc3 = (5313L * md_mixfreq) / REVERBERATION; + RVc4 = (5703L * md_mixfreq) / REVERBERATION; + RVc5 = (6250L * md_mixfreq) / REVERBERATION; + RVc6 = (6953L * md_mixfreq) / REVERBERATION; + RVc7 = (7813L * md_mixfreq) / REVERBERATION; + RVc8 = (8828L * 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((RVbuf5 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf6 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf7 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf8 = (SLONG *)_mm_calloc((RVc8+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; + if((RVbuf13 = (SLONG *)_mm_calloc((RVc5+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf14 = (SLONG *)_mm_calloc((RVc6+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf15 = (SLONG *)_mm_calloc((RVc7+1),sizeof(SLONG))) == NULL) return 1; + if((RVbuf16 = (SLONG *)_mm_calloc((RVc8+1),sizeof(SLONG))) == NULL) return 1; + } + + RVRindex = 0; + return 0; +} + + +void VC2_PlayStop(void) +{ + if(RVbuf1 != NULL) free(RVbuf1); + if(RVbuf2 != NULL) free(RVbuf2); + if(RVbuf3 != NULL) free(RVbuf3); + if(RVbuf4 != NULL) free(RVbuf4); + if(RVbuf5 != NULL) free(RVbuf5); + if(RVbuf6 != NULL) free(RVbuf6); + if(RVbuf7 != NULL) free(RVbuf7); + if(RVbuf8 != NULL) free(RVbuf8); + if(RVbuf9 != NULL) free(RVbuf9); + if(RVbuf10 != NULL) free(RVbuf10); + if(RVbuf11 != NULL) free(RVbuf11); + if(RVbuf12 != NULL) free(RVbuf12); + if(RVbuf13 != NULL) free(RVbuf13); + if(RVbuf14 != NULL) free(RVbuf14); + if(RVbuf15 != NULL) free(RVbuf15); + if(RVbuf16 != NULL) free(RVbuf16); + + RVbuf1 = NULL; RVbuf2 = NULL; RVbuf3 = NULL; RVbuf4 = NULL; + RVbuf5 = NULL; RVbuf6 = NULL; RVbuf7 = NULL; RVbuf8 = NULL; + RVbuf9 = NULL; RVbuf10 = NULL; RVbuf11 = NULL; RVbuf12 = NULL; + RVbuf13 = NULL; RVbuf14 = NULL; RVbuf15 = NULL; RVbuf16 = NULL; +} + + +BOOL VC2_Init(void) +{ + _mm_errno = MMERR_INITIALIZING_MIXER; + if((Samples = (SWORD **)calloc(MAXSAMPLEHANDLES, sizeof(SWORD *))) == NULL) return 1; + if(VC2_TICKBUF==NULL) if((VC2_TICKBUF=(SLONG *)malloc((TICKLSIZE+32) * sizeof(SLONG))) == NULL) return 1; + + if(md_mode & DMODE_STEREO) + { Mix32to16 = Mix32To16_Stereo; + Mix32to8 = Mix32To8_Stereo; + MixReverb = MixReverb_Stereo; + } else + { Mix32to16 = Mix32To16_Normal; + Mix32to8 = Mix32To8_Normal; + MixReverb = MixReverb_Normal; + } + + vc_mode = md_mode; + + _mm_errno = 0; + return 0; +} + + +void VC2_Exit(void) + +// Yay, he joys and fruits of C and C++ - +// Deallocation of arrays! + +{ + //if(VC2_TICKBUF!=NULL) free(VC2_TICKBUF); + if(vinf!=NULL) free(vinf); + if(Samples!=NULL) free(Samples); + +// VC2_TICKBUF = NULL; + vinf = NULL; + Samples = NULL; +} + + +BOOL VC2_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 VC2_VoiceSetVolume(UBYTE voice, UWORD vol) +{ + vinf[voice].vol = vol; +} + + +void VC2_VoiceSetFrequency(UBYTE voice, ULONG frq) +{ + vinf[voice].frq = frq; +} + + +void VC2_VoiceSetPanning(UBYTE voice, ULONG pan) +{ + vinf[voice].pan = pan; +} + + +void VC2_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 VC2_VoiceStop(UBYTE voice) +{ + vinf[voice].active = 0; +} + + +BOOL VC2_VoiceStopped(UBYTE voice) +{ + return(vinf[voice].active==0); +} + + +void VC2_VoiceReleaseSustain(UBYTE voice) +{ + +} + + +SLONG VC2_VoiceGetPosition(UBYTE voice) +{ + return(vinf[voice].current>>FRACBITS); +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ + + +void VC2_SampleUnload(SWORD handle) +{ + void *sampleadr = Samples[handle]; + + free(sampleadr); + Samples[handle] = NULL; +} + + +SWORD VC2_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); + + 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); + + // 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 VC2_SampleSpace(int type) +{ + return vc_memory; +} + + +ULONG VC2_SampleLength(int type, SAMPLE *s) +{ + return (s->length * ((s->flags & SF_16BITS) ? 2 : 1)) + 16; +} + + +/************************************************** +*************************************************** +*************************************************** +**************************************************/ +