Skip to content

Commit

Permalink
Cleanup and add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
cowgirl-coding committed Mar 28, 2020
1 parent 63cfca0 commit ef1f111
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 12 deletions.
4 changes: 4 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
use std::f32::consts::PI;

pub const TWO_PI: f32 = 2.0 * PI;

3 changes: 3 additions & 0 deletions src/conversion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn seconds_to_samples(seconds: f32, sample_rate: u32) -> f32 {
sample_rate as f32 * seconds
}
32 changes: 28 additions & 4 deletions src/delay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ impl CircularBuffer {
}
}

fn seconds_to_samples(seconds: f32, sample_rate: u32) -> f32 {
sample_rate as f32 * seconds
}
// Note that unlike read-only signal generators, effects with an internal
// CircularBuffer do manage their internal buffer, instead of reading from a
// referenced wavetable, and they also combine incrementing and reading
// operations. The internal buffer is managed because access to the write index
// is necessary for reading, and it's not useful to have multiple actors writing
// into a CircularBuffer. Reading and incrementing (i.e. writing) actions are
// combined becuase the input value to the write operation depends on the
// previous write operation whenever feedback designs are used.

// SimpleDelay manages its own buffer
pub struct SimpleDelay {
Expand All @@ -67,4 +72,23 @@ impl SimpleDelay {
}
}

pub struct DelayTap(pub f32, pub f32);
//pub struct DelayTap(pub f32, pub f32);

//pub struct UberDelay {
//input_buffer: CircularBuffer,
//capture_buffer: CircularBuffer,
//}

//impl UberDelay {
//pub fn new(buffer_size: usize) -> UberDelay {
//UberDelay {
//input_buffer: CircularBuffer::new(buffer_size),
//capture_buffer: CircularBuffer::new(buffer_size),
//}
//}
//// TODO: we need to recieve lots of params here and generate the multitap output
//// TODO: Create functions to make delay taps.
//pub fn tick(input_sample: f32, delay_taps: Vec<DelayTap>, feedback_amount: f32, pattern_length:f32) -> f32 {
//1.0
//}
//}
5 changes: 5 additions & 0 deletions src/midi.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Create a table of MIDI note frequencies and store it in memory. Frequencies
// are accessed from the table by index, which is the desired MIDI note. For
// example, notes[64] = 329.62..., which is the frequency at C4.
//
// See: http://subsynth.sourceforge.net/midinote2freq.html
pub fn make_midi_freq_table() -> Vec<f32> {
let notes: Vec<f32> = vec![
8.1757989156,
Expand Down
28 changes: 20 additions & 8 deletions src/wavetable.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::f32::consts::PI;
use std::f32::consts::E;
use std::f32::consts::PI;

const TWO_PI: f32 = 2.0 * PI;
// TODO: Figure out how to import this from the constants module.
pub const TWO_PI: f32 = 2.0 * PI;

type Wavetable = Vec<f32>;

Expand All @@ -24,8 +25,12 @@ pub fn make_exp_envelope(table_size: usize) -> Wavetable {

pub fn make_sine_table(table_size: usize) -> Wavetable {
make_fourier_table_norm(
table_size,
vec![Partial { freq: 1.0, amp: 1.0, phase: 0.0, }]
table_size,
vec![Partial {
freq: 1.0,
amp: 1.0,
phase: 0.0,
}],
)
}

Expand Down Expand Up @@ -54,7 +59,9 @@ fn make_square_partials(num_partials: usize) -> Vec<Partial> {
let mut partials = Vec::new();
for index in 1..num_partials {
// Even partials are not present in a square wave
if index % 2 == 0 { continue; }
if index % 2 == 0 {
continue;
}
let partial = Partial {
freq: index as f32,
amp: 1.0 / index as f32,
Expand All @@ -65,9 +72,13 @@ fn make_square_partials(num_partials: usize) -> Vec<Partial> {
partials.clone()
}

// This function combines creating a wavetable from a list of Partials, and
// normalizing the output vector so it's maximum absolute value is 1.0. These
// operations are combined here for computational efficiency.
pub fn make_fourier_table_norm(table_size: usize, partials: Vec<Partial>) -> Wavetable {
let mut wavetable: Vec<f32> = Vec::new();
// Track maximum amplitude while creating wavetable for normalization
// Track maximum amplitude while creating wavetable, since we need to know
// that to be able to normalize the wavetable.
let mut maximum_amplitude = 0.0;
let ts: f32 = 1.0 / table_size as f32;
for i in 0..table_size {
Expand All @@ -76,7 +87,9 @@ pub fn make_fourier_table_norm(table_size: usize, partials: Vec<Partial>) -> Wav
let angle = TWO_PI * partial.freq * i as f32 * ts + partial.phase;
sample += angle.sin() * partial.amp;
}
if sample.abs() > maximum_amplitude { maximum_amplitude = sample.abs(); }
if sample.abs() > maximum_amplitude {
maximum_amplitude = sample.abs();
}
wavetable.push(sample);
}
// Apply normalization to the generated wavetable by multiplying every
Expand All @@ -88,4 +101,3 @@ pub fn make_fourier_table_norm(table_size: usize, partials: Vec<Partial>) -> Wav
// Return the generated wavetable
wavetable.clone()
}

0 comments on commit ef1f111

Please sign in to comment.