Skip to content

Commit

Permalink
Implement slots. Now we can change values in an algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
ahicks92 committed Dec 18, 2024
1 parent e61f904 commit 50de271
Show file tree
Hide file tree
Showing 7 changed files with 515 additions and 21 deletions.
51 changes: 43 additions & 8 deletions crates/synthizer/examples/two_sine_waves.rs
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(())
}
28 changes: 28 additions & 0 deletions crates/synthizer/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,34 @@ where
}
}

/// Start a chain which reads from a slot.
pub fn read_slot<T>(
slot: &sigs::Slot<T>,
initial_value: T,
) -> Chain<impl IntoSignal<Signal = impl Signal<Input = (), Output = T>>>
where
T: Clone + Send + Sync + 'static,
{
Chain {
inner: slot.read_signal(initial_value),
}
}

/// Start a chain which reads from a slot, then includes whether or not the slot changed this block.
///
/// Returns `(T, bool)`.
pub fn read_slot_and_changed<T>(
slot: &sigs::Slot<T>,
initial_value: T,
) -> Chain<impl IntoSignal<Signal = impl Signal<Input = (), Output = (T, bool)>>>
where
T: Send + Sync + Clone + 'static,
{
Chain {
inner: slot.read_signal_and_change_flag(initial_value),
}
}

impl<S: IntoSignal> Chain<S> {
/// Start a chain.
///
Expand Down
126 changes: 126 additions & 0 deletions crates/synthizer/src/signals/map.rs
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,
}
}
}
2 changes: 2 additions & 0 deletions crates/synthizer/src/signals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod and_then;
mod audio_io;
mod consume_input;
mod conversion;
mod map;
mod null;
mod periodic_f64;
mod scalars;
Expand All @@ -12,6 +13,7 @@ pub use and_then::*;
pub use audio_io::*;
pub(crate) use consume_input::*;
pub use conversion::*;
pub use map::*;
pub use null::*;
pub use periodic_f64::*;
pub use slots::*;
Expand Down
Loading

0 comments on commit 50de271

Please sign in to comment.