forked from Allen-Synthesis/EuroPi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgates_and_triggers.py
158 lines (118 loc) · 4.69 KB
/
gates_and_triggers.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
#!/usr/bin/env python3
"""Convert incoming triggers to gates or gates to triggers
Also outputs a toggle input which changes state every time an incoming gate is received, or when either button is
pressed.
@author Chris Iverach-Brereton <ve4cib@gmail.com>
@year 2023
"""
import time
from europi import *
from europi_script import EuroPiScript
from math import sqrt
from experimental.screensaver import OledWithScreensaver
ssoled = OledWithScreensaver()
## All digital output signals are 5V
OUTPUT_VOLTAGE = 5.0
## Trigger outputs are 10ms long (rising/falling edges of gate signals)
TRIGGER_DURATION_MS = 10
class GatesAndTriggers(EuroPiScript):
def __init__(self):
super().__init__()
now = time.ticks_ms()
self.on_incoming_rise_start_time = now
self.on_incoming_fall_start_time = now
self.on_gate_fall_start_time = now
self.on_toggle_fall_start_time = now
# assign each of the CV outputs to specific duties
self.gate_out = cv1
self.incoming_rise_out = cv2
self.incoming_fall_out = cv3
self.gate_fall_out = cv4
self.toggle_out = cv5
self.toggle_fall_out = cv6
self.gate_on = False
self.toggle_on = False
self.k1_percent = int(k1.percent() * 100)
self.k2_percent = int(k2.percent() * 100)
turn_off_all_cvs()
@din.handler
def on_din_rising():
self.on_rise()
@din.handler_falling
def on_din_falling():
self.on_fall()
@b1.handler
def on_b1_press():
self.on_rise()
ssoled.notify_user_interaction()
@b1.handler_falling
def on_b1_release():
self.on_fall()
@b2.handler
def on_b2_press():
self.on_toggle()
ssoled.notify_user_interaction()
def on_rise(self):
"""Handle the rising edge of the input signal
"""
self.gate_on = True
self.on_incoming_rise_start_time = time.ticks_ms()
self.incoming_rise_out.voltage(OUTPUT_VOLTAGE)
self.gate_out.voltage(OUTPUT_VOLTAGE)
self.on_toggle()
def on_fall(self):
"""Handle the falling edge of the input signal
"""
self.on_incoming_fall_start_time = time.ticks_ms()
self.incoming_fall_out.voltage(OUTPUT_VOLTAGE)
def on_toggle(self):
"""Handle toggling the toggle output
"""
self.toggle_on = not self.toggle_on
if self.toggle_on:
self.toggle_out.voltage(OUTPUT_VOLTAGE)
else:
self.toggle_out.voltage(0)
self.toggle_fall_out.voltage(OUTPUT_VOLTAGE)
self.on_toggle_fall_start_time = time.ticks_ms()
def tick(self):
"""Advance the clock and set the outputs high/low as needed
"""
now = time.ticks_ms()
k1_percent = int(k1.percent() * 100)
k2_percent = int(k2.percent() * 100)
# if the user moved the knobs by more than 1% deactivate the screensaver
if abs(self.k1_percent - k1_percent) > 0 or abs(self.k2_percent - k2_percent) > 0:
ssoled.notify_user_interaction()
knob_lvl = k1_percent
cv_lvl = ain.percent() * (k2_percent * 0.02 - 1)
self.gate_duration = max(self.quadratic_knob(knob_lvl) + cv_lvl * 2000, TRIGGER_DURATION_MS)
if self.gate_on and time.ticks_diff(now, self.on_incoming_rise_start_time) > self.gate_duration:
self.gate_on = False
self.gate_out.voltage(0)
self.gate_fall_out.voltage(OUTPUT_VOLTAGE)
self.on_gate_fall_start_time = now
if time.ticks_diff(now, self.on_gate_fall_start_time) > TRIGGER_DURATION_MS:
self.gate_fall_out.voltage(0)
if time.ticks_diff(now, self.on_incoming_rise_start_time) > TRIGGER_DURATION_MS:
self.incoming_rise_out.voltage(0)
if time.ticks_diff(now, self.on_incoming_fall_start_time) > TRIGGER_DURATION_MS:
self.incoming_fall_out.voltage(0)
if time.ticks_diff(now, self.on_toggle_fall_start_time) > TRIGGER_DURATION_MS:
self.toggle_fall_out.voltage(0)
self.k1_percent = k1_percent
self.k2_percent = k2_percent
def quadratic_knob(self, x):
"""Some magic math to give us a quadratic response on the knob percentage
This gives us 10ms @ 0% and 2000ms @ 100% with greater precision at the higher end
where the differences will be more noticeable
"""
if x <= 0:
return 10
return 199 * sqrt(x) + 10
def main(self):
while(True):
self.tick()
ssoled.centre_text(f"Gate: {self.gate_duration:0.0f}ms")
if __name__=="__main__":
GatesAndTriggers().main()