sim_lib_stream_file/
midi.rs1use std::path::Path;
2
3use sim_kernel::{Error, Result};
4use sim_lib_midi_core::MemoryMidiSource;
5use sim_lib_midi_smf::{SmfDivision, SmfFile, SmfFormat, SmfTrack, read_smf, write_smf};
6use sim_lib_stream_core::{StreamMetadata, StreamValue};
7use sim_lib_stream_midi::{midi_source_to_stream, midi_stream_to_sink};
8
9use crate::effect_io::{read_file_with_effect, write_file_with_effect};
10
11pub fn read_smf_stream(
17 cx: &mut sim_kernel::Cx,
18 path: impl AsRef<Path>,
19 max_events: usize,
20 metadata: StreamMetadata,
21) -> Result<StreamValue> {
22 let bytes = read_file_with_effect(cx, path)?;
23 smf_bytes_to_stream(&bytes, max_events, metadata)
24}
25
26pub fn smf_bytes_to_stream(
28 bytes: &[u8],
29 max_events: usize,
30 metadata: StreamMetadata,
31) -> Result<StreamValue> {
32 let file = read_smf(bytes).map_err(|err| Error::Eval(format!("malformed SMF file: {err}")))?;
33 smf_file_to_stream(&file, max_events, metadata)
34}
35
36pub fn smf_file_to_stream(
41 file: &SmfFile,
42 max_events: usize,
43 metadata: StreamMetadata,
44) -> Result<StreamValue> {
45 let events = file
46 .merged_events()
47 .map_err(|err| Error::Eval(format!("cannot stream SMF file: {err}")))?
48 .into_iter()
49 .map(|tracked| tracked.event)
50 .collect();
51 let tpq = file.ticks_per_quarter().ok_or_else(|| {
52 Error::Eval("SMPTE SMF requires an explicit real-time stream clock adapter".to_owned())
53 })?;
54 let mut source = MemoryMidiSource::new(tpq, events);
55 midi_source_to_stream(&mut source, max_events, metadata)
56}
57
58pub fn write_smf_stream(
63 cx: &mut sim_kernel::Cx,
64 path: impl AsRef<Path>,
65 stream: &StreamValue,
66 tpq: u32,
67) -> Result<usize> {
68 let (file, count) = stream_to_smf_file(stream, tpq)?;
69 let bytes = write_smf(&file).map_err(|err| Error::Eval(format!("cannot write SMF: {err}")))?;
70 write_file_with_effect(cx, path, bytes)?;
71 Ok(count)
72}
73
74pub fn stream_to_smf_bytes(stream: &StreamValue, tpq: u32) -> Result<(Vec<u8>, usize)> {
78 let (file, count) = stream_to_smf_file(stream, tpq)?;
79 let bytes = write_smf(&file).map_err(|err| Error::Eval(format!("cannot write SMF: {err}")))?;
80 Ok((bytes, count))
81}
82
83pub fn stream_to_smf_file(stream: &StreamValue, tpq: u32) -> Result<(SmfFile, usize)> {
88 let division = u16::try_from(tpq)
89 .ok()
90 .and_then(SmfDivision::metrical)
91 .ok_or_else(|| {
92 Error::Eval(format!(
93 "SMF TPQ {tpq} exceeds the metrical Standard MIDI File range"
94 ))
95 })?;
96 let mut sink = sim_lib_midi_core::MemoryMidiSink::new(tpq);
97 let count = midi_stream_to_sink(stream, &mut sink)?;
98 let file = SmfFile {
99 format: SmfFormat::SingleTrack,
100 division,
101 tracks: vec![SmfTrack {
102 events: sink.events().to_vec(),
103 }],
104 };
105 Ok((file, count))
106}