Эх сурвалжийг харах

Finished clientside parsing, starting graphics

Graham Northup 8 жил өмнө
parent
commit
22dd5bc586

+ 12 - 0
Cargo.toml

@@ -3,8 +3,20 @@ name = "synfone"
 version = "0.1.0"
 authors = ["Graham Northup <grissess@nexusg.org>"]
 
+[features]
+default = ['graphics']
+
+# The following feature will always refer ultimately to whatever backend
+# graphics library is chosen--which is subject to change.
+graphics = ['glium']
+
 [dependencies]
 byteorder = "1.1.0"
 rand = "0.3"
 unicode-xid = "0.1.0"
 portaudio = "0.7.0"
+
+[dependencies.glium]
+version = "0.17.1"
+optional = true
+features = ["glutin"]

+ 1 - 0
gens/basic_saw.gen

@@ -0,0 +1 @@
+#gens/itlc_head.gen# saw(param('v_freq', 500)) #gens/itlc_tail.gen#

+ 1 - 0
gens/itlc_head.gen

@@ -0,0 +1 @@
+mul(

+ 1 - 0
gens/itlc_tail.gen

@@ -0,0 +1 @@
+, ifelse(rel(param('v_frame'), '<', param('v_deadline')), param('v_amp'), 0.0))

+ 12 - 0
gens/test.gen

@@ -0,0 +1,12 @@
+[
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#,
+	#gens/basic_saw.gen#
+]

+ 3 - 0
src/graphics/draw/mod.rs

@@ -0,0 +1,3 @@
+use super::*;
+
+/* TODO */

+ 4 - 0
src/graphics/mod.rs

@@ -0,0 +1,4 @@
+use super::*;
+use monitor::*;
+
+pub mod draw;

+ 43 - 10
src/lang/parser.rs

