I'm having some problems using the jack bindings for Rust.
I tried to make a simple synthesizer. It works decent at startup but the notes are out of tune and they change over time. Furthermore, the audio just stops working after about 5 minutes.
Adding some debug code shows that my global time variable is a bit out of whack. Every time I run the code it starts off fine, then delays, then runs ahead, then grinds to a halt and the audio stops.
I made a minimal example of simply playing a single tone and it has the same problem (but possibly to a lesser extent). My best guess is that the sample rate might be changing and jack doesn't realize because I'm using pipewire?
htop shows normal resource use.
Here's my minimal example:
use jack;
use std::f32::consts::TAU;
use std::io::stdin;
fn main() {
start_synth();
}
fn start_synth() {
// Define the jack device
let (client, _status) =
jack::Client::new("SimpleSynth", jack::ClientOptions::NO_START_SERVER).unwrap();
// Define audio output
let mut audio_out = client
.register_port("audio", jack::AudioOut::default())
.unwrap();
// The global time
let mut time: f32 = 0.0;
// Define the frequency
let frequency: f32 = 440.0;
// Create a jack process handler
let handler = jack::ClosureProcessHandler::new(
move |client: &jack::Client, process_scope: &jack::ProcessScope| -> jack::Control {
// I think the sample rate can dynamically change so I put it
// inside the process handler.
// Monitoring always shows 48000 so it's probably not necessary.
let time_per_sample: f32 = 1.0 / (client.sample_rate() as f32);
// Put notes in buffer
let buffer = audio_out.as_mut_slice(process_scope);
for sample in buffer.iter_mut() {
*sample = (time * frequency * TAU).sin();
time += time_per_sample;
}
// Tell jack to continue
jack::Control::Continue
},
);
// Activate the jack process
let _active_client = client.activate_async((), handler).unwrap();
// Print messages
loop {
let mut input_text = String::new();
stdin().read_line(&mut input_text).expect("error");
}
}
I figured it out!
And of course it was floating point numbers.
Here's an updated version of the example that uses integer time and runs perfectly fine.