3 releases
0.1.2 | Jul 30, 2023 |
---|---|
0.1.1 | Dec 31, 2021 |
0.1.0 | Aug 13, 2021 |
#350 in Audio
38KB
498 lines
Midi reader writer
Facilitate reading and writing midi files. This library does not serialise or deserialise
midi files, but uses another library for that. Currently supported is using the midly
library,
behind the engine-midly-0-5
feature.
In particular this create supports,
- creating an iterator over all the tracks, merged;
- given an iterator, separating the tracks, and
- converting time stamps from ticks to microseconds and vice versa.
Example
The following example illustrates the steps that could typically be used in an application
that transforms midi data.
Note: this example requires the convert-time
feature, the engine-midly-0-5
feature, and the read
feature.
use midi_reader_writer::{
ConvertTicksToMicroseconds, ConvertMicroSecondsToTicks,
midly_0_5::{exports::Smf, merge_tracks, TrackSeparator},
};
use std::{fs, error::Error, convert::TryFrom};
fn example(input_filename: &str, output_filename: &str) -> Result<(), Box<dyn Error>> {
// Read the midi file
let bytes = fs::read(input_filename)?;
let input_midi_file = Smf::parse(&bytes)?;
let mut ticks_to_microseconds = ConvertTicksToMicroseconds::try_from(input_midi_file.header)?;
let mut microseconds_to_ticks = ConvertMicroSecondsToTicks::from(input_midi_file.header);
let mut separator = TrackSeparator::new();
// Iterate over the events from all tracks:
for (ticks, track_index, event) in merge_tracks(&input_midi_file.tracks) {
// Convert the ticks to microseconds:
let microseconds = ticks_to_microseconds.convert(ticks, &event);
// Do something with the event:
// ... <- Insert your code here
// Convert from microseconds to ticks:
let new_ticks = microseconds_to_ticks.convert(microseconds, &event)?;
// Push the event to the appropriate track.
separator.push(ticks, track_index, event)?;
}
// Save the output:
let tracks = separator.collect();
let output_midi_file = Smf {
header: input_midi_file.header,
tracks,
};
output_midi_file.save(output_filename)?;
Ok(())
}
Features
This crate has a number of cargo features:
convert-time
(enabled by default): converting time stamps from ticks to microseconds and vice versa.read
(enabled by default): create an iterator over all the tracks of a midi file, mergedengine-midly-0-5
: use version 0.5.x of themidly
crate.
Note that at this point, this crate is not really useful without the engine-midly-0-5
feature.
Ecosystem
The dependency tree of an application that plays midi files is currently probably similar to the following:
(your crate that plays midi files)
├── midi-reader-writer : this crate
│ ├── timestamp-stretcher : high quality conversion from ticks to microseconds and vice versa
│ └── midly : midi file parser and writer
└── (a crate to play midi)
There are several options for playing midi, depending on the operating system(s) you want to target, and how you want to play the midi: as audio, or by sending midi messages. I would recommend to explore the list here. You can also ask for recommendations for your particular use case in the Rust audio discourse group.
Keep in mind that disk access is a no-go in a real-time audio context, since this may cause the audio to stutter.
So it's best to do that in a separate thread.
How that thread is managed, depends on the library that you use to play audio/midi.
In order to communicate between the two threads, you can use the rtrb
crate or any crate listed in the "Alternatives" section of its README.
Other related crates
- Parsing MIDI
wmidi
: high-level encoding and decoding of (real time) live midi eventsmidi-consts
: only constants, useful for low-level do-it-yourself midi handling (same author as this crate).
Contributing
See CONTRIBUTING.md for more information.
License
midi-reader-writer
is licensed under the Apache License, Version 2.0
or the MIT license, at your option.
For the application of the MIT license, the examples included in the doc comments are not considered "substantial portions of this Software".
Dependencies
~150KB