diff --git a/src/instruments.rs b/src/instruments.rs index 26051fb..0beb4c3 100644 --- a/src/instruments.rs +++ b/src/instruments.rs @@ -1,14 +1,16 @@ use nom::{ + branch::alt, bytes::complete::tag_no_case, - character::complete::{hex_digit1, line_ending, not_line_ending, space1}, - combinator::{map_parser, map_res, opt}, + character::complete::{digit1, hex_digit1, line_ending, not_line_ending, space1}, + combinator::{map_parser, map_res, opt, success, value}, error::{Error, ErrorKind}, - multi::fold_many0, - sequence::{preceded, separated_pair, terminated}, + multi::fold_many1, + sequence::{preceded, separated_pair, terminated, tuple}, IResult, }; #[derive(Default)] +#[cfg_attr(test, derive(Debug, PartialEq))] pub struct InstrumentSet([u8; 32]); impl InstrumentSet { @@ -20,10 +22,10 @@ impl InstrumentSet { } fn parse<'i>(input: &'i str) -> IResult<&'i str, Self> { - fold_many0( + fold_many1( terminated( opt(preceded( - tag_no_case("#WAVE"), + tag_no_case("#WAVE "), map_parser(not_line_ending, wave_numbers), )), line_ending, @@ -31,7 +33,7 @@ impl InstrumentSet { Self::default, |mut set, bytes: Option<(usize, u8)>| match bytes { Some((slot, sample)) => { - let pos = slot - 0x20; + let pos = (slot - 0x20) * 2; set.0[pos] = sample; set } @@ -41,18 +43,55 @@ impl InstrumentSet { } } +fn hexordecimal(input: &str) -> IResult<&str, (u32, &str)> { + alt(( + tuple((value(16, tag_no_case("0x")), hex_digit1)), + tuple((success(10), digit1)), + ))(input) +} + fn wave_numbers(input: &str) -> IResult<&str, (usize, u8)> { separated_pair( - map_res(hex_digit1, |s: &str| { - s.parse::().map_err(|_| nom::error::make_error::<&str, Error<&str>>(s, ErrorKind::HexDigit)).and_then(|n| { - if (0x20..0x30).contains(&n) { - Ok(n) - } else { - Err(nom::error::make_error(s, ErrorKind::MapRes)) - } - }) + map_res(hexordecimal, |(radix, s)| { + usize::from_str_radix(s, radix) + .map_err(|_| nom::error::make_error::<&str, Error<&str>>(s, ErrorKind::HexDigit)) + .and_then(|n| { + if (0x20..0x30).contains(&n) { + Ok(n) + } else { + Err(nom::error::make_error(s, ErrorKind::MapRes)) + } + }) }), space1, - map_res(hex_digit1, |s: &str| s.parse::()), + map_res(hexordecimal, |(radix, s)| { + u8::from_str_radix(s, radix) + }), )(input) } + +#[cfg(test)] +mod test { + use super::InstrumentSet; + + #[test] + fn parse_waves() { + let input = " +#WAVE 0x20 0xA5 flute +#WAVE 0x21 0x95 clari +#WAVE 0x22 0x65 strings +#WAVE 0x23 0x63 ostrings +#WAVE 0x24 0x34 guitar +#WAVE 0x25 0x53 fbass + "; + + assert_eq!( + InstrumentSet::generate(input), + InstrumentSet([ + 0xa5, 0x00, 0x95, 0x00, 0x65, 0x00, 0x63, 0x00, 0x34, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + ]) + ); + } +}