diff options
author | Chris Robinson <[email protected]> | 2019-12-19 04:38:34 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2019-12-19 04:38:34 -0800 |
commit | 4634002104a753714451e3701524a258ae2d0add (patch) | |
tree | 9062fcf052523c305c99a2daa959bd8a422950b6 /alc | |
parent | 6480c2c854b67979e07c5b6113169733760395ec (diff) |
Remix missing channels with direct channels enabled
Instead of dropping them.
Diffstat (limited to 'alc')
-rw-r--r-- | alc/alc.cpp | 64 | ||||
-rw-r--r-- | alc/alcmain.h | 9 | ||||
-rw-r--r-- | alc/alu.cpp | 16 |
3 files changed, 83 insertions, 6 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp index 06f8ce59..9c4dbcbd 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -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; diff --git a/alc/alcmain.h b/alc/alcmain.h index 1da332c0..673997dc 100644 --- a/alc/alcmain.h +++ b/alc/alcmain.h @@ -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; diff --git a/alc/alu.cpp b/alc/alu.cpp index f228ff29..deb0bb54 100644 --- a/alc/alu.cpp +++ b/alc/alu.cpp @@ -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 |