@@ -60,6 +60,86 @@ class MidiEvent:
6060 device : int = dataclasses .field (compare = False , default = 0 )
6161
6262
63+ def to_mido (self ) -> typing .Optional [typing .Union [mido .Message , mido .MetaMessage ]]:
64+
65+ """Convert this event to a mido.Message, or None if it's an internal type (like OSC)."""
66+
67+ if self .message_type in ('note_on' , 'note_off' ):
68+ return mido .Message (
69+ self .message_type ,
70+ channel = self .channel ,
71+ note = self .note ,
72+ velocity = self .velocity
73+ )
74+
75+ if self .message_type == 'control_change' :
76+ return mido .Message (
77+ 'control_change' ,
78+ channel = self .channel ,
79+ control = self .control ,
80+ value = self .value
81+ )
82+
83+ if self .message_type == 'pitchwheel' :
84+ return mido .Message (
85+ 'pitchwheel' ,
86+ channel = self .channel ,
87+ pitch = self .value
88+ )
89+
90+ if self .message_type == 'program_change' :
91+ return mido .Message (
92+ 'program_change' ,
93+ channel = self .channel ,
94+ program = self .value
95+ )
96+
97+ if self .message_type == 'sysex' :
98+ return mido .Message (
99+ 'sysex' ,
100+ data = self .data if self .data is not None else b''
101+ )
102+
103+ return None
104+
105+
106+ @classmethod
107+ def from_mido (cls , pulse : int , msg : typing .Union [mido .Message , mido .MetaMessage ], device : int = 0 ) -> "MidiEvent" :
108+
109+ """Convert a mido.Message to a MidiEvent."""
110+
111+ if msg .type == 'pitchwheel' :
112+ return cls (
113+ pulse = pulse ,
114+ message_type = 'pitchwheel' ,
115+ channel = msg .channel ,
116+ value = msg .pitch ,
117+ device = device ,
118+ )
119+
120+ if msg .type == 'control_change' :
121+ return cls (
122+ pulse = pulse ,
123+ message_type = 'control_change' ,
124+ channel = msg .channel ,
125+ control = msg .control ,
126+ value = msg .value ,
127+ device = device ,
128+ )
129+
130+ return cls (
131+ pulse = pulse ,
132+ message_type = msg .type ,
133+ channel = getattr (msg , 'channel' , 0 ),
134+ value = getattr (msg , 'value' , 0 ),
135+ note = getattr (msg , 'note' , 0 ),
136+ velocity = getattr (msg , 'velocity' , 0 ),
137+ data = getattr (msg , 'data' , None ),
138+ control = getattr (msg , 'control' , 0 ),
139+ device = device ,
140+ )
141+
142+
63143@dataclasses .dataclass
64144class ScheduledPattern :
65145
@@ -571,36 +651,6 @@ def _on_midi_input (self, message: typing.Any, device_idx: int = 0) -> None:
571651 self ._forward_buffer .append ((self .pulse_count , out_msg ))
572652
573653
574- def _msg_to_midi_event (self , pulse : int , msg : typing .Any ) -> MidiEvent :
575-
576- """Convert a mido.Message to a MidiEvent at the given pulse.
577-
578- Used to inject queued CC forwards into the event heap.
579- """
580-
581- if msg .type == 'pitchwheel' :
582- return MidiEvent (
583- pulse = pulse ,
584- message_type = 'pitchwheel' ,
585- channel = msg .channel ,
586- value = msg .pitch ,
587- )
588- elif msg .type == 'control_change' :
589- return MidiEvent (
590- pulse = pulse ,
591- message_type = 'control_change' ,
592- channel = msg .channel ,
593- control = msg .control ,
594- value = msg .value ,
595- )
596- else :
597- return MidiEvent (
598- pulse = pulse ,
599- message_type = msg .type ,
600- channel = getattr (msg , 'channel' , 0 ),
601- value = getattr (msg , 'value' , 0 ),
602- )
603-
604654
605655 def _estimate_bpm (self , tick_time : float ) -> None :
606656
@@ -1280,7 +1330,7 @@ async def _process_pulse (self, pulse: int) -> None:
12801330 # while the callback thread calls append().
12811331 while self ._forward_buffer :
12821332 fwd_pulse , fwd_msg = self ._forward_buffer .popleft ()
1283- heapq .heappush (self .event_queue , self . _msg_to_midi_event (fwd_pulse , fwd_msg ))
1333+ heapq .heappush (self .event_queue , MidiEvent . from_mido (fwd_pulse , fwd_msg ))
12841334
12851335 while self .event_queue and self .event_queue [0 ].pulse <= pulse :
12861336
@@ -1298,21 +1348,9 @@ async def _process_pulse (self, pulse: int) -> None:
12981348
12991349 if self .recording and event .message_type != 'osc' :
13001350
1301- if event .message_type in ('note_on' , 'note_off' ):
1302- self ._record_event (event .pulse , mido .Message (event .message_type , channel = event .channel , note = event .note , velocity = event .velocity ))
1303-
1304- elif event .message_type == 'control_change' :
1305- self ._record_event (event .pulse , mido .Message ('control_change' , channel = event .channel , control = event .control , value = event .value ))
1306-
1307- elif event .message_type == 'pitchwheel' :
1308- self ._record_event (event .pulse , mido .Message ('pitchwheel' , channel = event .channel , pitch = event .value ))
1309-
1310- elif event .message_type == 'program_change' :
1311- self ._record_event (event .pulse , mido .Message ('program_change' , channel = event .channel , program = event .value ))
1312-
1313- elif event .message_type == 'sysex' :
1314- raw = event .data if event .data is not None else b''
1315- self ._record_event (event .pulse , mido .Message ('sysex' , data = raw ))
1351+ mido_msg = event .to_mido ()
1352+ if mido_msg is not None :
1353+ self ._record_event (event .pulse , mido_msg )
13161354
13171355
13181356 async def _stop_all_active_notes (self ) -> None :
@@ -1343,49 +1381,14 @@ def _send_midi (self, event: MidiEvent) -> None:
13431381
13441382 try :
13451383
1346- if event .message_type in ('note_on' , 'note_off' ):
1347- msg = mido .Message (
1348- event .message_type ,
1349- channel = event .channel ,
1350- note = event .note ,
1351- velocity = event .velocity
1352- )
1353-
1354- elif event .message_type == 'control_change' :
1355- msg = mido .Message (
1356- 'control_change' ,
1357- channel = event .channel ,
1358- control = event .control ,
1359- value = event .value
1360- )
1361-
1362- elif event .message_type == 'pitchwheel' :
1363- msg = mido .Message (
1364- 'pitchwheel' ,
1365- channel = event .channel ,
1366- pitch = event .value
1367- )
1368-
1369- elif event .message_type == 'program_change' :
1370- msg = mido .Message (
1371- 'program_change' ,
1372- channel = event .channel ,
1373- program = event .value
1374- )
1375-
1376- elif event .message_type == 'sysex' :
1377- msg = mido .Message (
1378- 'sysex' ,
1379- data = event .data if event .data is not None else b''
1380- )
1381-
1382- elif event .message_type == 'osc' :
1384+ if event .message_type == 'osc' :
13831385 if self .osc_server is not None :
13841386 address , args = event .data
13851387 self .osc_server .send (address , * args )
13861388 return
13871389
1388- else :
1390+ msg = event .to_mido ()
1391+ if msg is None :
13891392 return
13901393
13911394 port .send (msg )
0 commit comments