Browse Source

Initial work on modular synthesis

Graham Northup 8 năm trước cách đây
commit
85925d69e0
9 tập tin đã thay đổi với 278 bổ sung0 xóa
  1. 3 0
      .gitignore
  2. 6 0
      Cargo.toml
  3. 11 0
      src/lib.rs
  4. 23 0
      src/main.rs
  5. 41 0
      src/synth/math.rs
  6. 155 0
      src/synth/mod.rs
  7. 14 0
      src/synth/param.rs
  8. 24 0
      src/synth/sine.rs
  9. 1 0
      src/types.rs

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+target/
+**/*.rs.bk
+Cargo.lock

+ 6 - 0
Cargo.toml

@@ -0,0 +1,6 @@
+[package]
+name = "synfone"
+version = "0.1.0"
+authors = ["Graham Northup <grissess@nexusg.org>"]
+
+[dependencies]

+ 11 - 0
src/lib.rs

@@ -0,0 +1,11 @@
+pub mod types;
+pub use types::*;
+
+pub mod synth;
+
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn it_works() {
+    }
+}

+ 23 - 0
src/main.rs

@@ -0,0 +1,23 @@
+use std::io;
+use std::io::*;
+
+extern crate synfone;
+use synfone::synth::*;
+
+const FRAMES: usize = 44100 * 2;
+
+fn main() {
+    let mut params = Default::default();
+    
+    let mut freq: GenBox = Box::new(Param { name: "freq".to_string(), default: 440.0, buf: SampleBuffer::new(1) });
+    let mut sg: GenBox = Box::new(Sine { freq: freq, phase: 0.0, buf: SampleBuffer::new(params.env.default_buffer_size) });
+
+    let mut counter = 0;
+    let mut out = io::stderr();
+
+    while counter < FRAMES {
+        let buf = sg.eval(&params);
+        out.write_all(buf.bytes());
+        counter += buf.len();
+    }
+}

+ 41 - 0
src/synth/math.rs

@@ -0,0 +1,41 @@
+use super::*;
+
+pub struct Add {
+    terms: Vec<GenBox>,
+    buf: SampleBuffer,
+}
+
+impl Generator for Add {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        if self.terms.is_empty() {
+            self.buf.zero();
+        } else {
+            let (first, next) = self.terms.split_at_mut(1);
+            self.buf.update_from(first[0].eval(params));
+            for term in next {
+                self.buf.sum_into(term.eval(params));
+            }
+        }
+        &self.buf
+    }
+}
+
+pub struct Mul {
+    factors: Vec<GenBox>,
+    buf: SampleBuffer,
+}
+
+impl Generator for Mul {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        if self.factors.is_empty() {
+            self.buf.zero();
+        } else {
+            let (first, next) = self.factors.split_at_mut(1);
+            self.buf.update_from(first[0].eval(params));
+            for factor in next {
+                self.buf.mul_into(factor.eval(params));
+            }
+        }
+        &self.buf
+    }
+}

+ 155 - 0
src/synth/mod.rs

@@ -0,0 +1,155 @@
+use std::{iter, cmp, slice, mem};
+use std::ops::{Index, IndexMut};
+use std::collections::HashMap;
+use super::*;
+
+#[derive(PartialEq,Eq,Clone,Copy)]
+pub enum Rate {
+    Sample,
+    Control,
+}
+
+pub struct SampleBuffer {
+    pub samples: Vec<Sample>,
+    pub rate: Rate,
+}
+
+pub struct Environment {
+    pub sample_rate: f32,
+    pub default_buffer_size: usize,
+}
+
+impl Default for Environment {
+    fn default() -> Environment {
+        Environment {
+            sample_rate: 44100.0,
+            default_buffer_size: 64,
+        }
+    }
+}
+
+pub struct Parameters {
+    pub env: Environment,
+    pub vars: HashMap<String, f32>,
+}
+
+impl Default for Parameters {
+    fn default() -> Parameters {
+        Parameters {
+            env: Default::default(),
+            vars: HashMap::new(),
+        }
+    }
+}
+
+impl SampleBuffer {
+    pub fn new(sz: usize) -> SampleBuffer {
+        let mut samples = Vec::with_capacity(sz);
+        samples.extend(iter::repeat(0 as Sample).take(sz));
+        SampleBuffer {
+            samples: samples,
+            rate: Rate::Sample,
+        }
+    }
+
+    pub fn len(&self) -> usize {
+        self.samples.len()
+    }
+
+    pub fn first(&self) -> Sample {
+        *self.samples.first().unwrap()
+    }
+
+    pub fn set(&mut self, val: Sample) {
+        self.samples[0] = val;
+        self.rate = Rate::Control;
+    }
+
+    pub fn update_from(&mut self, other: &SampleBuffer) {
+        self.rate = other.rate;
+        match self.rate {
+            Rate::Sample => {
+                for i in 0..cmp::min(self.len(), other.len()) {
+                    self.samples[i] = other.samples[i];
+                }
+            },
+            Rate::Control => {
+                self.samples[0] = other.samples[0];
+            },
+        }
+    }
+
+    pub fn sum_into(&mut self, other: &SampleBuffer) {
+        match self.rate {
+            Rate::Sample => {
+                for i in 0..cmp::min(self.len(), other.len()) {
+                    self.samples[i] += match other.rate {
+                        Rate::Sample => other.samples[i],
+                        Rate::Control => other.samples[0],
+                    };
+                }
+            },
+            Rate::Control => {
+                self.samples[0] += other.samples[0];
+            },
+        }
+    }
+
+    pub fn mul_into(&mut self, other: &SampleBuffer) {
+        match self.rate {
+            Rate::Sample => {
+                for i in 0..cmp::min(self.len(), other.len()) {
+                    self.samples[i] *= match other.rate {
+                        Rate::Sample => other.samples[i],
+                        Rate::Control => other.samples[0],
+                    };
+                }
+            },
+            Rate::Control => {
+                self.samples[0] *= other.samples[0];
+            },
+        }
+    }
+
+    pub fn zero(&mut self) {
+        for i in 0..self.len() {
+            self.samples[i] = 0.0;
+        }
+    }
+
+    pub fn bytes<'a>(&'a self) -> &'a [u8] {
+        unsafe {
+            slice::from_raw_parts(
+                self.samples.as_ptr() as *const u8,
+                self.samples.len() * mem::size_of::<Sample>(),
+            )
+        }
+    }
+}
+
+impl Index<usize> for SampleBuffer {
+    type Output = Sample;
+    fn index(&self, idx: usize) -> &Sample { &self.samples[idx] }
+}
+
+impl IndexMut<usize> for SampleBuffer {
+    fn index_mut(&mut self, idx: usize) -> &mut Sample { &mut self.samples[idx] }
+}
+
+pub trait Generator {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer;
+}
+
+pub type GenBox = Box<Generator>;
+
+pub mod param;
+pub use self::param::Param;
+pub mod math;
+pub use self::math::{Add, Mul};
+pub mod sine;
+pub use self::sine::Sine;
+//pub mod saw;
+//pub use saw::Saw;
+//pub mod triangle;
+//pub use triangle::Triangle;
+

+ 14 - 0
src/synth/param.rs

@@ -0,0 +1,14 @@
+use super::*;
+
+pub struct Param {
+    name: String,
+    default: Sample,
+    buf: SampleBuffer,
+}
+
+impl Generator for Param {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        self.buf.set(*params.vars.get(&self.name).unwrap_or(&self.default));
+        &self.buf
+    }
+}

+ 24 - 0
src/synth/sine.rs

@@ -0,0 +1,24 @@
+use std::f32::consts::PI;
+use super::*;
+
+const TAU: f32 = 2f32 * PI;
+
+pub struct Sine {
+    freq: GenBox,
+    phase: f32,
+    buf: SampleBuffer,
+}
+
+impl Generator for Sine {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        self.buf.rate = Rate::Control;
+
+        let pvel = TAU * self.freq.eval(params).first() / params.env.sample_rate;
+        for i in 0..self.buf.len() {
+            self.buf[i] = (self.phase + pvel * (i as f32)).sin()
+        }
+
+        self.phase = (self.phase + pvel * (self.buf.len() as f32)) % TAU;
+        &self.buf
+    }
+}

+ 1 - 0
src/types.rs

@@ -0,0 +1 @@
+pub type Sample = f32;