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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
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]]
|
[[package]]
|
||||||
name = "engine"
|
name = "engine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -59,6 +74,14 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jack-sine"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-channel",
|
||||||
|
"jack",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jack-sys"
|
name = "jack-sys"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["engine", "lib"]
|
members = ["engine", "examples/jack-sine", "lib"]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[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