0
# MIDI Operations
1
2
MIDI sequencing, playback, file I/O, and FluidSynth integration for real-time audio synthesis and MIDI file processing. These modules enable mingus to interface with MIDI devices, generate MIDI files, and provide audio output through software synthesizers.
3
4
## Capabilities
5
6
### MIDI Sequencer
7
8
Core MIDI sequencer for real-time playback and MIDI event handling with observer pattern support.
9
10
```python { .api }
11
class Sequencer:
12
"""Main MIDI sequencer for real-time playback."""
13
14
def __init__(self):
15
"""Create Sequencer object."""
16
17
def init(self) -> None:
18
"""Initialize sequencer for playback."""
19
20
def play_Note(self, note: Note, channel: int = 1, velocity: int = 100) -> None:
21
"""
22
Play Note object.
23
24
Parameters:
25
- note: Note object to play
26
- channel: MIDI channel (1-16)
27
- velocity: MIDI velocity (0-127)
28
"""
29
30
def stop_Note(self, note: Note, channel: int = 1) -> None:
31
"""
32
Stop Note object.
33
34
Parameters:
35
- note: Note object to stop
36
- channel: MIDI channel (1-16)
37
"""
38
39
def play_NoteContainer(self, nc: NoteContainer, channel: int = 1, velocity: int = 100) -> None:
40
"""
41
Play NoteContainer (chord).
42
43
Parameters:
44
- nc: NoteContainer to play
45
- channel: MIDI channel
46
- velocity: MIDI velocity
47
"""
48
49
def stop_NoteContainer(self, nc: NoteContainer, channel: int = 1) -> None:
50
"""
51
Stop NoteContainer.
52
53
Parameters:
54
- nc: NoteContainer to stop
55
- channel: MIDI channel
56
"""
57
58
def play_Bar(self, bar: Bar, channel: int = 1, bpm: int = 120) -> None:
59
"""
60
Play Bar with timing.
61
62
Parameters:
63
- bar: Bar object to play
64
- channel: MIDI channel
65
- bpm: Beats per minute tempo
66
"""
67
68
def play_Track(self, track: Track, channel: int = 1, bpm: int = 120) -> None:
69
"""
70
Play Track.
71
72
Parameters:
73
- track: Track object to play
74
- channel: MIDI channel
75
- bpm: Beats per minute tempo
76
"""
77
78
def play_Composition(self, composition: Composition, channels: List[int] = None, bpm: int = 120) -> None:
79
"""
80
Play Composition with multiple tracks.
81
82
Parameters:
83
- composition: Composition to play
84
- channels: List of MIDI channels for each track
85
- bpm: Beats per minute tempo
86
"""
87
88
def set_instrument(self, channel: int, instr: int, bank: int = 0) -> None:
89
"""
90
Set instrument for channel.
91
92
Parameters:
93
- channel: MIDI channel (1-16)
94
- instr: MIDI instrument number (0-127)
95
- bank: Bank number for instrument selection
96
"""
97
98
def control_change(self, channel: int, control: int, value: int) -> None:
99
"""
100
Send control change message.
101
102
Parameters:
103
- channel: MIDI channel (1-16)
104
- control: Controller number (0-127)
105
- value: Controller value (0-127)
106
"""
107
108
def modulation(self, channel: int, value: int) -> None:
109
"""
110
Set modulation (CC1).
111
112
Parameters:
113
- channel: MIDI channel
114
- value: Modulation amount (0-127)
115
"""
116
117
def main_volume(self, channel: int, value: int) -> None:
118
"""
119
Set main volume (CC7).
120
121
Parameters:
122
- channel: MIDI channel
123
- value: Volume level (0-127)
124
"""
125
126
def pan(self, channel: int, value: int) -> None:
127
"""
128
Set pan position (CC10).
129
130
Parameters:
131
- channel: MIDI channel
132
- value: Pan position (0=left, 64=center, 127=right)
133
"""
134
135
def stop_everything(self) -> None:
136
"""Stop all playing notes and reset sequencer."""
137
138
def sleep(self, seconds: float) -> None:
139
"""
140
Sleep for specified duration.
141
142
Parameters:
143
- seconds: Sleep duration in seconds
144
"""
145
146
def attach(self, observer: 'SequencerObserver') -> None:
147
"""
148
Attach observer for event notifications.
149
150
Parameters:
151
- observer: Observer object to attach
152
"""
153
154
def detach(self, observer: 'SequencerObserver') -> None:
155
"""
156
Detach observer.
157
158
Parameters:
159
- observer: Observer object to detach
160
"""
161
162
class SequencerObserver:
163
"""Observer for sequencer events."""
164
165
def play_int_note_event(self, int_note: int, channel: int, velocity: int) -> None:
166
"""
167
Handle note on event.
168
169
Parameters:
170
- int_note: MIDI note number (0-127)
171
- channel: MIDI channel
172
- velocity: Note velocity
173
"""
174
175
def stop_int_note_event(self, int_note: int, channel: int) -> None:
176
"""
177
Handle note off event.
178
179
Parameters:
180
- int_note: MIDI note number
181
- channel: MIDI channel
182
"""
183
184
def cc_event(self, channel: int, control: int, value: int) -> None:
185
"""
186
Handle control change event.
187
188
Parameters:
189
- channel: MIDI channel
190
- control: Controller number
191
- value: Controller value
192
"""
193
194
def instr_event(self, channel: int, instr: int, bank: int) -> None:
195
"""
196
Handle instrument change event.
197
198
Parameters:
199
- channel: MIDI channel
200
- instr: Instrument number
201
- bank: Bank number
202
"""
203
204
def sleep(self, seconds: float) -> None:
205
"""
206
Handle sleep event.
207
208
Parameters:
209
- seconds: Sleep duration
210
"""
211
```
212
213
### MIDI File Operations
214
215
Functions for importing and exporting MIDI files with mingus musical structures.
216
217
```python { .api }
218
# MIDI file export
219
def write_Note(file: str, note: Note, bpm: int = 120, repeat: int = 0, verbose: bool = False) -> None:
220
"""
221
Export Note to MIDI file.
222
223
Parameters:
224
- file: Output filename
225
- note: Note object to export
226
- bpm: Beats per minute
227
- repeat: Number of repeats
228
- verbose: Print export information
229
"""
230
231
def write_NoteContainer(file: str, notecontainer: NoteContainer, bpm: int = 120, repeat: int = 0, verbose: bool = False) -> None:
232
"""
233
Export NoteContainer to MIDI file.
234
235
Parameters:
236
- file: Output filename
237
- notecontainer: NoteContainer to export
238
- bpm: Beats per minute
239
- repeat: Number of repeats
240
- verbose: Print export information
241
"""
242
243
def write_Bar(file: str, bar: Bar, bpm: int = 120, repeat: int = 0, verbose: bool = False) -> None:
244
"""
245
Export Bar to MIDI file.
246
247
Parameters:
248
- file: Output filename
249
- bar: Bar object to export
250
- bpm: Beats per minute
251
- repeat: Number of repeats
252
- verbose: Print export information
253
"""
254
255
def write_Track(file: str, track: Track, bpm: int = 120, repeat: int = 0, verbose: bool = False) -> None:
256
"""
257
Export Track to MIDI file.
258
259
Parameters:
260
- file: Output filename
261
- track: Track object to export
262
- bpm: Beats per minute
263
- repeat: Number of repeats
264
- verbose: Print export information
265
"""
266
267
def write_Composition(file: str, composition: Composition, bpm: int = 120, repeat: int = 0, verbose: bool = False) -> None:
268
"""
269
Export Composition to MIDI file.
270
271
Parameters:
272
- file: Output filename
273
- composition: Composition to export
274
- bpm: Beats per minute
275
- repeat: Number of repeats
276
- verbose: Print export information
277
"""
278
279
# MIDI file import
280
def MIDI_to_Composition(file: str) -> Composition:
281
"""
282
Import MIDI file to Composition.
283
284
Parameters:
285
- file: MIDI filename to import
286
287
Returns:
288
Composition object containing imported data
289
"""
290
```
291
292
### FluidSynth Integration
293
294
High-level interface to FluidSynth software synthesizer for real-time audio playback.
295
296
```python { .api }
297
def init(sf2: str, driver: str = None, file: str = None) -> bool:
298
"""
299
Initialize FluidSynth with soundfont.
300
301
Parameters:
302
- sf2: Path to SoundFont file (.sf2)
303
- driver: Audio driver to use (auto-detect if None)
304
- file: Output file for rendering (real-time if None)
305
306
Returns:
307
True if initialization successful
308
"""
309
310
def play_Note(note: Note, channel: int = 1, velocity: int = 100) -> None:
311
"""
312
Play Note through FluidSynth.
313
314
Parameters:
315
- note: Note object to play
316
- channel: MIDI channel (1-16)
317
- velocity: Note velocity (0-127)
318
"""
319
320
def stop_Note(note: Note, channel: int = 1) -> None:
321
"""
322
Stop Note.
323
324
Parameters:
325
- note: Note object to stop
326
- channel: MIDI channel
327
"""
328
329
def play_NoteContainer(nc: NoteContainer, channel: int = 1, velocity: int = 100) -> None:
330
"""
331
Play NoteContainer (chord).
332
333
Parameters:
334
- nc: NoteContainer to play
335
- channel: MIDI channel
336
- velocity: Note velocity
337
"""
338
339
def stop_NoteContainer(nc: NoteContainer, channel: int = 1) -> None:
340
"""
341
Stop NoteContainer.
342
343
Parameters:
344
- nc: NoteContainer to stop
345
- channel: MIDI channel
346
"""
347
348
def play_Bar(bar: Bar, channel: int = 1, bpm: int = 120) -> None:
349
"""
350
Play Bar with timing.
351
352
Parameters:
353
- bar: Bar object to play
354
- channel: MIDI channel
355
- bpm: Beats per minute
356
"""
357
358
def play_Track(track: Track, channel: int = 1, bpm: int = 120) -> None:
359
"""
360
Play Track.
361
362
Parameters:
363
- track: Track to play
364
- channel: MIDI channel
365
- bpm: Beats per minute
366
"""
367
368
def play_Composition(composition: Composition, channels: List[int] = None, bpm: int = 120) -> None:
369
"""
370
Play Composition.
371
372
Parameters:
373
- composition: Composition to play
374
- channels: Channel assignments for tracks
375
- bpm: Beats per minute
376
"""
377
378
def set_instrument(channel: int, midi_instr: int, bank: int = 0) -> None:
379
"""
380
Set instrument for channel.
381
382
Parameters:
383
- channel: MIDI channel (1-16)
384
- midi_instr: MIDI instrument number (0-127)
385
- bank: Bank select for instrument
386
"""
387
388
def control_change(channel: int, control: int, value: int) -> None:
389
"""
390
Send control change message.
391
392
Parameters:
393
- channel: MIDI channel
394
- control: Controller number (0-127)
395
- value: Controller value (0-127)
396
"""
397
398
def modulation(channel: int, value: int) -> None:
399
"""
400
Set modulation wheel (CC1).
401
402
Parameters:
403
- channel: MIDI channel
404
- value: Modulation amount (0-127)
405
"""
406
407
def pan(channel: int, value: int) -> None:
408
"""
409
Set pan position (CC10).
410
411
Parameters:
412
- channel: MIDI channel
413
- value: Pan position (0-127, 64=center)
414
"""
415
416
def main_volume(channel: int, value: int) -> None:
417
"""
418
Set main volume (CC7).
419
420
Parameters:
421
- channel: MIDI channel
422
- value: Volume level (0-127)
423
"""
424
425
def stop_everything() -> None:
426
"""Stop all playback and reset FluidSynth."""
427
```
428
429
### Low-Level MIDI Track Generation
430
431
Advanced MIDI track generation with precise control over MIDI events and timing.
432
433
```python { .api }
434
class MidiTrack:
435
"""Low-level MIDI track generator."""
436
437
def __init__(self, start_bpm: int = 120):
438
"""
439
Create MIDI track generator.
440
441
Parameters:
442
- start_bpm: Initial tempo
443
"""
444
445
def note_on(self, channel: int, note: int, velocity: int) -> None:
446
"""
447
Add note on event.
448
449
Parameters:
450
- channel: MIDI channel (0-15)
451
- note: MIDI note number (0-127)
452
- velocity: Note velocity (0-127)
453
"""
454
455
def note_off(self, channel: int, note: int) -> None:
456
"""
457
Add note off event.
458
459
Parameters:
460
- channel: MIDI channel (0-15)
461
- note: MIDI note number (0-127)
462
"""
463
464
def program_change(self, channel: int, program: int) -> None:
465
"""
466
Add program change event.
467
468
Parameters:
469
- channel: MIDI channel (0-15)
470
- program: Program number (0-127)
471
"""
472
473
def control_change(self, channel: int, control: int, value: int) -> None:
474
"""
475
Add control change event.
476
477
Parameters:
478
- channel: MIDI channel (0-15)
479
- control: Controller number (0-127)
480
- value: Controller value (0-127)
481
"""
482
483
def set_tempo(self, bpm: int) -> None:
484
"""
485
Set tempo.
486
487
Parameters:
488
- bpm: Beats per minute
489
"""
490
491
def time_signature(self, numerator: int, denominator: int) -> None:
492
"""
493
Set time signature.
494
495
Parameters:
496
- numerator: Time signature numerator
497
- denominator: Time signature denominator
498
"""
499
500
def key_signature(self, key: int, mode: int) -> None:
501
"""
502
Set key signature.
503
504
Parameters:
505
- key: Key signature (-7 to 7)
506
- mode: Mode (0=major, 1=minor)
507
"""
508
509
def play_Note(self, note: Note, channel: int, velocity: int) -> None:
510
"""
511
Add Note to track.
512
513
Parameters:
514
- note: Note object
515
- channel: MIDI channel
516
- velocity: Note velocity
517
"""
518
519
def play_NoteContainer(self, nc: NoteContainer, channel: int, velocity: int) -> None:
520
"""
521
Add NoteContainer to track.
522
523
Parameters:
524
- nc: NoteContainer object
525
- channel: MIDI channel
526
- velocity: Note velocity
527
"""
528
529
def get_midi_data(self) -> bytes:
530
"""
531
Get raw MIDI data.
532
533
Returns:
534
Raw MIDI track data as bytes
535
"""
536
```
537
538
## Usage Examples
539
540
### Basic MIDI Playback
541
542
```python
543
from mingus.midi import Sequencer
544
from mingus.containers import Note, NoteContainer
545
546
# Initialize sequencer
547
seq = Sequencer()
548
seq.init()
549
550
# Play individual notes
551
note = Note("C", 4)
552
seq.play_Note(note, channel=1, velocity=100)
553
seq.sleep(1.0) # Wait 1 second
554
seq.stop_Note(note, channel=1)
555
556
# Play chords
557
chord = NoteContainer(["C", "E", "G"])
558
seq.play_NoteContainer(chord, channel=1, velocity=80)
559
seq.sleep(2.0)
560
seq.stop_NoteContainer(chord, channel=1)
561
```
562
563
### FluidSynth Audio Output
564
565
```python
566
from mingus.midi import fluidsynth
567
from mingus.containers import Track, Bar
568
569
# Initialize FluidSynth with soundfont
570
fluidsynth.init("/path/to/soundfont.sf2")
571
572
# Set piano instrument
573
fluidsynth.set_instrument(1, 0) # Channel 1, piano
574
575
# Create and play musical content
576
bar = Bar()
577
bar.place_notes("C", 4)
578
bar.place_notes("E", 4)
579
bar.place_notes("G", 2)
580
581
track = Track()
582
track.add_bar(bar)
583
584
# Play track with audio output
585
fluidsynth.play_Track(track, channel=1, bpm=120)
586
```
587
588
### MIDI File Export
589
590
```python
591
from mingus.midi import midi_file_out
592
from mingus.containers import Composition, Track, Bar
593
594
# Create composition
595
composition = Composition()
596
composition.set_title("My Song")
597
598
# Create track with content
599
track = Track()
600
bar = Bar()
601
bar.place_notes(["C", "E", "G"], 4) # Quarter note chord
602
bar.place_notes("F", 2) # Half note
603
track.add_bar(bar)
604
605
composition.add_track(track)
606
607
# Export to MIDI file
608
midi_file_out.write_Composition("my_song.mid", composition, bpm=120)
609
```
610
611
### MIDI File Import
612
613
```python
614
from mingus.midi import midi_file_in
615
616
# Import MIDI file
617
composition = midi_file_in.MIDI_to_Composition("input.mid")
618
619
# Access imported data
620
for i, track in enumerate(composition.tracks):
621
print(f"Track {i}: {len(track.bars)} bars")
622
for j, bar in enumerate(track.bars):
623
print(f" Bar {j}: {len(bar)} notes")
624
```
625
626
### Advanced MIDI Control
627
628
```python
629
from mingus.midi import Sequencer
630
631
seq = Sequencer()
632
seq.init()
633
634
# Set up instruments on different channels
635
seq.set_instrument(1, 0) # Piano on channel 1
636
seq.set_instrument(2, 32) # Bass on channel 2
637
seq.set_instrument(10, 128) # Drums on channel 10
638
639
# Control expression
640
seq.main_volume(1, 100) # Full volume
641
seq.pan(1, 64) # Center pan
642
seq.modulation(1, 20) # Light modulation
643
644
# Advanced control changes
645
seq.control_change(1, 64, 127) # Sustain pedal on
646
seq.control_change(1, 91, 40) # Reverb send
647
```