@@ -55,16 +55,18 @@ impl fmt::Display for ErrorType {
 
 pub struct Parser<T: Iterator<Item=char>> {
     tzr: Tokenizer<T>,
+    env: Environment,
     token: Token,
     pushback: Option<Token>,
     factories: HashMap<String, &'static GeneratorFactory>,
 }
 
 impl<T: Iterator<Item=char>> Parser<T> {
-    pub fn new(mut tzr: Tokenizer<T>) -> Result<Parser<T>, Box<Error>> {
+    pub fn new(mut tzr: Tokenizer<T>, env: Environment) -> Result<Parser<T>, Box<Error>> {
         let token = tzr.next_token()?;
         Ok(Parser {
             tzr: tzr,
+            env: env,
             token: token,
             pushback: None,
             factories: all_factories(),
@@ -105,15 +107,51 @@ impl<T: Iterator<Item=char>> Parser<T> {
         }
     }
 
-    pub fn parse(&mut self) -> Result<GenBox, Box<Error>> {
-        self.parse_gen()
+    pub fn parse_gen_vec(&mut self) -> Result<Vec<GenBox>, Box<Error>> {
+        let mut ret: Vec<GenBox> = Vec::new();
+        self.expect_op('[')?;
+
+
+        loop {
+            if self.expect_op(']').is_ok() {
+                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()?);
+
+            if self.expect_op(',').is_err() {
+                self.expect_op(']')?;
+                break;
+            }
+        }
+
+        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()),
+        };
+        factory.new(&mut params).map_err(Into::into)
+    }
 
+    pub fn parse_factory_params(&mut self) -> Result<FactoryParameters, Box<Error>> {
         self.expect_op('(')?;
-        let mut params: FactoryParameters = Default::default();
+
+        let mut params: FactoryParameters = FactoryParameters { env: self.env.clone(), ..Default::default() };
         let mut ctr = 0;
         loop {
             if self.expect_op(')').is_ok() {
@@ -124,17 +162,12 @@ impl<T: Iterator<Item=char>> Parser<T> {
             ctr = new_ctr;
 
             if self.expect_op(',').is_err() {
-                eprintln!("No comma: {:?}", self.token);
                 self.expect_op(')')?;
                 break;
             }
         }
 
-        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)
+        Ok(params)
     }
 
     pub fn parse_param(&mut self, pos: usize) -> Result<(String, ParamValue, usize), Box<Error>> {

+ 112 - 9
src/lang/tokenizer.rs

@@ -1,6 +1,7 @@
 use std::collections::HashMap;
 use std::error::Error;
-use std::fmt;
+use std::{fmt, io, fs};
+use std::io::Read;
 use super::*;
 use unicode_xid::UnicodeXID;
 
@@ -13,6 +14,7 @@ pub struct Lexemes {
     esc_oct: char,
     com_outer: char,
     com_inner: char,
+    include_delim: char,
     escapes: HashMap<char, char>
 }
 
@@ -27,6 +29,7 @@ impl Default for Lexemes {
             esc_oct: 'o',
             com_outer: '/',
             com_inner: '*',
+            include_delim: '#',
             escapes: HashMap::new(),
         };
 
@@ -44,6 +47,7 @@ impl Default for Lexemes {
 pub enum Location {
     InString,
     InStringEscape,
+    InInclude,
 }
 
 #[derive(Debug)]
@@ -64,6 +68,8 @@ pub enum ErrorKind {
     BadEscapeValue(EscapeKind, String, Option<Box<Error>>),
     BadNumericLiteral(NumericKind, String, Option<Box<Error>>),
     UnknownChar(char),
+    IncludeError(io::Error),
+    TooManyRecursions(usize),
 }
 
 #[derive(Debug)]
@@ -83,6 +89,7 @@ impl ErrorType {
             ErrorKind::UnexpectedEOF(ref loc) => format!("Unexpected EOF {}", match *loc {
                 Location::InString => "in string constant",
                 Location::InStringEscape => "in string escape",
+                Location::InInclude => "in include",
             }),
             ErrorKind::BadEscapeValue(ref kind, ref val, ref err) => format!("Bad {} escape {}: {:?}", match *kind {
                 EscapeKind::Hexadecimal => "hexadecimal",
@@ -93,6 +100,8 @@ impl ErrorType {
                 NumericKind::Float => "floating point",
             }, val, err),
             ErrorKind::UnknownChar(c) => format!("Unknown character {}", c),
+            ErrorKind::IncludeError(ref e) => format!("Error including file: {:?}", e),
+            ErrorKind::TooManyRecursions(n) => format!("Include recursed too many times ({})", n),
         };
 
         ret
@@ -117,7 +126,7 @@ impl Error for ErrorType {
                 Some(ref err) => Some(&**err),
                 None => None,
             },
-            ErrorKind::UnexpectedEOF(_) | ErrorKind::UnknownChar(_) => None,
+            _ => None,
         }
     }
 }
@@ -134,16 +143,56 @@ fn char_in(s: &str, c: char) -> bool {
     s.chars().find(|&x| x == c).map_or(false, |_| true)
 }
 
+pub struct ResumableChars {
+    string: String,
+    pos: usize,
+}
+
+impl ResumableChars {
+    pub fn new(s: String) -> ResumableChars {
+        ResumableChars {
+            string: s,
+            pos: 0,
+        }
+    }
+}
+
+impl Iterator for ResumableChars {
+    type Item = char;
+
+    fn next(&mut self) -> Option<char> {
+        if self.pos >= self.string.len() {
+            None
+        } else {
+            let mut iter = self.string[self.pos..].char_indices();
+            match iter.next() {
+                Some((pos, ch)) => {
+                    self.pos += match iter.next() {
+                        Some((pos, _)) => pos,
+                        None => self.string.len(),
+                    };
+                    Some(ch)
+                },
+                None => None,
+            }
+        }
+    }
+}
+
 pub struct Tokenizer<T: Iterator<Item=char>> {
     reader: T,
+    reader_stack: Vec<ResumableChars>,
     pushback: Option<char>,
     lexemes: Lexemes,
 }
 
 impl<T: Iterator<Item=char>> Tokenizer<T> {
+    const MAX_INCLUDE_RECURSIONS: usize = 256;
+
     pub fn new(reader: T) -> Tokenizer<T> {
         Tokenizer {
             reader: reader,
+            reader_stack: Vec::new(),
             pushback: None,
             lexemes: Default::default(),
         }
@@ -159,23 +208,49 @@ impl<T: Iterator<Item=char>> Tokenizer<T> {
         }
     }
 
+    pub fn push_reader(&mut self, rc: ResumableChars) -> Result<(), ErrorType> {
+        if self.reader_stack.len() > Self::MAX_INCLUDE_RECURSIONS {
+            Err(ErrorType::new(ErrorKind::TooManyRecursions(self.reader_stack.len())))
+        } else {
+            self.reader_stack.push(rc);
+            Ok(())
+        }
+    }
+
     fn next_char(&mut self) -> Option<char> {
         match self.pushback {
             Some(c) => {
                 self.pushback = None;
                 Some(c)
             },
-            None => self.reader.next(),
+            None => {
+                let mut ret = None;
+                let mut produced_idx: usize = 0;
+                let len = self.reader_stack.len();
+
+                for (idx, rc) in self.reader_stack.iter_mut().enumerate().rev() {
+                    match rc.next() {
+                        Some(c) => {
+                            ret = Some(c);
+                            produced_idx = idx;
+                            break;
+                        },
+                        None => {},
+                    }
+                }
+
+                match ret {
+                    Some(c) => {
+                        self.reader_stack.truncate(produced_idx + 1);
+                        Some(c)
+                    },
+                    None => self.reader.next(),
+                }
+            },
         }
     }
 
     pub fn next_token(&mut self) -> Result<Token, ErrorType> {
-        let res = self._next_token();
-        eprintln!("next_token: {:?}", res);
-        res
-    }
-
-    fn _next_token(&mut self) -> Result<Token, ErrorType> {
         let mut c = self.next_char();
         if c == None {
             return Ok(Token::EOF);
@@ -216,6 +291,34 @@ impl<T: Iterator<Item=char>> Tokenizer<T> {
             }
         }
 
+        /* Inclusion */
+        if cc == self.lexemes.include_delim {
+            let mut buffer = String::new();
+
+            loop {
+                let nc = self.next_char();
+                if nc == None {
+                    return Err(ErrorType::new(ErrorKind::UnexpectedEOF(Location::InInclude)));
+                }
+                let ncc = nc.unwrap();
+
+                if ncc == self.lexemes.include_delim {
+                    break;
+                } else {
+                    buffer.push(ncc);
+                }
+            }
+
+            let mut f = match fs::File::open(buffer) {
+                Err(err) => return Err(ErrorType::new(ErrorKind::IncludeError(err))),
+                Ok(f) => f,
+            };
+            let mut contents = String::new();
+            f.read_to_string(&mut contents);
+            self.push_reader(ResumableChars::new(contents))?;
+            return self.next_token()
+        }
+
         /* Strings */
         if char_in(&self.lexemes.string_delim, cc) {
             let mut buffer = String::new();

+ 4 - 0
src/lib.rs

@@ -11,6 +11,10 @@ pub mod synth;
 pub mod proto;
 pub mod lang;
 pub mod client;
+pub mod monitor;
+
+#[cfg(feature = "graphics")]
+pub mod graphics;
 
 #[cfg(test)]
 mod tests {

+ 9 - 8
src/main.rs

@@ -1,5 +1,6 @@
-use std::io;
+use std::{io, env};
 use std::io::*;
+use std::fs::*;
 use std::net::*;
 use std::sync::*;
 use std::collections::VecDeque;
@@ -13,18 +14,18 @@ use synfone::lang::*;
 use synfone::proto::*;
 use synfone::client::*;
 
-const GEN: &'static str = "mul(saw(param('v_freq', 500)), ifelse(rel(param('v_frame'), '<', param('v_deadline')), param('v_amp'), 0.0))";
-
 fn main() {
     let env = Environment::default();
 
-    let mut gens = Vec::new();
-    for _i in 0..25 {
-        let gen = Parser::new(Tokenizer::new(GEN.chars())).expect("Failed to get first token").parse().expect("Failed to compile generator");
-        gens.push(gen);
-    }
+    let mut genfile = File::open(env::args_os().nth(1).expect("Need first argument to be a file with a generator vector")).expect("Failed to open file");
+    let mut genstr = String::new();
+    genfile.read_to_string(&mut genstr);
+
+    let gens = Parser::new(Tokenizer::new(genstr.chars()), env.clone()).expect("Failed to get first token").parse_gen_vec().expect("Failed to compile generators");
     let sock = UdpSocket::bind("0.0.0.0:13676").expect("Failed to bind socket");
 
+    eprintln!("Parsed {} generator definitions", gens.len());
+
     let mut client = Arc::new(Mutex::new(Client::new(sock.try_clone().expect("Failed to clone socket"), gens, env.clone()).expect("Failed to create client")));
 
     let pa_inst = pa::PortAudio::new().expect("Failed to create PortAudio interface");

+ 36 - 0
src/monitor.rs

@@ -0,0 +1,36 @@
+use super::*;
+use synth::SampleBuffer;
+use std::collections::HashMap;
+
+pub struct VoiceDatum {
+    pitch: Pitch,
+    ampl: f32,
+}
+
+pub enum Datum {
+    Voices(Vec<VoiceDatum>),
+    Samples(SampleBuffer),
+    Playtime(f32, f32),
+}
+
+pub enum DatumKind {
+    Voices,
+    Samples,
+    Playtime,
+}
+
+impl<'a> From<&'a Datum> for DatumKind {
+    fn from(d: &'a Datum) -> DatumKind {
+        match *d {
+            Datum::Voices(_) => DatumKind::Voices,
+            Datum::Samples(_) => DatumKind::Samples,
+            Datum::Playtime(_, _) => DatumKind::Playtime,
+        }
+    }
+}
+
+pub type Data = HashMap<DatumKind, Datum>;
+
+pub trait Monitor {
+    fn process(&mut self, data: &Data);
+}

+ 9 - 0
src/synth/mod.rs

@@ -163,6 +163,15 @@ impl IndexMut<usize> for SampleBuffer {
     fn index_mut(&mut self, idx: usize) -> &mut Sample { &mut self.samples[idx] }
 }
 
+impl Clone for SampleBuffer {
+    fn clone(&self) -> SampleBuffer {
+        SampleBuffer {
+            samples: self.samples.clone(),
+            rate: self.rate,
+        }
+    }
+}
+
 pub trait Generator : Debug {
     fn eval<'a>(&'a mut self, params: &Parameters) -> &'a SampleBuffer;
     fn buffer(&self) -> &SampleBuffer;