diff options
| author | Graham Northup <grissess@nexusg.org> | 2019-02-12 23:36:38 -0500 | 
|---|---|---|
| committer | Graham Northup <grissess@nexusg.org> | 2019-02-12 23:36:38 -0500 | 
| commit | 5c39a9c26ddd9d7aa4a4fa1af0244348daab0011 (patch) | |
| tree | 7cc0c140ed8c801d276f87a7663c67be75a842ee /src/seq/file | |
| parent | 9f2b13aaf422014cb1988a8d91b55aef9c964f12 (diff) | |
| parent | 23c79cc00eb5d8e76148d79af83a9ab838e602f3 (diff) | |
Merge branch 'work' into nogfx
Diffstat (limited to 'src/seq/file')
| -rw-r--r-- | src/seq/file/iv.rs | 112 | ||||
| -rw-r--r-- | src/seq/file/mod.rs | 4 | 
2 files changed, 116 insertions, 0 deletions
| diff --git a/src/seq/file/iv.rs b/src/seq/file/iv.rs new file mode 100644 index 0000000..570f36d --- /dev/null +++ b/src/seq/file/iv.rs @@ -0,0 +1,112 @@ +use std::io; +use std::collections::HashMap; +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 super::*; + +struct AttrMapping(HashMap<String, String>); + +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()); +        } + +        AttrMapping(output) +    } + +    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) +    } + +    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) +        } +    } + +    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)?)) +    } +} + +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) +    } +} + +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 state = ReadState::Idle; + +    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!() +                } +            } +            XmlEvent::EndElement{name} => match (name.local_name.as_ref(), &state) { +                ("bpms", _) => { state = ReadState::Idle; }, +                ("streams", _) => { state = ReadState::Idle; }, +                _ => (), +            }, +            _ => (), +        } +    } +         + +    Ok(output) +} diff --git a/src/seq/file/mod.rs b/src/seq/file/mod.rs new file mode 100644 index 0000000..12662f8 --- /dev/null +++ b/src/seq/file/mod.rs @@ -0,0 +1,4 @@ +//pub mod iv; +//pub mod midi; + +use super::*; | 
