,
}
fn m_midi_part<'a>(data: &'a [u8]) -> IResult<&'a [u8], MMidiPart<'a>> {
let (r, (num32, name, data)) = tuple((be_u32, cmstring, count(be_u8, 17)))(&data)?;
Ok((r, MMidiPart { num32, name, data }))
}
fn node_value<'a>(class: &str, data: &'a [u8]) -> IResult<&'a [u8], NodeValue<'a>> {
match class {
"PAppVersion" => {
let (r, appver) = p_appversion(&data)?;
Ok((r, NodeValue::Version(appver)))
},
"PArrangement\0" => {
let (r, arr) = p_arrangement(&data)?;
Ok((r, NodeValue::Arrangement(arr)))
},
"MRoot\0" |
"MTrackList\0" => {
let (r, v) = counted_vec(&data)?;
Ok((r, NodeValue::Raw(v)))
},
"MInstrumentTrackEvent\0" => {
let (r, e) = m_instrument_track_event(&data)?;
Ok((r, NodeValue::InstrumentTrackEvent(e)))
},
"MTempoTrackEvent\0" => {
let (r, e) = m_tempo_track_event(&data)?;
Ok((r, NodeValue::TempoTrackEvent(e)))
},
"MSignatureTrackEvent\0" => {
let (r, e) = m_signature_track_event(&data)?;
Ok((r, NodeValue::SignatureTrackEvent(e)))
},
"MMidiPartEvent\0" => {
let (r, v) = count(be_u8, 30)(data)?;
Ok((r, NodeValue::MidiPartEvent(v)))
},
"MMidiPart\0" => {
let (r, v) = m_midi_part(&data)?;
Ok((r, NodeValue::MidiPart(v)))
},
"MMidiNote\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiNote(v)))
},
"MMidiPolyPressure\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiPolyPressure(v)))
},
"MMidiAfterTouch\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiAfterTouch(v)))
},
"MMidiProgramChange\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiProgramChange(v)))
},
"MMidiController\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiController(v)))
},
"MMidiPitchBend\0" => {
let (r, v) = be_u32(data)?;
Ok((r, NodeValue::MidiPitchBend(v)))
},
"MMidiSysex\0" => {
let sep = vec![0xff, 0xff, 0xff, 0xff];
let (r, v) = take_until(sep.as_slice())(data)?;
Ok((r, NodeValue::MidiSysex(v.to_vec())))
},
&_ => Ok((&[], NodeValue::Unknown)) //"Unknown node class \"{}\".", class)
}
}
fn nodetype<'a>(data: &'a [u8]) -> IResult<&'a [u8], NodeType> {
let (rest, nt) = be_u32(data)?;
Ok((rest, NodeType::from(nt)))
}
fn fourcc<'a>(data: &'a [u8]) -> IResult<&'a [u8], &'a str> {
let (rest, tag) = take(4usize)(data)?;
Ok((rest, std::str::from_utf8(tag).unwrap()))
}
fn root_chunk<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (rest, (key, val)) = tuple((cmstring, cmstring))(data)?;
println!(" {}: {}", key, val);
Ok((rest, ()))
}
/**
* A container node does not contain any data of it's own, but contains
* one or more sub elements. These can be either other containers, or
* object/leaf nodes.
*/
fn container_node<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (r, (_, name, num)) = tuple((tag(b"\xff\xff\xff\xfe"), cmstring, be_u16))(data)?;
println!(" Container: {}, {}", name, num);
Ok((r, ()))
}
/**
* An object node contains serialized structured data.
*
* It has a size, as well as a payload containing the actual serialized data.
*/
fn object_node<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (r, (_, name, num, payload)) = tuple((tag(b"\xff\xff\xff\xff"), cmstring, be_u16, length_data(be_u32)))(data)?;
println!(" Object: {}, {}, {}", name, num, payload.len());
let (_, nv) = node_value(name, payload)?;
println!(" {:?}", nv);
Ok((r, ()))
}
/**
* ARCH chunks contains one or more structured data elements that can be
* either container nodes or object/leaf nodes..
*/
fn arch_chunk<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (rest, _nodes) = many0(alt((container_node, object_node)))(data)?;
Ok((rest, ()))
}
fn chunk<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (rest, (tag, payload)) = tuple((fourcc, length_data(be_u32)))(data)?;
println!(" {}: {}", tag, payload.len());
match tag {
"ROOT" => root_chunk(payload)?,
"ARCH" => arch_chunk(payload)?,
&_ => (payload, ())
};
Ok((rest, ()))
}
/**
* Parse the Cubase project file header.
*
* A Cubase project file is almost a standard RIFF file, with the exception of an
* extra fourcc (NUND) following the global RIFF header. The extra (NUND) fourcc
* is _not_ followed by the length of the chunk, but rather immediately followed by
* the next chunk.
*/
fn file_hdr<'a>(data: &'a [u8]) -> IResult<&'a [u8], ()> {
let (rest, (_, len, _)) = tuple((tag("RIFF"), be_u32, tag("NUND")))(data)?;
println!("RIFF: {}, NUND", len);
Ok((rest, ()))
}
pub struct CubaseProject;
pub fn parse_cubase_project(filename: P) -> Result>
where
P: AsRef
{
println!("Reading {}...", filename.as_ref().to_str().ok_or("Invalid file name")?);
let data = std::fs::read(filename)?;
let (rest, _) = tuple((file_hdr, many0(chunk)))(&data)
.finish()
.map_err(|e| format!("{:?}", e))?;
println!("Rest: {}", rest.len());
// let mut rest = chunk.payload;
// while dbg!(rest.len()) > 0 {
// let (r, chunk) = parse_chunk(&rest).unwrap();
// println!(" Chunk id : {}", chunk.tag);
// println!(" Chunk data size : {}/{} bytes", chunk.len, chunk.payload.len());
// match chunk.tag {
// "NUNDROOT" | "ROOT" => {
// let (_r, hm) = parse_nundroot(&chunk.payload).unwrap();
// println!(" data : {:?}", hm);
// },
// "ARCH" => {
// let (_r, n) = node(&chunk.payload).unwrap();
// println!(" {}: {{", n.nodeclass);
// println!(" {:#?}", n.value);
// println!(" }},");
// },
// _ => (),
// };
// rest = r;
// std::thread::sleep(std::time::Duration::from_millis(200));
// }
Ok(CubaseProject {})
}
fn main() -> std::result::Result<(), Box> {
let filename = std::env::args()
.skip(1)
.next()
.expect("You must give me a file to analyze");
parse_cubase_project(filename)?;
Ok(())
}