-
Notifications
You must be signed in to change notification settings - Fork 0
/
examples.py
164 lines (146 loc) · 5.65 KB
/
examples.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
from tinkersynth.midi import midi_note_source, NO_VELOCITY, SQUARE_ROOT, create_controllers_from_mapping, cc, \
pitch_bend_controller
from tinkersynth.synthesizer import *
# MIDI controller mappings
arturia_keylab_essential_61 = {
# using Analog Lab map on keyboard
22: "part_1_btn", # 0 or 127
23: "part_2_btn", # 0 or 127
24: "part_3_btn", # 0 or 127
74: "cutoff", # linear between 0 and 127 from here on
71: "resonance",
76: "lfo_rate",
77: "lfo_amt",
93: "param_1",
18: "param_2",
19: "param_3",
16: "param_4",
17: "panning", # master_pan (turny-twisty thing above master volume slider)
73: "attack_1",
75: "decay_1",
79: "sustain_1",
72: "release_1",
80: "attack_2",
81: "decay_2",
82: "sustain_2",
83: "release_2",
85: "volume", # master_vol
# control cluster at center of keyboard:
116: "cat_btn",
117: "preset_btn",
28: "left_btn",
29: "right_btn",
114: "rotary_knob",
}
# Main functions
gate_state = HIGH
def gate_gen():
"""This is more of a test helper than anything else.
Maybe usable for playing notes without interaction.
midi_note_source() provides live gate generation."""
global gate_state
while True:
new_state = yield gate_state
if new_state is not None:
gate_state = new_state
def pad_test():
# print(f"main: {threading.active_count(), threading.current_thread()}")
freqs, gates = midi_note_source(0, velocity_curve=NO_VELOCITY) # 0 = Arturia KeyLab Essential 61 MIDI In
create_controllers_from_mapping(arturia_keylab_essential_61, overwrite=True)
pitch_bend = transpose(freqs, scale(pitch_bend_controller(), -3.0, 3.0))
pitch1, pitch2, pitch3, pitch4 = split(pitch_bend, 4)
saw = sawtooth(pitch1)
squ_frq1 = transpose(pitch2, -11.9)
squ_frq2 = transpose(pitch3, -12.0)
squ_frq3 = transpose(pitch4, -12.1)
squ1 = square(squ_frq1)
squ2 = square(squ_frq2)
squ3 = square(squ_frq3)
mixed = mix([saw, squ1, squ2, squ3], [1.0, 0.3, 0.3, 0.3])
envelope = eg(mixed, gate=gates, adsr=[1.0, 0.0, 1.0, 2.0])
lfo = scale(triangle(10), 0.8, 1.0)
with_vibrato = gain(envelope, lfo)
flt_cutoff = scale(cc["cutoff"], 0.0, 0.7)
filt = low_pass_filter(with_vibrato, alpha=flt_cutoff, poles=8)
vol = gain(filt, cc["volume"])
player = play_live(vol)
def lead_test():
freqs, gates = midi_note_source(0, velocity_curve=SQUARE_ROOT) # 0 = Arturia KeyLab Essential 61 MIDI In
create_controllers_from_mapping(arturia_keylab_essential_61, overwrite=True)
squ = square(mult(freqs, 0.5))
sinus = sine(freqs)
tri = triangle(freqs)
m = mix([squ, tri], [0.4, 1.0]) # 2 * sqrt(2) = ca. 1.4 RMS
envelope = eg(m, gate=gates, adsr=[cc["attack_1"], cc["decay_1"], cc["sustain_1"], cc["release_1"]])
flt = low_pass_filter(envelope, alpha=cc["cutoff"])
drv = drive(flt, gain=cc["param_1"], mixin=0.5)
rev = reverb_hall(drv)
dely = delay(rev, delay=cc["param_2"], mixin=cc["param_3"], feedback=cc["param_4"])
vol = cc["volume"]
scaled = gain(dely, gain=vol)
player = play_live(scaled)
def porta_test():
freqs, gates = midi_note_source(0, velocity_curve=SQUARE_ROOT) # 0 = Arturia KeyLab Essential 61 MIDI In
create_controllers_from_mapping(arturia_keylab_essential_61, overwrite=True)
gate1, gate2 = split(gates, 2)
porta = portamento(freqs, gate1, cc["panning"])
osc = scale(square(5), -0.2, 0.2)
tremolo = transpose(porta, osc)
tri = sawtooth(tremolo)
envelope = eg(tri, gate=gate2, adsr=[0.005, 0.1, 0.2, 0.1])
filt = low_pass_filter(envelope, alpha=cc["cutoff"], resonance=0.0)
scaled = gain(filt, gain=cc["volume"])
player = play_live(scaled)
def plot_test():
# todo: http://navjodh.com/test-and-measurement/continuously-updating-audio-waveform-display-using-python/
squ = square(440)
s = sine(440)
# filt = high_pass_filter(s, alpha=0.99, poles=32)
filt = drive(s, gain=5.0, mixin=0.0)
vals = []
for i in range(int(300)):
if i == sample_rate:
gate_state = LOW
vals.append(next(filt))
plt.plot(vals)
plt.show()
def play_notes():
flat_adsr = [0.0, 0.0, 1.0, 0.0]
pluck_adsr = [0.005, 0.0, 1.0, 0.3]
crash_adsr = [0.005, 0.5, 0.0, 0.0]
# TODO: make example for playing static notes work again
samples = [0.0] * 50 # Add some padding
envelope = []
note_freqs = [220, 220 * 5 / 4, 220 * 3 / 2, 440, 440 * 3 / 2, 440, 220 * 3 / 2, 220]
durations = [0.5] * len(note_freqs)
durations[-1] = 0.4
adsr_values = flat_adsr
a = 0.2
for freq, duration in zip(note_freqs, durations):
# todo
anzahl_benoetigte_samples = round(sample_rate * (duration + adsr_values[RELEASE]))
for sample_schritt in range(anzahl_benoetigte_samples):
aktuelle_laufzeit = sample_schritt / sample_rate
adsr_val = adsr.send(aktuelle_laufzeit < duration)
envelope.append(adsr_val)
sample = (
mixer.send(None) *
adsr_val
)
samples.append(sample)
play(samples)
# plt.plot(samples[:round(anzahl_benoetigte_samples/20)])
# plt.plot(samples[:round(sample_rate / f) * 3])
# plt.plot(all_envelopes)
plt.plot(samples[:round(anzahl_benoetigte_samples)])
plt.show()
def main():
print("Press Ctrl-C a couple of times to exit (for your own programs "
"you can use synthesizer.stop_stream() to stop playing)")
# plot_test()
porta_test()
# porta_test()
# lead_test()
if __name__ == '__main__':
# Create a thread to run the script
run_and_reload_on_change(main)