diff options
author | Graham Northup <grissess@nexusg.org> | 2017-09-19 23:56:15 -0400 |
---|---|---|
committer | Graham Northup <grissess@nexusg.org> | 2017-09-19 23:56:15 -0400 |
commit | 9866c0f34c268a09ecaaa9a4361c1c267799358e (patch) | |
tree | d10bea3717c25105ced7457535412072d343686f | |
parent | 26e95364ad9073dd7cb571454cd52ae66f320a73 (diff) |
Starting work on proto decode
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/lib.rs | 5 | ||||
-rw-r--r-- | src/main.rs | 22 | ||||
-rw-r--r-- | src/proto.rs | 58 | ||||
-rw-r--r-- | src/synth/math.rs | 9 | ||||
-rw-r--r-- | src/synth/mod.rs | 48 | ||||
-rw-r--r-- | src/synth/param.rs | 4 | ||||
-rw-r--r-- | src/synth/saw.rs | 25 | ||||
-rw-r--r-- | src/synth/sine.rs | 6 | ||||
-rw-r--r-- | src/synth/square.rs | 29 | ||||
-rw-r--r-- | src/synth/triangle.rs | 32 | ||||
-rw-r--r-- | src/types.rs | 25 |
12 files changed, 244 insertions, 20 deletions
@@ -4,3 +4,4 @@ version = "0.1.0" authors = ["Graham Northup <grissess@nexusg.org>"] [dependencies] +byteorder = "1.1.0" @@ -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 { diff --git a/src/main.rs b/src/main.rs index 711463b..05538e9 100644 --- a/src/main.rs +++ b/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(¶ms); - 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(¶ms); + 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(); } } diff --git a/src/proto.rs b/src/proto.rs new file mode 100644 index 0000000..06d7b49 --- /dev/null +++ b/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} + } + } + } +} diff --git a/src/synth/math.rs b/src/synth/math.rs index 66a86a0..91e58e3 100644 --- a/src/synth/math.rs +++ b/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) + } } diff --git a/src/synth/mod.rs b/src/synth/mod.rs index d0c837a..bf73200 100644 --- a/src/synth/mod.rs +++ b/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; diff --git a/src/synth/param.rs b/src/synth/param.rs index ced5900..f679b56 100644 --- a/src/synth/param.rs +++ b/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) + } } diff --git a/src/synth/saw.rs b/src/synth/saw.rs new file mode 100644 index 0000000..bfd3cb0 --- /dev/null +++ b/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) + } +} diff --git a/src/synth/sine.rs b/src/synth/sine.rs index 212ab21..90f3200 100644 --- a/src/synth/sine.rs +++ b/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) + } } diff --git a/src/synth/square.rs b/src/synth/square.rs new file mode 100644 index 0000000..8197110 --- /dev/null +++ b/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) + } +} diff --git a/src/synth/triangle.rs b/src/synth/triangle.rs new file mode 100644 index 0000000..c8380a1 --- /dev/null +++ b/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) + } +} diff --git a/src/types.rs b/src/types.rs index b9ff15f..dd450bb 100644 --- a/src/types.rs +++ b/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()) } +} |