aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-04-26 23:32:15 -0700
committerChris Robinson <[email protected]>2022-04-26 23:32:15 -0700
commit593966c8dbdbf2dbcd8768b258a3b22adb548b2f (patch)
tree720dd3a36188cdb1ff55165d1b2bd51e5fd7d687
parent07dd62e53f3abaf918262953895961bd38848a7e (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.cpp4
-rw-r--r--alc/backends/base.cpp74
-rw-r--r--alc/backends/base.h5
-rw-r--r--alc/backends/coreaudio.cpp1
-rw-r--r--alc/backends/dsound.cpp6
-rw-r--r--alc/backends/oboe.cpp1
-rw-r--r--alc/backends/opensl.cpp3
-rw-r--r--alc/backends/pipewire.cpp1
-rw-r--r--alc/backends/pulseaudio.cpp2
-rw-r--r--alc/backends/wasapi.cpp6
-rw-r--r--alc/backends/wave.cpp2
-rw-r--r--alc/backends/winmm.cpp10
-rw-r--r--alc/context.cpp4
-rw-r--r--alc/device.cpp1
-rw-r--r--alc/panning.cpp58
-rw-r--r--core/devformat.cpp2
-rw-r--r--core/devformat.h18
-rw-r--r--docs/3D7.1.txt15
-rw-r--r--presets/3D7.1.ambdec20
-rw-r--r--utils/alsoft-config/mainwindow.cpp5
-rw-r--r--utils/alsoft-config/mainwindow.h1
-rw-r--r--utils/alsoft-config/mainwindow.ui109
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">