Understanding Symphonia’s audio buffer types, sample formats, and signal specifications
Symphonia provides a comprehensive set of primitives for working with decoded audio data. These primitives handle different sample formats, provide efficient planar audio storage, and enable safe conversion between formats.
AudioBuffer<S> (symphonia-core/src/audio.rs:283) is the fundamental audio container. It stores multi-channel audio in a planar format.
pub struct AudioBuffer<S: Sample> { buf: Vec<S>, // All channel data spec: SignalSpec, // Signal characteristics n_frames: usize, // Number of frames written n_capacity: usize, // Maximum frames}
use symphonia::core::audio::RawSampleBuffer;let mut raw_buf = RawSampleBuffer::<f32>::new( decoded.capacity() as u64, *decoded.spec(),);// Copy as interleaved bytesraw_buf.copy_interleaved_ref(decoded);// Get as byte slicelet bytes: &[u8] = raw_buf.as_bytes();
pub enum Layout { Mono, // Single center channel Stereo, // Left + Right TwoPointOne, // Left + Right + LFE FivePointOne, // Front L/R/C + Rear L/R + LFE}// Convert to Channelslet channels = Layout::Stereo.into_channels();
Create SampleBuffer and RawSampleBuffer once and reuse them:
// Goodlet mut sample_buf = SampleBuffer::<f32>::new(capacity, spec);loop { let decoded = decoder.decode(&packet)?; sample_buf.copy_interleaved_ref(decoded); // Reuse}// Bad - allocates every iterationloop { let decoded = decoder.decode(&packet)?; let mut sample_buf = SampleBuffer::<f32>::new(capacity, spec); sample_buf.copy_interleaved_ref(decoded);}
Prefer f32 for Processing
Use f32 samples for DSP operations:
Normalized range [-1.0, 1.0]
No overflow/underflow concerns
Native format for most audio libraries
Good precision for audio work
Handle Format Changes
Be prepared for Error::ResetRequired:
match decoder.decode(&packet) { Ok(decoded) => { /* process */ } Err(Error::ResetRequired) => { // Recreate buffers with new spec decoder.reset(); // Re-examine codec parameters } Err(e) => return Err(e),}
Use Direct Access When Possible
If you only need one channel or specific processing, access channels directly:
// More efficient than copying to SampleBuffermatch decoded { AudioBufferRef::F32(buf) => { let left = buf.chan(0); let right = buf.chan(1); // Process directly } _ => { /* handle other formats */ }}