diff options
author | Chris Robinson <[email protected]> | 2016-02-26 21:48:03 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2016-02-26 21:48:03 -0800 |
commit | 99f685d20d0e9bece99a6019a98d8cb3aecef227 (patch) | |
tree | a000504d28b7228402b95d48700b1bf339148ca2 | |
parent | ac91083ceb27892ce1d474a578634bff580b56d3 (diff) |
Add an option for pair-wise stereo panning
-rw-r--r-- | Alc/ALc.c | 34 | ||||
-rw-r--r-- | Alc/ALu.c | 53 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 12 | ||||
-rw-r--r-- | alsoftrc.sample | 8 |
4 files changed, 81 insertions, 26 deletions
@@ -1972,8 +1972,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } device->Hrtf = NULL; - device->Hrtf_Mode = DisabledHrtf; al_string_clear(&device->Hrtf_Name); + device->Render_Mode = NormalRender; if(device->FmtChans != DevFmtStereo) { if(hrtf_appreq == Hrtf_Enable) @@ -1982,7 +1982,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) else { bool headphones = device->IsHeadphones; - enum HrtfMode hrtf_mode = FullHrtf; + enum RenderMode render_mode = HrtfRender; ALCenum hrtf_status = device->Hrtf_Status; const char *mode; int bs2blevel; @@ -2003,9 +2003,9 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) - hrtf_mode = FullHrtf; + render_mode = HrtfRender; else if(strcasecmp(mode, "basic") == 0) - hrtf_mode = BasicHrtf; + render_mode = NormalRender; else ERR("Unexpected hrtf-mode: %s\n", mode); } @@ -2068,8 +2068,8 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } if(device->Hrtf) { - device->Hrtf_Mode = hrtf_mode; device->Hrtf_Status = hrtf_status; + device->Render_Mode = render_mode; TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); } else @@ -2084,14 +2084,30 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + device->Render_Mode = StereoPair; TRACE("BS2B enabled\n"); } else { TRACE("BS2B disabled\n"); - } - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + render_mode = NormalRender; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) + { + if(strcasecmp(mode, "paired") == 0) + render_mode = StereoPair; + else if(strcasecmp(mode, "uhj") != 0) + ERR("Unexpected stereo-panning: %s\n", mode); + } + device->Render_Mode = render_mode; + if(render_mode == NormalRender) + { + device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + TRACE("UHJ enabled\n"); + } + else + TRACE("UHJ disabled\n"); + } } } @@ -3342,7 +3358,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Uhj_Encoder = NULL; VECTOR_INIT(device->Hrtf_List); AL_STRING_INIT(device->Hrtf_Name); - device->Hrtf_Mode = DisabledHrtf; + device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; @@ -3787,7 +3803,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN AL_STRING_INIT(device->Hrtf_Name); device->Bs2b = NULL; device->Uhj_Encoder = NULL; - device->Hrtf_Mode = DisabledHrtf; + device->Render_Mode = NormalRender; AL_STRING_INIT(device->DeviceName); device->DryBuffer = NULL; @@ -577,9 +577,9 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { if(Device->Hrtf || Device->Uhj_Encoder) { - /* DirectChannels with HRTF enabled. Skip the virtual channels - * and write FrontLeft and FrontRight inputs to the first and - * second outputs. + /* DirectChannels with HRTF or UHJ enabled. Skip the virtual + * channels and write FrontLeft and FrontRight inputs to the + * first and second outputs. */ voice->Direct.OutBuffer += voice->Direct.OutChannels; voice->Direct.OutChannels = 2; @@ -627,7 +627,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A voice->IsHrtf = AL_FALSE; } - else if(Device->Hrtf_Mode == FullHrtf) + else if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render each * input channel to the real outputs. @@ -686,7 +686,7 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A } else { - /* Basic or no HRTF rendering. Use normal panning to the output. */ + /* Non-HRTF rendering. Use normal panning to the output. */ for(c = 0;c < num_channels;c++) { /* Special-case LFE */ @@ -707,9 +707,24 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A continue; } - CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + if(Device->Render_Mode == StereoPair) + { + /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ + ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation); + coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5; + voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain; + voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain; + for(j = 2;j < MAX_OUTPUT_CHANNELS;j++) + voice->Direct.Gains[c].Target[j] = 0.0f; - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, voice->Direct.Gains[c].Target); + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + } + else + { + CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, + voice->Direct.Gains[c].Target); + } for(i = 0;i < NumSends;i++) { @@ -1105,7 +1120,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte BufferListItem = BufferListItem->next; } - if(Device->Hrtf_Mode == FullHrtf) + if(Device->Render_Mode == HrtfRender) { /* Full HRTF rendering. Skip the virtual channels and render to the * real outputs. @@ -1170,7 +1185,7 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte } else { - /* Basic or no HRTF rendering. Use normal panning to the output. */ + /* Non-HRTF rendering. */ ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; ALfloat radius = ALSource->Radius; ALfloat coeffs[MAX_AMBI_COEFFS]; @@ -1193,10 +1208,24 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte dir[1] *= dirfact; dir[2] *= dirfact; } - CalcDirectionCoeffs(dir, coeffs); - ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, - voice->Direct.Gains[0].Target); + if(Device->Render_Mode == StereoPair) + { + /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */ + coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5; + voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain; + voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain; + for(i = 2;i < MAX_OUTPUT_CHANNELS;i++) + voice->Direct.Gains[0].Target[i] = 0.0f; + + CalcDirectionCoeffs(dir, coeffs); + } + else + { + CalcDirectionCoeffs(dir, coeffs); + ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, + voice->Direct.Gains[0].Target); + } for(i = 0;i < NumSends;i++) { diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index f9532727..8c75cb83 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -387,10 +387,10 @@ enum DeviceType { }; -enum HrtfMode { - DisabledHrtf, - BasicHrtf, - FullHrtf +enum RenderMode { + NormalRender, + StereoPair, + HrtfRender }; @@ -465,7 +465,6 @@ struct ALCdevice_struct al_string Hrtf_Name; const struct Hrtf *Hrtf; ALCenum Hrtf_Status; - enum HrtfMode Hrtf_Mode; HrtfState Hrtf_State[MAX_OUTPUT_CHANNELS]; HrtfParams Hrtf_Params[MAX_OUTPUT_CHANNELS]; ALuint Hrtf_Offset; @@ -476,6 +475,9 @@ struct ALCdevice_struct // Stereo-to-binaural filter struct bs2b *Bs2b; + /* Rendering mode. */ + enum RenderMode Render_Mode; + // Device flags ALuint Flags; diff --git a/alsoftrc.sample b/alsoftrc.sample index 7d73b7c6..255f82d0 100644 --- a/alsoftrc.sample +++ b/alsoftrc.sample @@ -86,6 +86,14 @@ # Valid settings are auto, speakers, and headphones. #stereo-mode = auto +## stereo-panning: +# Specifies the panning method for non-HRTF stereo output. uhj (default) +# creates stereo-compatible two-channel UHJ output, which encodes some +# surround sound information, while paired uses standard pair-wise panning +# between -30 and +30 degrees. If crossfeed filters are used, uhj panning is +# disabled. +#stereo-panning = uhj + ## hrtf: # Controls HRTF processing. These filters provide better spatialization of # sounds while using headphones, but do require a bit more CPU power. The |