Skip to content

Audio: channel mixer matrix builder for QAudioFormat - #1600

Merged
Mysticial merged 3 commits into
mainfrom
audio-channel-matrix-builder
Oct 17, 2026
Merged

Mysticial merged 3 commits into
mainfrom
audio-channel-matrix-builder

Conversation

@Gin890

@Gin890 Gin890 commented Oct 16, 2026

Copy link
Copy Markdown
Collaborator

Adds build_channel_mixer_matrix(QAudioFormat in, QAudioFormat out) in CommonFramework/AudioPipeline/ChannelMixer.h/.cpp. It builds the N x M float weight matrix consumed by Kernels::AudioChannelMixer::mix_channels (column-major: index i + in_channels * o), so an input format's channels are converted to an output format's channels with conventional 'industry standard' coefficients (ITU-R BS.1116-1 style, matching FFmpeg's automatic rematrix):

  • same position on both sides: gain 1
  • mono -> stereo duplicates; L/R -> mono averages (0.5 each)
  • C -> L/R at 0.7 (only when the output has no center channel)
  • back/side surrounds -> front at 0.7 (only when the output has no surround on that side)
  • L/R -> C upmix at 0.7*(L+R)/2 = 0.35 per channel
  • LFE passes through to LFE only; top/bottom/back-center never mix
  • front-left/right-of-center and BL/SL cross-fill at 0.7 when the exact position is missing on either side

Failure semantics (per design): an empty vector is returned when either format's channel layout is ChannelConfigUnknown or has a non-positive channel count. Channels present in the frame but unnamed by the config contribute zero (FFmpeg does not guess per-channel identities). No renormalization is applied (FFmpeg uses these fixed coefficients; a full-scale multichannel source can exceed full-scale in a narrow downmix).

Qt 5 has no per-channel position info, so the builder returns empty there (Qt 6 API only), matching the existing PA_AUDIO_USE_CHANNEL_CONFIG convention.

Tests: new MixerMatrixTest infra (Kernels/AudioPipeline/Kernels_ChannelMixer_Matrix_TestInfra.h/.cpp) with 15 registered cases (mono<->stereo, 3.0<->2.0, 5.1<->2.0/3.0/2.1/7.1/5.1, unknown layouts). Full command-line suite: 5446 passed, 0 failed.

CommonFramework/AudioPipeline/ChannelMixer.h/.cpp:
build_channel_mixer_matrix() builds the N x M float weight matrix
(consumed by Kernels::AudioChannelMixer::mix_channels) from the
channel configs of two QAudioFormats, using the conventional
industry-standard coefficients (ITU-R BS.1116-1 style):

  - same position passes through at gain 1
  - mono <-> stereo duplicate / 0.5 average
  - C -> L/R at 0.7, L/R -> C (upmix) at 0.35 each
  - back/side surrounds -> front at 0.7 when the destination has
    no surround on that side; BL <-> SL cross-fill at 0.7
  - LFE passes through only, tops never mix
  - returns an empty vector when either format's channel layout is
    ChannelConfigUnknown; unnamed channels contribute zero

Kernels/AudioPipeline: add MixerMatrixTest infra and register 15
matrix cases (1<->2, 3.0, 5.1<->2.0/3.0/2.1/7.1, unknown layouts).
Kernels must not depend on Qt or CommonFramework, so the
MixerMatrixTest infra moves below build_channel_mixer_matrix in
CommonFramework/AudioPipeline/ChannelMixer.cpp, registered via
add_tests_ChannelMixerMatrix() from ComputerPrograms/UnitTestRunner.cpp
(the same pattern as BlackBorderDetector). Reverts the
Kernels/AudioPipeline changes and drops the Qt5 stub (Qt6+ required).
Also drops ffmpeg mentions from the comments.
@Mysticial
Mysticial merged commit cfdc6b5 into main Oct 17, 2026
14 checks passed
@Mysticial
Mysticial deleted the audio-channel-matrix-builder branch October 17, 2026 03:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants