Skip to content

Commit

Permalink
Implement part of pulse waves in new API
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed May 18, 2024
1 parent f54bb5f commit 3b66f6e
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 10 deletions.
14 changes: 7 additions & 7 deletions examples/triangle.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use fon::{chan::Ch16, Audio, Frame};
use twang::next::{Synth, Wave};
use fon::{chan::Ch16, Audio};
use twang::tree::{line::Line, Synth};

mod wav;
//mod plot;

fn main() {
// Define waveform
const TRIANGLE: Wave = Wave::sig(440.0).trap(Wave::ZERO, Wave::MAX);

let waveform = const { Line(440.0).osc().pulse(Line(0.0), Line(0.5)) };
// Initialize audio, and create synthesizer
let mut audio = Audio::<Ch16, 2>::with_silence(48_000, 48_000 * 5);
let mut synth = Synth::new(TRIANGLE);
let mut synth = Synth::new(waveform);

// Synthesize 5 seconds of audio
synth.stream(audio.sink(), &[]);

// Write synthesized audio to WAV file
// Plot synthesized audio, and write to a WAV file
//plot::write(&audio);
wav::write(audio, "triangle.wav").expect("Failed to write WAV file");
}
20 changes: 20 additions & 0 deletions src/tree/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ impl Chunk {
(self, other.borrow()).for_each_sample(|(s, o)| *s *= o)
}

#[inline(always)]
#[must_use]
pub(super) fn recip(self) -> Self {
self.for_each_sample(|sample| *sample = sample.recip())
}

#[inline(always)]
#[must_use]
pub(super) fn cosine(self) -> Self {
Expand All @@ -64,6 +70,12 @@ impl Chunk {
self.for_each_sample(|sample| *sample = -*sample)
}

#[inline(always)]
#[must_use]
pub(super) fn abs(self) -> Self {
self.for_each_sample(|sample| *sample = sample.abs())
}

#[inline(always)]
#[must_use]
pub(super) fn neg_abs(self) -> Self {
Expand All @@ -77,4 +89,12 @@ impl Chunk {
*sample = libm::copysignf(*sample, sign)
})
}

#[inline(always)]
#[must_use]
pub(super) fn clip(self) -> Self {
self.for_each_sample(|sample| {
*sample = libm::fminf(libm::fmaxf(*sample, -1.0), 1.0)
})
}
}
15 changes: 15 additions & 0 deletions src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,20 @@ macro_rules! const_postfix_waveform {
crate::tree::osc::Osc(self)

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, wasm32-unknown-unknown)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-apple-darwin)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-linux-gnu)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, aarch64-linux-android)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-unknown-redox)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-pc-windows-gnu)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-freebsd)

unnecessary qualification

Check warning on line 72 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile-ios (macos-latest, 1.70.0, aarch64-apple-ios)

unnecessary qualification
}

/// Postfix helper for wrapping synth instruction with [`osc::Pulse`].
///
/// [`osc::Pulse`]: crate::tree::osc::Pulse
pub const fn pulse<J, K>(
self,
duty: J,
alias: K,
) -> crate::tree::osc::Pulse<Self, J, K>

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, wasm32-unknown-unknown)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-apple-darwin)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-linux-gnu)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, aarch64-linux-android)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-unknown-redox)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-pc-windows-gnu)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-freebsd)

unnecessary qualification

Check warning on line 82 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile-ios (macos-latest, 1.70.0, aarch64-apple-ios)

unnecessary qualification
where
J: crate::tree::Wave
{
crate::tree::osc::Pulse(self, duty, alias)

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, wasm32-unknown-unknown)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-apple-darwin)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-linux-gnu)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, aarch64-linux-android)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, x86_64-unknown-redox)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-pc-windows-gnu)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile (ubuntu-latest, 1.70.0, i686-unknown-freebsd)

unnecessary qualification

Check warning on line 86 in src/tree/mod.rs

View workflow job for this annotation

GitHub Actions / cross-compile-ios (macos-latest, 1.70.0, aarch64-apple-ios)

unnecessary qualification
}

/// Postfix helper for wrapping synth instruction with [`osc::Sine`].
///
/// [`osc::Sine`]: crate::tree::osc::Sine
Expand Down Expand Up @@ -106,6 +120,7 @@ pub use self::synth::Synth;
for<T: Wave> &T,
for<T: Wave, U: Wave> osc::Bezier<T, U>,
for<T: Wave> osc::Osc<T>,
for<T: Wave, U: Wave, V: Wave> osc::Pulse<T, U, V>,
for<T: Wave> osc::Sine<T>,
)]
pub trait Wave {
Expand Down
4 changes: 3 additions & 1 deletion src/tree/osc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

const_postfix_waveform!(Bezier<T, U>, T, U);
const_postfix_waveform!(Osc<T>, T);
const_postfix_waveform!(Pulse<T, U, V>, T, U, V);
const_postfix_waveform!(Sine<T>, T);

mod bezier;
mod osc;
mod pulse;
mod sine;

pub use self::{bezier::Bezier, osc::Osc, sine::Sine};
pub use self::{bezier::Bezier, osc::Osc, pulse::Pulse, sine::Sine};
6 changes: 4 additions & 2 deletions src/tree/osc/osc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ use crate::tree::{Chunk, Wave};

/// Phase oscillator (sawtooth wave)
///
/// This is the most basic oscillator, which all other oscillators depend on for
/// their phase.
/// Takes frequency (non-zero) as input
///
/// This is the most basic oscillator, which all other oscillators must depend
/// on for their phase.
#[derive(Debug)]
pub struct Osc<I>(pub I);

Expand Down
23 changes: 23 additions & 0 deletions src/tree/osc/pulse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::tree::{Chunk, Wave};

/// Pulse wave
///
/// Takes phase (-1 to 1), duty (-1 to 1) and alias (0 to 1) as input
#[derive(Debug)]
pub struct Pulse<I, J, K>(pub I, pub J, pub K);

impl<I, J, K> Wave for Pulse<I, J, K>
where
I: Wave,
J: Wave,
K: Wave,
{
fn synthesize(&self, elapsed: u64, interval: u64, vars: &[f32]) -> Chunk {
let chunk = self.0.synthesize(elapsed, interval, vars);
let _cycle = self.1.synthesize(elapsed, interval, vars);
let alias = self.2.synthesize(elapsed, interval, vars);
let clip = alias.recip();

chunk.abs().gain(2.0).offset(-1.0).amplify(clip).clip()
}
}

0 comments on commit 3b66f6e

Please sign in to comment.