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). Metrical and valid SMPTE divisions are retained losslessly.
10//!
11//! # Examples
12//!
13//! Round-tripping a minimal single-track file:
14//!
15//! ```
16//! use sim_lib_midi_smf::{
17//! read_smf, write_smf, SmfDivision, SmfFile, SmfFormat, SmfTrack,
18//! };
19//! use sim_lib_midi_core::{
20//! MetaEvent, MidiEvent, MidiPayload, TickTime, synthetic_origin,
21//! };
22//!
23//! let file = SmfFile {
24//! format: SmfFormat::SingleTrack,
25//! division: SmfDivision::metrical(480).unwrap(),
26//! tracks: vec![SmfTrack {
27//! events: vec![MidiEvent {
28//! time: TickTime::new(0, 480).unwrap(),
29//! origin: synthetic_origin(),
30//! payload: MidiPayload::Meta(MetaEvent::EndOfTrack),
31//! }],
32//! }],
33//! };
34//! let bytes = write_smf(&file).unwrap();
35//! let parsed = read_smf(&bytes).unwrap();
36//! assert_eq!(parsed.format, SmfFormat::SingleTrack);
37//! assert_eq!(parsed.division, SmfDivision::metrical(480).unwrap());
38//! ```
39//!
40//! The variable-length quantity codec is reversible:
41//!
42//! ```
43//! use std::io::Cursor;
44//! use sim_lib_midi_smf::{decode_vlq, encode_vlq};
45//!
46//! let bytes = encode_vlq(0x4000);
47//! assert_eq!(decode_vlq(&mut Cursor::new(bytes)).unwrap(), 0x4000);
48//! ```
49
50#![forbid(unsafe_code)]
51#![deny(missing_docs)]
52
53mod error;
54mod limits;
55mod model;
56mod reader;
57mod vlq;
58mod writer;
59
60pub use error::*;
61pub use limits::*;
62pub use model::*;
63pub use reader::*;
64pub use vlq::*;
65pub use writer::*;
66
67#[cfg(test)]
68mod conformance_additional;
69#[cfg(test)]
70mod recipe_tests;
71#[cfg(test)]
72mod test_support;
73
74/// Cookbook recipes for this lib, embedded at build time.
75pub static RECIPES: sim_cookbook::EmbeddedDir =
76 include!(concat!(env!("OUT_DIR"), "/cookbook_recipes.rs"));
77
78#[cfg(test)]
79mod tests;