midi-player =========== A MIDI file player library with integrated synthesizer ([`rustysynth`](https://crates.io/crates/rustysynth)). It's independent from audio library, that means you should provide your own audio loop and run the render function within it. The player has play/stop, position, volume and tempo parameters, and position observer, which allows you to track the play position in the real-time. ## Example usage (with `cpal`) ```rust use std::{thread, time::Duration}; use cpal::{ traits::{DeviceTrait, HostTrait, StreamTrait}, StreamConfig, }; use midi_player::player::{Player, Settings}; fn main() { let settings = Settings::builder().build(); let (player, mut controller) = Player::new("examples/Nice-Steinway-Lite-v3.0.sf2", settings).unwrap(); thread::spawn(|| { start_audio_loop(player); }); thread::sleep(Duration::from_secs(2)); controller .set_file(Some("examples/Sibelius_The_Spruce.mid")) .unwrap(); controller.play(); loop {} } fn start_audio_loop(mut player: Player) { let host = cpal::default_host(); let device = host .default_output_device() .expect("No output device available"); let channels = 2 as usize; let config = StreamConfig { channels: channels as u16, sample_rate: cpal::SampleRate(player.settings().sample_rate), buffer_size: cpal::BufferSize::Fixed(player.settings().audio_buffer_size), }; let err_fn = |err| eprintln!("An error occurred on the output audio stream: {}", err); let mut left = vec![0f32; player.settings().audio_buffer_size as usize]; let mut right = vec![0f32; player.settings().audio_buffer_size as usize]; let stream = device .build_output_stream( &config.into(), move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { let sample_count = data.len() / channels; player.render(&mut left, &mut right); if !left.is_empty() { for i in 0..sample_count { data[channels * i] = left[i]; data[channels * i + 1] = right[i]; } } }, err_fn, None, ) .unwrap(); stream.play().expect("cannot run audio stream"); std::thread::park(); } ```