summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrissess <grissess@nexusg.org>2021-09-15 20:27:25 -0400
committerGrissess <grissess@nexusg.org>2021-09-15 20:27:25 -0400
commitb5ef93a1d8da6f683a58ba3ed8f3cd648706d303 (patch)
tree88bf30a81be1f4f2a56873849a87ff902c1b3754
parent2b388fe415ddedfdad96bf459204d85a0be7be4a (diff)
Remove JACK, begin IV parsingHEADdev
-rw-r--r--Cargo.toml6
-rw-r--r--src/lib.rs5
-rw-r--r--src/main.rs3
-rw-r--r--src/seq/file/iv.rs224
-rw-r--r--src/seq/file/mod.rs2
-rw-r--r--src/seq/mod.rs32
6 files changed, 184 insertions, 88 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1719a45..61ac23c 100644
--- a/Cargo.toml
+++ b/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"
diff --git a/src/lib.rs b/src/lib.rs
index def8457..c7e5a27 100644
--- a/src/lib.rs
+++ b/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::*;
diff --git a/src/main.rs b/src/main.rs
index 7cf1ae4..631f1b7 100644
--- a/src/main.rs
+++ b/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!");
diff --git a/src/seq/file/iv.rs b/src/seq/file/iv.rs
index de3f0b6..24b69e7 100644
--- a/src/seq/file/iv.rs
+++ b/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!()
}
diff --git a/src/seq/file/mod.rs b/src/seq/file/mod.rs
index 1f48c82..45c4a35 100644
--- a/src/seq/file/mod.rs
+++ b/src/seq/file/mod.rs
@@ -1,2 +1,2 @@
-//pub mod iv;
+pub mod iv;
//pub mod midi;
diff --git a/src/seq/mod.rs b/src/seq/mod.rs
index 1a4cc95..49802d1 100644
--- a/src/seq/mod.rs
+++ b/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 {