Trying to get into jack
Some checks failed
ci/woodpecker/push/code_tests Pipeline failed
ci/woodpecker/push/pre_commit_test Pipeline was successful

This commit is contained in:
2025-12-24 13:30:15 +01:00
parent 29181f9c76
commit 535727268d
3 changed files with 107 additions and 92 deletions

View File

@@ -1,101 +1,62 @@
use std::{fs::File, path::PathBuf};
use clap::{Parser, Subcommand, ValueEnum};
use jack::{AudioOut, Client, ClientOptions};
use symphonia::core::{audio::{AudioBufferRef, SampleBuffer}, codecs::DecoderOptions, formats::FormatOptions, io::MediaSourceStream, meta::MetadataOptions, probe::Hint};
use ringbuf::RingBuffer;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
enum Backend {
Jack,
Alsa,
Pulseaudio,
Coreaudio,
Cpal,
}
#[derive(Parser)]
#[command(version, about, long_about = None)]
struct Cli {
name: Option<String>,
#[arg(short, long, value_enum)]
backend: Option<Backend>,
#[arg(short, long)]
track: Option<Vec<String>>,
}
use std::{io, str::FromStr};
use ringbuf::{
traits::{Consumer, Producer, Split},
HeapRb,
};
fn main() {
let cli = Cli::parse();
let (client, _status) = Client::new("rust_jack_simple", ClientOptions::default()).unwrap();
let out_l = client.register_port("out_l", AudioOut::default()).unwrap();
let out_r = client.register_port("out_r", AudioOut::default()).unwrap();
let ring_l = RingBuffer::<f32>::new(48000 * 2);
let ring_r = RingBuffer::<f32>::new(48000 * 2);
let (prod_l, cons_l) = ring_l.split();
let (prod_r, cons_r) = ring_r.split();
if let Some(backend) = cli.backend {
match backend {
Backend::Jack => println!("jack"),
Backend::Alsa => println!("alsa"),
Backend::Pulseaudio => println!("pulse"),
Backend::Coreaudio => println!("coreaudio"),
Backend::Cpal => println!("cpal"),
/*
* Start the JACK backend and make it ready to play sounds
*
*/
let (client, _status) =
jack::Client::new("rust_jack_sine", jack::ClientOptions::default()).unwrap();
let mut out_a = client
.register_port("sine_out", jack::AudioOut::default())
.unwrap();
let rb = HeapRb::<f32>::new(128);
let (mut prod, mut cons) = rb.split();
let process_callback = move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control {
let mut out_a_p = out_a.as_mut_slice(ps);
for v in cons.iter_mut() {
println!("{:?}", v);
out_a_p.fill(*v);
}
jack::Control::Continue
};
let process = jack::contrib::ClosureProcessHandler::new(process_callback);
let active_client = client.activate_async((), process).unwrap();
active_client
.as_client()
.connect_ports_by_name("rust_jack_sine:sine_out", "system:playback_1")
.unwrap();
active_client
.as_client()
.connect_ports_by_name("rust_jack_sine:sine_out", "system:playback_2")
.unwrap();
// processing starts here
// 5. wait or do some processing while your handler is running in real time.
println!("Enter an integer value to change the frequency of the sine wave.");
while let Some(f) = read_freq() {
prod.try_push(f);
}
// 6. Optional deactivate. Not required since active_client will deactivate on
// drop, though explicit deactivate may help you identify errors in
// deactivate.
if let Err(err) = active_client.deactivate() {
eprintln!("JACK exited with error: {err}");
};
}
fn spawn_mp3_decoder(
path: String,
mut prod_l: ringbuf::Producer<f32>,
mut prod_r: ringbuf::Producer<f32>,
) {
thread::spawn(move || {
let file = File::open(path).expect("failed to open mp3");
let mss = MediaSourceStream::new(Box::new(file), Default::default());
let mut hint = Hint::new();
hint.with_extension("mp3");
let probed = symphonia::default::get_probe()
.format(
&hint,
mss,
&FormatOptions::default(),
&MetadataOptions::default(),
)
.expect("format probe failed");
let mut format = probed.format;
let track = format.default_track().unwrap();
let mut decoder = symphonia::default::get_codecs()
.make(&track.codec_params, &DecoderOptions::default())
.unwrap();
let mut sample_buf: Option<SampleBuffer<f32>> = None;
loop {
let packet = match format.next_packet() {
Ok(p) => p,
Err(_) => break,
};
let decoded = decoder.decode(&packet).unwrap();
let buf = sample_buf.get_or_insert_with(|| {
SampleBuffer::new(decoded.capacity() as u64, *decoded.spec())
});
buf.copy_interleaved_ref(decoded);
// Assume stereo
for frame in buf.samples().chunks(2) {
let _ = prod_l.push(frame[0]);
let _ = prod_r.push(frame[1]);
}
}
});
fn read_freq() -> Option<f32> {
let mut user_input = String::new();
match io::stdin().read_line(&mut user_input) {
Ok(_) => u16::from_str(user_input.trim()).ok().map(|n| n as f32),
Err(_) => None,
}
}