Remix missing channels with direct channels enabled
Instead of dropping them.
This commit is contained in:
+59
-5
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user