11use bevy:: prelude:: * ;
22use bevy_midi:: prelude:: * ;
33
4- use processing_core:: error:: Result ;
4+ use processing_core:: app_mut;
5+ use processing_core:: error:: { self , Result } ;
56
67pub struct MidiPlugin ;
78
9+ pub const NOTE_ON : u8 = 0b1001_0000 ;
10+ pub const NOTE_OFF : u8 = 0b1000_0000 ;
11+
812impl Plugin for MidiPlugin {
913 fn build ( & self , app : & mut App ) {
1014 // TODO: Update `bevy_midi` to treat connections as entities
@@ -18,10 +22,13 @@ impl Plugin for MidiPlugin {
1822}
1923
2024pub fn connect ( In ( port) : In < usize > , output : Res < MidiOutput > ) -> Result < ( ) > {
21- if let Some ( ( _, port) ) = output. ports ( ) . get ( port) {
22- output. connect ( port. clone ( ) ) ;
25+ match output. ports ( ) . get ( port) {
26+ Some ( ( _, p) ) => {
27+ output. connect ( p. clone ( ) ) ;
28+ Ok ( ( ) )
29+ }
30+ None => Err ( error:: ProcessingError :: MidiPortNotFound ( port) ) ,
2331 }
24- Ok ( ( ) )
2532}
2633
2734pub fn disconnect ( output : Res < MidiOutput > ) -> Result < ( ) > {
@@ -34,12 +41,69 @@ pub fn refresh_ports(output: Res<MidiOutput>) -> Result<()> {
3441 Ok ( ( ) )
3542}
3643
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+
3753pub fn play_notes ( In ( ( note, duration) ) : In < ( u8 , u64 ) > , output : Res < MidiOutput > ) -> Result < ( ) > {
38- output. send ( [ 0b1001_0000 , note, 127 ] . into ( ) ) ; // Note on, channel 1, max velocity
54+ output. send ( [ NOTE_ON , note, 127 ] . into ( ) ) ; // Note on, channel 1, max velocity
3955
4056 std:: thread:: sleep ( std:: time:: Duration :: from_millis ( duration) ) ;
4157
42- output. send ( [ 0b1000_0000 , note, 127 ] . into ( ) ) ; // Note on , channel 1, max velocity
58+ output. send ( [ NOTE_OFF , note, 127 ] . into ( ) ) ; // Note off , channel 1, max velocity
4359
4460 Ok ( ( ) )
4561}
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