ソースを参照

Starting work on proto decode

Graham Northup 8 年 前
コミット
9866c0f34c
12 ファイル変更244 行追加20 行削除
  1. 1 0
      Cargo.toml
  2. 5 0
      src/lib.rs
  3. 19 3
      src/main.rs
  4. 58 0
      src/proto.rs
  5. 9 0
      src/synth/math.rs
  6. 32 16
      src/synth/mod.rs
  7. 4 0
      src/synth/param.rs
  8. 25 0
      src/synth/saw.rs
  9. 5 1
      src/synth/sine.rs
  10. 29 0
      src/synth/square.rs
  11. 32 0
      src/synth/triangle.rs
  12. 25 0
      src/types.rs

+ 1 - 0
Cargo.toml

@@ -4,3 +4,4 @@ version = "0.1.0"
 authors = ["Graham Northup <grissess@nexusg.org>"]
 
 [dependencies]
+byteorder = "1.1.0"

+ 5 - 0
src/lib.rs

@@ -1,7 +1,12 @@
+#![feature(associated_consts)]
+
+extern crate byteorder;
+
 pub mod types;
 pub use types::*;
 
 pub mod synth;
+pub mod proto;
 
 #[cfg(test)]
 mod tests {

+ 19 - 3
src/main.rs

@@ -10,17 +10,33 @@ fn main() {
     let mut params = Parameters::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 sg: GenBox = Box::new(Saw { freq: freq, phase: 0.0, buf: SampleBuffer::new(params.env.default_buffer_size) });
+
+    let mut freq2: GenBox = Box::new(Param { name: "freq2".to_string(), default: 660.0, buf: SampleBuffer::new(1) });
+    let mut sg2: GenBox = Box::new(Sine { freq: freq2, phase: 0.0, buf: SampleBuffer::new(params.env.default_buffer_size) });
+
+    let mut half1: GenBox = Box::new(Param { name: "half".to_string(), default: 1.0, buf: SampleBuffer::new(1) });
+    let mut half2: GenBox = Box::new(Param { name: "half".to_string(), default: 0.0, buf: SampleBuffer::new(1) });
+    let mut sc1: GenBox = Box::new(Mul { factors: vec![sg, half1], buf: SampleBuffer::new(params.env.default_buffer_size) });
+    let mut sc2: GenBox = Box::new(Mul { factors: vec![sg2, half2], buf: SampleBuffer::new(params.env.default_buffer_size) });
+    let mut gen: GenBox = Box::new(Add { terms: vec![sc1, sc2], buf: SampleBuffer::new(params.env.default_buffer_size) });
 
     let mut counter = 0;
     let mut out = io::stdout();
+    let mut outbuf: Vec<u8> = Vec::new();
     
     params.vars.insert("freq".to_string(), 440.0);
+    params.vars.insert("freq2".to_string(), 660.0);
 
     while counter < FRAMES {
         *params.vars.get_mut("freq").unwrap() = 440.0 + 440.0 * ((counter as f32) / (FRAMES as f32));
-        let buf = sg.eval(&params);
-        out.write_all(buf.bytes());
+        *params.vars.get_mut("freq2").unwrap() = 660.0 + 220.0 * ((counter as f32) / (FRAMES as f32));
+        let buf = gen.eval(&params);
+        let curlen = outbuf.len();
+        outbuf.reserve_exact(buf.size() - curlen);
+        unsafe { outbuf.set_len(buf.size()); }
+        buf.bytes(&mut outbuf);
+        out.write_all(&outbuf);
         counter += buf.len();
     }
 }

+ 58 - 0
src/proto.rs

@@ -0,0 +1,58 @@
+use std::mem;
+use std::time::Duration;
+use super::*;
+
+use ::byteorder::{ByteOrder, NetworkEndian};
+
+const OBLIGATE_POLYPHONE: u32 = 0xffffffff;
+
+pub enum Command {
+    KeepAlive,
+    Ping{data: [u8; 32]},
+    Quit,
+    Play{sec: u32, usec: u32, freq: u32, amp: f32, voice: u32},
+    Caps{voices: u32, tp: [u8; 4], ident: [u8; 24]},
+    PCM{samples: [i16; 16]},
+    Unknown{data: [u8; 36]},
+}
+
+impl Command {
+    const SIZE: usize = 36;
+
+    fn duration(&self) -> Option<Duration> {
+        match *self {
+            Command::Play{sec, usec, ..} => Some(Duration::new(sec as u64, usec * 1000)),
+            _ => None,
+        }
+    }
+
+    fn pitch(&self) -> Option<Pitch> {
+        match *self {
+            Command::Play{freq, ..} => Some(Pitch::Freq(freq as f32)),
+            _ => None,
+        }
+    }
+}
+
+impl<'a> From<&'a [u8; 36]> for Command {
+    fn from(packet: &'a [u8; 36]) -> Command {
+        let mut fields_u32: [u32; 9] = unsafe { mem::uninitialized() };
+        let mut fields_f32: [f32; 9] = unsafe { mem::uninitialized() };
+        NetworkEndian::read_u32_into(packet, &mut fields_u32);
+        unsafe { NetworkEndian::read_f32_into_unchecked(packet, &mut fields_f32); }
+
+        match fields_u32[0] {
+            0 => Command::KeepAlive,
+            1 => {
+                let mut data: [u8; 32] = unsafe { mem::uninitialized() };
+                data.copy_from_slice(&packet[4..]);
+                Command::Ping{data: data}
+            }
+            _ => {
+                let mut data: [u8; 36] = unsafe { mem::uninitialized() };
+                data.copy_from_slice(packet);
+                Command::Unknown{data: data}
+            }
+        }
+    }
+}

+ 9 - 0
src/synth/math.rs

@@ -1,5 +1,7 @@
 use super::*;
+use std::mem;
 
+#[derive(Debug)]
 pub struct Add {
     pub terms: Vec<GenBox>,
     pub buf: SampleBuffer,
@@ -18,8 +20,12 @@ impl Generator for Add {
         }
         &self.buf
     }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
 }
 
