diff options
author | Graham Northup <grissess@nexusg.org> | 2017-10-13 12:54:04 -0400 |
---|---|---|
committer | Graham Northup <grissess@nexusg.org> | 2017-10-13 12:54:04 -0400 |
commit | 22cb7d7cbcacbfe3a7d3a2d454e6b8cf49ae989c (patch) | |
tree | 4d2d8cb2ce9c4441ce5cc525375665c44c31f9fb | |
parent | 255f0aa6de604e0bf9d37ba0ee5362ef3b9f235f (diff) |
Added LUTs and ControlRate; improved parser
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | gens/test.gen | 31 | ||||
-rw-r--r-- | gens/test_basic.gen | 1 | ||||
-rw-r--r-- | gens/test_lut.gen | 1 | ||||
-rw-r--r-- | gens/test_voice.gen | 2 | ||||
-rw-r--r-- | src/lang/parser.rs | 226 | ||||
-rw-r--r-- | src/lang/tokenizer.rs | 5 | ||||
-rw-r--r-- | src/main.rs | 11 | ||||
-rw-r--r-- | src/proto.rs | 16 | ||||
-rw-r--r-- | src/synth/adsr.rs | 122 | ||||
-rw-r--r-- | src/synth/lut.rs | 84 | ||||
-rw-r--r-- | src/synth/mod.rs | 49 | ||||
-rw-r--r-- | src/synth/param.rs | 2 | ||||
-rw-r--r-- | src/synth/rel.rs | 13 | ||||
-rw-r--r-- | src/synth/saw.rs | 2 | ||||
-rw-r--r-- | src/synth/sine.rs | 2 | ||||
-rw-r--r-- | src/synth/square.rs | 2 | ||||
-rw-r--r-- | src/synth/triangle.rs | 2 | ||||
-rw-r--r-- | src/synth/util.rs | 60 |
19 files changed, 544 insertions, 91 deletions
@@ -3,6 +3,10 @@ name = "synfone" version = "0.1.0" authors = ["Graham Northup <grissess@nexusg.org>"] +[[bin]] +name = "synfone" +doc = false + [features] default = ['graphics'] diff --git a/gens/test.gen b/gens/test.gen index be43356..4613c0c 100644 --- a/gens/test.gen +++ b/gens/test.gen @@ -1,12 +1,23 @@ [ - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen#, - #gens/test_voice.gen# + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen#, + #gens/test_basic.gen# ] diff --git a/gens/test_basic.gen b/gens/test_basic.gen new file mode 100644 index 0000000..cbbfbbc --- /dev/null +++ b/gens/test_basic.gen @@ -0,0 +1 @@ +lutgen(sine(lut_freq), 128, v_freq) * ifelse(v_frame < v_deadline, v_amp, 0) diff --git a/gens/test_lut.gen b/gens/test_lut.gen new file mode 100644 index 0000000..d9fc9fe --- /dev/null +++ b/gens/test_lut.gen @@ -0,0 +1 @@ +lutgen(sine(lut_freq), 256, 440) diff --git a/gens/test_voice.gen b/gens/test_voice.gen index 855568b..41684c1 100644 --- a/gens/test_voice.gen +++ b/gens/test_voice.gen @@ -1 +1 @@ -mul(sine(param('v_freq', 500)), ifelse(rel(param('v_frame'), '<', param('v_deadline')), mul(param('v_amp'), add(param('v_frame'), negate(param('v_start'))), reciprocate(add(param('v_deadline'), negate(param('v_start'))))), 0.0)) +(lutgen(sine(lut_freq), 128, v_freq) * controlrate(dahdsr(v_frame < v_deadline, 0, 4 / samplerate(), 0, 1, 1, 8 / samplerate()))) * v_amp diff --git a/src/lang/parser.rs b/src/lang/parser.rs index c49cf65..35df372 100644 --- a/src/lang/parser.rs +++ b/src/lang/parser.rs @@ -7,6 +7,7 @@ use synth::*; #[derive(Debug)] pub enum ErrorKind { Unexpected(TokType, TokType), + Unparseable(TokType, String), ExpectedOp(char, TokType), UnknownGen(String), } @@ -26,6 +27,7 @@ impl ErrorType { ret.desc = match ret.kind { ErrorKind::Unexpected(found, expected) => format!("Found {:?}, expected {:?}", found, expected), + ErrorKind::Unparseable(found, ref term) => format!("Cannot consume {:?} token in {}", found, term), ErrorKind::ExpectedOp(c, found) => format!("Expected {:?}, found {:?}", c, found), ErrorKind::UnknownGen(ref s) => format!("Unknown generator name {}", s), }; @@ -76,20 +78,27 @@ impl<T: Iterator<Item=char>> Parser<T> { pub fn push_back(&mut self, tok: Token) { match self.pushback { None => { - self.pushback = Some(mem::replace(&mut self.token, tok)); + self.pushback = Some(tok); }, Some(_) => panic!("too many pushbacks on Parser"), } } + pub fn cur_token(&self) -> &Token { + match self.pushback { + Some(ref tok) => tok, + None => &self.token, + } + } + pub fn expect(&mut self, ty: TokType) -> Result<Token, Box<Error>> { - if ty == self.token.to_type() { - Ok(mem::replace(&mut self.token, match self.pushback { - Some(_) => mem::replace(&mut self.pushback, None).unwrap(), - None => self.tzr.next_token()?, - })) - } else { + if ty != self.cur_token().to_type() { Err(ErrorType::new(ErrorKind::Unexpected(self.token.to_type(), ty)).into()) + } else { + Ok(match self.pushback { + Some(_) => mem::replace(&mut self.pushback, None).unwrap(), + None => mem::replace(&mut self.token, self.tzr.next_token()?), + }) } } @@ -101,9 +110,18 @@ impl<T: Iterator<Item=char>> Parser<T> { } pub fn expect_op(&mut self, oper: char) -> Result<(), Box<Error>> { - match self.token { + eprintln!("expect_op: {:?} ({})", self.cur_token(), oper); + match *self.cur_token() { Token::Oper(c) if c == oper => { self.expect(TokType::Oper)?; Ok(()) }, - _ => Err(ErrorType::new(ErrorKind::ExpectedOp(oper, self.token.to_type())).into()), + _ => Err(ErrorType::new(ErrorKind::ExpectedOp(oper, self.cur_token().to_type())).into()), + } + } + + pub fn peek_op(&self, oper: char) -> bool { + eprintln!("peek_op: {:?} ({})", self.cur_token(), oper); + match *self.cur_token() { + Token::Oper(c) if c == oper => true, + _ => false } } @@ -117,17 +135,7 @@ impl<T: Iterator<Item=char>> Parser<T> { break; } - /* TODO: Can't yet clone a GenBox safely - let repeat = match self.token { - Token::Integer(v) => { - self.expect_op('*')?; - v - }, - _ => 1, - }; - */ - - ret.push(self.parse_gen()?); + ret.push(self.parse_gen_rel()?); if self.expect_op(',').is_err() { self.expect_op(']')?; @@ -138,17 +146,150 @@ impl<T: Iterator<Item=char>> Parser<T> { Ok(ret) } - pub fn parse_gen(&mut self) -> Result<GenBox, Box<Error>> { - let name = self.expect_ident()?; - let mut params = self.parse_factory_params()?; - let factory = match self.factories.get(&name) { - Some(fac) => fac, - None => return Err(ErrorType::new(ErrorKind::UnknownGen(name)).into()), - }; + pub fn parse_gen_rel(&mut self) -> Result<GenBox, Box<Error>> { + let left = self.parse_gen_terms()?; + + match *self.cur_token() { + Token::Oper(c) => { + if c == '>' || c == '!' || c == '<' || c == '=' { // TODO: Conflict with param name + self.expect(TokType::Oper)?; + let relop = match (c, self.cur_token()) { + ('<', &Token::Oper('=')) => { self.expect(TokType::Oper)?; RelOp::LessEqual }, + ('=', &Token::Oper('=')) => { self.expect(TokType::Oper)?; RelOp::Equal }, + ('>', &Token::Oper('=')) => { self.expect(TokType::Oper)?; RelOp::Greater }, + ('!', &Token::Oper('=')) => { self.expect(TokType::Oper)?; RelOp::NotEqual }, + ('<', _) => RelOp::Less, + ('>', _) => RelOp::Greater, + _ => return Err(ErrorType::new(ErrorKind::Unparseable(TokType::Oper, "rel expr".to_string())).into()), + }; + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::Generator(left)); + params.vars.insert("1".to_string(), ParamValue::String(relop.to_param_string().to_string())); + params.vars.insert("2".to_string(), ParamValue::Generator(self.parse_gen_rel()?)); + let factory = self.factories.get("rel").ok_or(ErrorType::new(ErrorKind::UnknownGen("rel".to_string())))?; + factory.new(&mut params).map_err(Into::into) + } else { + Ok(left) + } + }, + _ => Ok(left), + } + } + + pub fn parse_gen_terms(&mut self) -> Result<GenBox, Box<Error>> { + let mut gens: Vec<GenBox> = Vec::new(); + gens.push(self.parse_gen_factors()?); + + loop { + match *self.cur_token() { + Token::Oper('+') => { + self.expect_op('+')?; + gens.push(self.parse_gen_factors()?); + }, + Token::Oper('-') => { + self.expect_op('-')?; + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::Generator(self.parse_gen_factors()?)); + let factory = self.factories.get("negate").ok_or(ErrorType::new(ErrorKind::UnknownGen("negate".to_string())))?; + gens.push(factory.new(&mut params).map_err(GenFactoryErrorType::from)?); + }, + _ => break, + } + } + + if gens.len() == 1 { + return Ok(gens.pop().unwrap()); + } + + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + for (idx, gen) in gens.into_iter().enumerate() { + params.vars.insert(idx.to_string(), ParamValue::Generator(gen)); + } + let factory = self.factories.get("add").ok_or(ErrorType::new(ErrorKind::UnknownGen("add".to_string())))?; + factory.new(&mut params).map_err(Into::into) + } + + pub fn parse_gen_factors(&mut self) -> Result<GenBox, Box<Error>> { + let mut gens: Vec<GenBox> = Vec::new(); + gens.push(self.parse_gen()?); + + loop { + match *self.cur_token() { + Token::Oper('*') => { + self.expect_op('*')?; + gens.push(self.parse_gen()?); + }, + Token::Oper('/') => { + self.expect_op('/')?; + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::Generator(self.parse_gen()?)); + let factory = self.factories.get("reciprocate").ok_or(ErrorType::new(ErrorKind::UnknownGen("reciprocate".to_string())))?; + gens.push(factory.new(&mut params).map_err(GenFactoryErrorType::from)?); + }, + _ => break, + } + } + + if gens.len() == 1 { + return Ok(gens.pop().unwrap()); + } + + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + for (idx, gen) in gens.into_iter().enumerate() { + params.vars.insert(idx.to_string(), ParamValue::Generator(gen)); + } + let factory = self.factories.get("mul").ok_or(ErrorType::new(ErrorKind::UnknownGen("mul".to_string())))?; factory.new(&mut params).map_err(Into::into) } + pub fn parse_gen(&mut self) -> Result<GenBox, Box<Error>> { + match *self.cur_token() { + Token::Integer(v) => { + self.expect(TokType::Integer)?; + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::String("_".to_string())); + params.vars.insert("1".to_string(), ParamValue::Integer(v)); + let factory = self.factories.get("param").ok_or(ErrorType::new(ErrorKind::UnknownGen("param".to_string())))?; + factory.new(&mut params).map_err(Into::into) + }, + Token::Float(v) => { + self.expect(TokType::Float)?; + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::String("_".to_string())); + params.vars.insert("1".to_string(), ParamValue::Float(v)); + let factory = self.factories.get("param").ok_or(ErrorType::new(ErrorKind::UnknownGen("param".to_string())))?; + factory.new(&mut params).map_err(Into::into) + }, + Token::Ident(_) => { + let name = self.expect_ident()?; + if self.peek_op('(') { + let mut params = self.parse_factory_params()?; + let factory = match self.factories.get(&name) { + Some(fac) => fac, + None => return Err(ErrorType::new(ErrorKind::UnknownGen(name)).into()), + }; + factory.new(&mut params).map_err(Into::into) + } else { + let mut params = FactoryParameters { env: self.env.clone(), ..Default::default() }; + params.vars.insert("0".to_string(), ParamValue::String(name)); + let factory = self.factories.get("param").ok_or(ErrorType::new(ErrorKind::UnknownGen("param".to_string())))?; + factory.new(&mut params).map_err(Into::into) + } + }, + Token::Oper('(') => { + eprintln!("consuming paren in parse_gen"); + self.expect(TokType::Oper)?; + let ret = self.parse_gen_rel()?; + eprintln!("parenthesized generator is concluding"); + self.expect_op(')')?; + Ok(ret) + }, + _ => Err(ErrorType::new(ErrorKind::Unparseable(self.cur_token().to_type(), "gen".to_string())).into()), + } + } + pub fn parse_factory_params(&mut self) -> Result<FactoryParameters, Box<Error>> { + eprintln!("consuming paren in factory_params"); self.expect_op('(')?; let mut params: FactoryParameters = FactoryParameters { env: self.env.clone(), ..Default::default() }; @@ -161,7 +302,9 @@ impl<T: Iterator<Item=char>> Parser<T> { params.vars.insert(nm, vl); ctr = new_ctr; - if self.expect_op(',').is_err() { + eprintln!("before factory_params comma, tok is {:?}", self.cur_token()); + if self.expect_op(',').map_err(|e| eprintln!("factory_params consume comma failed: {:?}", e)).is_err() { + eprintln!("factory_params is concluding"); self.expect_op(')')?; break; } @@ -177,14 +320,9 @@ impl<T: Iterator<Item=char>> Parser<T> { if self.expect_op('=').is_ok() { nm } else { - match self.token { - Token::Oper(c) if c == '(' => { - self.push_back(Token::Ident(nm)); - ctr += 1; - (ctr - 1).to_string() - }, - _ => return Err(ErrorType::new(ErrorKind::Unexpected(self.token.to_type(), TokType::Ident)).into()), - } + self.push_back(Token::Ident(nm)); + ctr += 1; + (ctr - 1).to_string() } }, Err(_) => { @@ -193,16 +331,12 @@ impl<T: Iterator<Item=char>> Parser<T> { }, }; - let ret = match self.token { - Token::Integer(v) => Ok((name, ParamValue::Integer(v), ctr)), - Token::Float(v) => Ok((name, ParamValue::Float(v), ctr)), - Token::String(ref v) => Ok((name, ParamValue::String(v.clone()), ctr)), - Token::Ident(_) => return Ok((name, ParamValue::Generator(self.parse_gen()?), ctr)), - _ => return Err(ErrorType::new(ErrorKind::Unexpected(self.token.to_type(), TokType::Ident)).into()), - }; + eprintln!("about to consume param value, token is {:?}", self.cur_token()); - let tp = self.token.to_type(); - self.expect(tp)?; - ret + match self.cur_token().clone() { // FIXME: Does this really need to be cloned? + Token::String(ref v) => { self.expect(TokType::String)?; Ok((name, ParamValue::String(v.clone()), ctr)) }, + Token::Integer(_) | Token::Float(_) | Token::Ident(_) | Token::Oper('(') => Ok((name, ParamValue::Generator(self.parse_gen_rel()?), ctr)), + _ => Err(ErrorType::new(ErrorKind::Unparseable(self.cur_token().to_type(), "param value".to_string())).into()), + } } } diff --git a/src/lang/tokenizer.rs b/src/lang/tokenizer.rs index 1d62f3e..6de825b 100644 --- a/src/lang/tokenizer.rs +++ b/src/lang/tokenizer.rs @@ -425,9 +425,12 @@ impl<T: Iterator<Item=char>> Tokenizer<T> { floating = true; buffer.push(cc); buffer.push(ncc); - } else { + } else if ncc.is_digit(10) { buffer.push(cc); buffer.push(ncc); + } else { + self.push_back(ncc); + return Ok(Token::Integer(0)); } } else { buffer.push(cc); diff --git a/src/main.rs b/src/main.rs index ad121e7..6aacda1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,8 @@ use synfone::lang::*; use synfone::proto::*; use synfone::client::*; +const GFX: bool = false; + fn main() { let env = Environment::default(); @@ -72,7 +74,7 @@ fn main() { eprintln!("Audio stream started."); - { + let net_thread = { let client = client.clone(); let net_thread = thread::spawn(move || { let mut buffer: [u8; Command::SIZE] = [0u8; Command::SIZE]; @@ -91,13 +93,14 @@ fn main() { } } }); - } + net_thread + }; eprintln!("Network thread started."); //net_thread.join().expect("Network thread panicked"); - { + if GFX { let last_buffer = last_buffer.clone(); let mut events_loop = glutin::EventsLoop::new(); @@ -348,6 +351,8 @@ fn main() { //display.swap_buffers().expect("Failed to swap buffers"); } + } else { + net_thread.join().expect("Network thread panicked"); } eprintln!("Exiting."); diff --git a/src/proto.rs b/src/proto.rs index 630e3e8..279cd3f 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -71,15 +71,15 @@ impl Command { impl fmt::Debug for Command { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!(f, "Command::")?; + f.write_str("Command::")?; match *self { - Command::KeepAlive => write!(f, "KeepAlive"), - Command::Ping{data} => write!(f, "Ping {{ data: {:?} }}", &data), - Command::Quit => write!(f, "Quit"), - Command::Play{sec, usec, freq, amp, voice} => write!(f, "Play {{ sec: {:?}, usec: {:?}, freq: {:?}, amp: {:?}, voice: {:?} }}", sec, usec, freq, amp, voice), - Command::Caps{voices, tp, ident} => write!(f, "Caps {{ voices: {:?}, tp: {:?}, ident: {:?} }}", voices, &tp, &ident), - Command::PCM{samples} => write!(f, "PCM {{ samples: {:?} }}", &samples), - Command::Unknown{data} => write!(f, "Unknown {{ data: {:?} }}", &data as &[u8]), + Command::KeepAlive => f.write_str("KeepAlive"), + Command::Ping{data} => f.debug_struct("Ping").field("data", &data).finish(), + Command::Quit => f.write_str("Quit"), + Command::Play{sec, usec, freq, amp, voice} => f.debug_struct("Play").field("sec", &sec).field("usec", &usec).field("freq", &freq).field("amp", &).field("voice", &voice).finish(), + Command::Caps{voices, tp, ident} => f.debug_struct("Caps").field("voices", &voices).field("tp", &tp).field("ident", &ident).finish(), + Command::PCM{samples} => f.debug_struct("PCM").field("samples", &samples).finish(), + Command::Unknown{data} => f.debug_struct("Unknown").field("data", &(&data as &[u8])).finish(), } } } diff --git a/src/synth/adsr.rs b/src/synth/adsr.rs new file mode 100644 index 0000000..ca7be9c --- /dev/null +++ b/src/synth/adsr.rs @@ -0,0 +1,122 @@ +use super::*; + +#[derive(Debug,Clone,Copy,PartialEq,Eq)] +pub enum Phase { + Delay, + Attack, + Hold, + Decay, + Sustain, + Release, +} + +#[derive(Debug)] +pub struct DAHDSR { + pub delay: GenBox, + pub attack: GenBox, + pub hold: GenBox, + pub decay: GenBox, + pub sustain: GenBox, + pub release: GenBox, + pub gate: GenBox, + pub phase: Phase, + pub cur: f32, + pub attack_cd: f32, + pub decay_cd: f32, + pub buf: SampleBuffer, +} + +impl Generator for DAHDSR { + fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer { + self.buf.rate = Rate::Sample; + + let delay = self.delay.eval(params).first(); + let attack = self.attack.eval(params).first(); + let hold = self.attack.eval(params).first(); + let decay = self.decay.eval(params).first(); + let sustain = self.sustain.eval(params).first(); + let release = self.release.eval(params).first(); + let gate = self.gate.eval(params).first(); + + if gate >= 0.5 { + if self.phase == Phase::Release { + self.phase = Phase::Delay; + self.attack_cd = delay; + self.cur = 0.0; + } + } else{ + self.phase = Phase::Release; + } + + for samp in self.buf.samples.iter_mut() { + match self.phase { + Phase::Delay => { + self.attack_cd -= 1.0; + if self.attack_cd <= 0.0 { + self.phase = Phase::Attack; + } + }, + Phase::Attack => { + self.cur += attack; + if self.cur >= 1.0 { + self.cur = 1.0; + self.phase = Phase::Hold; + self.decay_cd = hold; + } + }, + Phase::Hold => { + self.decay_cd -= 1.0; + if self.decay_cd <= 0.0 { + self.phase = Phase::Decay; + } + }, + Phase::Decay => { + self.cur -= decay; + if self.cur <= sustain { + self.cur = sustain; + self.phase = Phase::Sustain; + } + }, + Phase::Sustain => { + self.cur = sustain; + }, + Phase::Release => { + self.cur -= release; + if self.cur < 0.0 { + self.cur = 0.0; + } + }, + } + *samp = self.cur; + } + + &self.buf + } + fn buffer(&self) -> &SampleBuffer { &self.buf } + fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer { + mem::replace(&mut self.buf, buf) + } +} + +pub struct DAHDSRFactory; + +impl GeneratorFactory for DAHDSRFactory { + fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { + Ok(Box::new(DAHDSR { + delay: params.remove_param("delay", 1)?.into_gen()?, + attack: params.remove_param("attack", 2)?.into_gen()?, + hold: params.remove_param("hold", 3)?.into_gen()?, + decay: params.remove_param("decay", 4)?.into_gen()?, + sustain: params.remove_param("sustain", 5)?.into_gen()?, + release: params.remove_param("release", 6)?.into_gen()?, + gate: params.remove_param("gate", 0)?.into_gen()?, + phase: Phase::Release, + cur: 0.0, + attack_cd: 0.0, + decay_cd: 0.0, + buf: SampleBuffer::new(params.env.default_buffer_size), + })) + } +} + +pub static Factory: DAHDSRFactory = DAHDSRFactory; diff --git a/src/synth/lut.rs b/src/synth/lut.rs new file mode 100644 index 0000000..73b5efa --- /dev/null +++ b/src/synth/lut.rs @@ -0,0 +1,84 @@ +use super::*; + +#[derive(Debug)] +pub struct Lut { + pub freq: GenBox, + pub phase: f32, + pub lut: Vec<Sample>, + pub buf: SampleBuffer, +} + +impl Generator for Lut { + 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] = self.lut[(((self.phase + pvel * (i as f32)) % 1.0) * (self.lut.len() as f32)) as usize]; + } + + self.phase = (self.phase + pvel * (self.buf.len() as f32)) % 1.0; + &self.buf + } + fn buffer(&self) -> &SampleBuffer { &self.buf } + fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer { + mem::replace(&mut self.buf, buf) + } +} + +pub struct LutDataFactory; + +impl GeneratorFactory for LutDataFactory { + fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { + Ok(Box::new(Lut { + freq: params.remove_param("freq", 0)?.into_gen()?, + phase: params.get_param("phase", 1, &mut ParamValue::Float(0.0)).as_f32()?, + buf: SampleBuffer::new(params.env.default_buffer_size), + lut: { + let mut lut: Vec<Sample> = Vec::new(); + let mut i = 0; + + while let Ok(samp) = params.get_req_param("_", 2 + i).and_then(|pv| pv.as_f32()) { + lut.push(samp); + i += 1; + } + + if lut.is_empty() { + return Err(GenFactoryError::MissingRequiredParam("samples".to_string(), 2)); + } + + lut + }, + })) + } +} + +pub static FactoryLutData: LutDataFactory = LutDataFactory; + +pub struct LutGenFactory; + +impl GeneratorFactory for LutGenFactory { + fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { + eprintln!("LutGenFactory::new({:?})", params); + Ok(Box::new(Lut { + freq: params.remove_param("freq", 2)?.into_gen()?, + phase: params.get_param("phase", 3, &mut ParamValue::Float(0.0)).as_f32()?, + buf: SampleBuffer::new(params.env.default_buffer_size), + lut: { + let mut gen = params.remove_param("gen", 0)?.into_gen()?; + let samps = params.get_req_param("samples", 1)?.as_f32()?; + let var = params.get_param("var", 4, &mut ParamValue::String("lut_freq".to_string())).as_string()?; + let mut genparams = Parameters { env: params.env.clone(), ..Default::default() }; + genparams.env.sample_rate = samps; + genparams.vars.insert(var, 1.0); + + gen.set_buffer(SampleBuffer::new(samps as usize)); + gen.eval(&genparams); + + gen.set_buffer(SampleBuffer::new(0)).samples + }, + })) + } +} + +pub static FactoryLutGen: LutGenFactory = LutGenFactory; diff --git a/src/synth/mod.rs b/src/synth/mod.rs index 55268a7..862ca38 100644 --- a/src/synth/mod.rs +++ b/src/synth/mod.rs @@ -249,6 +249,7 @@ pub enum ParamKind { Generator, } +#[derive(Debug)] pub enum ParamValue { Integer(isize), Float(f32), @@ -266,21 +267,21 @@ impl ParamValue { } } - pub fn as_isize(&self) -> Result<isize, GenFactoryError> { + pub fn as_isize(&mut self) -> Result<isize, GenFactoryError> { match *self { ParamValue::Integer(v) => Ok(v), ParamValue::Float(v) => Ok(v as isize), ParamValue::String(ref v) => v.parse().map_err(|_| GenFactoryError::CannotConvert(ParamKind::String, ParamKind::Integer)), - ParamValue::Generator(_) => Err(GenFactoryError::CannotConvert(ParamKind::Generator, ParamKind::Integer)), + ParamValue::Generator(ref mut g) => Ok(g.eval(&Default::default()).first() as isize), } } - pub fn as_f32(&self) -> Result<f32, GenFactoryError> { + pub fn as_f32(&mut self) -> Result<f32, GenFactoryError> { match *self { ParamValue::Integer(v) => Ok(v as f32), ParamValue::Float(v) => Ok(v), ParamValue::String(ref v) => v.parse().map_err(|_| GenFactoryError::CannotConvert(ParamKind::String, ParamKind::Float)), - ParamValue::Generator(_) => Err(GenFactoryError::CannotConvert(ParamKind::Generator, ParamKind::Float)), + ParamValue::Generator(ref mut g) => Ok(g.eval(&Default::default()).first()), } } @@ -309,25 +310,30 @@ impl<'a> From<&'a ParamValue> for ParamKind { } } -#[derive(Default)] +#[derive(Debug,Default)] pub struct FactoryParameters { pub env: Environment, pub vars: HashMap<String, ParamValue>, } impl FactoryParameters { - pub fn get_param<'a, 'b : 'a>(&'a self, name: &str, position: usize, default: &'b ParamValue) -> &'a ParamValue { - ( - self.vars.get(name).or_else(|| - self.vars.get(&position.to_string()).or(Some(default)) - ) - ).unwrap() + pub fn get_param<'a, 'b : 'a>(&'a mut self, name: &str, position: usize, default: &'b mut ParamValue) -> &'a mut ParamValue { + let position = position.to_string(); + + match (self.vars.contains_key(name), self.vars.contains_key(&position)) { + (true, _) => self.vars.get_mut(name).unwrap(), + (false, true) => self.vars.get_mut(&position).unwrap(), + (false, false) => default, + } } - pub fn get_req_param(&self, name: &str, position: usize) -> Result<&ParamValue, GenFactoryError> { - match self.vars.get(name).or_else(|| self.vars.get(&position.to_string())) { - Some(v) => Ok(v), - None => Err(GenFactoryError::MissingRequiredParam(name.to_string(), position)), + pub fn get_req_param(&mut self, name: &str, position: usize) -> Result<&mut ParamValue, GenFactoryError> { + let pos = position.to_string(); + + match (self.vars.contains_key(name), self.vars.contains_key(&pos)) { + (true, _) => Ok(self.vars.get_mut(name).unwrap()), + (false, true) => Ok(self.vars.get_mut(&pos).unwrap()), + (false, false) => Err(GenFactoryError::MissingRequiredParam(name.to_string(), position)), } } @@ -367,6 +373,10 @@ pub mod rel; pub use self::rel::{Rel, RelOp}; pub mod logic; pub use self::logic::IfElse; +pub mod util; +pub use self::util::{ControlRate, SampleRate}; +pub mod lut; +pub use self::lut::Lut; pub mod sine; pub use self::sine::Sine; pub mod saw; @@ -377,8 +387,8 @@ pub mod square; pub use self::square::Square; pub mod noise; pub use self::noise::Noise; -//pub mod adsr; -//pub use self::adsr::ADSR; +pub mod adsr; +pub use self::adsr::DAHDSR; pub fn all_factories() -> HashMap<String, &'static GeneratorFactory> { let mut ret = HashMap::new(); @@ -390,11 +400,16 @@ pub fn all_factories() -> HashMap<String, &'static GeneratorFactory> { ret.insert("reciprocate".to_string(), &self::math::FactoryReciprocate as &GeneratorFactory); ret.insert("rel".to_string(), &self::rel::Factory as &GeneratorFactory); ret.insert("ifelse".to_string(), &self::logic::Factory as &GeneratorFactory); + ret.insert("controlrate".to_string(), &self::util::FactoryControlRate as &GeneratorFactory); + ret.insert("samplerate".to_string(), &self::util::FactorySampleRate as &GeneratorFactory); + ret.insert("lutdata".to_string(), &self::lut::FactoryLutData as &GeneratorFactory); + ret.insert("lutgen".to_string(), &self::lut::FactoryLutGen as &GeneratorFactory); ret.insert("sine".to_string(), &self::sine::Factory as &GeneratorFactory); ret.insert("saw".to_string(), &self::saw::Factory as &GeneratorFactory); ret.insert("triangle".to_string(), &self::triangle::Factory as &GeneratorFactory); ret.insert("square".to_string(), &self::square::Factory as &GeneratorFactory); ret.insert("noise".to_string(), &self::noise::Factory as &GeneratorFactory); + ret.insert("dahdsr".to_string(), &self::adsr::Factory as &GeneratorFactory); ret } diff --git a/src/synth/param.rs b/src/synth/param.rs index b020574..602be1d 100644 --- a/src/synth/param.rs +++ b/src/synth/param.rs @@ -24,7 +24,7 @@ impl GeneratorFactory for ParamFactory { fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { Ok(Box::new(Param { name: params.get_req_param("name", 0)?.as_string()?, - default: params.get_param("default", 1, &ParamValue::Float(0.0)).as_f32()?, + default: params.get_param("default", 1, &mut ParamValue::Float(0.0)).as_f32()?, buf: SampleBuffer::new(1), })) } diff --git a/src/synth/rel.rs b/src/synth/rel.rs index e3c4216..d2fbb70 100644 --- a/src/synth/rel.rs +++ b/src/synth/rel.rs @@ -11,6 +11,19 @@ pub enum RelOp { Less, } +impl RelOp { + pub fn to_param_string(&self) -> &'static str { + match *self { + RelOp::Greater => ">", + RelOp::GreaterEqual => ">=", + RelOp::Equal => "==", + RelOp::NotEqual => "!=", + RelOp::LessEqual => "<=", + RelOp::Less => "<", + } + } +} + /* TODO impl<T: PartialEq<isize>> From<T> for RelOp { fn from(i: T) -> RelOp { diff --git a/src/synth/saw.rs b/src/synth/saw.rs index 054b3c8..3e30ca6 100644 --- a/src/synth/saw.rs +++ b/src/synth/saw.rs @@ -31,7 +31,7 @@ impl GeneratorFactory for SawFactory { fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { Ok(Box::new(Saw { freq: params.remove_param("freq", 0)?.into_gen()?, - phase: params.get_param("phase", 1, &ParamValue::Float(0.0)).as_f32()?, + phase: params.get_param("phase", 1, &mut ParamValue::Float(0.0)).as_f32()?, buf: SampleBuffer::new(params.env.default_buffer_size), })) } diff --git a/src/synth/sine.rs b/src/synth/sine.rs index 66f29ef..4476d4a 100644 --- a/src/synth/sine.rs +++ b/src/synth/sine.rs @@ -34,7 +34,7 @@ impl GeneratorFactory for SineFactory { fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { Ok(Box::new(Sine { freq: params.remove_param("freq", 0)?.into_gen()?, - phase: params.get_param("phase", 1, &ParamValue::Float(0.0)).as_f32()?, + phase: params.get_param("phase", 1, &mut ParamValue::Float(0.0)).as_f32()?, buf: SampleBuffer::new(params.env.default_buffer_size), })) } diff --git a/src/synth/square.rs b/src/synth/square.rs index 9b4374f..4b01e07 100644 --- a/src/synth/square.rs +++ b/src/synth/square.rs @@ -35,7 +35,7 @@ impl GeneratorFactory for SquareFactory { fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { Ok(Box::new(Square { freq: params.remove_param("freq", 0)?.into_gen()?, - phase: params.get_param("phase", 1, &ParamValue::Float(0.0)).as_f32()?, + phase: params.get_param("phase", 1, &mut ParamValue::Float(0.0)).as_f32()?, buf: SampleBuffer::new(params.env.default_buffer_size), })) } diff --git a/src/synth/triangle.rs b/src/synth/triangle.rs index 19a2296..944c539 100644 --- a/src/synth/triangle.rs +++ b/src/synth/triangle.rs @@ -39,7 +39,7 @@ impl GeneratorFactory for TriangleFactory { fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { Ok(Box::new(Triangle { freq: params.remove_param("freq", 0)?.into_gen()?, - phase: params.get_param("phase", 1, &ParamValue::Float(0.0)).as_f32()?, + phase: params.get_param("phase", 1, &mut ParamValue::Float(0.0)).as_f32()?, buf: SampleBuffer::new(params.env.default_buffer_size), })) } diff --git a/src/synth/util.rs b/src/synth/util.rs new file mode 100644 index 0000000..5bde721 --- /dev/null +++ b/src/synth/util.rs @@ -0,0 +1,60 @@ +use super::*; + +#[derive(Debug)] +pub struct ControlRate { + pub value: GenBox, + pub buf: SampleBuffer, +} + +impl ControlRate { + pub fn new(mut gen: GenBox) -> ControlRate { + gen.set_buffer(SampleBuffer::new(1)); + ControlRate { value: gen, buf: SampleBuffer::new(1) } + } +} + +impl Generator for ControlRate { + fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer { + self.buf.rate = Rate::Control; + self.buf.update_from(self.value.eval(params)); + &self.buf + } + fn buffer(&self) -> &SampleBuffer { &self.buf } + fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer { mem::replace(&mut self.buf, buf) } +} + +pub struct ControlRateFactory; + +impl GeneratorFactory for ControlRateFactory { + fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { + Ok(Box::new(ControlRate::new(params.remove_param("gen", 0)?.into_gen()?))) + } +} + +pub static FactoryControlRate: ControlRateFactory = ControlRateFactory; + +#[derive(Debug)] +pub struct SampleRate { + pub buf: SampleBuffer, +} + +impl Generator for SampleRate { + fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer { + self.buf.set(params.env.sample_rate); + &self.buf + } + fn buffer(&self) -> &SampleBuffer { &self.buf } + fn set_buffer(&mut self, buf: SampleBuffer) -> SampleBuffer { + mem::replace(&mut self.buf, buf) + } +} + +pub struct SampleRateFactory; + +impl GeneratorFactory for SampleRateFactory { + fn new(&self, params: &mut FactoryParameters) -> Result<GenBox, GenFactoryError> { + Ok(Box::new(SampleRate { buf: SampleBuffer::new(1) })) + } +} + +pub static FactorySampleRate: SampleRateFactory = SampleRateFactory; |