Signal specifications define the characteristics of an audio signal including sample rate and channel configuration.
SignalSpec
SignalSpec describes the fundamental properties of an audio signal.
pub struct SignalSpec {
pub rate: u32,
pub channels: Channels,
}
Sample rate in hertz (Hz). Common values: 44100, 48000, 96000
Channel configuration as a bitmask
Creating SignalSpec
new
pub fn new(rate: u32, channels: Channels) -> Self
Creates a SignalSpec with the specified sample rate and channel configuration.
Example:
use symphonia::core::audio::{SignalSpec, Channels};
let spec = SignalSpec::new(
48000,
Channels::FRONT_LEFT | Channels::FRONT_RIGHT
);
new_with_layout
pub fn new_with_layout(rate: u32, layout: Layout) -> Self
Creates a SignalSpec using a standard channel layout.
Standard channel layout (Mono, Stereo, etc.)
Example:
use symphonia::core::audio::{SignalSpec, Layout};
let stereo_spec = SignalSpec::new_with_layout(48000, Layout::Stereo);
let mono_spec = SignalSpec::new_with_layout(44100, Layout::Mono);
let surround_spec = SignalSpec::new_with_layout(48000, Layout::FivePointOne);
Channels
Channels is a bitmask representing the audio channels in a signal. The first 18 channels are compatible with Microsoft’s WAVEFORMATEXTENSIBLE structure.
Standard Channel Flags
Front-left (left) or Mono channel
Front-right (right) channel
Front-centre (center) channel
Low frequency effects channel 1 (subwoofer)
Rear-left (surround rear left) channel
Rear-right (surround rear right) channel
Front left-of-centre channel
Front right-of-centre channel
Rear-centre (surround rear centre) channel
Side left (surround left) channel
Side right (surround right) channel
Additional Channel Flags
Channels also supports additional positions:
TOP_CENTRE, TOP_FRONT_LEFT, TOP_FRONT_CENTRE, TOP_FRONT_RIGHT
TOP_REAR_LEFT, TOP_REAR_CENTRE, TOP_REAR_RIGHT
REAR_LEFT_CENTRE, REAR_RIGHT_CENTRE
FRONT_LEFT_WIDE, FRONT_RIGHT_WIDE
FRONT_LEFT_HIGH, FRONT_CENTRE_HIGH, FRONT_RIGHT_HIGH
LFE2 - Second low frequency channel
Channels Methods
count
pub fn count(self) -> usize
Returns the number of channels in the bitmask.
Example:
let channels = Channels::FRONT_LEFT | Channels::FRONT_RIGHT;
assert_eq!(channels.count(), 2);
let surround = Channels::FRONT_LEFT | Channels::FRONT_RIGHT
| Channels::FRONT_CENTRE | Channels::LFE1
| Channels::REAR_LEFT | Channels::REAR_RIGHT;
assert_eq!(surround.count(), 6);
iter
pub fn iter(&self) -> ChannelsIter
Returns an iterator over individual channels in the bitmask.
Example:
let channels = Channels::FRONT_LEFT | Channels::FRONT_RIGHT;
for channel in channels.iter() {
println!("Channel: {:?}", channel);
}
// Output:
// Channel: FRONT_LEFT
// Channel: FRONT_RIGHT
Layout
Layout provides common channel configurations as convenient presets.
pub enum Layout {
Mono,
Stereo,
TwoPointOne,
FivePointOne,
}
Layout Variants
Left and right channels
- Channels:
FRONT_LEFT | FRONT_RIGHT
Stereo with subwoofer
- Channels:
FRONT_LEFT | FRONT_RIGHT | LFE1
5.1 surround sound
- Channels:
FRONT_LEFT | FRONT_RIGHT | FRONT_CENTRE | REAR_LEFT | REAR_RIGHT | LFE1
into_channels
pub fn into_channels(self) -> Channels
Converts a Layout into its corresponding Channels bitmask.
Example:
use symphonia::core::audio::Layout;
let stereo = Layout::Stereo.into_channels();
assert_eq!(stereo.count(), 2);
let surround = Layout::FivePointOne.into_channels();
assert_eq!(surround.count(), 6);
Common Patterns
Creating Custom Channel Configurations
use symphonia::core::audio::{SignalSpec, Channels};
// Quad surround (4.0)
let quad = Channels::FRONT_LEFT | Channels::FRONT_RIGHT
| Channels::REAR_LEFT | Channels::REAR_RIGHT;
let spec = SignalSpec::new(48000, quad);
// 7.1 surround
let surround_7_1 = Channels::FRONT_LEFT | Channels::FRONT_RIGHT
| Channels::FRONT_CENTRE | Channels::LFE1
| Channels::REAR_LEFT | Channels::REAR_RIGHT
| Channels::SIDE_LEFT | Channels::SIDE_RIGHT;
let spec = SignalSpec::new(48000, surround_7_1);
Checking Channel Configuration
use symphonia::core::audio::Channels;
let channels = decoded.spec().channels;
// Check if stereo
if channels == (Channels::FRONT_LEFT | Channels::FRONT_RIGHT) {
println!("Stereo audio");
}
// Check if mono
if channels == Channels::FRONT_LEFT {
println!("Mono audio");
}
// Check channel count
match channels.count() {
1 => println!("Mono"),
2 => println!("Stereo"),
6 => println!("5.1 Surround"),
_ => println!("{} channels", channels.count()),
}
Iterating Channels
use symphonia::core::audio::{AudioBuffer, Signal};
let buffer: AudioBuffer<f32> = /* ... */;
let channels = buffer.spec().channels;
// Process each channel
for (idx, channel_flag) in channels.iter().enumerate() {
let samples = buffer.chan(idx);
println!("Channel {:?} has {} samples", channel_flag, samples.len());
// Process samples for this channel
for &sample in samples {
// ...
}
}
Matching Common Layouts
use symphonia::core::audio::{Channels, Layout};
let channels = decoded.spec().channels;
if channels == Layout::Stereo.into_channels() {
// Optimized stereo processing
let left = buffer.chan(0);
let right = buffer.chan(1);
} else if channels == Layout::Mono.into_channels() {
// Mono processing
let mono = buffer.chan(0);
} else {
// Generic multi-channel processing
for ch in 0..channels.count() {
let samples = buffer.chan(ch);
// ...
}
}
Working with Sample Rates
use symphonia::core::audio::SignalSpec;
let spec = decoded.spec();
// Common sample rates
match spec.rate {
44100 => println!("CD quality"),
48000 => println!("Professional audio"),
88200 | 96000 => println!("High resolution"),
_ => println!("Sample rate: {} Hz", spec.rate),
}
// Calculate duration
let frames = decoded.frames();
let duration_secs = frames as f64 / spec.rate as f64;
println!("Duration: {:.2} seconds", duration_secs);
Complete Example
use symphonia::core::audio::{SignalSpec, Layout, Channels};
use symphonia::core::audio::AudioBuffer;
fn process_audio(decoded: AudioBufferRef) {
let spec = decoded.spec();
println!("Sample rate: {} Hz", spec.rate);
println!("Channels: {}", spec.channels.count());
// Check for common layouts
if spec.channels == Layout::Stereo.into_channels() {
println!("Stereo audio detected");
match decoded {
AudioBufferRef::F32(buf) => {
let left = buf.chan(0);
let right = buf.chan(1);
// Process stereo
for (l, r) in left.iter().zip(right.iter()) {
// ...
}
}
_ => { /* Handle other formats */ }
}
} else {
println!("Multi-channel audio");
// Generic processing
for ch in 0..spec.channels.count() {
println!("Processing channel {}", ch);
}
}
}
See Also