+#[derive(Debug)]
 pub struct Mul {
     pub factors: Vec<GenBox>,
     pub buf: SampleBuffer,
@@ -38,4 +44,7 @@ impl Generator for Mul {
         }
         &self.buf
     }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
 }

+ 32 - 16
src/synth/mod.rs

@@ -1,14 +1,18 @@
 use std::{iter, cmp, slice, mem};
+use std::fmt::Debug;
 use std::ops::{Index, IndexMut};
 use std::collections::HashMap;
 use super::*;
 
-#[derive(PartialEq,Eq,Clone,Copy)]
+use ::byteorder::ByteOrder;
+
+#[derive(PartialEq,Eq,Clone,Copy,Debug)]
 pub enum Rate {
     Sample,
     Control,
 }
 
+#[derive(Debug)]
 pub struct SampleBuffer {
     pub samples: Vec<Sample>,
     pub rate: Rate,
@@ -82,7 +86,11 @@ impl SampleBuffer {
     pub fn sum_into(&mut self, other: &SampleBuffer) {
         match self.rate {
             Rate::Sample => {
-                for i in 0..cmp::min(self.len(), other.len()) {
+                let bound = match other.rate {
+                    Rate::Sample => cmp::min(self.len(), other.len()),
+                    Rate::Control => self.len(),
+                };
+                for i in 0..bound {
                     self.samples[i] += match other.rate {
                         Rate::Sample => other.samples[i],
                         Rate::Control => other.samples[0],
@@ -98,7 +106,11 @@ impl SampleBuffer {
     pub fn mul_into(&mut self, other: &SampleBuffer) {
         match self.rate {
             Rate::Sample => {
-                for i in 0..cmp::min(self.len(), other.len()) {
+                let bound = match other.rate {
+                    Rate::Sample => cmp::min(self.len(), other.len()),
+                    Rate::Control => self.len(),
+                };
+                for i in 0..bound {
                     self.samples[i] *= match other.rate {
                         Rate::Sample => other.samples[i],
                         Rate::Control => other.samples[0],
@@ -117,13 +129,13 @@ impl SampleBuffer {
         }
     }
 
-    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>(),
-            )
-        }
+    pub fn size(&self) -> usize {
+        mem::size_of::<Sample>() * self.samples.len()
+    }
+
+    pub fn bytes(&self, buf: &mut [u8]) {
+        // FIXME: Depends on f32 instead of Sample alias
+        ::byteorder::LittleEndian::write_f32_into(&self.samples, buf);
     }
 }
 
@@ -136,8 +148,9 @@ impl IndexMut<usize> for SampleBuffer {
     fn index_mut(&mut self, idx: usize) -> &mut Sample { &mut self.samples[idx] }
 }
 
-pub trait Generator {
+pub trait Generator : Debug {
     fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer;
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer;
 }
 
 pub type GenBox = Box<Generator>;
@@ -148,8 +161,11 @@ 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;
-
+pub mod saw;
+pub use self::saw::Saw;
+pub mod triangle;
+pub use self::triangle::Triangle;
+pub mod square;
+pub use self::square::Square;
+//pub mod asdr;
+//pub use self::asdr::ASDR;

+ 4 - 0
src/synth/param.rs

@@ -1,5 +1,6 @@
 use super::*;
 
+#[derive(Debug)]
 pub struct Param {
     pub name: String,
     pub default: Sample,
@@ -11,4 +12,7 @@ impl Generator for Param {
         self.buf.set(*params.vars.get(&self.name).unwrap_or(&self.default));
         &self.buf
     }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
 }

+ 25 - 0
src/synth/saw.rs

@@ -0,0 +1,25 @@
+use super::*;
+
+#[derive(Debug)]
+pub struct Saw {
+    pub freq: GenBox,
+    pub phase: f32,
+    pub buf: SampleBuffer,
+}
+
+impl Generator for Saw {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        self.buf.rate = Rate::Sample;
+
+        let pvel = self.freq.eval(params).first() / params.env.sample_rate;
+        for i in 0..self.buf.len() {
+            self.buf[i] = 2.0 * ((self.phase + pvel * (i as f32)) % 1.0) - 1.0;
+        }
+
+        self.phase = (self.phase + pvel * (self.buf.len() as f32)) % 1.0;
+        &self.buf
+    }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
+}

+ 5 - 1
src/synth/sine.rs

@@ -3,6 +3,7 @@ use super::*;
 
 const TAU: f32 = 2f32 * PI;
 
+#[derive(Debug)]
 pub struct Sine {
     pub freq: GenBox,
     pub phase: f32,
@@ -11,7 +12,7 @@ pub struct Sine {
 
 impl Generator for Sine {
     fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
-        self.buf.rate = Rate::Control;
+        self.buf.rate = Rate::Sample;
 
         let pvel = TAU * self.freq.eval(params).first() / params.env.sample_rate;
         for i in 0..self.buf.len() {
@@ -21,4 +22,7 @@ impl Generator for Sine {
         self.phase = (self.phase + pvel * (self.buf.len() as f32)) % TAU;
         &self.buf
     }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
 }

+ 29 - 0
src/synth/square.rs

@@ -0,0 +1,29 @@
+use super::*;
+
+#[derive(Debug)]
+pub struct Square {
+    pub freq: GenBox,
+    pub phase: f32,
+    pub buf: SampleBuffer,
+}
+
+impl Generator for Square {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        self.buf.rate = Rate::Sample;
+
+        let pvel = self.freq.eval(params).first() / params.env.sample_rate;
+        for i in 0..self.buf.len() {
+            self.buf[i] = if ((self.phase + pvel * (i as f32)) % 1.0) < 0.5 {
+                -1.0
+            } else {
+                1.0
+            };
+        }
+
+        self.phase = (self.phase + pvel * (self.buf.len() as f32)) % 1.0;
+        &self.buf
+    }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
+}

+ 32 - 0
src/synth/triangle.rs

@@ -0,0 +1,32 @@
+use super::*;
+
+#[derive(Debug)]
+pub struct Triangle {
+    pub freq: GenBox,
+    pub phase: f32,
+    pub buf: SampleBuffer,
+}
+
+impl Generator for Triangle {
+    fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer {
+        self.buf.rate = Rate::Sample;
+
+        let pvel = self.freq.eval(params).first() / params.env.sample_rate;
+        for i in 0..self.buf.len() {
+            let ph = (self.phase + pvel * (i as f32)) % 1.0;
+            self.buf[i] = if ph < 0.25 {
+                4.0 * ph
+            } else if ph > 0.75 {
+                4.0 * ph - 4.0
+            } else {
+                -4.0 * ph + 2.0
+            };
+        }
+
+        self.phase = (self.phase + pvel * (self.buf.len() as f32)) % 1.0;
+        &self.buf
+    }
+    fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer {
+        mem::replace(&mut self.buf, buf)
+    }
+}

+ 25 - 0
src/types.rs

@@ -1 +1,26 @@
 pub type Sample = f32;
+
+pub enum Pitch {
+    Freq(f32),
+    MIDI(f32),
+}
+
+impl Pitch {
+    pub fn to_midi(&self) -> f32 {
+        match *self {
+            Pitch::MIDI(x) => x,
+            Pitch::Freq(x) => 
+                12.0 * (x / 440.0).log2() + 69.0,
+        }
+    }
+    pub fn to_midi_pitch(&self) -> Pitch { Pitch::MIDI(self.to_midi()) }
+
+    pub fn to_freq(&self) -> f32 {
+        match *self {
+            Pitch::MIDI(x) =>
+                440.0 * (2.0f32).powf((x - 69.0) / 12.0),
+            Pitch::Freq(x) => x,
+        }
+    }
+    pub fn to_freq_pitch(&self) -> Pitch { Pitch::Freq(self.to_freq()) }
+}