assets.rs
1 use bevy::asset::{io::Reader, AssetLoader, LoadContext}; 2 #[cfg(feature = "bevy_audio")] 3 use bevy::prelude::*; 4 use itertools::Itertools; 5 use rustysynth::{MidiFile, MidiFileSequencer, SoundFont, Synthesizer, SynthesizerSettings}; 6 #[cfg(feature = "kira")] 7 use std::future::Future; 8 use std::{ 9 io::{self, Cursor}, 10 sync::Arc, 11 time::Duration, 12 }; 13 14 use crate::SOUNDFONT; 15 16 /// Represents a single MIDI note in a sequence 17 #[derive(Clone, Debug)] 18 pub struct MidiNote { 19 /// Channel to play the note on 20 pub channel: i32, 21 /// Preset (instrument) to play the note with (see GM spec.) 22 pub preset: i32, 23 /// Bank to play note with 24 pub bank: i32, 25 /// Key to play (60 is middle C) 26 pub key: i32, 27 /// Velocity to play note at 28 pub velocity: i32, 29 /// Duration to play note for 30 pub duration: Duration, 31 } 32 33 impl Default for MidiNote { 34 fn default() -> Self { 35 Self { 36 channel: 0, 37 preset: 0, 38 bank: 0, 39 key: 60, 40 velocity: 100, 41 duration: Duration::from_secs(1), 42 } 43 } 44 } 45 46 /// AssetLoader for MIDI files (.mid/.midi) 47 #[derive(Default, Debug)] 48 pub struct MidiAssetLoader; 49 50 /// Decoder for MIDI file playback 51 pub struct MidiFileDecoder { 52 sample_rate: usize, 53 data: Vec<f32>, 54 #[cfg(feature = "bevy_audio")] 55 index: usize, 56 } 57 58 impl MidiFileDecoder { 59 /// Construct and render a MIDI sequence with the given MIDI data and soundfont. 60 pub fn new(midi_data: Vec<u8>, soundfont: Arc<SoundFont>) -> Self { 61 let sample_rate = 44100_usize; 62 let settings = SynthesizerSettings::new(sample_rate as i32); 63 let synthesizer = 64 Synthesizer::new(&soundfont, &settings).expect("Failed to create synthesizer."); 65 66 let mut data = Vec::new(); 67 let mut sequencer = MidiFileSequencer::new(synthesizer); 68 let mut midi_data = Cursor::new(midi_data); 69 let midi = Arc::new(MidiFile::new(&mut midi_data).expect("Failed to read midi file.")); 70 sequencer.play(&midi, false); 71 let mut left: Vec<f32> = vec![0_f32; sample_rate]; 72 let mut right: Vec<f32> = vec![0_f32; sample_rate]; 73 while !sequencer.end_of_sequence() { 74 sequencer.render(&mut left, &mut right); 75 for value in left.iter().interleave(right.iter()) { 76 data.push(*value); 77 } 78 } 79 Self { 80 sample_rate, 81 data, 82 #[cfg(feature = "bevy_audio")] 83 index: 0, 84 } 85 } 86 87 /// Render a MIDI sequence with the given soundfont. 88 pub fn new_sequence(midi_sequence: Vec<MidiNote>, soundfont: Arc<SoundFont>) -> Self { 89 let sample_rate = 44100_usize; 90 let settings = SynthesizerSettings::new(sample_rate as i32); 91 let mut synthesizer = 92 Synthesizer::new(&soundfont, &settings).expect("Failed to create synthesizer."); 93 94 let mut data = Vec::new(); 95 96 for MidiNote { 97 channel, 98 preset, 99 bank, 100 key, 101 velocity, 102 duration, 103 } in midi_sequence.iter() 104 { 105 synthesizer.process_midi_message(*channel, 0xB0, 0x00, *bank); 106 synthesizer.process_midi_message(*channel, 0xC0, *preset, 0); 107 synthesizer.note_on(*channel, *key, *velocity); 108 let note_length = (sample_rate as f32 * duration.as_secs_f32()) as usize; 109 let mut left: Vec<f32> = vec![0_f32; note_length]; 110 let mut right: Vec<f32> = vec![0_f32; note_length]; 111 for (left, right) in left 112 .chunks_mut(sample_rate) 113 .zip(right.chunks_mut(sample_rate)) 114 { 115 synthesizer.render(left, right); 116 for value in left.iter().interleave(right.iter()) { 117 data.push(*value); 118 } 119 } 120 synthesizer.note_off(*channel, *key); 121 } 122 Self { 123 sample_rate, 124 data, 125 #[cfg(feature = "bevy_audio")] 126 index: 0, 127 } 128 } 129 } 130 131 #[cfg(all(feature = "bevy_audio", not(feature = "kira")))] 132 /// Asset containing MIDI file data to be used as a `Decodable` audio source 133 #[derive(Asset, TypePath, Debug)] 134 pub struct MidiAudio(Vec<u8>); 135 136 #[cfg(all(feature = "bevy_audio", not(feature = "kira")))] 137 mod bevy_audio { 138 use super::*; 139 use bevy::audio::{Decodable, Source}; 140 141 impl Source for MidiFileDecoder { 142 fn current_frame_len(&self) -> Option<usize> { 143 None 144 } 145 146 fn channels(&self) -> u16 { 147 2 148 } 149 150 fn sample_rate(&self) -> u32 { 151 self.sample_rate as u32 152 } 153 154 fn total_duration(&self) -> Option<std::time::Duration> { 155 None 156 } 157 } 158 159 impl Decodable for MidiAudio { 160 type Decoder = MidiFileDecoder; 161 162 type DecoderItem = <MidiFileDecoder as Iterator>::Item; 163 164 fn decoder(&self) -> Self::Decoder { 165 MidiFileDecoder::new( 166 self.0.clone(), 167 SOUNDFONT.lock().unwrap().as_ref().unwrap().clone(), 168 ) 169 } 170 } 171 172 impl AssetLoader for MidiAssetLoader { 173 type Asset = MidiAudio; 174 175 type Settings = (); 176 177 type Error = io::Error; 178 179 async fn load( 180 &self, 181 reader: &mut dyn Reader, 182 _settings: &Self::Settings, 183 _load_context: &mut LoadContext<'_>, 184 ) -> Result<Self::Asset, Self::Error> { 185 let mut bytes = vec![]; 186 reader.read_to_end(&mut bytes).await?; 187 Ok(MidiAudio(bytes)) 188 } 189 190 fn extensions(&self) -> &[&str] { 191 &["mid", "midi"] 192 } 193 } 194 195 impl Iterator for MidiFileDecoder { 196 type Item = f32; 197 198 fn next(&mut self) -> Option<Self::Item> { 199 let result = self.data.get(self.index).copied(); 200 self.index += 1; 201 result 202 } 203 } 204 } 205 206 #[cfg(all(feature = "kira", not(feature = "bevy_audio")))] 207 /// Extensions For Rendering MIDI Audio 208 pub trait MidiAudioExtensions { 209 /// Renders MIDI audio from orovided data 210 fn from_midi_file(data: Vec<u8>) -> impl Future<Output = Self> + Send; 211 /// Renders MIDI audio from provided note sequence 212 fn from_midi_sequence(sequence: Vec<MidiNote>) -> impl Future<Output = Self> + Send; 213 } 214 215 #[cfg(all(feature = "kira", not(feature = "bevy_audio")))] 216 mod kira { 217 use super::*; 218 use bevy_kira_audio::{ 219 prelude::{Frame, StaticSoundData, StaticSoundSettings}, 220 AudioSource, 221 }; 222 223 impl AssetLoader for MidiAssetLoader { 224 type Asset = AudioSource; 225 226 type Settings = (); 227 228 type Error = io::Error; 229 230 async fn load( 231 &self, 232 reader: &mut dyn Reader, 233 _settings: &Self::Settings, 234 _load_context: &mut LoadContext<'_>, 235 ) -> Result<Self::Asset, Self::Error> { 236 let mut bytes = vec![]; 237 reader.read_to_end(&mut bytes).await?; 238 Ok(AudioSource::from_midi_file(bytes).await) 239 } 240 241 fn extensions(&self) -> &[&str] { 242 &["mid", "midi"] 243 } 244 } 245 246 impl MidiAudioExtensions for AudioSource { 247 async fn from_midi_file(data: Vec<u8>) -> Self { 248 let decoder = 249 MidiFileDecoder::new(data, SOUNDFONT.lock().unwrap().as_ref().unwrap().clone()); 250 let frames = decoder 251 .data 252 .chunks(2) 253 .map(|sample| Frame::new(sample[0], sample[1])) 254 .collect::<Arc<[_]>>(); 255 let sample_rate = decoder.sample_rate as u32; 256 let settings = StaticSoundSettings { 257 ..Default::default() 258 }; 259 AudioSource { 260 sound: StaticSoundData { 261 sample_rate, 262 frames, 263 settings, 264 slice: None, 265 }, 266 } 267 } 268 269 async fn from_midi_sequence(sequence: Vec<MidiNote>) -> Self { 270 let decoder = MidiFileDecoder::new_sequence( 271 sequence, 272 SOUNDFONT.lock().unwrap().as_ref().unwrap().clone(), 273 ); 274 let frames = decoder 275 .data 276 .chunks(2) 277 .map(|sample| Frame::new(sample[0], sample[1])) 278 .collect::<Arc<[_]>>(); 279 let sample_rate = decoder.sample_rate as u32; 280 let settings = StaticSoundSettings { 281 ..Default::default() 282 }; 283 AudioSource { 284 sound: StaticSoundData { 285 sample_rate, 286 frames, 287 settings, 288 slice: None, 289 }, 290 } 291 } 292 } 293 }