Struggling to capture audio using nannou_audio despite successfully opening stream

Hello all! I'm trying to get very basic audio capture working using nannou, similar to this old example.

Here is my full source:

use std::sync::Arc;
use nannou::prelude::*;
use nannou_audio as audio;
use ringbuf::{Producer, Consumer, HeapRb};


struct Model {
    consumer: Consumer<f32, Arc<HeapRb<f32>>>,
}

struct CaptureModel {
    producer: Producer<f32, Arc<HeapRb<f32>>>,
}

fn capture(model: &mut CaptureModel, buffer: &audio::Buffer) {
    println!("capture");
    for frame in buffer.frames() {
        model.producer.push(frame[0]).unwrap();
    }
}

fn main() {
    nannou::app(model).update(update).run();
}

fn model(app: &App) -> Model {
    app.new_window()
        .view(view)
        .build()
        .unwrap();

    let audio_host = audio::Host::new();

    let samples = 1024;
    let buffer = HeapRb::<f32>::new(samples * 2);
    let (mut producer, consumer) = buffer.split();
    for _ in 0..samples {
        producer.push(0.0).unwrap();
    }

    let capture_model = CaptureModel {
        producer
    };
    let stream = audio_host.new_input_stream(capture_model)
        .capture(capture)
        .build()
        .unwrap();
    stream.play().unwrap();


    Model {
        consumer
    }
}

fn update(_app: &App, model: &mut Model, _update: Update) {
    let mut buffer = [0.0; 1024];
    model.consumer.pop_slice(&mut buffer);
}

fn view(app: &App, model: &Model, frame: Frame) {
    frame.clear(DIMGRAY);
}

The code compiles and runs, however, it seems that my capture function is never called and no samples are written to the ring buffer - the result is the same with all possible input devices. I also tried creating the input stream using the CPAL API directly, encountering the same issue.

I'm using stock Pop!_OS 22.04. Any ideas as to why this is happening or how to fix it?

I assume that your input stream gets immediately closed after you created your app model. Try adding the stream to your your Model type:

struct Model {
    consumer: Consumer<f32, Arc<HeapRb<f32>>>,
    stream: audio::Stream<CaptureModel>
}

and simply assign the stream you already correctly started via .play() to your model: Model { consumer, stream }

This should keep the stream alive.

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.