From 1393af4f9f2bb081b48006b29fed6ec56dc2dbab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Mon, 9 Feb 2015 08:11:07 -0800 Subject: Add a comment detailing how the HRTF channel buffer is set up --- Alc/ALu.c | 64 ++++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/Alc/ALu.c b/Alc/ALu.c index 0edf57bb..cd23057c 100644 --- a/Alc/ALu.c +++ b/Alc/ALu.c @@ -93,6 +93,27 @@ extern inline void aluMatrixSet(aluMatrix *restrict matrix, ALfloat m00, ALfloat ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); +/* NOTE: HRTF is set up a bit special in the device. By default, the device's + * DryBuffer, NumChannels, ChannelName, and Channel fields correspond to the + * output mixing format, and the DryBuffer is then converted and written to the + * backend's audio buffer. + * + * With HRTF, these fields correspond to a virtual format (typically 8-channel + * cube), and the actual output is stored in DryBuffer[NumChannels] for the + * left channel and DryBuffer[NumChannels+1] for the right. As a final output + * step, the virtual channels will have HRTF applied and written to the actual + * output. Things like effects and B-Format decoding will want to write to the + * virtual channels so that they can be mixed with HRTF in full 3D. + * + * Sources that get mixed using HRTF directly will need to offset the output + * buffer so that they skip the virtual output and write to the actual output + * channels. This is the reason you'll see + * + * voice->Direct.OutBuffer += voice->Direct.OutChannels; + * voice->Direct.OutChannels = 2; + * + * at various points in the code where HRTF is explicitly used or bypassed. + */ static inline HrtfMixerFunc SelectHrtfMixer(void) { @@ -1176,24 +1197,29 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { - ALuint outchanoffset = 0; - ALuint outchancount = device->NumChannels; + ALfloat (*OutBuffer)[BUFFERSIZE]; + ALuint OutChannels; IncrementRef(&device->MixCount); + OutBuffer = device->DryBuffer; + OutChannels = device->NumChannels; + SamplesToDo = minu(size, BUFFERSIZE); - for(c = 0;c < device->NumChannels;c++) - memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + for(c = 0;c < OutChannels;c++) + memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); if(device->Hrtf) { - outchanoffset = device->NumChannels; - outchancount = 2; - for(c = 0;c < outchancount;c++) - memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat)); + /* Set OutBuffer/OutChannels to correspond to the actual output + * with HRTF. Make sure to clear them too. */ + OutBuffer += OutChannels; + OutChannels = 2; + for(c = 0;c < OutChannels;c++) + memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); } V0(device->Backend,lock)(); - V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]); + V(device->Synth,process)(SamplesToDo, OutBuffer); ctx = ATOMIC_LOAD(&device->ContextList); while(ctx) @@ -1278,9 +1304,9 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) HrtfMixerFunc HrtfMix = SelectHrtfMixer(); ALuint irsize = GetHrtfIrSize(device->Hrtf); for(c = 0;c < device->NumChannels;c++) - HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], 0, - device->Hrtf_Offset, 0, irsize, &device->Hrtf_Params[c], - &device->Hrtf_State[c], SamplesToDo + HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset, + 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c], + SamplesToDo ); device->Hrtf_Offset += SamplesToDo; } @@ -1307,25 +1333,25 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) switch(device->FmtType) { case DevFmtByte: - WRITE(ALbyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUByte: - WRITE(ALubyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtShort: - WRITE(ALshort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUShort: - WRITE(ALushort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtInt: - WRITE(ALint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUInt: - WRITE(ALuint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtFloat: - WRITE(ALfloat, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount); + WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels); break; } #undef WRITE -- cgit v1.2.3