Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/virtch2.c @ 9:990c9dadb348
Initial revision
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:10 +0000 |
parents | 5d614bcc4287 |
children |
line wrap: on
line source
/* 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; } /************************************************** *************************************************** *************************************************** **************************************************/