Remix missing channels with direct channels enabled

Instead of dropping them.
This commit is contained in:
Chris Robinson
2019-12-19 04:38:34 -08:00
parent 6480c2c854
commit 4634002104
3 changed files with 83 additions and 6 deletions
+59 -5
View File
@@ -1308,8 +1308,10 @@ ALuint ChannelsFromDevFmt(DevFmtChannels chans, ALuint ambiorder) noexcept
return 0;
}
namespace {
struct DevFmtPair { DevFmtChannels chans; DevFmtType type; };
static al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
{
static const struct {
ALenum format;
@@ -1350,7 +1352,7 @@ static al::optional<DevFmtPair> DecomposeDevFormat(ALenum format)
return al::nullopt;
}
static ALCboolean IsValidALCType(ALCenum type)
ALCboolean IsValidALCType(ALCenum type)
{
switch(type)
{
@@ -1366,7 +1368,7 @@ static ALCboolean IsValidALCType(ALCenum type)
return ALC_FALSE;
}
static ALCboolean IsValidALCChannels(ALCenum channels)
ALCboolean IsValidALCChannels(ALCenum channels)
{
switch(channels)
{
@@ -1382,7 +1384,7 @@ static ALCboolean IsValidALCChannels(ALCenum channels)
return ALC_FALSE;
}
static ALCboolean IsValidAmbiLayout(ALCenum layout)
ALCboolean IsValidAmbiLayout(ALCenum layout)
{
switch(layout)
{
@@ -1393,7 +1395,7 @@ static ALCboolean IsValidAmbiLayout(ALCenum layout)
return ALC_FALSE;
}
static ALCboolean IsValidAmbiScaling(ALCenum scaling)
ALCboolean IsValidAmbiScaling(ALCenum scaling)
{
switch(scaling)
{
@@ -1405,6 +1407,45 @@ static ALCboolean IsValidAmbiScaling(ALCenum scaling)
return ALC_FALSE;
}
/* Downmixing channel arrays, to map the given format's missing channels to
* existing ones. Based on Wine's DSound downmix values, which are based on
* PulseAudio's.
*/
const std::array<InputRemixMap,6> StereoDownmix{{
{ FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
{ SideLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
{ SideRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
{ BackLeft, {{{FrontLeft, 1.0f/9.0f}, {FrontRight, 0.0f}}} },
{ BackRight, {{{FrontLeft, 0.0f}, {FrontRight, 1.0f/9.0f}}} },
{ BackCenter, {{{FrontLeft, 0.5f/9.0f}, {FrontRight, 0.5f/9.0f}}} },
}};
const std::array<InputRemixMap,4> QuadDownmix{{
{ FrontCenter, {{{FrontLeft, 0.5f}, {FrontRight, 0.5f}}} },
{ SideLeft, {{{FrontLeft, 0.5f}, {BackLeft, 0.5f}}} },
{ SideRight, {{{FrontRight, 0.5f}, {BackRight, 0.5f}}} },
{ BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
}};
const std::array<InputRemixMap,3> X51Downmix{{
{ BackLeft, {{{SideLeft, 1.0f}, {SideRight, 0.0f}}} },
{ BackRight, {{{SideLeft, 0.0f}, {SideRight, 1.0f}}} },
{ BackCenter, {{{SideLeft, 0.5f}, {SideRight, 0.5f}}} },
}};
const std::array<InputRemixMap,3> X51RearDownmix{{
{ SideLeft, {{{BackLeft, 1.0f}, {BackRight, 0.0f}}} },
{ SideRight, {{{BackLeft, 0.0f}, {BackRight, 1.0f}}} },
{ BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
}};
const std::array<InputRemixMap,2> X61Downmix{{
{ BackLeft, {{{BackCenter, 0.5f}, {SideLeft, 0.5f}}} },
{ BackRight, {{{BackCenter, 0.5f}, {SideRight, 0.5f}}} },
}};
const std::array<InputRemixMap,1> X71Downmix{{
{ BackCenter, {{{BackLeft, 0.5f}, {BackRight, 0.5f}}} },
}};
} // namespace
/************************************************
* Miscellaneous ALC helpers
************************************************/
@@ -1859,6 +1900,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
device->Dry.AmbiMap.fill(BFChannelConfig{});
device->Dry.Buffer = {};
std::fill(std::begin(device->NumChannelsPerOrder), std::end(device->NumChannelsPerOrder), 0u);
device->RealOut.RemixMap = {};
device->RealOut.ChannelIndex.fill(INVALID_CHANNEL_INDEX);
device->RealOut.Buffer = {};
device->MixBuffer.clear();
@@ -1935,6 +1977,18 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType),
device->Frequency, device->UpdateSize, device->BufferSize);
switch(device->FmtChans)
{
case DevFmtStereo: device->RealOut.RemixMap = StereoDownmix; break;
case DevFmtQuad: device->RealOut.RemixMap = QuadDownmix; break;
case DevFmtX51: device->RealOut.RemixMap = X51Downmix; break;
case DevFmtX51Rear: device->RealOut.RemixMap = X51RearDownmix; break;
case DevFmtX61: device->RealOut.RemixMap = X61Downmix; break;
case DevFmtX71: device->RealOut.RemixMap = X71Downmix; break;
case DevFmtMono:
case DevFmtAmbi3D: break;
}
aluInitRenderer(device, hrtf_id, hrtf_appreq, hrtf_userreq);
device->NumAuxSends = new_sends;
+9
View File
@@ -60,6 +60,14 @@ enum RenderMode {
};
struct InputRemixMap {
struct TargetMix { Channel channel; float mix; };
Channel channel;
std::array<TargetMix,2> targets;
};
struct BufferSubList {
uint64_t FreeMask{~0_u64};
ALbuffer *Buffers{nullptr}; /* 64 */
@@ -184,6 +192,7 @@ struct MixParams {
};
struct RealMixParams {
al::span<const InputRemixMap> RemixMap;
std::array<ALuint,MaxChannels> ChannelIndex{};
al::span<FloatBufferLine> Buffer;
+15 -1
View File
@@ -942,9 +942,23 @@ void CalcPanningAndFilters(ALvoice *voice, const ALfloat xpos, const ALfloat ypo
for(ALuint c{0};c < num_channels;c++)
{
const ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
ALuint idx{GetChannelIdxByName(Device->RealOut, chans[c].channel)};
if(idx != INVALID_CHANNEL_INDEX)
voice->mChans[c].mDryParams.Gains.Target[idx] = DryGain;
else
{
auto match_channel = [chans,c](const InputRemixMap &map) -> bool
{ return chans[c].channel == map.channel; };
auto remap = std::find_if(Device->RealOut.RemixMap.cbegin(),
Device->RealOut.RemixMap.cend(), match_channel);
if(remap != Device->RealOut.RemixMap.cend())
for(const auto &target : remap->targets)
{
idx = GetChannelIdxByName(Device->RealOut, target.channel);
if(idx != INVALID_CHANNEL_INDEX)
voice->mChans[c].mDryParams.Gains.Target[idx] = target.mix;
}
}
}
/* Auxiliary sends still use normal channel panning since they mix to