Przeglądaj źródła

Remove JACK, begin IV parsing

Grissess 4 lat temu
rodzic
commit
b5ef93a1d8
6 zmienionych plików z 184 dodań i 88 usunięć
  1. 3 3
      Cargo.toml
  2. 2 3
      src/lib.rs
  3. 3 0
      src/main.rs
  4. 143 81
      src/seq/file/iv.rs
  5. 1 1
      src/seq/file/mod.rs
  6. 32 0
      src/seq/mod.rs

+ 3 - 3
Cargo.toml

@@ -12,7 +12,7 @@ doc = false
 [dependencies]
 byteorder = "1.1.0"
 rand = "0.3"
-cpal = { version = "0.13", features = [ "jack" ] }
+cpal = "0.13"
 unicode-xid = "0.1.0"
-xml-rs = "0.8.0"
-failure = "0.1"
+quick-xml = "0.22.0"
+midly = "0.5.2"

+ 2 - 3
src/lib.rs

@@ -1,9 +1,8 @@
 extern crate byteorder;
 extern crate rand;
 extern crate unicode_xid;
-extern crate xml;
-#[macro_use]
-extern crate failure;
+extern crate quick_xml;
+extern crate midly;
 
 pub mod types;
 pub use types::*;

+ 3 - 0
src/main.rs

