From 9db5d76c122f0af43f0d0436b976b8c4d24180c3 Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Mon, 27 Oct 2025 16:55:32 -0600 Subject: [PATCH 1/5] simple wavetable --- .gitignore | 2 ++ Cargo.toml | 6 ++++++ README.md | 10 ++++++++++ src/lib.rs | 2 ++ src/wavetable.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs create mode 100644 src/wavetable.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b330586 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "wavetable-synth" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d00e421 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# WAVETABLE SYNTH +synthesizes sounds using a wavetable. + +## REQUIREMENTS +`no_std` compatible + + +## MODULES +### `wavetable` +trait definitions for a wavetable manager diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..08af373 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +#![no_std] +mod wavetable; diff --git a/src/wavetable.rs b/src/wavetable.rs new file mode 100644 index 0000000..b101ce3 --- /dev/null +++ b/src/wavetable.rs @@ -0,0 +1,48 @@ +pub trait Wavetable { + type OutputType; + /// get next sample + fn next(&mut self) -> Self::OutputType; +} + +pub struct SimpleWavetable<'a> { + // byte array for waveform + table: &'a [u8], + // index in the waveform + index: usize, +} + +impl<'a> Wavetable for SimpleWavetable<'a> { + type OutputType = u8; + fn next(&mut self) -> Self::OutputType { + let value = self.table[self.index]; + self.index += 1; + if self.index > self.table.len() { + self.index = 0; + } + value + } +} + +impl<'a> SimpleWavetable<'a> { + pub fn new(table: &'a [u8]) -> Self { + Self { table, index: 0 } + } +} + +// TESTS +#[cfg(test)] +pub mod test { + use super::*; + + #[test] + fn wavetable_t1() { + let table_data: [u8; 2] = [0, 255]; + let mut w = SimpleWavetable::new(&table_data); + for point in table_data { + assert!(w.next() == point); + } + } +} + +// TODO: +// - interpolated wavetable From e9a9ee2264072fe180f7f87be002d58b8d04ad15 Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Mon, 27 Oct 2025 16:55:33 -0600 Subject: [PATCH 2/5] allow wavetable to be generic over data width --- src/wavetable.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/wavetable.rs b/src/wavetable.rs index b101ce3..5105607 100644 --- a/src/wavetable.rs +++ b/src/wavetable.rs @@ -4,15 +4,17 @@ pub trait Wavetable { fn next(&mut self) -> Self::OutputType; } -pub struct SimpleWavetable<'a> { +/// non-interpolated, simple wavetable that produces the next sample +/// every time [`Wavetable::next()`] is called. +pub struct SimpleWavetable<'a, T: Copy> { // byte array for waveform - table: &'a [u8], + table: &'a [T], // index in the waveform index: usize, } -impl<'a> Wavetable for SimpleWavetable<'a> { - type OutputType = u8; +impl<'a, T: Copy> Wavetable for SimpleWavetable<'a, T> { + type OutputType = T; fn next(&mut self) -> Self::OutputType { let value = self.table[self.index]; self.index += 1; @@ -23,8 +25,8 @@ impl<'a> Wavetable for SimpleWavetable<'a> { } } -impl<'a> SimpleWavetable<'a> { - pub fn new(table: &'a [u8]) -> Self { +impl<'a, T: Copy> SimpleWavetable<'a, T> { + pub fn new(table: &'a [T]) -> Self { Self { table, index: 0 } } } @@ -36,8 +38,8 @@ pub mod test { #[test] fn wavetable_t1() { - let table_data: [u8; 2] = [0, 255]; - let mut w = SimpleWavetable::new(&table_data); + let table_data = [0, 255]; + let mut w = SimpleWavetable::::new(&table_data); for point in table_data { assert!(w.next() == point); } From 4d7f1d9c32b38630afec88b87d5a4b4d6aa7a883 Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Mon, 27 Oct 2025 16:56:11 -0600 Subject: [PATCH 3/5] simple wavetable --- .gitignore | 2 ++ Cargo.toml | 6 ++++++ README.md | 10 ++++++++++ src/lib.rs | 2 ++ src/wavetable.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs create mode 100644 src/wavetable.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b330586 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "wavetable-synth" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/README.md b/README.md new file mode 100644 index 0000000..d00e421 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# WAVETABLE SYNTH +synthesizes sounds using a wavetable. + +## REQUIREMENTS +`no_std` compatible + + +## MODULES +### `wavetable` +trait definitions for a wavetable manager diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..08af373 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +#![no_std] +mod wavetable; diff --git a/src/wavetable.rs b/src/wavetable.rs new file mode 100644 index 0000000..b101ce3 --- /dev/null +++ b/src/wavetable.rs @@ -0,0 +1,48 @@ +pub trait Wavetable { + type OutputType; + /// get next sample + fn next(&mut self) -> Self::OutputType; +} + +pub struct SimpleWavetable<'a> { + // byte array for waveform + table: &'a [u8], + // index in the waveform + index: usize, +} + +impl<'a> Wavetable for SimpleWavetable<'a> { + type OutputType = u8; + fn next(&mut self) -> Self::OutputType { + let value = self.table[self.index]; + self.index += 1; + if self.index > self.table.len() { + self.index = 0; + } + value + } +} + +impl<'a> SimpleWavetable<'a> { + pub fn new(table: &'a [u8]) -> Self { + Self { table, index: 0 } + } +} + +// TESTS +#[cfg(test)] +pub mod test { + use super::*; + + #[test] + fn wavetable_t1() { + let table_data: [u8; 2] = [0, 255]; + let mut w = SimpleWavetable::new(&table_data); + for point in table_data { + assert!(w.next() == point); + } + } +} + +// TODO: +// - interpolated wavetable From e43186ee4bf328892c359f796b5e3398aa038734 Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Mon, 27 Oct 2025 16:56:11 -0600 Subject: [PATCH 4/5] allow wavetable to be generic over data width --- src/wavetable.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/wavetable.rs b/src/wavetable.rs index b101ce3..5105607 100644 --- a/src/wavetable.rs +++ b/src/wavetable.rs @@ -4,15 +4,17 @@ pub trait Wavetable { fn next(&mut self) -> Self::OutputType; } -pub struct SimpleWavetable<'a> { +/// non-interpolated, simple wavetable that produces the next sample +/// every time [`Wavetable::next()`] is called. +pub struct SimpleWavetable<'a, T: Copy> { // byte array for waveform - table: &'a [u8], + table: &'a [T], // index in the waveform index: usize, } -impl<'a> Wavetable for SimpleWavetable<'a> { - type OutputType = u8; +impl<'a, T: Copy> Wavetable for SimpleWavetable<'a, T> { + type OutputType = T; fn next(&mut self) -> Self::OutputType { let value = self.table[self.index]; self.index += 1; @@ -23,8 +25,8 @@ impl<'a> Wavetable for SimpleWavetable<'a> { } } -impl<'a> SimpleWavetable<'a> { - pub fn new(table: &'a [u8]) -> Self { +impl<'a, T: Copy> SimpleWavetable<'a, T> { + pub fn new(table: &'a [T]) -> Self { Self { table, index: 0 } } } @@ -36,8 +38,8 @@ pub mod test { #[test] fn wavetable_t1() { - let table_data: [u8; 2] = [0, 255]; - let mut w = SimpleWavetable::new(&table_data); + let table_data = [0, 255]; + let mut w = SimpleWavetable::::new(&table_data); for point in table_data { assert!(w.next() == point); } From 96e26ce493e3a884a5f402a686aca75fda54a3c3 Mon Sep 17 00:00:00 2001 From: sigil-03 Date: Mon, 27 Oct 2025 16:56:11 -0600 Subject: [PATCH 5/5] WIP synthesizer --- src/lib.rs | 4 ++++ src/synthesizer.rs | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 src/synthesizer.rs diff --git a/src/lib.rs b/src/lib.rs index 08af373..caac1e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,6 @@ #![no_std] +mod synthesizer; mod wavetable; + +//TODO: +// * patch mod w/ trait Input and trait Output(?) diff --git a/src/synthesizer.rs b/src/synthesizer.rs new file mode 100644 index 0000000..9979397 --- /dev/null +++ b/src/synthesizer.rs @@ -0,0 +1,21 @@ +use crate::wavetable::Wavetable; + +pub trait Synthesizer {} + +pub struct SimpleWavetableSynthesizer { + wavetable: W, + clock_freq_hz: usize, + output_freq_hz: usize, + enable: bool, +} + +impl SimpleWavetableSynthesizer { + pub fn new(wavetable: W, clock_freq_hz: usize) -> Self { + Self { + wavetable, + clock_freq_hz, + output_freq_hz: 0, + enable: false, + } + } +}