-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement slots. Now we can change values in an algorithm
- Loading branch information
Showing
7 changed files
with
515 additions
and
21 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,26 +1,61 @@ | ||
use anyhow::Result; | ||
use synthizer::*; | ||
|
||
fn main() { | ||
const C_FREQ: f64 = 261.63; | ||
const E_FREQ: f64 = 329.63; | ||
const G_FREQ: f64 = 392.00; | ||
|
||
fn main() -> Result<()> { | ||
let mut synth = Synthesizer::new_default_output().unwrap(); | ||
|
||
let pi2 = 2.0f64 * std::f64::consts::PI; | ||
let chain1 = Chain::new(500f64) | ||
|
||
let freq1; | ||
let freq2; | ||
let freq3; | ||
|
||
{ | ||
let mut b = synth.batch(); | ||
freq1 = b.allocate_slot::<f64>(); | ||
freq2 = b.allocate_slot::<f64>(); | ||
freq3 = b.allocate_slot::<f64>(); | ||
} | ||
|
||
let note1 = read_slot(&freq1, C_FREQ) | ||
.divide_by_sr() | ||
.periodic_sum(1.0f64, 0.0f64) | ||
.inline_mul(Chain::new(pi2)) | ||
.sin(); | ||
let chain2 = Chain::new(600f64) | ||
let note2 = read_slot(&freq2, E_FREQ) | ||
.divide_by_sr() | ||
.periodic_sum(1.0f64, 0.0) | ||
.inline_mul(Chain::new(pi2)) | ||
.sin(); | ||
let note3 = read_slot(&freq3, G_FREQ) | ||
.divide_by_sr() | ||
.periodic_sum(1.0f64, 0.0) | ||
.inline_mul(Chain::new(pi2)) | ||
.sin(); | ||
let added = chain1 + chain2; | ||
|
||
let added = note1 + note2 + note3; | ||
let ready = added * Chain::new(0.1f64); | ||
let to_dev = ready.to_audio_device(); | ||
|
||
let mut synth = Synthesizer::new_default_output().unwrap(); | ||
let _handle = { | ||
let handle = { | ||
let mut batch = synth.batch(); | ||
batch.mount(to_dev) | ||
batch.mount(to_dev)? | ||
}; | ||
|
||
std::thread::sleep(std::time::Duration::from_secs(5)); | ||
std::thread::sleep(std::time::Duration::from_secs(1)); | ||
|
||
{ | ||
let mut batch = synth.batch(); | ||
batch.replace_slot_value(&handle, &freq1, C_FREQ * 2.0)?; | ||
batch.replace_slot_value(&handle, &freq2, E_FREQ * 2.0)?; | ||
batch.replace_slot_value(&handle, &freq3, G_FREQ * 2.0)?; | ||
} | ||
|
||
std::thread::sleep(std::time::Duration::from_secs(1)); | ||
|
||
Ok(()) | ||
} |
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,126 @@ | ||
use std::marker::PhantomData as PD; | ||
use std::mem::MaybeUninit; | ||
|
||
use crate::config; | ||
use crate::core_traits::*; | ||
|
||
pub struct MapSignal<ParSig, F, O>(PD<*const (ParSig, F, O)>); | ||
unsafe impl<ParSig, F, O> Send for MapSignal<ParSig, F, O> {} | ||
unsafe impl<ParSig, F, O> Sync for MapSignal<ParSig, F, O> {} | ||
|
||
pub struct MapSignalConfig<ParSigCfg, F, O> { | ||
parent: ParSigCfg, | ||
closure: F, | ||
_phantom: PD<O>, | ||
} | ||
|
||
pub struct MapSignalState<ParSig: Signal, F> { | ||
closure: F, | ||
|
||
parent_state: SignalState<ParSig>, | ||
} | ||
|
||
unsafe impl<ParSig, F, O> Signal for MapSignal<ParSig, F, O> | ||
where | ||
ParSig: Signal, | ||
F: FnMut(&SignalOutput<ParSig>) -> O + Send + Sync + 'static, | ||
O: Send, | ||
{ | ||
type Input = SignalInput<ParSig>; | ||
type Output = O; | ||
type Parameters = ParSig::Parameters; | ||
type State = MapSignalState<ParSig, F>; | ||
|
||
fn on_block_start( | ||
ctx: &mut crate::context::SignalExecutionContext<'_, '_, Self::State, Self::Parameters>, | ||
) { | ||
ParSig::on_block_start(&mut ctx.wrap(|s| &mut s.parent_state, |p| p)); | ||
} | ||
|
||
fn tick1<D: SignalDestination<Self::Output>>( | ||
ctx: &mut crate::context::SignalExecutionContext<'_, '_, Self::State, Self::Parameters>, | ||
input: &'_ Self::Input, | ||
destination: D, | ||
) { | ||
let mut par_in = MaybeUninit::uninit(); | ||
ParSig::tick1(&mut ctx.wrap(|s| &mut s.parent_state, |p| p), input, |x| { | ||
par_in.write(x); | ||
}); | ||
|
||
destination.send((ctx.state.closure)(unsafe { par_in.assume_init_ref() })); | ||
} | ||
|
||
fn tick_block< | ||
'a, | ||
I: FnMut(usize) -> &'a Self::Input, | ||
D: ReusableSignalDestination<Self::Output>, | ||
>( | ||
ctx: &'_ mut crate::context::SignalExecutionContext<'_, '_, Self::State, Self::Parameters>, | ||
input: I, | ||
mut destination: D, | ||
) where | ||
Self::Input: 'a, | ||
{ | ||
let mut outs: [MaybeUninit<SignalOutput<ParSig>>; config::BLOCK_SIZE] = | ||
[const { MaybeUninit::uninit() }; config::BLOCK_SIZE]; | ||
let mut i = 0; | ||
ParSig::tick_block(&mut ctx.wrap(|s| &mut s.parent_state, |p| p), input, |x| { | ||
outs[i].write(x); | ||
i += 1; | ||
}); | ||
|
||
outs.iter().for_each(|i| { | ||
destination.send_reusable((ctx.state.closure)(unsafe { i.assume_init_ref() })) | ||
}); | ||
|
||
// The mapping closure gets references, so we must drop this ourselves. | ||
unsafe { | ||
crate::unsafe_utils::drop_initialized_array(outs); | ||
} | ||
} | ||
|
||
fn trace_slots< | ||
Tracer: FnMut( | ||
crate::unique_id::UniqueId, | ||
std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>, | ||
), | ||
>( | ||
state: &Self::State, | ||
parameters: &Self::Parameters, | ||
inserter: &mut Tracer, | ||
) { | ||
ParSig::trace_slots(&state.parent_state, parameters, inserter); | ||
} | ||
} | ||
|
||
impl<ParSig, F, O> IntoSignal for MapSignalConfig<ParSig, F, O> | ||
where | ||
F: FnMut(&IntoSignalOutput<ParSig>) -> O + Send + Sync + 'static, | ||
ParSig: IntoSignal, | ||
O: Send + 'static, | ||
{ | ||
type Signal = MapSignal<ParSig::Signal, F, O>; | ||
|
||
fn into_signal(self) -> IntoSignalResult<Self> { | ||
let par = self.parent.into_signal()?; | ||
|
||
Ok(ReadySignal { | ||
parameters: par.parameters, | ||
state: MapSignalState { | ||
closure: self.closure, | ||
parent_state: par.state, | ||
}, | ||
signal: MapSignal(PD), | ||
}) | ||
} | ||
} | ||
|
||
impl<ParSig, F, O> MapSignalConfig<ParSig, F, O> { | ||
pub(crate) fn new(parent: ParSig, closure: F) -> Self { | ||
Self { | ||
closure, | ||
parent, | ||
_phantom: PD, | ||
} | ||
} | ||
} |
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
Oops, something went wrong.