|
1 | 1 | use bevy::prelude::*; |
2 | 2 | use bevy_midi::prelude::*; |
3 | 3 |
|
| 4 | +use processing_core::app_mut; |
| 5 | +use processing_core::error::{self, Result}; |
| 6 | + |
4 | 7 | pub struct MidiPlugin; |
5 | 8 |
|
| 9 | +pub const NOTE_ON: u8 = 0b1001_0000; |
| 10 | +pub const NOTE_OFF: u8 = 0b1000_0000; |
| 11 | + |
6 | 12 | impl Plugin for MidiPlugin { |
7 | 13 | fn build(&self, app: &mut App) { |
| 14 | + // TODO: Update `bevy_midi` to treat connections as entities |
| 15 | + // in order to support hot-plugging |
8 | 16 | app.insert_resource(MidiOutputSettings { |
9 | | - port_name: "output", |
10 | | - }) |
11 | | - .add_plugins(MidiOutputPlugin); |
| 17 | + port_name: "libprocessing output", |
| 18 | + }); |
| 19 | + |
| 20 | + app.add_plugins(MidiOutputPlugin); |
| 21 | + } |
| 22 | +} |
| 23 | + |
| 24 | +pub fn connect(In(port): In<usize>, output: Res<MidiOutput>) -> Result<()> { |
| 25 | + match output.ports().get(port) { |
| 26 | + Some((_, p)) => { |
| 27 | + output.connect(p.clone()); |
| 28 | + Ok(()) |
| 29 | + } |
| 30 | + None => Err(error::ProcessingError::MidiPortNotFound(port)), |
12 | 31 | } |
13 | 32 | } |
14 | 33 |
|
15 | | -pub fn connect(_port: usize) { |
16 | | - // we need to work with the ECS |
17 | | - // do we pass a MidiCommand to Bevy? |
| 34 | +pub fn disconnect(output: Res<MidiOutput>) -> Result<()> { |
| 35 | + output.disconnect(); |
| 36 | + Ok(()) |
18 | 37 | } |
19 | 38 |
|
20 | | -pub fn disconnect() {} |
21 | | -pub fn refresh_ports() {} |
| 39 | +pub fn refresh_ports(output: Res<MidiOutput>) -> Result<()> { |
| 40 | + output.refresh_ports(); |
| 41 | + Ok(()) |
| 42 | +} |
| 43 | + |
| 44 | +pub fn list_ports(output: Res<MidiOutput>) -> Result<Vec<String>> { |
| 45 | + Ok(output |
| 46 | + .ports() |
| 47 | + .iter() |
| 48 | + .enumerate() |
| 49 | + .map(|(i, (name, _))| format!("{}: {}", i, name)) |
| 50 | + .collect()) |
| 51 | +} |
| 52 | + |
| 53 | +pub fn play_notes(In((note, duration)): In<(u8, u64)>, output: Res<MidiOutput>) -> Result<()> { |
| 54 | + output.send([NOTE_ON, note, 127].into()); // Note on, channel 1, max velocity |
| 55 | + |
| 56 | + std::thread::sleep(std::time::Duration::from_millis(duration)); |
| 57 | + |
| 58 | + output.send([NOTE_OFF, note, 127].into()); // Note off, channel 1, max velocity |
22 | 59 |
|
23 | | -pub fn play_notes() {} |
| 60 | + Ok(()) |
| 61 | +} |
| 62 | + |
| 63 | +#[cfg(not(target_arch = "wasm32"))] |
| 64 | +pub fn midi_refresh_ports() -> error::Result<()> { |
| 65 | + app_mut(|app| { |
| 66 | + let world = app.world_mut(); |
| 67 | + world.run_system_cached(refresh_ports).unwrap() |
| 68 | + })?; |
| 69 | + // run the `PreUpdate` schedule to let `bevy_midi` process it's callbacks and update the ports list |
| 70 | + // TODO: race condition is still present here in theory |
| 71 | + app_mut(|app| { |
| 72 | + app.world_mut().run_schedule(PreUpdate); |
| 73 | + Ok(()) |
| 74 | + }) |
| 75 | +} |
| 76 | + |
| 77 | +#[cfg(not(target_arch = "wasm32"))] |
| 78 | +pub fn midi_list_ports() -> error::Result<Vec<String>> { |
| 79 | + app_mut(|app| { |
| 80 | + let world = app.world_mut(); |
| 81 | + world.run_system_cached(list_ports).unwrap() |
| 82 | + }) |
| 83 | +} |
| 84 | + |
| 85 | +#[cfg(not(target_arch = "wasm32"))] |
| 86 | +pub fn midi_connect(port: usize) -> error::Result<()> { |
| 87 | + app_mut(|app| { |
| 88 | + let world = app.world_mut(); |
| 89 | + world.run_system_cached_with(connect, port).unwrap() |
| 90 | + }) |
| 91 | +} |
| 92 | + |
| 93 | +#[cfg(not(target_arch = "wasm32"))] |
| 94 | +pub fn midi_disconnect() -> error::Result<()> { |
| 95 | + app_mut(|app| { |
| 96 | + let world = app.world_mut(); |
| 97 | + world.run_system_cached(disconnect).unwrap() |
| 98 | + }) |
| 99 | +} |
| 100 | + |
| 101 | +#[cfg(not(target_arch = "wasm32"))] |
| 102 | +pub fn midi_play_notes(note: u8, duration: u64) -> error::Result<()> { |
| 103 | + app_mut(|app| { |
| 104 | + let world = app.world_mut(); |
| 105 | + world |
| 106 | + .run_system_cached_with(play_notes, (note, duration)) |
| 107 | + .unwrap() |
| 108 | + }) |
| 109 | +} |
0 commit comments