forked from SpotlightKid/python-rtmidi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwavetablemodstep.py
More file actions
100 lines (77 loc) · 3.17 KB
/
Copy pathwavetablemodstep.py
File metadata and controls
100 lines (77 loc) · 3.17 KB
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# wavetablemodstep.py
#
"""Play a note and step through MIDI Control Change #1 (modulation) values.
Optionally allows to send a Control Change #70 first, to set the wavetable
of the current sound on a Waldorf Microwave II/XT(k) synthesizer.
I use this with a Microwave sound program where the CC #1 is mapped to
wavetable position of oscillator 1. This script then allows me to listen to
all the waves in a selected wavetable in succession.
"""
import time
import rtmidi
from rtmidi.midiconstants import (CONTROL_CHANGE, MODULATION_WHEEL,
NOTE_OFF, NOTE_ON, RESET_ALL_CONTROLLERS)
CC_SET_WAVETABLE = 70
class Midi(object):
"""Encapsulate MIDI output."""
def __init__(self, port):
self.midi = rtmidi.MidiOut()
self.midi.open_port(port)
def play_stepping(self, note, cc, dur=0.2, step=1, vel=64, rvel=None, ch=0):
"""Play given note and step through ctrl values over time."""
# note on
note &= 0x7F
ch &= 0x0F
self.midi.send_message([CONTROL_CHANGE | ch, cc, 0])
time.sleep(0.1)
self.midi.send_message([NOTE_ON | ch, note, vel & 0x7F])
# step through modulation controller values
for i in range(0, 128, step):
self.midi.send_message([CONTROL_CHANGE | ch, cc, i])
time.sleep(dur)
# note off
self.midi.send_message(
[NOTE_OFF | ch, note, (vel if rvel is None else rvel) & 0x7F])
def reset_controllers(self, ch=0):
"""Reset controllers on given channel."""
self.midi.send_message(
[CONTROL_CHANGE | (ch & 0xF), RESET_ALL_CONTROLLERS, 0])
def set_wavetable(self, wt, ch=0):
"""Set wavetable for current sound to given number."""
self.midi.send_message(
[CONTROL_CHANGE | (ch & 0xF), CC_SET_WAVETABLE, wt & 0x7F])
def close(self):
"""Close MIDI outpurt."""
self.midi.close_port()
del self.midi
if __name__ == '__main__':
import argparse
argparser = argparse.ArgumentParser()
aadd = argparser.add_argument
aadd('-c', '--channel', type=int, default=1,
help="MIDI channel (1-based, default: %(default)s)")
aadd('-C', '--controller', type=int, default=MODULATION_WHEEL,
help="MIDI controller number (default: %(default)s)")
aadd('-p', '--port', type=int, default=0,
help="MIDI output port (default: %(default)s)")
aadd('-l', '--length', type=float, default=0.3,
help="Length (in sec.) of each wave (default: %(default)s)")
aadd('-n', '--note', type=int, default=60,
help="MIDI note number to play (default: %(default)s)")
aadd('-w', '--wavetable', type=int,
help="Send CC #70 to set wavetable number (1-based, default: none)")
args = argparser.parse_args()
m = Midi(args.port)
ch = max(0, args.channel - 1)
if args.wavetable:
m.set_wavetable(args.wavetable - 1, ch=args.channel - 1)
time.sleep(0.1)
try:
m.reset_controllers(ch)
m.play_stepping(args.note, args.controller, dur=args.length, step=2, ch=ch)
finally:
m.reset_controllers(ch)
m.close()