Skip to content

Channel Formats ​

libsonare recognizes four channel layouts system-wide — mono, stereo, 5.1 and 7.1 — but different modules were built for different jobs, so a channel count above 2 is not handled the same way everywhere. This page is the map: which module accepts how many channels, what canonical order and LFE handling mean, and how narrowing and widening work. There is one downmix rule and two upmix behaviors.

Layouts and Speaker Roles ​

LayoutChannelsRoles, canonical order
Mono1(no role; a single channel)
Stereo2L, R
5.16L, R, C, LFE, Ls, Rs
7.18L, R, C, LFE, Ls, Rs, Lss, Rss

Canonical order matches WAVE_FORMAT_EXTENSIBLE. In 7.1, Ls/Rs (indices 4/5) and Lss/Rss (indices 6/7) are two distinct role pairs, not the same pair renamed — see Widening for where each one sits.

The figure below places each role around the listener, with its plane index. Loudness metering weighs a channel by +1.5 dB when its speaker sits between 60° and 120° to either side, so the 5.1 surround pair and the 7.1 side pair are weighted while the 7.1 rear pair is not.

5.1 and 7.1 speaker positions
5.1L·0 −30°R·1 +30°C·2 0°Ls·4 −110°Rs·5 +110°listener7.1L·0 −30°R·1 +30°C·2 0°Ls·4 −135°Rs·5 +135°Lss·6 −90°Rss·7 +90°listener
  • L / R front pair
  • C centre
  • Ls / Rs surround (rear in 7.1)
  • Lss / Rss side
  • loudness weight +1.5 dB (60°–120°)
  • LFE: no direction, not in the loudness sum
Top-down view, front at the top; each speaker shows its role, plane index and angle. The shaded sectors are where the BS.1770 loudness sum weighs a channel by 1.41 (+1.5 dB). The LFE has no direction and is left out of the loudness sum, so it is drawn as a ring around the listener.

LFE (low-frequency effects) carries only the bass content mixed into the track at reduced level, on the assumption a decoder boosts it back by about 10 dB on the way to a subwoofer. In the playback renderer, three rules cover every case a target can end up in. The shared downmix function used elsewhere simply drops the LFE unless includeLfe is set (see Narrowing).

  • Fold-in (no LFE channel on the target, or bass management has no subwoofer): the LFE signal is low-pass filtered at 120 Hz and added into the L/R pair at reduced level.
  • Subwoofer feed (bass management enabled with a subwoofer): the LFE signal is boosted and combined with the low-frequency content crossed over from speakers marked "small", then sent to the LFE channel.
  • With bass management disabled and a target that does have an LFE channel, the LFE channel passes through unchanged, because the downstream amplifier is assumed to apply its own +10 dB.

Channel Handling by Module ​

Most of the library processes mono or stereo and rejects anything wider; only the modules below accept a surround channel count, and each one decides differently what to do with material wider than what it renders.

ModuleAcceptsWider-than-stereo behavior
Audio file loadingFolds to mono, or passes an interleaved buffer through untouched1/2/6/8-channel files fold to mono through the BS.775 downmix below; any other count is averaged
Analysis and streaming analysisMono onlyCaller folds first
Loudness metering (lufsInterleaved)Any channel countBS.1770 channel weights are selected by channel count
True peak, correlation, phase scopeMono / stereoRejected
One-shot effects and mastering processors1–2Rejected
Repair session (masteringRepairAnalyze / masteringRepairApply)Any non-empty planar channel setRuns the selected stages across all channels; denoise and dereverb use linked masks
Realtime processors (dynamics, EQ, …)Up to 64 planarRuns per-plane; a stereo-pair-only effect on a wide bus acts on the front pair only
Mixing bus, strip, meter1 / 2 / 6 / 8Follows the bus's declared layout
Mixer graphBus width as declaredA narrower destination (a smaller bus, a stereo sidechain key) gets the BS.775 downmix; a wider one receives the source planes unchanged
Realtime engine / project bounceBus layout; output is 1 / 2 / 6 / 8Same rule as the mixer graph; a request wider than the master bus is refused. In an AudioWorklet, the meter snapshot of a 5.1 or 7.1 target adds per-channel arrays
Realtime engine track lane (setTrackLanes)Stereo source onlyMono, 5.1 and 7.1 sources are refused (InvalidParameter; RangeError in the WASM worklet facade). A C caller sets SONARE_CHANNEL_LAYOUT_STEREO, because a zero-initialized lane reads as mono. setTrackLanes also refuses more than MAX_TRACK_LANES (32) lanes, a lane pan outside −1…+1, a width outside 0…2 and a fader outside the fader range
Realtime voice changer1–2Rejected
Playback renderer1 / 2 / 6 / 8, plus a channel mapFollows the conversion table below in both directions

Declaring an Input Layout with a Channel Map ​

Decoders disagree on channel order. AAC uses C L R Ls Rs LFE, some frameworks distinguish "5.1" from "5.1(side)", and platform APIs each have their own convention. The playback renderer's input.channel_map names the role of each input channel explicitly (input.layout must then be a fixed layout, not "auto") instead of asking every caller to reorder its own buffers first: an incorrect map fails loudly as a validation error rather than landing as a silently swapped or missing channel. A 5.1(side) source's SL/SR channels map onto the Ls/Rs roles; the role name is "left/right surround"; the angle it ends up at is decided by the output side, not the input labeling.

Narrowing (Downmix) ​

