diff --git a/src/hardware/mixer.cpp b/src/hardware/mixer.cpp index 9a6ffcdd..d351c149 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -50,10 +50,21 @@ #include "midi.h" #define MIXER_SSIZE 4 -#define MIXER_SHIFT 14 -#define MIXER_REMAIN ((1< MIN_AUDIO) @@ -64,9 +75,12 @@ static INLINE Bit16s MIXER_CLIP(Bits SAMP) { static struct { Bit32s work[MIXER_BUFSIZE][2]; + //Write/Read pointers for the buffer Bitu pos,done; Bitu needed, min_needed, max_needed; - Bit32u tick_add,tick_remain; + //For every millisecond tick how many samples need to be generated + Bit32u tick_add; + Bit32u tick_counter; float mastervol[2]; MixerChannel * channels; bool nosound; @@ -85,6 +99,7 @@ MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * nam chan->next=mixer.channels; chan->SetVolume(1,1); chan->enabled=false; + chan->interpolate = false; mixer.channels=chan; return chan; } @@ -132,65 +147,75 @@ void MixerChannel::Enable(bool _yesno) { if (_yesno==enabled) return; enabled=_yesno; if (enabled) { - freq_index=MIXER_REMAIN; + freq_counter = 0; SDL_LockAudio(); if (donedone) { - Bitu todo=needed-done; - todo *= freq_add; - todo = (todo >> MIXER_SHIFT) + ((todo & MIXER_REMAIN)!=0); - handler(todo); + Bitu left = (needed - done); + handler(left); } } void MixerChannel::AddSilence(void) { if (done inline void MixerChannel::AddSamples(Bitu len, const Type* data) { - Bits diff[2]; - Bitu mixpos=mixer.pos+done; - freq_index&=MIXER_REMAIN; - Bitu pos=0;Bitu new_pos; - - goto thestart; - for (;;) { - new_pos=freq_index >> MIXER_SHIFT; - if (pos=len) return; + //Position where to write the data + Bitu mixpos = mixer.pos + done; + //Position in the incoming data + Bitu pos = 0; + //Mix and data for the full length + while (1) { + //Does new data need to get read? + while (freq_counter >= FREQ_NEXT) { + //Would this overflow the source data, then it's time to leave + if (pos >= len) + return; + freq_counter -= FREQ_NEXT; + prevSample[0] = nextSample[0]; + if (stereo) { + prevSample[1] = nextSample[1]; + } if ( sizeof( Type) == 1) { if (!signeddata) { if (stereo) { - diff[0]=(((Bit8s)(data[pos*2+0] ^ 0x80)) << 8)-last[0]; - diff[1]=(((Bit8s)(data[pos*2+1] ^ 0x80)) << 8)-last[1]; + nextSample[0]=(((Bit8s)(data[pos*2+0] ^ 0x80)) << 8); + nextSample[1]=(((Bit8s)(data[pos*2+1] ^ 0x80)) << 8); } else { - diff[0]=(((Bit8s)(data[pos] ^ 0x80)) << 8)-last[0]; + nextSample[0]=(((Bit8s)(data[pos] ^ 0x80)) << 8); } } else { if (stereo) { - diff[0]=(data[pos*2+0] << 8)-last[0]; - diff[1]=(data[pos*2+1] << 8)-last[1]; + nextSample[0]=(data[pos*2+0] << 8); + nextSample[1]=(data[pos*2+1] << 8); } else { - diff[0]=(data[pos] << 8)-last[0]; + nextSample[0]=(data[pos] << 8); } } //16bit and 32bit both contain 16bit data internally @@ -198,64 +223,78 @@ thestart: if (signeddata) { if (stereo) { if (nativeorder) { - diff[0]=data[pos*2+0]-last[0]; - diff[1]=data[pos*2+1]-last[1]; + nextSample[0]=data[pos*2+0]; + nextSample[1]=data[pos*2+1]; } else { if ( sizeof( Type) == 2) { - diff[0]=(Bit16s)host_readw((HostPt)&data[pos*2+0])-last[0]; - diff[1]=(Bit16s)host_readw((HostPt)&data[pos*2+1])-last[1]; + nextSample[0]=(Bit16s)host_readw((HostPt)&data[pos*2+0]); + nextSample[1]=(Bit16s)host_readw((HostPt)&data[pos*2+1]); } else { - diff[0]=(Bit32s)host_readd((HostPt)&data[pos*2+0])-last[0]; - diff[1]=(Bit32s)host_readd((HostPt)&data[pos*2+1])-last[1]; + nextSample[0]=(Bit32s)host_readd((HostPt)&data[pos*2+0]); + nextSample[1]=(Bit32s)host_readd((HostPt)&data[pos*2+1]); } } } else { if (nativeorder) { - diff[0]=data[pos]-last[0]; + nextSample[0] = data[pos]; } else { if ( sizeof( Type) == 2) { - diff[0]=(Bit16s)host_readw((HostPt)&data[pos])-last[0]; + nextSample[0]=(Bit16s)host_readw((HostPt)&data[pos]); } else { - diff[0]=(Bit32s)host_readd((HostPt)&data[pos])-last[0]; + nextSample[0]=(Bit32s)host_readd((HostPt)&data[pos]); } } } } else { if (stereo) { if (nativeorder) { - diff[0]=(Bits)data[pos*2+0]-32768-last[0]; - diff[1]=(Bits)data[pos*2+1]-32768-last[1]; + nextSample[0]=(Bits)data[pos*2+0]-32768; + nextSample[1]=(Bits)data[pos*2+1]-32768; } else { if ( sizeof( Type) == 2) { - diff[0]=(Bits)host_readw((HostPt)&data[pos*2+0])-32768-last[0]; - diff[1]=(Bits)host_readw((HostPt)&data[pos*2+1])-32768-last[1]; + nextSample[0]=(Bits)host_readw((HostPt)&data[pos*2+0])-32768; + nextSample[1]=(Bits)host_readw((HostPt)&data[pos*2+1])-32768; } else { - diff[0]=(Bits)host_readd((HostPt)&data[pos*2+0])-32768-last[0]; - diff[1]=(Bits)host_readd((HostPt)&data[pos*2+1])-32768-last[1]; + nextSample[0]=(Bits)host_readd((HostPt)&data[pos*2+0])-32768; + nextSample[1]=(Bits)host_readd((HostPt)&data[pos*2+1])-32768; } } } else { if (nativeorder) { - diff[0]=(Bits)data[pos]-32768-last[0]; + nextSample[0]=(Bits)data[pos]-32768; } else { if ( sizeof( Type) == 2) { - diff[0]=(Bits)host_readw((HostPt)&data[pos])-32768-last[0]; + nextSample[0]=(Bits)host_readw((HostPt)&data[pos])-32768; } else { - diff[0]=(Bits)host_readd((HostPt)&data[pos])-32768-last[0]; + nextSample[0]=(Bits)host_readd((HostPt)&data[pos])-32768; } } } } } + //This sample has been handled now, increase position + pos++; } - Bits diff_mul=freq_index & MIXER_REMAIN; - freq_index+=freq_add; - mixpos&=MIXER_BUFMASK; - Bits sample=last[0]+((diff[0]*diff_mul) >> MIXER_SHIFT); - mixer.work[mixpos][0]+=sample*volmul[0]; - if (stereo) sample=last[1]+((diff[1]*diff_mul) >> MIXER_SHIFT); - mixer.work[mixpos][1]+=sample*volmul[1]; - mixpos++;done++; + //Where to write + mixpos &= MIXER_BUFMASK; + Bit32s* write = mixer.work[mixpos]; + if (!interpolate) { + write[0] += prevSample[0] * volmul[0]; + write[1] += (stereo ? prevSample[1] : prevSample[0]) * volmul[1]; + } + else { + Bits diff_mul = freq_counter & FREQ_MASK; + Bits sample = prevSample[0] + (((nextSample[0] - prevSample[0]) * diff_mul) >> FREQ_SHIFT); + write[0] += sample*volmul[0]; + if (stereo) { + sample = prevSample[1] + (((nextSample[1] - prevSample[1]) * diff_mul) >> FREQ_SHIFT); + } + write[1] += sample*volmul[1]; + } + //Prepare for next sample + freq_counter += freq_add; + mixpos++; + done++; } } @@ -264,23 +303,26 @@ void MixerChannel::AddStretched(Bitu len,Bit16s * data) { LOG_MSG("Can't add, buffer full"); return; } - Bitu outlen=needed-done;Bits diff; - freq_index=0; - Bitu temp_add=(len << MIXER_SHIFT)/outlen; - Bitu mixpos=mixer.pos+done;done=needed; + //Target samples this inputs gets stretched into + Bitu outlen=needed-done; + Bitu index = 0; + Bitu index_add = (len << FREQ_SHIFT)/outlen; + Bitu mixpos=mixer.pos+done; + done=needed; Bitu pos=0; - diff=data[0]-last[0]; + while (outlen--) { - Bitu new_pos=freq_index >> MIXER_SHIFT; - if (pos> FREQ_SHIFT; + if (pos != new_pos) { + //Forward the previous sample + prevSample[0] = data[0]; + data++; } - Bits diff_mul=freq_index & MIXER_REMAIN; - freq_index+=temp_add; - mixpos&=MIXER_BUFMASK; - Bits sample=last[0]+((diff*diff_mul) >> MIXER_SHIFT); + Bits diff = data[0] - prevSample[0]; + Bits diff_mul = index & FREQ_MASK; + index += index_add; + mixpos &= MIXER_BUFMASK; + Bits sample = prevSample[0]+((diff*diff_mul) >> FREQ_SHIFT); mixer.work[mixpos][0]+=sample*volmul[0]; mixer.work[mixpos][1]+=sample*volmul[1]; mixpos++; @@ -378,16 +420,16 @@ static void MIXER_MixData(Bitu needed) { } //Reset the the tick_add for constant speed if( Mixer_irq_important() ) - mixer.tick_add = ((mixer.freq) << MIXER_SHIFT)/1000; + mixer.tick_add = ((mixer.freq) << TICK_SHIFT)/1000; mixer.done = needed; } static void MIXER_Mix(void) { SDL_LockAudio(); MIXER_MixData(mixer.needed); - mixer.tick_remain+=mixer.tick_add; - mixer.needed+=(mixer.tick_remain>>MIXER_SHIFT); - mixer.tick_remain&=MIXER_REMAIN; + mixer.tick_counter += mixer.tick_add; + mixer.needed+=(mixer.tick_counter >> TICK_SHIFT); + mixer.tick_counter &= TICK_MASK; SDL_UnlockAudio(); } @@ -405,9 +447,9 @@ static void MIXER_Mix_NoSound(void) { else chan->done=0; } /* Set values for next tick */ - mixer.tick_remain+=mixer.tick_add; - mixer.needed=mixer.tick_remain>>MIXER_SHIFT; - mixer.tick_remain&=MIXER_REMAIN; + mixer.tick_counter += mixer.tick_add; + mixer.needed += (mixer.tick_counter >> TICK_SHIFT); + mixer.tick_counter &= TICK_MASK; mixer.done=0; } @@ -415,7 +457,9 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { Bitu need=(Bitu)len/MIXER_SSIZE; Bit16s * output=(Bit16s *)stream; Bitu reduce; - Bitu pos, index, index_add; + Bitu pos; + //Local resampling counter to manipulate the data when sending it off to the callback + Bitu index, index_add; Bits sample; /* Enough room in the buffer ? */ if (mixer.done < need) { @@ -423,15 +467,15 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { if((need - mixer.done) > (need >>7) ) //Max 1 procent stretch. return; reduce = mixer.done; - index_add = (reduce << MIXER_SHIFT) / need; - mixer.tick_add = ((mixer.freq+mixer.min_needed) << MIXER_SHIFT)/1000; + index_add = (reduce << TICK_SHIFT) / need; + mixer.tick_add = ((mixer.freq+mixer.min_needed) << TICK_SHIFT)/1000; } else if (mixer.done < mixer.max_needed) { Bitu left = mixer.done - need; if (left < mixer.min_needed) { if( !Mixer_irq_important() ) { Bitu needed = mixer.needed - need; Bitu diff = (mixer.min_needed>needed?mixer.min_needed:needed) - left; - mixer.tick_add = ((mixer.freq+(diff*3)) << MIXER_SHIFT)/1000; + mixer.tick_add = ((mixer.freq+(diff*3)) << TICK_SHIFT)/1000; left = 0; //No stretching as we compensate with the tick_add value } else { left = (mixer.min_needed - left); @@ -439,10 +483,10 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { } // LOG_MSG("needed underrun need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left); reduce = need - left; - index_add = (reduce << MIXER_SHIFT) / need; + index_add = (reduce << TICK_SHIFT) / need; } else { reduce = need; - index_add = (1 << MIXER_SHIFT); + index_add = (1 << TICK_SHIFT); // LOG_MSG("regular run need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left); /* Mixer tick value being updated: @@ -454,11 +498,11 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { Bitu diff = left - mixer.min_needed; if(diff > (mixer.min_needed<<1)) diff = mixer.min_needed<<1; if(diff > (mixer.min_needed>>1)) - mixer.tick_add = ((mixer.freq-(diff/5)) << MIXER_SHIFT)/1000; + mixer.tick_add = ((mixer.freq-(diff/5)) << TICK_SHIFT)/1000; else if (diff > (mixer.min_needed>>4)) - mixer.tick_add = ((mixer.freq-(diff>>3)) << MIXER_SHIFT)/1000; + mixer.tick_add = ((mixer.freq-(diff>>3)) << TICK_SHIFT)/1000; else - mixer.tick_add = (mixer.freq<< MIXER_SHIFT)/1000; + mixer.tick_add = (mixer.freq<< TICK_SHIFT)/1000; } } else { /* There is way too much data in the buffer */ @@ -467,9 +511,9 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { index_add = MIXER_BUFSIZE - 2*mixer.min_needed; else index_add = mixer.done - 2*mixer.min_needed; - index_add = (index_add << MIXER_SHIFT) / need; + index_add = (index_add << TICK_SHIFT) / need; reduce = mixer.done - 2* mixer.min_needed; - mixer.tick_add = ((mixer.freq-(mixer.min_needed/5)) << MIXER_SHIFT)/1000; + mixer.tick_add = ((mixer.freq-(mixer.min_needed/5)) << TICK_SHIFT)/1000; } /* Reduce done count in all channels */ for (MixerChannel * chan=mixer.channels;chan;chan=chan->next) { @@ -479,7 +523,7 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { // Reset mixer.tick_add when irqs are important if( Mixer_irq_important() ) - mixer.tick_add=(mixer.freq<< MIXER_SHIFT)/1000; + mixer.tick_add=(mixer.freq<< TICK_SHIFT)/1000; mixer.done -= reduce; mixer.needed -= reduce; @@ -488,7 +532,7 @@ static void SDLCALL MIXER_CallBack(void * userdata, Uint8 *stream, int len) { index = 0; if(need != reduce) { while (need--) { - Bitu i = (pos + (index >> MIXER_SHIFT )) & MIXER_BUFMASK; + Bitu i = (pos + (index >> TICK_SHIFT )) & MIXER_BUFMASK; index += index_add; sample=mixer.work[i][0]>>MIXER_VOLSHIFT; *output++=MIXER_CLIP(sample); @@ -633,22 +677,22 @@ void MIXER_Init(Section* sec) { spec.userdata=NULL; spec.samples=(Uint16)mixer.blocksize; - mixer.tick_remain=0; + mixer.tick_counter=0; if (mixer.nosound) { LOG_MSG("MIXER: No Sound Mode Selected."); - mixer.tick_add=((mixer.freq) << MIXER_SHIFT)/1000; + mixer.tick_add=((mixer.freq) << TICK_SHIFT)/1000; TIMER_AddTickHandler(MIXER_Mix_NoSound); } else if (SDL_OpenAudio(&spec, &obtained) <0 ) { mixer.nosound = true; LOG_MSG("MIXER: Can't open audio: %s , running in nosound mode.",SDL_GetError()); - mixer.tick_add=((mixer.freq) << MIXER_SHIFT)/1000; + mixer.tick_add=((mixer.freq) << TICK_SHIFT)/1000; TIMER_AddTickHandler(MIXER_Mix_NoSound); } else { if((mixer.freq != obtained.freq) || (mixer.blocksize != obtained.samples)) LOG_MSG("MIXER: Got different values from SDL: freq %d, blocksize %d",obtained.freq,obtained.samples); mixer.freq=obtained.freq; mixer.blocksize=obtained.samples; - mixer.tick_add=(mixer.freq << MIXER_SHIFT)/1000; + mixer.tick_add=(mixer.freq << TICK_SHIFT)/1000; TIMER_AddTickHandler(MIXER_Mix); SDL_PauseAudio(0); }