Mercurial > ~darius > hgwebdir.cgi > mikmod
view playercode/virtch.c @ 11:d5cb2cfc8eca
Initial revision
author | darius |
---|---|
date | Fri, 23 Jan 1998 16:05:11 +0000 |
parents | d14fd386d182 |
children |
line wrap: on
line source
/* 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; }