-
-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
252 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
--- | ||
layout: page | ||
title: Closure Callbacks | ||
parent: Contrib | ||
permalink: /closure-callbacks | ||
nav_order: 1 | ||
--- | ||
|
||
# Closure Callbacks | ||
|
||
Closure callbacks allow you to define functionality inline. | ||
|
||
## Process Closure | ||
|
||
The typical use case for a process closure involves creating a closure that | ||
contains captures the required state and then activating it. | ||
|
||
```rust | ||
// 1. Create the client. | ||
let (client, _status) = | ||
jack::Client::new("silence", jack::ClientOptions::NO_START_SERVER).unwrap(); | ||
|
||
// 2. Define the state. | ||
let mut output = client.register_port("out", jack::AudioOut::default()); | ||
let silence_value = 0.0; | ||
|
||
// 3. Define the closure. Use `move` to capture the required state. | ||
let process_callback = move |_: &jack::Client, ps: &jack::ProcessScope| -> jack::Control { | ||
output.as_mut_slice(ps).fill(silence_value); | ||
jack::Control::Continue | ||
}; | ||
|
||
// 4. Start processing. | ||
let process = jack::contrib::ClosureProcessHandler::new(process_callback); | ||
let active_client = client.activate_async((), process).unwrap(); | ||
``` | ||
|
||
## State + Process Closure + Buffer Closure | ||
|
||
`jack::contrib::ClosureProcessHandler` also allows defining a buffer size | ||
callback that can share state with the process callback. The buffer size | ||
callback is useful as it allows the handler to adapt to any changes in the | ||
buffer size. | ||
|
||
```rust | ||
// 1. Create the client. | ||
let (client, _status) = | ||
jack::Client::new("silence", jack::ClientOptions::NO_START_SERVER).unwrap(); | ||
|
||
// 2. Define the state. | ||
struct State { | ||
silence: Vec<f32>, | ||
output: jack::Port<jack::AudioOut>, | ||
} | ||
let state = State { | ||
silence: Vec::new(), | ||
output: client | ||
.register_port("out", jack::AudioOut::default()) | ||
.unwrap(), | ||
}; | ||
|
||
// 3. Define the state and closure. | ||
let process_callback = |state: &mut State, _: &jack::Client, ps: &jack::ProcessScope| { | ||
state | ||
.output | ||
.as_mut_slice(ps) | ||
.copy_from_slice(state.silence.as_slice()); | ||
jack::Control::Continue | ||
}; | ||
let buffer_callback = |state: &mut State, _: &jack::Client, len: jack::Frames| { | ||
state.silence = vec![0f32; len as usize]; | ||
jack::Control::Continue | ||
}; | ||
|
||
// 4. Start processing. | ||
let process = | ||
jack::contrib::ClosureProcessHandler::with_state(state, process_callback, buffer_callback); | ||
let active_client = client.activate_async((), process).unwrap(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
layout: page | ||
title: Contrib | ||
permalink: /contrib | ||
nav_order: 3 | ||
--- | ||
|
||
# Contrib | ||
|
||
`jack::contrib` contains convenient but optional utilities. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
use crate::{Client, Control, Frames, ProcessHandler, ProcessScope}; | ||
|
||
/// Wrap a closure that can handle the `process` callback. This is called every time data from ports | ||
/// is available from JACK. | ||
pub struct ClosureProcessHandler<T, F> { | ||
pub state: T, | ||
pub callbacks: F, | ||
} | ||
|
||
impl<ProcessCallback> ClosureProcessHandler<(), ProcessCallback> | ||
where | ||
ProcessCallback: 'static + Send + FnMut(&Client, &ProcessScope) -> Control, | ||
{ | ||
/// Create a new `jack::ProcessHandler` with the given process callback. | ||
/// | ||
/// ```rust | ||
/// // Run one cycle of processing | ||
/// let mut has_run = false; | ||
/// let handler = jack::contrib::ClosureProcessHandler::new(move |_client, _process_scope| { | ||
/// if has_run { | ||
/// jack::Control::Quit | ||
/// } else { | ||
/// has_run = true; | ||
/// jack::Control::Continue | ||
/// } | ||
/// }); | ||
/// ``` | ||
pub fn new(process_callback: ProcessCallback) -> Self { | ||
ClosureProcessHandler { | ||
state: (), | ||
callbacks: process_callback, | ||
} | ||
} | ||
} | ||
|
||
impl<ProcessCallback> ProcessHandler for ClosureProcessHandler<(), ProcessCallback> | ||
where | ||
ProcessCallback: 'static + Send + FnMut(&Client, &ProcessScope) -> Control, | ||
{ | ||
fn process(&mut self, c: &Client, ps: &ProcessScope) -> Control { | ||
(self.callbacks)(c, ps) | ||
} | ||
} | ||
|
||
pub struct ProcessCallbacks<ProcessCallback, BufferCallback> { | ||
process: ProcessCallback, | ||
buffer: BufferCallback, | ||
} | ||
|
||
impl<T, ProcessCallback, BufferCallback> | ||
ClosureProcessHandler<T, ProcessCallbacks<ProcessCallback, BufferCallback>> | ||
where | ||
T: Send, | ||
ProcessCallback: 'static + Send + FnMut(&mut T, &Client, &ProcessScope) -> Control, | ||
BufferCallback: 'static + Send + FnMut(&mut T, &Client, Frames) -> Control, | ||
{ | ||
/// Create a new `jack::ProcessHandler` with some state. | ||
/// | ||
/// ```rust | ||
/// // 1. Create the client. | ||
/// let (client, _status) = jack::Client::new("silence", jack::ClientOptions::NO_START_SERVER).unwrap(); | ||
/// | ||
/// // 2. Define the state. | ||
/// struct State{ | ||
/// silence: Vec<f32>, | ||
/// output: jack::Port<jack::AudioOut>, | ||
/// } | ||
/// let state = State{ | ||
/// silence: Vec::new(), | ||
/// output: client.register_port("out", jack::AudioOut::default()).unwrap(), | ||
/// }; | ||
/// | ||
/// // 3. Define the state and closure. | ||
/// let process_callback = |state: &mut State, _: &jack::Client, ps: &jack::ProcessScope| -> jack::Control { | ||
/// state.output.as_mut_slice(ps).copy_from_slice(state.silence.as_slice()); | ||
/// jack::Control::Continue | ||
/// }; | ||
/// let buffer_callback = |state: &mut State, _: &jack::Client, len: jack::Frames| -> jack::Control { | ||
/// state.silence = vec![0f32; len as usize]; | ||
/// jack::Control::Continue | ||
/// }; | ||
/// | ||
/// // 4. Start processing. | ||
/// let process = jack::contrib::ClosureProcessHandler::with_state(state, process_callback, buffer_callback); | ||
/// let active_client = client.activate_async((), process).unwrap(); | ||
/// ``` | ||
pub fn with_state( | ||
state: T, | ||
process_callback: ProcessCallback, | ||
buffer_callback: BufferCallback, | ||
) -> Self { | ||
ClosureProcessHandler { | ||
state, | ||
callbacks: ProcessCallbacks { | ||
process: process_callback, | ||
buffer: buffer_callback, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
impl<T, ProcessCallback, BufferCallback> ProcessHandler | ||
for ClosureProcessHandler<T, ProcessCallbacks<ProcessCallback, BufferCallback>> | ||
where | ||
T: Send, | ||
ProcessCallback: 'static + Send + FnMut(&mut T, &Client, &ProcessScope) -> Control, | ||
BufferCallback: 'static + Send + FnMut(&mut T, &Client, Frames) -> Control, | ||
{ | ||
fn process(&mut self, c: &Client, ps: &ProcessScope) -> Control { | ||
(self.callbacks.process)(&mut self.state, c, ps) | ||
} | ||
|
||
fn buffer_size(&mut self, c: &Client, size: Frames) -> Control { | ||
(self.callbacks.buffer)(&mut self.state, c, size) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters