Skip to main content

sim_lib_midi_smf/
lib.rs

1//! Standard MIDI File (SMF) reading and writing for the SIM music stack.
2//!
3//! This crate parses the on-disk `.mid`/`.smf` byte format into the in-memory
4//! [`SmfFile`] model and serialises it back, reusing the event types from
5//! [`sim_lib_midi_core`]. It covers the three SMF formats ([`SmfFormat`]), the
6//! variable-length quantity encoding ([`encode_vlq`]/[`decode_vlq`]), running
7//! status, and track canonicalisation/merging. Reading is [`read_smf`];
8//! writing is [`write_smf`] (or [`write_smf_with_options`] for running-status
9//! control). Only metric (ticks-per-quarter) division is supported; SMPTE
10//! division is rejected.
11//!
12//! # Examples
13//!
14//! Round-tripping a minimal single-track file:
15//!
16//! ```
17//! use sim_lib_midi_smf::{read_smf, write_smf, SmfFile, SmfFormat, SmfTrack};
18//! use sim_lib_midi_core::{
19//!     MetaEvent, MidiEvent, MidiPayload, TickTime, synthetic_origin,
20//! };
21//!
22//! let file = SmfFile {
23//!     format: SmfFormat::SingleTrack,
24//!     tpq: 480,
25//!     tracks: vec![SmfTrack {
26//!         events: vec![MidiEvent {
27//!             time: TickTime::new(0, 480).unwrap(),
28//!             origin: synthetic_origin(),
29//!             payload: MidiPayload::Meta(MetaEvent::EndOfTrack),
30//!         }],
31//!     }],
32//! };
33//! let bytes = write_smf(&file).unwrap();
34//! let parsed = read_smf(&bytes).unwrap();
35//! assert_eq!(parsed.format, SmfFormat::SingleTrack);
36//! assert_eq!(parsed.tpq, 480);
37//! ```
38//!
39//! The variable-length quantity codec is reversible:
40//!
41//! ```
42//! use std::io::Cursor;
43//! use sim_lib_midi_smf::{decode_vlq, encode_vlq};
44//!
45//! let bytes = encode_vlq(0x4000);
46//! assert_eq!(decode_vlq(&mut Cursor::new(bytes)).unwrap(), 0x4000);
47//! ```
48
49#![forbid(unsafe_code)]
50#![deny(missing_docs)]
51
52mod error;
53mod model;
54mod reader;
55mod vlq;
56mod writer;
57
58pub use error::*;
59pub use model::*;
60pub use reader::*;
61pub use vlq::*;
62pub use writer::*;
63
64#[cfg(test)]
65mod recipe_tests;
66
67#[cfg(test)]
68mod tests;