rodio icon indicating copy to clipboard operation
rodio copied to clipboard

Cannot get any better than 12-16 ms latency

Open reo6 opened this issue 2 years ago • 3 comments

#[allow(dead_code)]
pub struct SamplePlayer {
    output_handle: OutputStreamHandle,
    stream: OutputStream,
}

impl SamplePlayer {
    pub fn new() -> Self {
        let (_stream, stream_handle) = OutputStream::try_default().unwrap();
        Self { output_handle: stream_handle, stream: _stream }
    }

    pub fn play_sample(&self, sample: &Sample) {
        let now = Instant::now();
        let _ = &self.output_handle.play_raw(sample.raw_audio.clone());
        println!("{}", now.elapsed().as_secs_f32() * 1000.);
    }
}

Sample:

pub struct Sample {
    pub raw_audio: SamplesConverter<Buffered<Decoder<File>>, f32>,
}

impl Sample {
    pub fn new(file: File) -> Self {
        let source = Decoder::new(file).unwrap();
        let buffer = source.buffered();

        Self {
            raw_audio: buffer.convert_samples(),
        }
    }

    pub fn new_from_filepath(path: String) -> Self {
        let f = File::open(path).unwrap();
        Self::new(f)
    }
}

Hello everybody, I'm working on a simple drum machine. Since this is an instrument, it's latency must be lower than ~8 ms. But I cannot get any lower than 12-16 ms right now. And I know, this is a playback library and might not be the right way to create a low latency instrument, but I think 16 ms is still way too much for a playback library.

This is the project link if you want to check the entire code. I can create a small test version of just the audio part if needed.

reo6 avatar Dec 21 '22 15:12 reo6

@ramazanemreosmanoglu In

pub fn play_sample(&self, sample: &Sample) {
        let now = Instant::now();
        let _ = &self.output_handle.play_raw(sample.raw_audio.clone());
        println!("{}", now.elapsed().as_secs_f32() * 1000.);
}

You're cloning inside of timing block. So you're really measuring clone + play_raw.

Move the clone outside of the timing block:

pub fn play_sample(&self, sample: &Sample) {
        let signal = sample.raw_audio.clone();
        let now = Instant::now();
        let _ = &self.output_handle.play_raw(signal);
        println!("{}", now.elapsed().as_secs_f32() * 1000.);
    }

davidclevenger avatar Jan 23 '23 18:01 davidclevenger

Is there a way to play a source without cloning? As far as I can see playing the same source repeatedly simply requires a clone (using a buffered source), because play_raw moves the source. I'm also noticing a latency above what I was hoping for, and haven't figured out yet how to avoid cloning, which likely contributes to it.

bluenote10 avatar Oct 19 '23 22:10 bluenote10

couldn't you preload all the sounds at the start, pause them and then unpause them, when you need to use them?

Per6 avatar Dec 23 '23 19:12 Per6