Skip to content

Commit

Permalink
Draft new tree API
Browse files Browse the repository at this point in the history
  • Loading branch information
AldaronLau committed May 5, 2024
1 parent 8c2d45a commit b527e48
Show file tree
Hide file tree
Showing 5 changed files with 305 additions and 14 deletions.
58 changes: 51 additions & 7 deletions examples/piano.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
//! A Minor on an Electric Piano

use fon::chan::Ch16;
use fon::{Audio, Frame};
use twang::noise::White;
use twang::ops::Gain;
use twang::osc::Sine;
use twang::Synth;
use fon::{chan::Ch16, Audio, Frame};
use twang::next::{Synth, Wave};

mod wav;

Expand All @@ -18,16 +14,64 @@ const PITCHES: [f32; 3] = [220.0, 220.0 * 32.0 / 27.0, 220.0 * 3.0 / 2.0];
/// Volume of the piano
const VOLUME: f32 = 1.0 / 3.0;

/*
// State of the synthesizer.
#[derive(Default)]
struct Processors {
// White noise generator.
white: White,
// 10 harmonics for 3 pitches.
piano: [[Sine; 10]; 3],
} */
const GAINS: &[Wave; 10] = &[
Wave::sig(HARMONICS[0]),
Wave::sig(HARMONICS[1]),
Wave::sig(HARMONICS[2]),
Wave::sig(HARMONICS[3]),
Wave::sig(HARMONICS[4]),
Wave::sig(HARMONICS[5]),
Wave::sig(HARMONICS[6]),
Wave::sig(HARMONICS[7]),
Wave::sig(HARMONICS[8]),
Wave::sig(HARMONICS[9]),
];

/// Play a note on the piano from a sine wave
const fn piano(sine: &'static Wave) -> [Wave<'static>; 10] {
[
sine.amp(&GAINS[0]),
sine.amp(&GAINS[1]),
sine.amp(&GAINS[2]),
sine.amp(&GAINS[3]),
sine.amp(&GAINS[4]),
sine.amp(&GAINS[5]),
sine.amp(&GAINS[6]),
sine.amp(&GAINS[7]),
sine.amp(&GAINS[8]),
sine.amp(&GAINS[9]),
]
}

fn main() {
// Define waveform
const FIRST: Wave = Wave::mix(&piano(&Wave::sig(PITCHES[0]).sine()));
const THIRD: Wave = Wave::mix(&piano(&Wave::sig(PITCHES[1]).sine()));
const FIFTH: Wave = Wave::mix(&piano(&Wave::sig(PITCHES[2]).sine()));
const PIANO: Wave =
Wave::mix(&[FIRST, THIRD, FIFTH]).amp(&Wave::sig(VOLUME));

// Initialize audio, and create synthesizer
let mut audio = Audio::<Ch16, 2>::with_silence(48_000, 48_000 * 5);
let mut synth = Synth::new(PIANO);

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

// Plot synthesized audio, and write to a WAV file
// plot::write(&audio);
wav::write(audio, "piano.wav").expect("Failed to write WAV file");

/*
// Initialize audio
let mut audio = Audio::<Ch16, 2>::with_silence(48_000, 48_000 * 5);
// Create audio processors
Expand All @@ -53,5 +97,5 @@ fn main() {
// Synthesize 5 seconds of audio
synth.stream(audio.sink());
// Write synthesized audio to WAV file
wav::write(audio, "piano.wav").expect("Failed to write WAV file");
wav::write(audio, "piano.wav").expect("Failed to write WAV file"); */
}
12 changes: 7 additions & 5 deletions examples/sine.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use fon::{chan::Ch16, Audio, Frame};
use twang::next::{Synth, Wave};
use twang::tree::{Synth, Sine, Hz, Wave};

mod wav;

fn main() {
// Define waveform
const SINE: Wave = Wave::sig(440.0).sine();
// Define waveform
const fn waveform() -> impl Wave {

Check failure on line 7 in examples/sine.rs

View workflow job for this annotation

GitHub Actions / test (ubuntu-latest, 1.60.0)

`impl Trait` is not allowed in constant functions
Sine(Hz(440.0))
}

fn main() {
// Initialize audio, and create synthesizer
let mut audio = Audio::<Ch16, 2>::with_silence(48_000, 48_000 * 5);
let mut synth = Synth::new(SINE);
let mut synth = Synth::new(waveform());

// Synthesize 5 seconds of audio
synth.stream(audio.sink(), &[]);
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
variant_size_differences
)]

extern crate std; // FIXME: for debugging
extern crate alloc;

mod math;
Expand All @@ -117,5 +118,7 @@ pub mod osc;
pub mod file;
// FIXME
pub mod next;
// FIXME
pub mod tree;

pub use synth::Synth;
54 changes: 52 additions & 2 deletions src/next.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,37 @@ enum Node<'a> {
File(&'a [u8]),
}

impl Node<'_> {
/// Recursively count the number of oscillators
fn count_osc(&self) -> usize {
use Node::*;
match *self {
Sig(_) => 0,
Mix(nodes) => {
let mut count = 0;
for node in nodes {
count += node.count_osc();
}
count
}
Sine { hz } => 1 + hz.count_osc(),
Ramp { hz, curve } => 1 + hz.count_osc() + curve.count_osc(),
Pulse { hz, duty, alias } => {
1 + hz.count_osc() + duty.count_osc() + alias.count_osc()
}
Mul(nodes) => {
let mut count = 0;
for node in nodes {
count += node.count_osc();
}
count
}
Amp(a, b) => a.count_osc() + b.count_osc(),
File(_) => todo!(),
}
}
}

/// A parameterized waveform.
///
/// For all oscillators, there is a built-in phase offset so that the first
Expand Down Expand Up @@ -388,6 +419,7 @@ impl<'a> Wave<'a> {
Self(Node::Mix(Self::as_nodes(nodes)))
}

/// Get node slice from wave slice
// Safe transmute because of `repr(transparent)`
#[allow(unsafe_code)]
const fn as_nodes(nodes: &'a [Self]) -> &'a [Node<'a>] {
Expand All @@ -413,11 +445,17 @@ pub struct Synth<'a> {
impl<'a> Synth<'a> {
/// Create a new synthesizer for a parameterized waveform.
pub fn new(wave: Wave<'a>) -> Self {
let phase = Vec::from([0.0]); //FIXME: Calculate size based on osc count
let phase = {
let mut phase = Vec::new();
phase.resize(wave.0.count_osc(), 0.0);
phase
};
let stack = Vec::from([[0.0; 32]]);
let index = 32;
let wave = Some(wave);

// panic!("{}", phase.len());

Synth {
wave,
phase,
Expand Down Expand Up @@ -573,7 +611,19 @@ impl<'a> Synth<'a> {
}
}
Node::Mul(nodes) => todo!("{nodes:?}"),
Node::Amp(main, amp) => todo!("{main:?} {amp:?}"),
Node::Amp(main, amp) => {
self.stack.push([0.0; 32]);
self.node(amp, delta, osc);
let amp = self.stack.pop().unwrap();

*osc += 1;
self.node(main, delta, osc);
for (main, amp) in
self.stack.last_mut().unwrap().iter_mut().zip(amp.iter())
{
*main *= amp;
}
}
Node::File(bytes) => todo!("{:?}", bytes),
}
}
Expand Down
Loading

0 comments on commit b527e48

Please sign in to comment.