use std::{ io::{self, Cursor}, sync::Arc, }; use async_channel::{Receiver, TryRecvError}; use bevy::{ asset::{io::Reader, AssetLoader, AsyncReadExt, LoadContext}, audio::Source, prelude::*, tasks::AsyncComputeTaskPool, }; use itertools::Itertools; use rustysynth::{MidiFile, MidiFileSequencer, SoundFont, Synthesizer, SynthesizerSettings}; /// MIDI audio asset #[derive(Asset, TypePath)] pub struct MidiAudio { /// MIDI file data pub midi: Vec, } /// AssetLoader for MIDI files (.mid/.midi) #[derive(Default, Debug)] pub struct MidiAssetLoader; impl AssetLoader for MidiAssetLoader { type Asset = MidiAudio; type Settings = (); type Error = io::Error; async fn load<'a>( &'a self, reader: &'a mut Reader<'_>, _settings: &'a Self::Settings, _load_context: &'a mut LoadContext<'_>, ) -> Result { let mut bytes = vec![]; reader.read_to_end(&mut bytes).await?; Ok(MidiAudio { midi: bytes }) } } /// Decoder for MIDI file playback pub struct MidiDecoder { sample_rate: usize, stream: Receiver, } impl MidiDecoder { /// Construct and begin a new MIDI sequencer with the given MIDI data and soundfont. /// /// The sequencer will push at most 1 second's worth of audio ahead, allowing the decoder to /// be paused without endlessly backing up data forever. pub fn new(midi: Vec, soundfont: Arc) -> Self { let mut midi = Cursor::new(midi); let sample_rate = 44100_usize; let (tx, rx) = async_channel::bounded::(sample_rate * 2); AsyncComputeTaskPool::get() .spawn(async move { let midi = Arc::new(MidiFile::new(&mut midi).expect("Failed to read midi file.")); let settings = SynthesizerSettings::new(sample_rate as i32); let synthesizer = Synthesizer::new(&soundfont, &settings).expect("Failed to create synthesizer."); let mut sequencer = MidiFileSequencer::new(synthesizer); sequencer.play(&midi, true); let mut left: Vec = vec![0_f32; sample_rate]; let mut right: Vec = vec![0_f32; sample_rate]; while !sequencer.end_of_sequence() { sequencer.render(&mut left, &mut right); for value in left.iter().interleave(right.iter()) { if let Err(e) = tx.send(*value).await { error!("{e}"); }; } } tx.close(); }) .detach(); Self { sample_rate, stream: rx, } } } impl Iterator for MidiDecoder { type Item = f32; fn next(&mut self) -> Option { match self.stream.try_recv() { Ok(value) => Some(value), Err(e) => match e { TryRecvError::Empty => Some(0.0), TryRecvError::Closed => None, }, } } } impl Source for MidiDecoder { fn current_frame_len(&self) -> Option { None } fn channels(&self) -> u16 { 2 } fn sample_rate(&self) -> u32 { self.sample_rate as u32 } fn total_duration(&self) -> Option { None } } impl Decodable for MidiAudio { type Decoder = MidiDecoder; type DecoderItem = ::Item; fn decoder(&self) -> Self::Decoder { MidiDecoder::new(self.midi.clone(), crate::SOUNDFONT.get().unwrap().clone()) } }