Decode a audio file that cpal can consume properly

Hi, I need to decode a audio file that cpal can play. Actually I did it with symphonia but problem is: audios are playing fast then normal. Example Video (forum doesn't let me upload video so it's external resource. Song is freebird). Here is my code that produces this result, since code is a bit longer here is my logic first:

decode with symphonia, store in ring buffer, consume buffer with cpal.

Code:

fn listen() {
     let file = File::open("music.mp3").unwrap();

    //Buffer limit can be detected automatically
    let (mut producer, mut receiver) = HeapRb::<f32>::new(BUFFER_LENGTH*100).split();

    let media_source_stream = MediaSourceStream::new(Box::new(file), Default::default());

    let hint = Hint::new();

    let metadata_options = MetadataOptions::default();
    let format_options = FormatOptions::default();

    let probed = symphonia::default::get_probe()
        .format(
            &hint,
            media_source_stream,
            &format_options,
            &metadata_options,
        )
        .unwrap();

    let mut format = probed.format;

    let track = format
        .tracks()
        .iter()
        .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
        .unwrap();

    DecoderOptions::default();
    let decoder_options = DecoderOptions::default();
    let mut decoder = symphonia::default::get_codecs()
        .make(&track.codec_params, &decoder_options)
        .unwrap();

    let track_id = track.id;

    loop {
        let packet = match format.next_packet() {
            Ok(packet) => packet,
            Err(err_val) => {
                eprintln!("Error: Packaging Audio File | {}", err_val);
                break;
            }
        };

        while !format.metadata().is_latest() {
            format.metadata().pop();
        }

        if packet.track_id() != track_id {
            continue;
        }

        let _ = playing_to_base_sender.send(true);
        match decoder.decode(&packet) {
            Ok(decoded) => match decoded {
                AudioBufferRef::F32(buf) => {
                    println!("Size = {:#?}", buf.capacity());
                    for &sample in buf.chan(0) {
                        match producer.push(sample) {
                            Ok(_) => {
                                //println!("{}", sample);
                            }
                            Err(_) => {
                                println!("E");
                            }
                        }
                    }
                }
                _ => {}
            },
            Err(_) => {
                //eprintln!("Error: Sample Decode | {}", err_val);
                println!("End ?");
            }
        }
    }

    let host = cpal::default_host();
    let output_device = host.default_output_device().unwrap();
    let config: cpal::StreamConfig = output_device.default_output_config().unwrap().into();

    let output_data_fn = move |data:&mut [f32], _: &cpal::OutputCallbackInfo| {
        for sample in data {
            let mini_packet = receiver.pop().unwrap();
            *sample = mini_packet;
        }
    };

    let output_stream = output_device.build_output_stream(&config, output_data_fn, err_fn, None).unwrap();

    output_stream.play().unwrap();

    std::thread::sleep(Duration::from_secs(10000000));
    output_stream.pause().unwrap();
    drop(output_stream);
}

fn err_fn(err: cpal::StreamError) {
    eprintln!("Something Happened: {}", err);
}

How can I fix this ?

Fixed it, main problem was I only listening one channel out of two channel, then other problem is sample rate difference. I used rubato to make them equal as my output device.

some places are hard coded as you can see. this is just concept code. you can modify them:

use std::{fs::File, time::Duration};
 
use cpal::{traits::{DeviceTrait, HostTrait, StreamTrait}, FromSample};
use ringbuf::HeapRb;
use rubato::{Resampler, SincFixedIn, SincInterpolationParameters, SincInterpolationType, WindowFunction};
use symphonia::core::{
    audio::{AudioBufferRef, SampleBuffer, Signal},
    codecs::{DecoderOptions, CODEC_TYPE_NULL},
    formats::FormatOptions,
    io::MediaSourceStream,
    meta::MetadataOptions,
    probe::Hint,
};
use tokio::sync::broadcast::{Receiver, Sender};
 
use crate::BUFFER_LENGTH;
 
