Trying to get into jack
This commit is contained in:
52
Cargo.lock
generated
52
Cargo.lock
generated
@@ -242,6 +242,56 @@ dependencies = [
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-deque",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-queue",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
@@ -981,6 +1031,8 @@ dependencies = [
|
||||
"clap",
|
||||
"coreaudio-rs",
|
||||
"cpal",
|
||||
"crossbeam",
|
||||
"crossbeam-channel",
|
||||
"jack",
|
||||
"pulseaudio",
|
||||
"ringbuf",
|
||||
|
||||
@@ -12,6 +12,8 @@ symphonia = { version = "0.5.5", features = ["mp3"] }
|
||||
coreaudio-rs = { version = "0.13.0", optional = true }
|
||||
cpal = { version = "0.16.0", optional = true }
|
||||
ringbuf = "0.4.8"
|
||||
crossbeam = { version = "0.8.4", features = ["crossbeam-channel"] }
|
||||
crossbeam-channel = "0.5.15"
|
||||
|
||||
[features]
|
||||
pulseaudio = ["dep:pulseaudio"]
|
||||
|
||||
147
src/main.rs
147
src/main.rs
@@ -1,101 +1,62 @@
|
||||
use std::{fs::File, path::PathBuf};
|
||||
use std::{io, str::FromStr};
|
||||
|
||||
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>>,
|
||||
}
|
||||
|
||||
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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,
|
||||
use ringbuf::{
|
||||
traits::{Consumer, Producer, Split},
|
||||
HeapRb,
|
||||
};
|
||||
|
||||
let decoded = decoder.decode(&packet).unwrap();
|
||||
fn main() {
|
||||
/*
|
||||
* 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 buf = sample_buf.get_or_insert_with(|| {
|
||||
SampleBuffer::new(decoded.capacity() as u64, *decoded.spec())
|
||||
});
|
||||
let active_client = client.activate_async((), process).unwrap();
|
||||
|
||||
buf.copy_interleaved_ref(decoded);
|
||||
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
|
||||
|
||||
// Assume stereo
|
||||
for frame in buf.samples().chunks(2) {
|
||||
let _ = prod_l.push(frame[0]);
|
||||
let _ = prod_r.push(frame[1]);
|
||||
// 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 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,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user