11use caw_core:: { Buf , Sig , SigShared , SigT , Zip , sig_shared} ;
22use caw_keyboard:: Note ;
3- use caw_midi:: { MidiController01 , MidiKeyPress , MidiMessages , MidiMessagesT } ;
4- use caw_midi_udp:: { MidiLiveUdp , MidiLiveUdpChannel } ;
3+ use caw_midi:: {
4+ MidiChannel , MidiController01 , MidiEventsT , MidiKeyPress , MidiMessages ,
5+ MidiMessagesT ,
6+ } ;
7+ use caw_midi_udp:: MidiLiveUdp ;
58use lazy_static:: lazy_static;
9+ use midly:: num:: { u4, u7} ;
610use std:: {
711 collections:: HashMap ,
812 net:: SocketAddr ,
913 process:: { Child , Command } ,
1014 sync:: Mutex ,
1115} ;
1216
13- // For now this library only supports midi channel 0
14- const CHANNEL : u8 = 0 ;
17+ struct ChannelAllocator {
18+ next_channel : Option < u4 > ,
19+ next_controller_index_by_channel : HashMap < u4 , Option < u7 > > ,
20+ }
21+
22+ impl ChannelAllocator {
23+ fn new ( ) -> Self {
24+ Self {
25+ next_channel : Some ( 0 . into ( ) ) ,
26+ next_controller_index_by_channel : HashMap :: new ( ) ,
27+ }
28+ }
29+
30+ fn alloc_channel ( & mut self ) -> u4 {
31+ let channel = self . next_channel . expect ( "Can't allocate MIDI channel because all MIDI channels are in use already." ) ;
32+ self . next_channel = if channel == u4:: max_value ( ) {
33+ None
34+ } else {
35+ Some ( ( u8:: from ( channel) + 1 ) . into ( ) )
36+ } ;
37+ channel
38+ }
39+
40+ fn alloc_controller ( & mut self , channel : u4 ) -> u7 {
41+ if let Some ( next_channel) = self . next_channel {
42+ assert ! (
43+ channel < next_channel,
44+ "Attempted to allocate controller on unallocated channel."
45+ ) ;
46+ }
47+ let next_controller = self
48+ . next_controller_index_by_channel
49+ . entry ( channel)
50+ . or_insert_with ( || Some ( 0 . into ( ) ) ) ;
51+ if let Some ( controller) = * next_controller {
52+ * next_controller = if controller == u7:: max_value ( ) {
53+ None
54+ } else {
55+ Some ( ( u8:: from ( controller) + 1 ) . into ( ) )
56+ } ;
57+ controller
58+ } else {
59+ panic ! (
60+ "Can't allocate MIDI controller because all MIDI controllers on channel {} are in use already." ,
61+ channel
62+ ) ;
63+ }
64+ }
65+ }
1566
1667lazy_static ! {
1768 // A stream of MIDI events received by the UDP/IP server. It owns the UDP/IP server.
18- static ref SIG : Sig <SigShared <MidiLiveUdpChannel >> =
19- sig_shared( MidiLiveUdp :: new_unspecified( ) . unwrap( ) . channel ( CHANNEL ) . 0 ) ;
69+ static ref SIG : Sig <SigShared <MidiLiveUdp >> =
70+ sig_shared( MidiLiveUdp :: new_unspecified( ) . unwrap( ) ) ;
2071
2172 // Used to prevent multiple windows from opening at the same time with the same name. Note that
2273 // when using with evcxr this seems to get cleared when a cell is recomputed, but this is still
@@ -32,36 +83,29 @@ lazy_static! {
3283 static ref COMPUTER_KEYBOARDS_BY_TITLE : Mutex <HashMap <String , Sig <SigShared <ComputerKeyboard >>>> =
3384 Mutex :: new( HashMap :: new( ) ) ;
3485
35- /// MIDI controller indices are allocated dynamically and this global tracks the value of the
36- /// next controller index to allocate.
37- static ref NEXT_CONTROLLER_INDEX : Mutex <u8 > = Mutex :: new( 0 ) ;
86+ static ref CHANNEL_ALLOCATOR : Mutex <ChannelAllocator > = Mutex :: new( ChannelAllocator :: new( ) ) ;
3887}
3988
4089/// Returns the IP address of the server that will receive MIDI events.
4190fn sig_server_local_socket_address ( ) -> SocketAddr {
42- SIG . 0 . with_inner ( |midi_live_udp_channel | {
43- midi_live_udp_channel . server . local_socket_address ( ) . unwrap ( )
91+ SIG . 0 . with_inner ( |midi_live_udp | {
92+ midi_live_udp . local_socket_address ( ) . unwrap ( )
4493 } )
4594}
4695
47- /// Allocates and returns unique MIDI controller value.
48- fn alloc_controller ( ) -> u8 {
49- let mut next_controller_index = NEXT_CONTROLLER_INDEX . lock ( ) . unwrap ( ) ;
50- let controller_index = * next_controller_index;
51- * next_controller_index += 1 ;
52- controller_index
53- }
54-
5596const PROGRAM_NAME : & str = "caw_midi_udp_widgets_app" ;
5697
98+ type MidiChannelUdp = MidiChannel < SigShared < MidiLiveUdp > > ;
99+
57100struct Widget {
58101 title : String ,
59102 process : Option < Child > ,
60103}
61104
62105pub struct Button {
63106 widget : Widget ,
64- sig : Sig < MidiKeyPress < SigShared < MidiLiveUdpChannel > > > ,
107+ sig : Sig < MidiKeyPress < MidiChannelUdp > > ,
108+ channel_index : u4 ,
65109}
66110
67111impl Button {
@@ -70,14 +114,18 @@ impl Button {
70114 if let Some ( button) = buttons_by_title. get ( & title) {
71115 button. clone ( )
72116 } else {
117+ let channel_index =
118+ CHANNEL_ALLOCATOR . lock ( ) . unwrap ( ) . alloc_channel ( ) ;
119+ let channel = SIG . clone ( ) . channel ( channel_index. into ( ) ) ;
73120 // The choice of note here is arbitrary.
74- let sig = Sig ( SIG . clone ( ) . key_press ( Note :: default ( ) ) ) ;
121+ let sig = Sig ( channel . key_press ( Note :: default ( ) ) ) ;
75122 let mut s = Self {
76123 widget : Widget {
77124 title : title. clone ( ) ,
78125 process : None ,
79126 } ,
80127 sig,
128+ channel_index,
81129 } ;
82130 let child = match s. command ( ) . spawn ( ) {
83131 Ok ( child) => child,
@@ -100,7 +148,7 @@ impl Button {
100148 "--server={}" ,
101149 sig_server_local_socket_address( ) . to_string( )
102150 ) ,
103- format!( "--channel={}" , CHANNEL ) ,
151+ format!( "--channel={}" , self . channel_index ) ,
104152 format!( "--title={}" , self . widget. title. clone( ) ) ,
105153 "button" . to_string( ) ,
106154 ] ;
@@ -145,7 +193,8 @@ pub struct Knob {
145193 controller : u8 ,
146194 initial_value_01 : f32 ,
147195 sensitivity : f32 ,
148- sig : Sig < MidiController01 < SigShared < MidiLiveUdpChannel > > > ,
196+ sig : Sig < MidiController01 < MidiChannelUdp > > ,
197+ channel_index : u4 ,
149198}
150199
151200impl Knob {
@@ -158,9 +207,11 @@ impl Knob {
158207 if let Some ( knob) = knobs_by_title. get ( & title) {
159208 knob. clone ( )
160209 } else {
161- let controller = alloc_controller ( ) ;
162- let sig = SIG
163- . clone ( )
210+ let mut allocator = CHANNEL_ALLOCATOR . lock ( ) . unwrap ( ) ;
211+ let channel_index = allocator. alloc_channel ( ) ;
212+ let controller = allocator. alloc_controller ( channel_index) . into ( ) ;
213+ let channel = SIG . clone ( ) . channel ( channel_index. into ( ) ) ;
214+ let sig = channel
164215 . controllers ( )
165216 . get_with_initial_value_01 ( controller, initial_value_01) ;
166217 let mut s = Self {
@@ -172,6 +223,7 @@ impl Knob {
172223 initial_value_01,
173224 sensitivity,
174225 sig,
226+ channel_index,
175227 } ;
176228 let child = match s. command ( ) . spawn ( ) {
177229 Ok ( child) => child,
@@ -194,7 +246,7 @@ impl Knob {
194246 "--server={}" ,
195247 sig_server_local_socket_address( ) . to_string( )
196248 ) ,
197- format!( "--channel={}" , CHANNEL ) ,
249+ format!( "--channel={}" , self . channel_index ) ,
198250 format!( "--title={}" , self . widget. title. clone( ) ) ,
199251 "knob" . to_string( ) ,
200252 format!( "--controller={}" , self . controller) ,
@@ -247,10 +299,11 @@ pub struct Xy {
247299 controller_y : u8 ,
248300 sig : Sig <
249301 Zip <
250- MidiController01 < SigShared < MidiLiveUdpChannel > > ,
251- MidiController01 < SigShared < MidiLiveUdpChannel > > ,
302+ MidiController01 < SigShared < MidiChannelUdp > > ,
303+ MidiController01 < SigShared < MidiChannelUdp > > ,
252304 > ,
253305 > ,
306+ channel_index : u4 ,
254307}
255308
256309impl Xy {
@@ -259,13 +312,16 @@ impl Xy {
259312 if let Some ( xy) = xys_by_title. get ( & title) {
260313 xy. clone ( )
261314 } else {
262- let controller_x = alloc_controller ( ) ;
263- let controller_y = alloc_controller ( ) ;
264- let sig_x = SIG
315+ let mut allocator = CHANNEL_ALLOCATOR . lock ( ) . unwrap ( ) ;
316+ let channel_index = allocator. alloc_channel ( ) ;
317+ let controller_x = allocator. alloc_controller ( channel_index) . into ( ) ;
318+ let controller_y = allocator. alloc_controller ( channel_index) . into ( ) ;
319+ let channel = SIG . clone ( ) . channel ( channel_index. into ( ) ) . shared ( ) ;
320+ let sig_x = channel
265321 . clone ( )
266322 . controllers ( )
267323 . get_with_initial_value_01 ( controller_x, 0.5 ) ;
268- let sig_y = SIG
324+ let sig_y = channel
269325 . clone ( )
270326 . controllers ( )
271327 . get_with_initial_value_01 ( controller_y, 0.5 ) ;
@@ -278,6 +334,7 @@ impl Xy {
278334 controller_x,
279335 controller_y,
280336 sig,
337+ channel_index,
281338 } ;
282339 let child = match s. command ( ) . spawn ( ) {
283340 Ok ( child) => child,
@@ -300,7 +357,7 @@ impl Xy {
300357 "--server={}" ,
301358 sig_server_local_socket_address( ) . to_string( )
302359 ) ,
303- format!( "--channel={}" , CHANNEL ) ,
360+ format!( "--channel={}" , self . channel_index ) ,
304361 format!( "--title={}" , self . widget. title. clone( ) ) ,
305362 "xy" . to_string( ) ,
306363 format!( "--controller-x={}" , self . controller_x) ,
@@ -345,7 +402,8 @@ pub use xy_builder::xy;
345402pub struct ComputerKeyboard {
346403 widget : Widget ,
347404 start_note : Note ,
348- sig : Sig < SigShared < MidiLiveUdpChannel > > ,
405+ sig : Sig < MidiChannelUdp > ,
406+ channel_index : u4 ,
349407}
350408
351409impl ComputerKeyboard {
@@ -356,14 +414,17 @@ impl ComputerKeyboard {
356414 {
357415 computer_keyboard. clone ( )
358416 } else {
359- let sig = SIG . clone ( ) ;
417+ let mut allocator = CHANNEL_ALLOCATOR . lock ( ) . unwrap ( ) ;
418+ let channel_index = allocator. alloc_channel ( ) ;
419+ let sig = SIG . clone ( ) . channel ( channel_index. into ( ) ) ;
360420 let mut s = Self {
361421 widget : Widget {
362422 title : title. clone ( ) ,
363423 process : None ,
364424 } ,
365425 start_note,
366426 sig,
427+ channel_index,
367428 } ;
368429 let child = match s. command ( ) . spawn ( ) {
369430 Ok ( child) => child,
@@ -386,7 +447,7 @@ impl ComputerKeyboard {
386447 "--server={}" ,
387448 sig_server_local_socket_address( ) . to_string( )
388449 ) ,
389- format!( "--channel={}" , CHANNEL ) ,
450+ format!( "--channel={}" , self . channel_index ) ,
390451 format!( "--title={}" , self . widget. title. clone( ) ) ,
391452 "computer-keyboard" . to_string( ) ,
392453 format!( "--start-note={}" , self . start_note) ,
0 commit comments