@@ -29,11 +29,14 @@ fn main() -> Result<(), std::io::Error> {
 }
 
 fn main_client(args: Vec<ffi::OsString>) -> Result<(), std::io::Error> {
+    /*
     let host = if let Ok(host) = cpal::host_from_id(cpal::HostId::Jack) {
         host
     } else {
         cpal::default_host()
     };
+    */
+    let host = cpal::default_host();
     let device = host.default_output_device().expect("no default host audio device!");
     let mut conf_ranges = device.supported_output_configs().expect("could not query audio device capabilities -- audio device disconnected?");
     let conf_range = conf_ranges.next().expect("audio device has no configurations!");

+ 143 - 81
src/seq/file/iv.rs

@@ -1,111 +1,173 @@
 use std::io;
-use std::collections::HashMap;
+use std::convert::TryFrom;
+use std::str::{from_utf8, Utf8Error};
 use std::borrow::Borrow;
 
-use xml::reader;
-use xml::reader::{EventReader, XmlEvent};
-use xml::attribute::OwnedAttribute;
-use std::hash::Hash;
-use std::cmp::Eq;
-use std::str::FromStr;
-use std::fmt::Display;
-use failure::Error;
+use crate::seq::{IV, Version, VersionDecodeError, IVMeta, BPMTable};
 
-struct AttrMapping(HashMap<String, String>);
+use quick_xml::events::{Event, BytesStart};
 
-impl AttrMapping {
-    pub fn make(attrs: Vec<OwnedAttribute>) -> AttrMapping {
-        let mut output = HashMap::new();
 
-        for attr in attrs {
-            output.insert(attr.name.local_name.clone(), attr.value.clone());
-        }
+struct State<'s, B: io::BufRead> {
+    iv: &'s mut IV,
+    rdr: &'s mut quick_xml::Reader<B>,
+}
 
-        AttrMapping(output)
-    }
+#[derive(Debug)]
+pub enum Error {
+    QXML(quick_xml::Error),
+    VersionDecodeError,
+    UTF8(Utf8Error),
+    Unexpected { scope: Scope, event: String },
+}
 
-    pub fn get_str<'a, 'b, 'c: 'a, Q: Hash+Eq+Display+?Sized>(&'a self, key: &'b Q, default: &'c str) -> &'a str where String: Borrow<Q> {
-        self.0.get(key).map(|x| &**x).unwrap_or(default)
-    }
+#[derive(Debug, Clone, Copy, Hash)]
+pub enum Scope {
+    TopLevel,
+}
 
-    pub fn req<V: FromStr, Q: Hash+Eq+Display+?Sized>(&self, key: &Q) -> Result<V, Error> where String: Borrow<Q>, V::Err: failure::Fail {
-        match self.0.get(key){ 
-            Some(x) => Ok(x.parse()?),
-            None => bail!("{} not found in attrs", key)
-        }
+impl From<quick_xml::Error> for Error {
+    fn from(t: quick_xml::Error) -> Self {
+        Error::QXML(t)
     }
+}
 
-    pub fn req_midi_pitch<Q: Hash+Eq+Display+?Sized>(&self, key: &Q) -> Result<Pitch, Error> where String: Borrow<Q> {
-        Ok(Pitch::MIDI(self.req::<f32, Q>(key)?))
+impl From<VersionDecodeError> for Error {
+    fn from(v: VersionDecodeError) -> Self {
+        Error::VersionDecodeError
     }
 }
 
-fn parse_note(ev: XmlEvent, into: &mut Vec<Note>) -> Result<bool, Error> {
-    match ev {
-        XmlEvent::StartElement{name, attributes, ..} => {
-            if name.local_name.as_ref() != "note" { bail!("malformed iv: non-note attr in note stream"); }
-            let attrs = AttrMapping::make(attributes);
-            into.push(Note {
-                time: attrs.req("time")?,
-                ampl: attrs.req("ampl")?,
-                dur: attrs.req("dur")?,
-                pitch: attrs.req_midi_pitch("pitch")?,
-                start_tick: None,
-                dur_ticks: None
-            });
-            Ok(false)
-        },
-        _ => Ok(true)
+impl From<Utf8Error> for Error {
+    fn from(e: Utf8Error) -> Self {
+        Error::UTF8(e)
     }
 }
 
 pub fn read<R: io::Read>(source: R) -> Result<IV, Error> {
     let mut output: IV = Default::default();
-    let mut event_reader = EventReader::new(source);
-
-    #[derive(Debug)]
-    enum ReadState<'a> {
-        Idle,
-        InStreams,
-        InBPMs,
-        InNoteStream(&'a mut NoteStream),
-        InAuxStream(&'a mut AuxStream),
+    let mut reader = quick_xml::Reader::from_reader(
+        io::BufReader::new(source)
+    );
+    let mut state = State {
+        iv: &mut output,
+        rdr: &mut reader,
+    };
+    
+    read_toplevel(&mut state)?;
+
+    Ok(output)
+}
+
+const IV_NAME: &[u8] = b"iv";
+const IV_VERSION: &[u8] = b"version";
+const IV_SOURCE: &[u8] = b"src";
+fn read_toplevel<'s, B: io::BufRead>(state: &mut State<'s, B>) -> Result<(), Error> {
+    let mut buffer: Vec<u8> = Vec::new();
+    loop {
+        match state.rdr.read_event(&mut buffer)? {
+            Event::Decl(_) => (),  // Don't care
+            Event::Start(bs) => {
+                match_iv(state, bs, false);
+                break;
+            },
+            Event::Empty(bs) => {
+                match_iv(state, bs, true);
+                break;
+            },
+            ev => return Err(Error::Unexpected {
+                scope: Scope::TopLevel,
+                event: format!("{:?}", ev),
+            }),
+        }
+    }
+    Ok(())
+}
+
+fn match_iv<'s, 'a, B: io::BufRead>(state: &mut State<'s, B>, bs: BytesStart<'a>, empty: bool) -> Result<(), Error> {
+    if bs.name() != IV_NAME {
+        return Err(Error::Unexpected {
+            scope: Scope::TopLevel,
+            event: format!("start tag: {:?}", bs.name()),
+        });
+    }
+    for attr in bs.attributes() {
+        let attr = attr?;
+        match attr.key {
+            key if key == IV_VERSION => {
+                let value = attr.unescaped_value()?;
+                state.iv.version =
+                    Version::try_from(value.borrow())?;
+            },
+            key if key == IV_SOURCE => {
+                state.iv.source =
+                    Some(from_utf8(
+                            attr.unescaped_value()?.borrow()
+                    )?.into());
+            },
+            _ => (),
+        }
     }
+    if !empty { read_iv(state)?; }
+    Ok(())
+}
 
-    let mut state = ReadState::Idle;
+const META_NAME: &[u8] = b"meta";
+const STREAMS_NAME: &[u8] = b"streams";
+fn read_iv<'s, B: io::BufRead>(state: &mut State<'s, B>) -> Result<(), Error> {
+    let mut buffer: Vec<u8> = Vec::new();
+    loop {
+        match state.rdr.read_event(&mut buffer)? {
+            Event::Start(bs) => {
+                match_in_iv(state, bs, false);
+            },
+            Event::Empty(bs) => {
+                match_in_iv(state, bs, true);
+            },
+            Event::End(be) => {
+                if be.name() == IV_NAME {
+                    break;
+                }
+            },
+            _ => (),
+        }
+    }
+    Ok(())
+}
 
+fn read_until<'s, B: io::BufRead>(state: &mut State<'s, B>, name: &[u8]) -> Result<(), Error> {
+    let mut buffer: Vec<u8> = Vec::new();
     loop {
-        match event_reader.next()? {
-            XmlEvent::StartElement{name, attributes, ..} => {
-                let attrmap = AttrMapping::make(attributes);
-
-                match name.local_name.as_ref() {
-                    "bpms" => { }
-                    "streams" => {
-                        match attrmap.get_str("type", "") {
-                            "ns" => {
-                                let mut notes = Vec::new();
-
-                                loop {
-                                    if !parse_note(event_reader.next()?, &mut notes)? { break; }
-                                }
-
-                            },
-                            _ => unimplemented!()
-                        }
-                    },
-                    _ => unimplemented!()
+        match state.rdr.read_event(&mut buffer)? {
+            Event::End(be) => {
+                if be.name() == name {
+                    return Ok(());
                 }
             }
-            XmlEvent::EndElement{name} => match (name.local_name.as_ref(), &state) {
-                ("bpms", _) => { state = ReadState::Idle; },
-                ("streams", _) => { state = ReadState::Idle; },
-                _ => (),
-            },
             _ => (),
         }
     }
-        
+}
 
-    Ok(output)
+fn match_in_iv<'s, 'a, B: io::BufRead>(state: &mut State<'s, B>, bs: BytesStart<'a>, empty: bool) -> Result<(), Error> {
+    match bs.name() {
+        nm if nm == META_NAME => {
+            if !empty { read_meta(state)?; }
+        },
+        nm if nm == STREAMS_NAME => {
+            if !empty { read_streams(state)?; }
+        },
+        nm => {
+            if !empty { read_until(state, nm.borrow())?; }
+        }
+    }
+    Ok(())
+}
+
+fn read_meta<'s, B: io::BufRead>(state: &mut State<'s, B>) -> Result<(), Error> {
+    todo!()
+}
+
+fn read_streams<'s, B: io::BufRead>(state: &mut State<'s, B>) -> Result<(), Error> {
+    todo!()
 }

+ 1 - 1
src/seq/file/mod.rs

@@ -1,2 +1,2 @@
-//pub mod iv;
+pub mod iv;
 //pub mod midi;

+ 32 - 0
src/seq/mod.rs

@@ -4,6 +4,7 @@ pub mod file;
 
 use std::collections::HashMap;
 use std::{cmp, ops};
+use std::convert::TryFrom;
 
 use super::Pitch;
 
@@ -250,11 +251,42 @@ pub struct IVMeta {
     pub app: Option<String>,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum Version {
+    Ver1_0,
+    Ver1_1,
+}
+
+impl Default for Version {
+    fn default() -> Self {
+        Version::Ver1_1
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct VersionDecodeError;
+
+const VER1_0: &[u8] = b"1.0";
+const VER1_1: &[u8] = b"1.1";
+impl<'a> TryFrom<&'a [u8]> for Version {
+    type Error = VersionDecodeError;
+    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
+        use Version::*;
+        match value {
+            v if v == VER1_0 => Ok(Ver1_0),
+            v if v == VER1_1 => Ok(Ver1_1),
+            _ => Err(VersionDecodeError),
+        }
+    }
+}
+
 #[derive(Default)]
 pub struct IV {
     pub default_group: Group,
     pub groups: HashMap<String, Group>,
     pub meta: IVMeta,
+    pub source: Option<String>,
+    pub version: Version,
 }
 
 impl IV {