Every module that renders a surround bus to something narrower (file loading, the mixer graph, project bounce and the playback renderer) uses the same ITU-R BS.775 coefficients, exposed as downmix in the mixing module. BS.775 itself defines the downmix for formats up to 5.1; the 7.1 rules below extend it by folding each side pair into its surround pair. The surround pair enters the front pair at reduced level, and the LFE channel stays out of the arithmetic: downmix drops it unless includeLfe is set, while the playback renderer applies its own LFE fold-in (above). In JavaScript the same coefficients are downmix(channels, targetLayout): centre and surround enter the front pair at -3 dB and the LFE plane is dropped. decodeChannels(bytes) keeps every channel of a file so you can narrow it yourself, and the browser-codec fallback of Audio.fromMemoryWithBrowserFallback folds to mono through this rule, so both decoders give the same samples.

downmix reads the source layout from the channel count (1, 2, 6 or 8). The target is a ChannelLayout ordinal: 0 mono, 1 stereo, 2 5.1, 3 7.1.

SourceTargetRule
StereoMonoPlain average of L and R
5.1 or 7.1MonoThe stereo fold below, then the average of the two channels
5.1StereoL + 0.707 C + 0.707 Ls, and the same for the right side; LFE dropped
7.1StereoAs 5.1, with Lss added at -3 dB beside Ls
7.15.1Ls + Lss and Rs + Rss summed at unity gain; the other channels pass through
Same layoutSame layoutCopied
AnyA wider layoutRefused: InvalidParameter, "downmix cannot upmix"
Any other channel countMonoUnweighted mean of the channels
Any other channel countAny other targetRefused: InvalidParameter

The fold is not normalized by default

The fold is not scaled to stay inside full scale. A full-scale, in-phase 5.1 source reaches 2.41 in stereo and in mono, and a 7.1 source reaches 3.12 in stereo. Audio.fromMemory of a 5.1 file uses the same fold, so it can also exceed full scale. Pass normalize (below) or limit the result before writing it.

Two options change the fold. normalize divides the output by the worst-case sum, so a source with every plane at full scale and in phase lands at exactly 1.0; the divisor is fixed by the layouts, not measured from the signal, so typical material comes out a few dB quieter. includeLfe folds the LFE plane into the front pair at -3 dB instead of dropping it, which raises the same worst case to 3.12 (5.1) or 3.83 (7.1). The options apply to a narrowing into stereo or mono; a 7.1 to 5.1 fold keeps the LFE plane either way. They are { normalize, includeLfe } in JavaScript and normalize=, include_lfe= in Python; the C form is sonare_downmix_ex.

5.1 · DOWNMIXIDLE
5.1 downmix: a fold that can pass full scale

The six channels play their own sounds in canonical order (L, R, C, LFE, Ls, Rs), then one in-phase sine together. downmix adds the centre and surrounds at −3 dB (×0.707), drops the LFE and does not normalize, so at full scale the in-phase sine reaches 2.414 (+7.66 dBFS) in stereo and in mono. Switch channels off to see which ones push the fold past 0 dBFS.

Target
Peak per channel
0 dBFS
typescript
import { init, decodeChannels, downmix } from '@libraz/libsonare';

await init();
const { channels, sampleRate } = decodeChannels(fileBytes);
const stereo = channels.length > 2 ? downmix(channels, 1) : channels;
python
from libsonare import decode_channels, downmix, ChannelLayout

channels, sample_rate = decode_channels(file_bytes)   # (channel_count, frames), float32
stereo = downmix(channels, ChannelLayout.STEREO) if channels.shape[0] > 2 else channels

See JavaScript/TypeScript Audio and Streaming API for the signatures, C++ API for the C and C++ forms, and Surround group buses and wide meters for the mixer graph's own narrowing rule.

The playback renderer's own conversion table, by source and target. "Rendered binaurally" means the speaker feeds are filtered through measured head-related responses (HRTF), so the speakers seem to sit outside the head:

Source \ TargetStereo speakers5.1 speakers7.1 speakersHeadphones
MonoL/R, -3 dBCentre onlyCentre onlyCentre, rendered binaurally
StereoPassthroughUpmix (or L/R only, upmix.enabled: false)Upmix (or L/R only)Upmix, then rendered binaurally (or L/R only at ±30°)
5.1BS.775 downmix + LFE fold-inPassthroughL/R/C/LFE unchanged; Ls/Rs move to Lss/Rss; 7.1's own Ls/Rs are silent5.1, rendered binaurally
7.1BS.775 downmix + LFE fold-inBS.775 downmix (LFE unchanged)Passthrough7.1, rendered binaurally

Widening (Upmix) ​

The mixer and the playback renderer widen channel beds differently. The mixer sums a narrower bus into the same plane indices of a wider bus, leaving the additional planes silent. The playback renderer uses speaker geometry when mapping ambience to a wider layout.

ConversionMixerPlayback renderer
5.1 to 7.1Ls/Rs stay at indices 4 and 5; the side planes at 6 and 7 stay silentLs/Rs move to the side planes at 6 and 7; the rear planes at 4 and 5 stay silent
Stereo to 7.1Front pair only; other planes silentAmbience generated for both rear and side pairs, with an extra anti-phase component on the rear pair

The surround panner uses the speaker angles in the layout figure in both modules, but they only place a panned source; they do not decide how a bus is widened. At full pan the panner silences the far channel exactly.

The renderer does not create a rear pair from a 5.1 source (no synthetic rear-channel generation), and it does not upmix to a wide-plus-height format — see Playback Renderer § Non-Goals.