Add a dummy jack example
Signed-off-by: Nikolai Rodionov <allanger@badhouseplants.net>
This commit is contained in:
23
Cargo.lock
generated
23
Cargo.lock
generated
@@ -26,6 +26,21 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[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-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "engine"
|
||||
version = "0.1.0"
|
||||
@@ -59,6 +74,14 @@ dependencies = [
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jack-sine"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"jack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jack-sys"
|
||||
version = "0.5.1"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["engine", "lib"]
|
||||
members = ["engine", "examples/jack-sine", "lib"]
|
||||
|
||||
[workspace.dependencies]
|
||||
|
||||
8
examples/jack-sine/Cargo.toml
Normal file
8
examples/jack-sine/Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "jack-sine"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
crossbeam-channel = "0.5.15"
|
||||
jack = "0.13.3"
|
||||
2
examples/jack-sine/README.md
Normal file
2
examples/jack-sine/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
Set this on mac ❯ export DYLD_FALLBACK_LIBRARY_PATH="$(brew --prefix jack)/lib:${DYLD_FALLBACK_LIBRARY_PATH:-}"
|
||||
|
||||
94
examples/jack-sine/src/main.rs
Normal file
94
examples/jack-sine/src/main.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
//! Sine wave generator with frequency configuration exposed through standard
|
||||
//! input.
|
||||
|
||||
use crossbeam_channel::bounded;
|
||||
use std::io;
|
||||
use std::str::FromStr;
|
||||
|
||||
fn main() {
|
||||
// 1. open a client
|
||||
let (client, _status) =
|
||||
jack::Client::new("rust_jack_sine", jack::ClientOptions::default()).unwrap();
|
||||
|
||||
// 2. register port
|
||||
let out_port = client
|
||||
.register_port("sine_out", jack::AudioOut::default())
|
||||
.unwrap();
|
||||
|
||||
// 3. define process callback handler
|
||||
let (tx, rx) = bounded(1_000_000);
|
||||
struct State {
|
||||
out_port: jack::Port<jack::AudioOut>,
|
||||
rx: crossbeam_channel::Receiver<f64>,
|
||||
frequency: f64,
|
||||
frame_t: f64,
|
||||
time: f64,
|
||||
}
|
||||
let process = jack::contrib::ClosureProcessHandler::with_state(
|
||||
State {
|
||||
out_port,
|
||||
rx,
|
||||
frequency: 220.0,
|
||||
frame_t: 1.0 / client.sample_rate() as f64,
|
||||
time: 0.0,
|
||||
},
|
||||
|state, _, ps| -> jack::Control {
|
||||
// Get output buffer
|
||||
let out = state.out_port.as_mut_slice(ps);
|
||||
|
||||
// Check frequency requests
|
||||
while let Ok(f) = state.rx.try_recv() {
|
||||
state.time = 0.0;
|
||||
state.frequency = f;
|
||||
}
|
||||
|
||||
// Write output
|
||||
for v in out.iter_mut() {
|
||||
let x = state.frequency * state.time * 2.0 * std::f64::consts::PI;
|
||||
let y = x.sin();
|
||||
*v = y as f32;
|
||||
state.time += state.frame_t;
|
||||
}
|
||||
|
||||
// Continue as normal
|
||||
jack::Control::Continue
|
||||
},
|
||||
move |_, _, _| jack::Control::Continue,
|
||||
);
|
||||
|
||||
// 4. Activate the client. Also connect the ports to the system audio.
|
||||
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() {
|
||||
tx.send(f).unwrap();
|
||||
}
|
||||
|
||||
// 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}");
|
||||
};
|
||||
}
|
||||
|
||||
/// Attempt to read a frequency from standard in. Will block until there is
|
||||
/// user input. `None` is returned if there was an error reading from standard
|
||||
/// in, or the retrieved string wasn't a compatible u16 integer.
|
||||
fn read_freq() -> Option<f64> {
|
||||
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 f64),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user