diff options
author | Chris Robinson <[email protected]> | 2022-04-26 23:32:15 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2022-04-26 23:32:15 -0700 |
commit | 593966c8dbdbf2dbcd8768b258a3b22adb548b2f (patch) | |
tree | 720dd3a36188cdb1ff55165d1b2bd51e5fd7d687 | |
parent | 07dd62e53f3abaf918262953895961bd38848a7e (diff) |
Handle 3D7.1 as a separate channel configuration
It's treated as 5.1 + 2 aux channels. This allows AL_DIRECT_CHANNELS_SOFT to
behave better, not forwarding rear left/right channel inputs to lower front and
upper rear, and allows reporting a more appropriate output mode to the app
instead of 7.1.
-rw-r--r-- | alc/alc.cpp | 4 | ||||
-rw-r--r-- | alc/backends/base.cpp | 74 | ||||
-rw-r--r-- | alc/backends/base.h | 5 | ||||
-rw-r--r-- | alc/backends/coreaudio.cpp | 1 | ||||
-rw-r--r-- | alc/backends/dsound.cpp | 6 | ||||
-rw-r--r-- | alc/backends/oboe.cpp | 1 | ||||
-rw-r--r-- | alc/backends/opensl.cpp | 3 | ||||
-rw-r--r-- | alc/backends/pipewire.cpp | 1 | ||||
-rw-r--r-- | alc/backends/pulseaudio.cpp | 2 | ||||
-rw-r--r-- | alc/backends/wasapi.cpp | 6 | ||||
-rw-r--r-- | alc/backends/wave.cpp | 2 | ||||
-rw-r--r-- | alc/backends/winmm.cpp | 10 | ||||
-rw-r--r-- | alc/context.cpp | 4 | ||||
-rw-r--r-- | alc/device.cpp | 1 | ||||
-rw-r--r-- | alc/panning.cpp | 58 | ||||
-rw-r--r-- | core/devformat.cpp | 2 | ||||
-rw-r--r-- | core/devformat.h | 18 | ||||
-rw-r--r-- | docs/3D7.1.txt | 15 | ||||
-rw-r--r-- | presets/3D7.1.ambdec | 20 | ||||
-rw-r--r-- | utils/alsoft-config/mainwindow.cpp | 5 | ||||
-rw-r--r-- | utils/alsoft-config/mainwindow.h | 1 | ||||
-rw-r--r-- | utils/alsoft-config/mainwindow.ui | 109 |
22 files changed, 219 insertions, 129 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp index 3bbe43d0..686b794e 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -1441,6 +1441,8 @@ ALCenum EnumFromDevFmt(DevFmtChannels channels) case DevFmtX61: return ALC_6POINT1_SOFT; case DevFmtX71: return ALC_7POINT1_SOFT; case DevFmtAmbi3D: return ALC_BFORMAT3D_SOFT; + /* FIXME: Shouldn't happen. */ + case DevFmtX3D71: break; } throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))}; } @@ -1911,6 +1913,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) { "surround51", DevFmtX51, 0 }, { "surround61", DevFmtX61, 0 }, { "surround71", DevFmtX71, 0 }, + { "surround3d71", DevFmtX3D71, 0 }, { "surround51rear", DevFmtX51, 0 }, { "ambi1", DevFmtAmbi3D, 1 }, { "ambi2", DevFmtAmbi3D, 2 }, @@ -2090,6 +2093,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break; case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break; case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break; + case DevFmtX3D71: device->RealOut.RemixMap = X51Downmix; break; case DevFmtAmbi3D: break; } diff --git a/alc/backends/base.cpp b/alc/backends/base.cpp index cd1b76ba..4abd7c03 100644 --- a/alc/backends/base.cpp +++ b/alc/backends/base.cpp @@ -98,6 +98,16 @@ void BackendBase::setDefaultWFXChannelOrder() mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; break; + case DevFmtX3D71: + mDevice->RealOut.ChannelIndex[FrontLeft] = 0; + mDevice->RealOut.ChannelIndex[FrontRight] = 1; + mDevice->RealOut.ChannelIndex[FrontCenter] = 2; + mDevice->RealOut.ChannelIndex[LFE] = 3; + mDevice->RealOut.ChannelIndex[Aux0] = 4; + mDevice->RealOut.ChannelIndex[Aux1] = 5; + mDevice->RealOut.ChannelIndex[SideLeft] = 6; + mDevice->RealOut.ChannelIndex[SideRight] = 7; + break; case DevFmtAmbi3D: break; } @@ -127,6 +137,16 @@ void BackendBase::setDefaultChannelOrder() mDevice->RealOut.ChannelIndex[SideLeft] = 6; mDevice->RealOut.ChannelIndex[SideRight] = 7; return; + case DevFmtX3D71: + mDevice->RealOut.ChannelIndex[FrontLeft] = 0; + mDevice->RealOut.ChannelIndex[FrontRight] = 1; + mDevice->RealOut.ChannelIndex[Aux0] = 2; + mDevice->RealOut.ChannelIndex[Aux1] = 3; + mDevice->RealOut.ChannelIndex[FrontCenter] = 4; + mDevice->RealOut.ChannelIndex[LFE] = 5; + mDevice->RealOut.ChannelIndex[SideLeft] = 6; + mDevice->RealOut.ChannelIndex[SideRight] = 7; + return; /* Same as WFX order */ case DevFmtMono: @@ -138,57 +158,3 @@ void BackendBase::setDefaultChannelOrder() break; } } - -#ifdef _WIN32 -void BackendBase::setChannelOrderFromWFXMask(uint chanmask) -{ - static constexpr uint x51{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER - | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT}; - static constexpr uint x51rear{SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER - | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT}; - /* Swap a 5.1 mask using the back channels for one with the sides. */ - if(chanmask == x51rear) chanmask = x51; - - auto get_channel = [](const DWORD chanbit) noexcept -> al::optional<Channel> - { - switch(chanbit) - { - case SPEAKER_FRONT_LEFT: return al::make_optional(FrontLeft); - case SPEAKER_FRONT_RIGHT: return al::make_optional(FrontRight); - case SPEAKER_FRONT_CENTER: return al::make_optional(FrontCenter); - case SPEAKER_LOW_FREQUENCY: return al::make_optional(LFE); - case SPEAKER_BACK_LEFT: return al::make_optional(BackLeft); - case SPEAKER_BACK_RIGHT: return al::make_optional(BackRight); - case SPEAKER_FRONT_LEFT_OF_CENTER: break; - case SPEAKER_FRONT_RIGHT_OF_CENTER: break; - case SPEAKER_BACK_CENTER: return al::make_optional(BackCenter); - case SPEAKER_SIDE_LEFT: return al::make_optional(SideLeft); - case SPEAKER_SIDE_RIGHT: return al::make_optional(SideRight); - case SPEAKER_TOP_CENTER: return al::make_optional(TopCenter); - case SPEAKER_TOP_FRONT_LEFT: return al::make_optional(TopFrontLeft); - case SPEAKER_TOP_FRONT_CENTER: return al::make_optional(TopFrontCenter); - case SPEAKER_TOP_FRONT_RIGHT: return al::make_optional(TopFrontRight); - case SPEAKER_TOP_BACK_LEFT: return al::make_optional(TopBackLeft); - case SPEAKER_TOP_BACK_CENTER: return al::make_optional(TopBackCenter); - case SPEAKER_TOP_BACK_RIGHT: return al::make_optional(TopBackRight); - } - WARN("Unhandled WFX channel bit 0x%lx\n", chanbit); - return al::nullopt; - }; - - const uint numchans{mDevice->channelsFromFmt()}; - uint idx{0}; - while(chanmask) - { - const int bit{al::countr_zero(chanmask)}; - const uint mask{1u << bit}; - chanmask &= ~mask; - - if(auto label = get_channel(mask)) - { - mDevice->RealOut.ChannelIndex[*label] = idx; - if(++idx == numchans) break; - } - } -} -#endif diff --git a/alc/backends/base.h b/alc/backends/base.h index a3562f54..65bc636b 100644 --- a/alc/backends/base.h +++ b/alc/backends/base.h @@ -41,11 +41,6 @@ protected: void setDefaultChannelOrder(); /** Sets the default channel order used by WaveFormatEx. */ void setDefaultWFXChannelOrder(); - -#ifdef _WIN32 - /** Sets the channel order given the WaveFormatEx mask. */ - void setChannelOrderFromWFXMask(uint chanmask); -#endif }; using BackendPtr = std::unique_ptr<BackendBase>; diff --git a/alc/backends/coreaudio.cpp b/alc/backends/coreaudio.cpp index ed85e2a9..b81bd58a 100644 --- a/alc/backends/coreaudio.cpp +++ b/alc/backends/coreaudio.cpp @@ -764,6 +764,7 @@ void CoreAudioCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/alc/backends/dsound.cpp b/alc/backends/dsound.cpp index 0edc286f..36c4cd78 100644 --- a/alc/backends/dsound.cpp +++ b/alc/backends/dsound.cpp @@ -421,6 +421,7 @@ bool DSoundPlayback::reset() case DevFmtX51: OutputType.dwChannelMask = X5DOT1; break; case DevFmtX61: OutputType.dwChannelMask = X6DOT1; break; case DevFmtX71: OutputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: OutputType.dwChannelMask = X7DOT1; break; } retry_open: @@ -514,7 +515,7 @@ retry_open: } ResetEvent(mNotifyEvent); - setChannelOrderFromWFXMask(OutputType.dwChannelMask); + setDefaultWFXChannelOrder(); return true; } @@ -635,6 +636,7 @@ void DSoundCapture::open(const char *name) case DevFmtX51: InputType.dwChannelMask = X5DOT1; break; case DevFmtX61: InputType.dwChannelMask = X6DOT1; break; case DevFmtX71: InputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: case DevFmtAmbi3D: WARN("%s capture not supported\n", DevFmtChannelsString(mDevice->FmtChans)); throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", @@ -689,7 +691,7 @@ void DSoundCapture::open(const char *name) } mBufferBytes = DSCBDescription.dwBufferBytes; - setChannelOrderFromWFXMask(InputType.dwChannelMask); + setDefaultWFXChannelOrder(); mDevice->DeviceName = name; } diff --git a/alc/backends/oboe.cpp b/alc/backends/oboe.cpp index 38f048cb..03930ad8 100644 --- a/alc/backends/oboe.cpp +++ b/alc/backends/oboe.cpp @@ -234,6 +234,7 @@ void OboeCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/alc/backends/opensl.cpp b/alc/backends/opensl.cpp index 85a5f483..76b2095e 100644 --- a/alc/backends/opensl.cpp +++ b/alc/backends/opensl.cpp @@ -71,7 +71,8 @@ constexpr SLuint32 GetChannelMask(DevFmtChannels chans) noexcept case DevFmtX61: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_CENTER | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | + case DevFmtX71: + case DevFmtX3D71: return SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER | SL_SPEAKER_LOW_FREQUENCY | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT; case DevFmtAmbi3D: diff --git a/alc/backends/pipewire.cpp b/alc/backends/pipewire.cpp index a19dcb61..95845158 100644 --- a/alc/backends/pipewire.cpp +++ b/alc/backends/pipewire.cpp @@ -1181,6 +1181,7 @@ spa_audio_info_raw make_spa_info(DeviceBase *device, bool is51rear, use_f32p_e u break; case DevFmtX61: map = X61Map; break; case DevFmtX71: map = X71Map; break; + case DevFmtX3D71: map = X71Map; break; case DevFmtAmbi3D: info.flags |= SPA_AUDIO_FLAG_UNPOSITIONED; info.channels = device->channelsFromFmt(); diff --git a/alc/backends/pulseaudio.cpp b/alc/backends/pulseaudio.cpp index 67e00234..30f486c7 100644 --- a/alc/backends/pulseaudio.cpp +++ b/alc/backends/pulseaudio.cpp @@ -893,6 +893,7 @@ bool PulsePlayback::reset() chanmap = X61ChanMap; break; case DevFmtX71: + case DevFmtX3D71: chanmap = X71ChanMap; break; } @@ -1173,6 +1174,7 @@ void PulseCapture::open(const char *name) case DevFmtX71: chanmap = X71ChanMap; break; + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/alc/backends/wasapi.cpp b/alc/backends/wasapi.cpp index 063fca98..4e0f67a2 100644 --- a/alc/backends/wasapi.cpp +++ b/alc/backends/wasapi.cpp @@ -926,6 +926,7 @@ HRESULT WasapiPlayback::resetProxy() OutputType.dwChannelMask = X6DOT1; break; case DevFmtX71: + case DevFmtX3D71: OutputType.Format.nChannels = 8; OutputType.dwChannelMask = X7DOT1; break; @@ -1021,6 +1022,7 @@ HRESULT WasapiPlayback::resetProxy() chansok = (chancount >= 7 && (chanmask&X61Mask) == X6DOT1); break; case DevFmtX71: + case DevFmtX3D71: chansok = (chancount >= 8 && (chanmask&X71Mask) == X7DOT1); break; case DevFmtAmbi3D: @@ -1087,7 +1089,7 @@ HRESULT WasapiPlayback::resetProxy() const EndpointFormFactor formfactor{get_device_formfactor(mMMDev.get())}; mDevice->Flags.set(DirectEar, (formfactor == Headphones || formfactor == Headset)); - setChannelOrderFromWFXMask(OutputType.dwChannelMask); + setDefaultWFXChannelOrder(); hr = mClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, buf_time.count(), 0, &OutputType.Format, nullptr); @@ -1476,6 +1478,7 @@ HRESULT WasapiCapture::resetProxy() InputType.dwChannelMask = X7DOT1; break; + case DevFmtX3D71: case DevFmtAmbi3D: return E_FAIL; } @@ -1556,6 +1559,7 @@ HRESULT WasapiCapture::resetProxy() case DevFmtX61: return (chancount == 7 && (chanmask == 0 || (chanmask&X61Mask) == X6DOT1)); case DevFmtX71: + case DevFmtX3D71: return (chancount == 8 && (chanmask == 0 || (chanmask&X71Mask) == X7DOT1)); case DevFmtAmbi3D: return (chanmask == 0 && chancount == device->channelsFromFmt()); diff --git a/alc/backends/wave.cpp b/alc/backends/wave.cpp index 6360166c..80e93f69 100644 --- a/alc/backends/wave.cpp +++ b/alc/backends/wave.cpp @@ -265,6 +265,8 @@ bool WaveBackend::reset() case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + /* NOTE: Same as 7.1. */ + case DevFmtX3D71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; case DevFmtAmbi3D: /* .amb output requires FuMa */ mDevice->mAmbiOrder = minu(mDevice->mAmbiOrder, 3); diff --git a/alc/backends/winmm.cpp b/alc/backends/winmm.cpp index 0fdd8a02..14cc4f9e 100644 --- a/alc/backends/winmm.cpp +++ b/alc/backends/winmm.cpp @@ -301,23 +301,16 @@ bool WinMMPlayback::reset() return false; } - uint chanmask{}; if(mFormat.nChannels >= 2) - { mDevice->FmtChans = DevFmtStereo; - chanmask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; - } else if(mFormat.nChannels == 1) - { mDevice->FmtChans = DevFmtMono; - chanmask = SPEAKER_FRONT_CENTER; - } else { ERR("Unhandled channel count: %d\n", mFormat.nChannels); return false; } - setChannelOrderFromWFXMask(chanmask); + setDefaultWFXChannelOrder(); uint BufferSize{mDevice->UpdateSize * mFormat.nChannels * mDevice->bytesFromFmt()}; @@ -476,6 +469,7 @@ void WinMMCapture::open(const char *name) case DevFmtX51: case DevFmtX61: case DevFmtX71: + case DevFmtX3D71: case DevFmtAmbi3D: throw al::backend_exception{al::backend_error::DeviceError, "%s capture not supported", DevFmtChannelsString(mDevice->FmtChans)}; diff --git a/alc/context.cpp b/alc/context.cpp index 456c054e..34da3784 100644 --- a/alc/context.cpp +++ b/alc/context.cpp @@ -558,6 +558,10 @@ unsigned long ALCcontext::eax_detect_speaker_configuration() const case DevFmtX51: return SPEAKERS_5; case DevFmtX61: return SPEAKERS_6; case DevFmtX71: return SPEAKERS_7; + /* 3D7.1 is only compatible with 5.1. This could instead be HEADPHONES to + * suggest full-sphere surround sound (like HRTF). + */ + case DevFmtX3D71: return SPEAKERS_5; /* This could also be HEADPHONES, since headphones-based HRTF and Ambi3D * provide full-sphere surround sound. Depends if apps are more likely to * consider headphones or 7.1 for surround sound support. diff --git a/alc/device.cpp b/alc/device.cpp index e06c0d74..6eeb907e 100644 --- a/alc/device.cpp +++ b/alc/device.cpp @@ -84,6 +84,7 @@ auto ALCdevice::getOutputMode1() const noexcept -> OutputMode1 case DevFmtX51: return OutputMode1::X51; case DevFmtX61: return OutputMode1::X61; case DevFmtX71: return OutputMode1::X71; + case DevFmtX3D71: case DevFmtAmbi3D: break; } return OutputMode1::Any; diff --git a/alc/panning.cpp b/alc/panning.cpp index 00bf5662..d0afd577 100644 --- a/alc/panning.cpp +++ b/alc/panning.cpp @@ -89,6 +89,23 @@ inline const char *GetLabelFromChannel(Channel channel) case TopBackCenter: return "top-back-center"; case TopBackRight: return "top-back-right"; + case Aux0: return "Aux0"; + case Aux1: return "Aux1"; + case Aux2: return "Aux2"; + case Aux3: return "Aux3"; + case Aux4: return "Aux4"; + case Aux5: return "Aux5"; + case Aux6: return "Aux6"; + case Aux7: return "Aux7"; + case Aux8: return "Aux8"; + case Aux9: return "Aux9"; + case Aux10: return "Aux10"; + case Aux11: return "Aux11"; + case Aux12: return "Aux12"; + case Aux13: return "Aux13"; + case Aux14: return "Aux14"; + case Aux15: return "Aux15"; + case MaxChannels: break; } return "(unknown)"; @@ -202,6 +219,8 @@ struct DecoderConfig<DualBand, 0> { mCoeffsLF = rhs.mCoeffsLF; return *this; } + + explicit operator bool() const noexcept { return mOrder != 0; } }; using DecoderView = DecoderConfig<DualBand, 0>; @@ -412,8 +431,15 @@ DecoderView MakeDecoderView(ALCdevice *device, const AmbDecConf *conf, ch = BackCenter; else { - ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str()); - continue; + int idx{}; + char c{}; + if(sscanf(speaker.Name.c_str(), "AUX%d%c", &idx, &c) != 1 || idx < 0 + || idx >= MaxChannels-Aux0) + { + ERR("AmbDec speaker label \"%s\" not recognized\n", speaker.Name.c_str()); + continue; + } + ch = static_cast<Channel>(Aux0+idx); } decoder.mChannels[chan_count] = ch; @@ -537,11 +563,33 @@ constexpr DecoderConfig<DualBand, 6> X71Config{ {{1.66666667e-1f, -9.62250449e-2f, -1.66666667e-1f, 1.49071198e-1f, 8.60662966e-2f, -7.96819073e-2f, 0.00000000e+0f}}, }} }; +constexpr DecoderConfig<DualBand, 6> X3D71Config{ + 1, true, {{Aux0, SideLeft, FrontLeft, FrontRight, SideRight, Aux1}}, + DevAmbiScaling::N3D, + /*HF*/{{1.73205081e+0f, 1.00000000e+0f}}, + {{ + {{1.66669447e-1f, 0.00000000e+0f, 2.36070520e-1f, -1.66153012e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 0.00000000e+0f, -2.36070520e-1f, 1.66153012e-1f}}, + }}, + /*LF*/{{1.00000000e+0f, 1.00000000e+0f}}, + {{ + {{1.66669447e-1f, 0.00000000e+0f, 2.36070520e-1f, -1.66153012e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, 1.17487922e-1f, 1.66927066e-1f}}, + {{1.66669447e-1f, -2.04127551e-1f, -1.17487922e-1f, -1.66927066e-1f}}, + {{1.66669447e-1f, 0.00000000e+0f, -2.36070520e-1f, 1.66153012e-1f}}, + }} +}; void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize=false, DecoderView decoder={}) { - if(!decoder.mOrder) + if(!decoder) { switch(device->FmtChans) { @@ -551,6 +599,7 @@ void InitPanning(ALCdevice *device, const bool hqdec=false, const bool stablize= case DevFmtX51: decoder = X51Config; break; case DevFmtX61: decoder = X61Config; break; case DevFmtX71: decoder = X71Config; break; + case DevFmtX3D71: decoder = X3D71Config; break; case DevFmtAmbi3D: auto&& acnmap = GetAmbiLayout(device->mAmbiLayout); auto&& n3dscale = GetAmbiScales(device->mAmbiScale); @@ -906,6 +955,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional<StereoEncoding case DevFmtX51: layout = "surround51"; break; case DevFmtX61: layout = "surround61"; break; case DevFmtX71: layout = "surround71"; break; + case DevFmtX3D71: layout = "surround3d71"; break; /* Mono, Stereo, and Ambisonics output don't use custom decoders. */ case DevFmtMono: case DevFmtStereo: @@ -915,7 +965,7 @@ void aluInitRenderer(ALCdevice *device, int hrtf_id, al::optional<StereoEncoding std::unique_ptr<DecoderConfig<DualBand,MAX_OUTPUT_CHANNELS>> decoder_store; DecoderView decoder{}; - float speakerdists[MaxChannels]{}; + float speakerdists[MAX_OUTPUT_CHANNELS]{}; auto load_config = [device,&decoder_store,&decoder,&speakerdists](const char *config) { AmbDecConf conf{}; diff --git a/core/devformat.cpp b/core/devformat.cpp index c841b634..cbe8eaf3 100644 --- a/core/devformat.cpp +++ b/core/devformat.cpp @@ -28,6 +28,7 @@ uint ChannelsFromDevFmt(DevFmtChannels chans, uint ambiorder) noexcept case DevFmtX51: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; + case DevFmtX3D71: return 8; case DevFmtAmbi3D: return (ambiorder+1) * (ambiorder+1); } return 0; @@ -57,6 +58,7 @@ const char *DevFmtChannelsString(DevFmtChannels chans) noexcept case DevFmtX51: return "5.1 Surround"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; + case DevFmtX3D71: return "3D7.1 Surround"; case DevFmtAmbi3D: return "Ambisonic 3D"; } return "(unknown channels)"; diff --git a/core/devformat.h b/core/devformat.h index e6d30924..f2a372c1 100644 --- a/core/devformat.h +++ b/core/devformat.h @@ -25,6 +25,23 @@ enum Channel : unsigned char { TopBackCenter, TopBackRight, + Aux0, + Aux1, + Aux2, + Aux3, + Aux4, + Aux5, + Aux6, + Aux7, + Aux8, + Aux9, + Aux10, + Aux11, + Aux12, + Aux13, + Aux14, + Aux15, + MaxChannels }; @@ -48,6 +65,7 @@ enum DevFmtChannels : unsigned char { DevFmtX51, DevFmtX61, DevFmtX71, + DevFmtX3D71, DevFmtAmbi3D, DevFmtChannelsDefault = DevFmtStereo diff --git a/docs/3D7.1.txt b/docs/3D7.1.txt index 1d40bec6..b7249c22 100644 --- a/docs/3D7.1.txt +++ b/docs/3D7.1.txt @@ -58,17 +58,10 @@ Software Setup ============== To enable 3D7.1 on OpenAL Soft, first make sure the audio device is configured -for 7.1 output. Then in the alsoft-config utility, under the Renderer tab, -select the 3D7.1.ambdec preset for the 7.1 Surround decoder configuration. And -that's it. Any applications using OpenAL Soft can take advantage of fully 3D -audio, and multi-channel sounds will be properly remixed for the speaker -layout. - -Playback can be improved by (copying and) modifying the 3D7.1.ambdec preset, -changing the specified speaker distances to match the the real distance (in -meters) from the center of the speaker array, then enable High Quality Mode in -alsoft-config. That will improve the quality when the speakers are not all -equidistant. +for 7.1 output. Then in the alsoft-config utility, for the Channels setting +choose "3D7.1 Surround" from the drop-down list. And that's it. Any application +using OpenAL Soft can take advantage of fully 3D audio, and multi-channel +sounds will be properly remixed for the speaker layout. Note that care must be taken that the audio device is not treated as a "true" 7.1 device by non-3D7.1-capable applications. In particular, the audio server diff --git a/presets/3D7.1.ambdec b/presets/3D7.1.ambdec index 66e56501..8ab0b060 100644 --- a/presets/3D7.1.ambdec +++ b/presets/3D7.1.ambdec @@ -5,6 +5,10 @@ /description 3D7-noCenter_1h1v_pinv_even_energy_rV_max_rE_2_band +# In OpenAL Soft, 3D7.1 is a distinct configuration that uses the standard 5.1 +# channels (FL, FR, FC, SL, SR), plus two auxiliary channels (AUX0, AUX1) in +# place of the rear speakers. + # Similar to the the ITU-5.1-nocenter configuration, the front-center is # declared here so that an appropriate distance may be set (for proper delaying # or attenuating of dialog and such which feed it directly). It otherwise does @@ -25,15 +29,15 @@ /opt/xover_ratio 0.000000 /speakers/{ -# id dist azim elev conn +# id dist azim elev conn #----------------------------------------------------------------------- -add_spkr FL 1.828800 51.000000 24.000000 -add_spkr FR 1.828800 -51.000000 24.000000 -add_spkr FC 1.828800 0.000000 0.000000 -add_spkr BL 1.828800 180.000000 55.000000 -add_spkr BR 1.828800 0.000000 -55.000000 -add_spkr SL 1.828800 129.000000 -24.000000 -add_spkr SR 1.828800 -129.000000 -24.000000 +add_spkr FL 1.828800 51.000000 24.000000 +add_spkr FR 1.828800 -51.000000 24.000000 +add_spkr FC 1.828800 0.000000 0.000000 +add_spkr AUX0 1.828800 180.000000 55.000000 +add_spkr AUX1 1.828800 0.000000 -55.000000 +add_spkr SL 1.828800 129.000000 -24.000000 +add_spkr SR 1.828800 -129.000000 -24.000000 /} /lfmatrix/{ diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp index 8a179ada..3565493e 100644 --- a/utils/alsoft-config/mainwindow.cpp +++ b/utils/alsoft-config/mainwindow.cpp @@ -86,6 +86,7 @@ static const struct NameValuePair { { "5.1 Surround", "surround51" }, { "6.1 Surround", "surround61" }, { "7.1 Surround", "surround71" }, + { "3D7.1 Surround", "surround3d71" }, { "Ambisonic, 1st Order", "ambi1" }, { "Ambisonic, 2nd Order", "ambi2" }, @@ -412,6 +413,8 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->decoder61Button, &QPushButton::clicked, this, &MainWindow::select61DecoderFile); connect(ui->decoder71LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); connect(ui->decoder71Button, &QPushButton::clicked, this, &MainWindow::select71DecoderFile); + connect(ui->decoder3D71LineEdit, &QLineEdit::textChanged, this, &MainWindow::enableApplyButton); + connect(ui->decoder3D71Button, &QPushButton::clicked, this, &MainWindow::select3D71DecoderFile); connect(ui->preferredHrtfComboBox, qcb_cicint, this, &MainWindow::enableApplyButton); connect(ui->hrtfStateComboBox, qcb_cicint, this, &MainWindow::enableApplyButton); @@ -1252,6 +1255,8 @@ void MainWindow::select61DecoderFile() { selectDecoderFile(ui->decoder61LineEdit, "Select 6.1 Surround Decoder");} void MainWindow::select71DecoderFile() { selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} +void MainWindow::select3D71DecoderFile() +{ selectDecoderFile(ui->decoder3D71LineEdit, "Select 3D7.1 Surround Decoder");} void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) { QString dir{line->text()}; diff --git a/utils/alsoft-config/mainwindow.h b/utils/alsoft-config/mainwindow.h index ca53582b..f7af8eac 100644 --- a/utils/alsoft-config/mainwindow.h +++ b/utils/alsoft-config/mainwindow.h @@ -39,6 +39,7 @@ private slots: void select51DecoderFile(); void select61DecoderFile(); void select71DecoderFile(); + void select3D71DecoderFile(); void updateJackBufferSizeEdit(int size); void updateJackBufferSizeSlider(); diff --git a/utils/alsoft-config/mainwindow.ui b/utils/alsoft-config/mainwindow.ui index 84a99385..8d057679 100644 --- a/utils/alsoft-config/mainwindow.ui +++ b/utils/alsoft-config/mainwindow.ui @@ -668,9 +668,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>-10</x> - <y>160</y> + <y>140</y> <width>551</width> - <height>161</height> + <height>231</height> </rect> </property> <property name="title"> @@ -682,10 +682,10 @@ configuration file.</string> <widget class="QLineEdit" name="decoderQuadLineEdit"> <property name="geometry"> <rect> - <x>120</x> + <x>130</x> <y>30</y> - <width>311</width> - <height>21</height> + <width>301</width> + <height>25</height> </rect> </property> </widget> @@ -694,8 +694,8 @@ configuration file.</string> <rect> <x>20</x> <y>30</y> - <width>91</width> - <height>21</height> + <width>101</width> + <height>25</height> </rect> </property> <property name="text"> @@ -711,7 +711,7 @@ configuration file.</string> <x>440</x> <y>30</y> <width>91</width> - <height>21</height> + <height>25</height> </rect> </property> <property name="text"> @@ -721,10 +721,10 @@ configuration file.</string> <widget class="QLineEdit" name="decoder51LineEdit"> <property name="geometry"> <rect> - <x>120</x> - <y>60</y> - <width>311</width> - <height>21</height> + <x>130</x> + <y>70</y> + <width>301</width> + <height>25</height> </rect> </property> </widget> @@ -732,9 +732,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>440</x> - <y>60</y> + <y>70</y> <width>91</width> - <height>21</height> + <height>25</height> </rect> </property> <property name="text"> @@ -745,9 +745,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>20</x> - <y>60</y> - <width>91</width> - <height>21</height> + <y>70</y> + <width>101</width> + <height>25</height> </rect> </property> <property name="text"> @@ -761,9 +761,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>20</x> - <y>90</y> - <width>91</width> - <height>21</height> + <y>110</y> + <width>101</width> + <height>25</height> </rect> </property> <property name="text"> @@ -776,10 +776,10 @@ configuration file.</string> <widget class="QLineEdit" name="decoder61LineEdit"> <property name="geometry"> <rect> - <x>120</x> - <y>90</y> - <width>311</width> - <height>21</height> + <x>130</x> + <y>110</y> + <width>301</width> + <height>25</height> </rect> </property> </widget> @@ -787,9 +787,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>440</x> - <y>90</y> + <y>110</y> <width>91</width> - <height>21</height> + <height>25</height> </rect> </property> <property name="text"> @@ -800,9 +800,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>440</x> - <y>120</y> + <y>150</y> <width>91</width> - <height>21</height> + <height>25</height> </rect> </property> <property name="text"> @@ -812,10 +812,10 @@ configuration file.</string> <widget class="QLineEdit" name="decoder71LineEdit"> <property name="geometry"> <rect> - <x>120</x> - <y>120</y> - <width>311</width> - <height>21</height> + <x>130</x> + <y>150</y> + <width>301</width> + <height>25</height> </rect> </property> </widget> @@ -823,9 +823,9 @@ configuration file.</string> <property name="geometry"> <rect> <x>20</x> - <y>120</y> - <width>91</width> - <height>21</height> + <y>150</y> + <width>101</width> + <height>25</height> </rect> </property> <property name="text"> @@ -835,6 +835,45 @@ configuration file.</string> <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> </property> </widget> + <widget class="QLabel" name="label_33"> + <property name="geometry"> + <rect> + <x>20</x> + <y>190</y> + <width>101</width> + <height>25</height> + </rect> + </property> + <property name="text"> + <string>3D7.1 Surround:</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + <widget class="QLineEdit" name="decoder3D71LineEdit"> + <property name="geometry"> + <rect> + <x>130</x> + <y>190</y> + <width>301</width> + <height>25</height> + </rect> + </property> + </widget> + <widget class="QPushButton" name="decoder3D71Button"> + <property name="geometry"> + <rect> + <x>440</x> + <y>190</y> + <width>91</width> + <height>25</height> + </rect> + </property> + <property name="text"> + <string>Browse...</string> + </property> + </widget> </widget> <widget class="QCheckBox" name="decoderNFEffectsCheckBox"> <property name="geometry"> |