pub async fn play() {
    let file = File::open("music.mp3").unwrap();
    let mut counter = 0;
    //Buffer limit can be detected automatically
    let (mut producer, mut receiver) = HeapRb::<f32>::new(BUFFER_LENGTH*100).split();
 
    let mut audio_decoded_left = vec![];
    let mut audio_decoded_right = vec![];
    let media_source_stream = MediaSourceStream::new(Box::new(file), Default::default());
 
    let hint = Hint::new();
 
    let metadata_options = MetadataOptions::default();
    let format_options = FormatOptions::default();
 
    let probed = symphonia::default::get_probe()
        .format(
            &hint,
            media_source_stream,
            &format_options,
            &metadata_options,
        )
        .unwrap();
 
    let mut format = probed.format;
 
    let track = format
        .tracks()
        .iter()
        .find(|t| t.codec_params.codec != CODEC_TYPE_NULL)
        .unwrap();
 
    DecoderOptions::default();
    let decoder_options = DecoderOptions::default();
    let mut decoder = symphonia::default::get_codecs()
        .make(&track.codec_params, &decoder_options)
        .unwrap();
 
    let track_id = track.id;
 
    loop {
        let packet = match format.next_packet() {
            Ok(packet) => packet,
            Err(err_val) => {
                eprintln!("Error: Packaging Audio File | {}", err_val);
                break;
            }
        };
 
        while !format.metadata().is_latest() {
            format.metadata().pop();
        }
 
        if packet.track_id() != track_id {
            continue;
        }
 
        match decoder.decode(&packet) {
            Ok(decoded) => match decoded {
                AudioBufferRef::F32(buf) => {
                    counter += 1;
                    println!("Size = {:#?}", buf.capacity());
                    for (left, right) in buf.chan(0).iter().zip(buf.chan(1).iter()) {
 
                        audio_decoded_left.push(*left as f64);
                        audio_decoded_right.push(*right as f64);
                    }
                }
                _ => {}
            },
            Err(_) => {
                //eprintln!("Error: Sample Decode | {}", err_val);
                println!("End ?");
            }
        }
    }
 
    let params = SincInterpolationParameters {
        sinc_len: 256,
        f_cutoff: 0.95,
        interpolation: SincInterpolationType::Linear,
        oversampling_factor: 256,
        window: WindowFunction::BlackmanHarris2,
    };
    let mut resampler = SincFixedIn::<f64>::new(
        44100 as f64 / 48000 as f64,
        2.0,
        params,
        audio_decoded_left.len(),
        2,
    ).unwrap();
 
    let audio_decoded_channes_combined = vec![audio_decoded_left, audio_decoded_right];
    let audio_resampled = resampler.process(&audio_decoded_channes_combined, None).unwrap();
 
 
    let mut audio_resampled_left = vec![];
    let mut audio_resampled_right = vec![];
 
    for sample in &audio_resampled[0] {
        audio_resampled_left.push(*sample);
    }
 
    for sample in &audio_resampled[1] {
        audio_resampled_right.push(*sample);
    }
 
    audio_resampled_left.reverse();
    audio_resampled_right.reverse();
 
 
    for _ in 0..audio_resampled_left.clone().len() {
        producer.push(audio_resampled_left.pop().unwrap() as f32).unwrap();
        producer.push(audio_resampled_right.pop().unwrap() as f32).unwrap();
    }
 
    let host = cpal::default_host();
    let output_device = host.default_output_device().unwrap();
    let config: cpal::StreamConfig = output_device.default_output_config().unwrap().into();
 
    println!("{:#?}", config.sample_rate);
 
    let output_data_fn = move |data:&mut [f32], _: &cpal::OutputCallbackInfo| {
        for sample in data {
            let mini_packet = match receiver.pop() {
                Some(single) => {
                    single
			},
                None => 0.0,
            };
            if audio_stream_sender.receiver_count() > 0 {
                let _= audio_stream_sender.send(mini_packet);
            }
            *sample = mini_packet;
        }
    };
 
    let output_stream = output_device.build_output_stream(&config, output_data_fn, err_fn, None).unwrap();
 
    output_stream.play().unwrap();
 
    std::thread::sleep(Duration::from_secs(10000000));
    output_stream.pause().unwrap();
    drop(output_stream);
}
 
fn err_fn(err: cpal::StreamError) {
    eprintln!("Something Happened: {}", err);
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.