/** * OpenAL cross platform audio library * Copyright (C) 1999-2007 by authors. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ #include "config.h" #include #include #include #include #include #include "alMain.h" #include "AL/al.h" #include "AL/alc.h" #include "alSource.h" #include "alBuffer.h" #include "alThunk.h" #include "alListener.h" #include "alAuxEffectSlot.h" #include "alu.h" #include "bs2b.h" #include "alReverb.h" #if defined(HAVE_STDINT_H) #include typedef int64_t ALint64; #elif defined(HAVE___INT64) typedef __int64 ALint64; #elif (SIZEOF_LONG == 8) typedef long ALint64; #elif (SIZEOF_LONG_LONG == 8) typedef long long ALint64; #endif #define FRACTIONBITS 14 #define FRACTIONMASK ((1L<Send[i].Slot->effect.type == AL_EFFECT_REVERB) wetgainhf[i] *= ALSource->Send[0].Slot->effect.Reverb.GainHF; switch(ALSource->Send[i].WetFilter.type) { case AL_FILTER_LOWPASS: wetsend[i] *= ALSource->Send[i].WetFilter.Gain; wetgainhf[i] *= ALSource->Send[i].WetFilter.GainHF; break; } wetsend[i] *= ListenerGain; } else { wetsend[i] = 0.0f; wetgainhf[i] = 1.0f; } } for(i = NumSends;i < MAX_SENDS;i++) { wetsend[i] = 0.0f; wetgainhf[i] = 1.0f; } //5. Apply filter gains and filters switch(ALSource->DirectFilter.type) { case AL_FILTER_LOWPASS: DryMix *= ALSource->DirectFilter.Gain; DryGainHF *= ALSource->DirectFilter.GainHF; break; } DryMix *= ListenerGain; // Use energy-preserving panning algorithm for multi-speaker playback length = aluSqrt(Position[0]*Position[0] + Position[1]*Position[1] + Position[2]*Position[2]); length = __max(length, MinDist); if(length > 0.0f) { ALfloat invlen = 1.0f/length; Position[0] *= invlen; Position[1] *= invlen; Position[2] *= invlen; } pos = aluCart2LUTpos(-Position[2], Position[0]); SpeakerGain = &ALContext->PanningLUT[OUTPUTCHANNELS * pos]; DirGain = aluSqrt(Position[0]*Position[0] + Position[2]*Position[2]); // elevation adjustment for directional gain. this sucks, but // has low complexity AmbientGain = 1.0/aluSqrt(ALContext->NumChan) * (1.0-DirGain); for(s = 0; s < OUTPUTCHANNELS; s++) { ALfloat gain = SpeakerGain[s]*DirGain + AmbientGain; drysend[s] = DryMix * gain; } *drygainhf = DryGainHF; } else { //1. Multi-channel buffers always play "normal" pitch[0] = ALSource->flPitch; DryMix = SourceVolume; DryMix = __min(DryMix,MaxVolume); DryMix = __max(DryMix,MinVolume); switch(ALSource->DirectFilter.type) { case AL_FILTER_LOWPASS: DryMix *= ALSource->DirectFilter.Gain; DryGainHF *= ALSource->DirectFilter.GainHF; break; } drysend[FRONT_LEFT] = DryMix * ListenerGain; drysend[FRONT_RIGHT] = DryMix * ListenerGain; drysend[SIDE_LEFT] = DryMix * ListenerGain; drysend[SIDE_RIGHT] = DryMix * ListenerGain; drysend[BACK_LEFT] = DryMix * ListenerGain; drysend[BACK_RIGHT] = DryMix * ListenerGain; drysend[FRONT_CENTER] = DryMix * ListenerGain; drysend[BACK_CENTER] = DryMix * ListenerGain; drysend[LFE] = DryMix * ListenerGain; *drygainhf = DryGainHF; for(i = 0;i < MAX_SENDS;i++) { wetsend[i] = 0.0f; wetgainhf[i] = 1.0f; } } } static __inline ALshort lerp(ALshort val1, ALshort val2, ALint frac) { return val1 + (((val2-val1)*frac)>>FRACTIONBITS); } ALvoid aluMixData(ALCcontext *ALContext,ALvoid *buffer,ALsizei size,ALenum format) { static float DryBuffer[BUFFERSIZE][OUTPUTCHANNELS]; static float DummyBuffer[BUFFERSIZE]; ALfloat *WetBuffer[MAX_SENDS]; ALfloat (*Matrix)[OUTPUTCHANNELS] = ALContext->ChannelMatrix; ALfloat DrySend[OUTPUTCHANNELS] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; ALfloat WetSend[MAX_SENDS]; ALfloat DryGainHF = 0.0f; ALfloat WetGainHF[MAX_SENDS]; ALuint rampLength; ALfloat dryGainStep[OUTPUTCHANNELS]; ALfloat wetGainStep[MAX_SENDS]; ALuint BlockAlign,BufferSize; ALuint DataSize=0,DataPosInt=0,DataPosFrac=0; ALuint Channels,Frequency,ulExtraSamples; ALfloat Pitch; ALint Looping,State; ALint increment; ALuint Buffer; ALuint SamplesToDo; ALsource *ALSource; ALbuffer *ALBuffer; ALeffectslot *ALEffectSlot; ALfloat values[OUTPUTCHANNELS]; ALfloat value; ALshort *Data; ALuint i,j,k,out; ALfloat cw, a, g; ALbufferlistitem *BufferListItem; ALuint loop; ALint64 DataSize64,DataPos64; FILTER *DryFilter, *WetFilter[MAX_SENDS]; int fpuState; SuspendContext(ALContext); #if defined(HAVE_FESETROUND) fpuState = fegetround(); fesetround(FE_TOWARDZERO); #elif defined(HAVE__CONTROLFP) fpuState = _controlfp(0, 0); _controlfp(_RC_CHOP, _MCW_RC); #else (void)fpuState; #endif //Figure output format variables BlockAlign = aluChannelsFromFormat(format); BlockAlign *= aluBytesFromFormat(format); size /= BlockAlign; while(size > 0) { //Setup variables SamplesToDo = min(size, BUFFERSIZE); if(ALContext) { ALEffectSlot = ALContext->AuxiliaryEffectSlot; ALSource = ALContext->Source; rampLength = ALContext->Frequency * MIN_RAMP_LENGTH / 1000; } else { ALEffectSlot = NULL; ALSource = NULL; rampLength = 0; } rampLength = max(rampLength, SamplesToDo); //Clear mixing buffer memset(DryBuffer, 0, SamplesToDo*OUTPUTCHANNELS*sizeof(ALfloat)); //Actual mixing loop while(ALSource) { j = 0; State = ALSource->state; while(State == AL_PLAYING && j < SamplesToDo) { DataSize = 0; DataPosInt = 0; DataPosFrac = 0; //Get buffer info if((Buffer = ALSource->ulBufferID)) { ALBuffer = (ALbuffer*)ALTHUNK_LOOKUPENTRY(Buffer); Data = ALBuffer->data; Channels = aluChannelsFromFormat(ALBuffer->format); DataSize = ALBuffer->size; DataSize /= Channels * aluBytesFromFormat(ALBuffer->format); Frequency = ALBuffer->frequency; DataPosInt = ALSource->position; DataPosFrac = ALSource->position_fraction; if(DataPosInt >= DataSize) goto skipmix; //Get source info DryFilter = &ALSource->iirFilter; for(i = 0;i < MAX_SENDS;i++) { WetFilter[i] = &ALSource->Send[i].iirFilter; WetBuffer[i] = (ALSource->Send[i].Slot ? ALSource->Send[i].Slot->WetBuffer : DummyBuffer); } CalcSourceParams(ALContext, ALSource, (Channels==1) ? AL_TRUE : AL_FALSE, DrySend, WetSend, &Pitch, &DryGainHF, WetGainHF); Pitch = (Pitch*Frequency) / ALContext->Frequency; if(Channels == 1) { // Update filter coefficients. Calculations based on // the I3DL2 spec. cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / ALContext->Frequency); // We use four chained one-pole filters, so we need to // take the fourth root of the squared gain, which is // the same as the square root of the base gain. // Be careful with gains < 0.0001, as that causes the // coefficient to head towards 1, which will flatten // the signal g = aluSqrt(__max(DryGainHF, 0.0001f)); a = 0.0f; if(g < 0.9999f) // 1-epsilon a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); DryFilter->coeff = a; for(i = 0;i < MAX_SENDS;i++) { // The wet path uses two chained one-pole filters, // so take the base gain (square root of the // squared gain) g = __max(WetGainHF[i], 0.01f); a = 0.0f; if(g < 0.9999f) // 1-epsilon a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); WetFilter[i]->coeff = a; } } else { // Multi-channel sources use two chained one-pole // filters cw = cos(2.0*M_PI * LOWPASSFREQCUTOFF / ALContext->Frequency); g = __max(DryGainHF, 0.01f); a = 0.0f; if(g < 0.9999f) // 1-epsilon a = (1 - g*cw - aluSqrt(2*g*(1-cw) - g*g*(1 - cw*cw))) / (1 - g); DryFilter->coeff = a; for(i = 0;i < MAX_SENDS;i++) WetFilter[i]->coeff = 0.0f; if(DuplicateStereo && Channels == 2) { Matrix[FRONT_LEFT][SIDE_LEFT] = 1.0f; Matrix[FRONT_RIGHT][SIDE_RIGHT] = 1.0f; Matrix[FRONT_LEFT][BACK_LEFT] = 1.0f; Matrix[FRONT_RIGHT][BACK_RIGHT] = 1.0f; } else if(DuplicateStereo) { Matrix[FRONT_LEFT][SIDE_LEFT] = 0.0f; Matrix[FRONT_RIGHT][SIDE_RIGHT] = 0.0f; Matrix[FRONT_LEFT][BACK_LEFT] = 0.0f; Matrix[FRONT_RIGHT][BACK_RIGHT] = 0.0f; } } //Compute the gain steps for each output channel if(ALSource->FirstStart && DataPosInt == 0 && DataPosFrac == 0) { for(i = 0;i < OUTPUTCHANNELS;i++) dryGainStep[i] = 0; for(i = 0;i < MAX_SENDS;i++) wetGainStep[i] = 0; } else { for(i = 0;i < OUTPUTCHANNELS;i++) { dryGainStep[i] = (DrySend[i]-ALSource->DryGains[i]) / rampLength; DrySend[i] = ALSource->DryGains[i]; } for(i = 0;i < MAX_SENDS;i++) { wetGainStep[i] = (WetSend[i]-ALSource->WetGains[i]) / rampLength; WetSend[i] = ALSource->WetGains[i]; } } ALSource->FirstStart = AL_FALSE; //Compute 18.14 fixed point step if(Pitch > (float)MAX_PITCH) Pitch = (float)MAX_PITCH; increment = (ALint)(Pitch*(ALfloat)(1L<queue; for(loop = 0; loop < ALSource->BuffersPlayed; loop++) { if(BufferListItem) BufferListItem = BufferListItem->next; } if (BufferListItem) { if (BufferListItem->next) { ALbuffer *NextBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(BufferListItem->next->buffer); if(NextBuf && NextBuf->data) { ulExtraSamples = min(NextBuf->size, (ALint)(ALBuffer->padding*Channels*2)); memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples); } } else if (ALSource->bLooping) { ALbuffer *NextBuf = (ALbuffer*)ALTHUNK_LOOKUPENTRY(ALSource->queue->buffer); if (NextBuf && NextBuf->data) { ulExtraSamples = min(NextBuf->size, (ALint)(ALBuffer->padding*Channels*2)); memcpy(&Data[DataSize*Channels], NextBuf->data, ulExtraSamples); } } else memset(&Data[DataSize*Channels], 0, (ALBuffer->padding*Channels*2)); } BufferSize = min(BufferSize, (SamplesToDo-j)); //Actual sample mixing loop k = 0; Data += DataPosInt*Channels; if(Channels == 1) /* Mono */ { ALfloat outsamp; while(BufferSize--) { for(i = 0;i < OUTPUTCHANNELS;i++) DrySend[i] += dryGainStep[i]; for(i = 0;i < MAX_SENDS;i++) WetSend[i] += wetGainStep[i]; //First order interpolator value = lerp(Data[k], Data[k+1], DataPosFrac); //Direct path final mix buffer and panning outsamp = lpFilter4P(DryFilter, 0, value); DryBuffer[j][FRONT_LEFT] += outsamp*DrySend[FRONT_LEFT]; DryBuffer[j][FRONT_RIGHT] += outsamp*DrySend[FRONT_RIGHT]; DryBuffer[j][SIDE_LEFT] += outsamp*DrySend[SIDE_LEFT]; DryBuffer[j][SIDE_RIGHT] += outsamp*DrySend[SIDE_RIGHT]; DryBuffer[j][BACK_LEFT] += outsamp*DrySend[BACK_LEFT]; DryBuffer[j][BACK_RIGHT] += outsamp*DrySend[BACK_RIGHT]; DryBuffer[j][FRONT_CENTER] += outsamp*DrySend[FRONT_CENTER]; DryBuffer[j][BACK_CENTER] += outsamp*DrySend[BACK_CENTER]; //Room path final mix buffer and panning for(i = 0;i < MAX_SENDS;i++) { outsamp = lpFilter2P(WetFilter[i], 0, value); WetBuffer[i][j] += outsamp*WetSend[i]; } DataPosFrac += increment; k += DataPosFrac>>FRACTIONBITS; DataPosFrac &= FRACTIONMASK; j++; } } else if(Channels == 2) /* Stereo */ { const int chans[] = { FRONT_LEFT, FRONT_RIGHT }; #define DO_MIX() do { \ for(i = 0;i < MAX_SENDS;i++) \ WetSend[i] += wetGainStep[i]*BufferSize; \ while(BufferSize--) \ { \ for(i = 0;i < OUTPUTCHANNELS;i++) \ DrySend[i] += dryGainStep[i]; \ \ for(i = 0;i < Channels;i++) \ { \ value = lerp(Data[k*Channels + i], Data[(k+1)*Channels + i], DataPosFrac); \ values[i] = lpFilter2P(DryFilter, chans[i]*2, value)*DrySend[chans[i]]; \ } \ for(out = 0;out < OUTPUTCHANNELS;out++) \ { \ ALfloat sum = 0.0f; \ for(i = 0;i < Channels;i++) \ sum += values[i]*Matrix[chans[i]][out]; \ DryBuffer[j][out] += sum; \ } \ \ DataPosFrac += increment; \ k += DataPosFrac>>FRACTIONBITS; \ DataPosFrac &= FRACTIONMASK; \ j++; \ } \ } while(0) DO_MIX(); } else if(Channels == 4) /* Quad */ { const int chans[] = { FRONT_LEFT, FRONT_RIGHT, BACK_LEFT, BACK_RIGHT }; DO_MIX(); } else if(Channels == 6) /* 5.1 */ { const int chans[] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_LEFT, BACK_RIGHT }; DO_MIX(); } else if(Channels == 7) /* 6.1 */ { const int chans[] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_CENTER, SIDE_LEFT, SIDE_RIGHT }; DO_MIX(); } else if(Channels == 8) /* 7.1 */ { const int chans[] = { FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER, LFE, BACK_LEFT, BACK_RIGHT, SIDE_LEFT, SIDE_RIGHT }; DO_MIX(); #undef DO_MIX } else /* Unknown? */ { for(i = 0;i < OUTPUTCHANNELS;i++) DrySend[i] += dryGainStep[i]*BufferSize; for(i = 0;i < MAX_SENDS;i++) WetSend[i] += wetGainStep[i]*BufferSize; while(BufferSize--) { DataPosFrac += increment; k += DataPosFrac>>FRACTIONBITS; DataPosFrac &= FRACTIONMASK; j++; } } DataPosInt += k; //Update source info ALSource->position = DataPosInt; ALSource->position_fraction = DataPosFrac; for(i = 0;i < OUTPUTCHANNELS;i++) ALSource->DryGains[i] = DrySend[i]; for(i = 0;i < MAX_SENDS;i++) ALSource->WetGains[i] = WetSend[i]; skipmix: ; } //Handle looping sources if(!Buffer || DataPosInt >= DataSize) { //queueing if(ALSource->queue) { Looping = ALSource->bLooping; if(ALSource->BuffersPlayed < (ALSource->BuffersInQueue-1)) { BufferListItem = ALSource->queue; for(loop = 0; loop <= ALSource->BuffersPlayed; loop++) { if(BufferListItem) { if(!Looping) BufferListItem->bufferstate = PROCESSED; BufferListItem = BufferListItem->next; } } if(BufferListItem) ALSource->ulBufferID = BufferListItem->buffer; ALSource->position = DataPosInt-DataSize; ALSource->position_fraction = DataPosFrac; ALSource->BuffersPlayed++; } else { if(!Looping) { /* alSourceStop */ ALSource->state = AL_STOPPED; ALSource->inuse = AL_FALSE; ALSource->BuffersPlayed = ALSource->BuffersInQueue; BufferListItem = ALSource->queue; while(BufferListItem != NULL) { BufferListItem->bufferstate = PROCESSED; BufferListItem = BufferListItem->next; } ALSource->position = DataSize; ALSource->position_fraction = 0; } else { /* alSourceRewind */ /* alSourcePlay */ ALSource->state = AL_PLAYING; ALSource->inuse = AL_TRUE; ALSource->play = AL_TRUE; ALSource->BuffersPlayed = 0; BufferListItem = ALSource->queue; while(BufferListItem != NULL) { BufferListItem->bufferstate = PENDING; BufferListItem = BufferListItem->next; } ALSource->ulBufferID = ALSource->queue->buffer; if(ALSource->BuffersInQueue == 1) ALSource->position = DataPosInt%DataSize; else ALSource->position = DataPosInt-DataSize; ALSource->position_fraction = DataPosFrac; } } } } //Get source state State = ALSource->state; } ALSource = ALSource->next; } // effect slot processing while(ALEffectSlot) { if(ALEffectSlot->effect.type == AL_EFFECT_REVERB) VerbProcess(ALEffectSlot->ReverbState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer); else if(ALEffectSlot->effect.type == AL_EFFECT_ECHO) EchoProcess(ALEffectSlot->EchoState, SamplesToDo, ALEffectSlot->WetBuffer, DryBuffer); for(i = 0;i < SamplesToDo;i++) ALEffectSlot->WetBuffer[i] = 0.0f; ALEffectSlot = ALEffectSlot->next; } //Post processing loop switch(format) { case AL_FORMAT_MONO8: for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT])>>8)+128); buffer = ((ALubyte*)buffer) + 1; } break; case AL_FORMAT_STEREO8: if(ALContext && ALContext->bs2b) { for(i = 0;i < SamplesToDo;i++) { float samples[2]; samples[0] = DryBuffer[i][FRONT_LEFT]; samples[1] = DryBuffer[i][FRONT_RIGHT]; bs2b_cross_feed(ALContext->bs2b, samples); ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(samples[0])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(samples[1])>>8)+128); buffer = ((ALubyte*)buffer) + 2; } } else { for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128); buffer = ((ALubyte*)buffer) + 2; } } break; case AL_FORMAT_QUAD8: for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128); ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128); buffer = ((ALubyte*)buffer) + 4; } break; case AL_FORMAT_51CHN8: for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128); #ifdef _WIN32 /* Of course, Windows can't use the same ordering... */ ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128); ((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128); ((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128); #else ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128); ((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128); ((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128); #endif buffer = ((ALubyte*)buffer) + 6; } break; case AL_FORMAT_61CHN8: for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128); ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128); ((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_CENTER])>>8)+128); ((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128); ((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT])>>8)+128); buffer = ((ALubyte*)buffer) + 7; } break; case AL_FORMAT_71CHN8: for(i = 0;i < SamplesToDo;i++) { ((ALubyte*)buffer)[0] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_LEFT])>>8)+128); ((ALubyte*)buffer)[1] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_RIGHT])>>8)+128); #ifdef _WIN32 ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128); ((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128); ((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128); #else ((ALubyte*)buffer)[2] = (ALubyte)((aluF2S(DryBuffer[i][BACK_LEFT])>>8)+128); ((ALubyte*)buffer)[3] = (ALubyte)((aluF2S(DryBuffer[i][BACK_RIGHT])>>8)+128); ((ALubyte*)buffer)[4] = (ALubyte)((aluF2S(DryBuffer[i][FRONT_CENTER])>>8)+128); ((ALubyte*)buffer)[5] = (ALubyte)((aluF2S(DryBuffer[i][LFE])>>8)+128); #endif ((ALubyte*)buffer)[6] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_LEFT])>>8)+128); ((ALubyte*)buffer)[7] = (ALubyte)((aluF2S(DryBuffer[i][SIDE_RIGHT])>>8)+128); buffer = ((ALubyte*)buffer) + 8; } break; case AL_FORMAT_MONO16: for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]+DryBuffer[i][FRONT_RIGHT]); buffer = ((ALshort*)buffer) + 1; } break; case AL_FORMAT_STEREO16: if(ALContext && ALContext->bs2b) { for(i = 0;i < SamplesToDo;i++) { float samples[2]; samples[0] = DryBuffer[i][FRONT_LEFT]; samples[1] = DryBuffer[i][FRONT_RIGHT]; bs2b_cross_feed(ALContext->bs2b, samples); ((ALshort*)buffer)[0] = aluF2S(samples[0]); ((ALshort*)buffer)[1] = aluF2S(samples[1]); buffer = ((ALshort*)buffer) + 2; } } else { for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]); ((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]); buffer = ((ALshort*)buffer) + 2; } } break; case AL_FORMAT_QUAD16: for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]); ((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]); ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]); buffer = ((ALshort*)buffer) + 4; } break; case AL_FORMAT_51CHN16: for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]); ((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]); #ifdef _WIN32 ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]); ((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]); ((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]); #else ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]); ((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][FRONT_CENTER]); ((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]); #endif buffer = ((ALshort*)buffer) + 6; } break; case AL_FORMAT_61CHN16: for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]); ((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]); ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]); ((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_CENTER]); ((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][SIDE_LEFT]); ((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_RIGHT]); buffer = ((ALshort*)buffer) + 7; } break; case AL_FORMAT_71CHN16: for(i = 0;i < SamplesToDo;i++) { ((ALshort*)buffer)[0] = aluF2S(DryBuffer[i][FRONT_LEFT]); ((ALshort*)buffer)[1] = aluF2S(DryBuffer[i][FRONT_RIGHT]); #ifdef _WIN32 ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][FRONT_CENTER]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][LFE]); ((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][BACK_LEFT]); ((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][BACK_RIGHT]); #else ((ALshort*)buffer)[2] = aluF2S(DryBuffer[i][BACK_LEFT]); ((ALshort*)buffer)[3] = aluF2S(DryBuffer[i][BACK_RIGHT]); ((ALshort*)buffer)[4] = aluF2S(DryBuffer[i][FRONT_CENTER]); ((ALshort*)buffer)[5] = aluF2S(DryBuffer[i][LFE]); #endif ((ALshort*)buffer)[6] = aluF2S(DryBuffer[i][SIDE_LEFT]); ((ALshort*)buffer)[7] = aluF2S(DryBuffer[i][SIDE_RIGHT]); buffer = ((ALshort*)buffer) + 8; } break; default: break; } size -= SamplesToDo; } #if defined(HAVE_FESETROUND) fesetround(fpuState); #elif defined(HAVE__CONTROLFP) _controlfp(fpuState, 0xfffff); #endif ProcessContext(ALContext); }