-
Notifications
You must be signed in to change notification settings - Fork 0
/
multimidiseq.py
174 lines (141 loc) · 5.04 KB
/
multimidiseq.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# multimidiseq.py
#
# based on: drumseq.py
# from here: https://github.com/SpotlightKid/python-rtmidi/tree/master/examples/drumseq
# which is itself based on:
# MIDI Drum sequencer prototype, by Michiel Overtoom, motoom@xs4all.nl
#
"""Play sequencer patterns from file to MIDI out."""
import argparse
import sys
from multimidiseq import PatternSequencer as pseq
from multimidiseq import DrumPattern as dp
from multimidiseq import Track as tp
from multimidiseq import SongSequencer as sos
from multimidiseq import MultilineNotePattern as mnp
from time import sleep, time as timenow
from rtmidi.midiutil import open_midioutput, list_output_ports, list_input_ports
import rtmidi
# BD1 = BaseDrum1
# CHH = Closed Hi-hat
# OHH = Open Hi-hat
# SN1 = Snare1
# SN2 = Snare2
# CR1 = Crash1
# CR2 = Crash2
# RD1 = Ride1
# RD2 = Ride2
# CB1 = Cowbell1
# CP1 = Clap1
# TM1 = TOM1
# TM2 = TOM2
# TM3 = TOM3
# TM4 = TOM4
# Korg Wavestate Single Multisample: "Drm_WS: Drum Kit".
# On Wavestate Layer A: Octave +2 (so that you can use the keys
# on the Wavestate to play the other layers)
DRUMMIDIASSIGN_KorkWavestate_DrumKit = """
BD1 12
SN1 15
SN2 16
CHH 29
OHH 31
CR1 32
CB1 41
CP1 22
"""
FUTUREDRUMPATTERN1 = """
BD1 x.....s.x.......x.....m.x.......
SN1 ....m-......m-......m-......m-..
CHH xsssxsssxsssxsssxsssxsssxsssxsss
"""
# Wave Sequencing 2.0 Synth Pattern
WSSPATTERN1 = """"
BASENOTE 48
KEYUPLIMIT 50
KEYLOWLIMIT 48
TIMING 014 014 014 014 014 014 014 318 318 318
PITCH --- --- --- --- --- --- --- 000 007 012
VEL --- --- --- --- --- --- --- sss sss sss
"""
def selectInputPort():
portnrstr = input("Select the input port by typing the corresponding number: ")
selected_input_port = int(portnrstr)
return selected_input_port
def selectOutputPort():
portnrstr = input("Select the output port by typing the corresponding number: ")
selected_output_port = int(portnrstr)
return selected_output_port
def main(args=None):
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
aadd = ap.add_argument
aadd('-b', '--bpm', type=float, default=100,
help="Beats per minute (BPM) (default: %(default)s)")
aadd('--virtualout', type=bool, default=False,
help="Create a MIDI out to SW instruments (like e.g. Korg opsix native) (default: %(default)s)")
aadd('-r', '--repeats', type=int, default=0,
help="Number of repeats. 0=infinite (default: %(default)s)")
aadd('-c', '--channel', type=int, default=1, metavar='CH',
help="MIDI channel (default: %(default)s)")
aadd('-p', '--port',
help="MIDI output port number (default: ask)")
aadd('-k', '--kit', type=int, metavar='KIT',
help="Drum kit MIDI program number (default: none)")
aadd('--bank-msb', type=int, metavar='MSB',
help="MIDI bank select MSB (CC#00) number (default: none)")
aadd('--bank-lsb', type=int, metavar='MSB',
help="MIDI bank select LSB (CC#32) number (default: none)")
aadd('-H', '--humanize', type=float, default=0.0, metavar='VAL',
help="Random velocity variation (float, default: 0, try ~0.03)")
aadd('-m', '--midimap', type=argparse.FileType(), metavar='DMM',
help="Midi Map File to map the drum instrument shortcuts to MIDI notes")
aadd('pattern', nargs='?', type=argparse.FileType(),
help="Drum pattern file (default: use built-in pattern)")
args = ap.parse_args(args)
if args.midimap:
drummidimap = args.midimap.read()
else:
drummidimap = DRUMMIDIASSIGN_KorkWavestate_DrumKit
if args.pattern:
filetype = str(args.pattern.name).split(".")[2]
pattern = args.pattern.read()
else:
pattern = FUTUREDRUMPATTERN1
if filetype == "sdp":
kit = (args.bank_msb, args.bank_lsb, args.kit)
drumpattern = dp.DrumPattern(pattern, drummidimap, kit=kit,
humanize=args.humanize)
elif filetype == "sst":
trackpattern = tp.Track(pattern)
elif filetype == "mnp":
mnpattern = mnp.MultilineNotePattern(pattern)
list_output_ports()
if args.virtualout:
midiout = rtmidi.MidiOut()
midiout.open_virtual_port("MultiMidiSequencer")
else:
selected_output_port = selectOutputPort()
midiout, port_name = open_midioutput(selected_output_port)
if filetype == "sdp":
seq = pseq.PatternSequencer(midiout, drumpattern, args.bpm, args.repeats, args.channel - 1)
elif filetype == "sst":
seq = sos.SongSequencer(midiout, pattern, args.channel - 1)
elif filetype == "mnp":
seq = pseq.PatternSequencer(midiout, mnpattern, args.bpm, args.repeats, args.channel - 1)
print("Playing drum loop at %.1f BPM, press Control-C to quit." % seq.bpm)
try:
while True:
sleep(1)
except KeyboardInterrupt:
print('')
finally:
seq.done = True # And kill it.
seq.join()
midiout.close_port()
del midiout
print("Done")
if __name__ == "__main__":
sys.exit(main() or 0)