Skip to content

Commit ea83d2f

Browse files
authored
Separate tick into 2 functions; the previous one was too long for the UF2 builder to compile as a native function (#477)
1 parent b77bd04 commit ea83d2f

1 file changed

Lines changed: 85 additions & 75 deletions

File tree

software/contrib/pams.py

Lines changed: 85 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,88 +1213,98 @@ def tick(self):
12131213
# reset waves are always low; the clock's stop() function handles triggering them
12141214
out_volts = 0.0
12151215
else:
1216-
if self.wave_counter % 2 == 0:
1217-
# first half of the swing; if swing < 50% this is short, otherwise long
1218-
swing_amt = self.swing.value / 100.0
1219-
else:
1220-
# second half of the swing; if swing < 50% this is long, otherwise short
1221-
swing_amt = (100 - self.swing.value) / 100.0
1222-
ticks_per_note = round(2 * MasterClock.PPQN / self.real_clock_mod * swing_amt)
1223-
if ticks_per_note == 0:
1224-
# we're swinging SO HARD that one beat is squashed out of existence!
1225-
# move immediately to the other beat
1226-
self.e_position = self.e_position + 1
1227-
if self.e_position >= len(self.e_pattern):
1228-
self.e_position = 0
1229-
ticks_per_note = round(2 * MasterClock.PPQN / self.real_clock_mod)
1230-
1231-
e_step = self.e_pattern[self.e_position]
1232-
wave_position = self.clock.elapsed_pulses % ticks_per_note
1233-
# are we starting a new repeat of the pattern?
1234-
rising_edge = (wave_position == int(self.phase.value * ticks_per_note / 100.0)) and e_step
1235-
# determine if we should skip this sample playback
1236-
if rising_edge:
1237-
self.skip_this_step = random.randint(0, 100) < self.skip.value
1238-
self.wave_counter += 1
1239-
1240-
wave_sample = int(e_step) * int (not self.skip_this_step)
1241-
if self.wave_shape.value == WAVE_RANDOM:
1242-
if rising_edge and not self.skip_this_step:
1243-
wave_sample = random.random() * (self.amplitude.value / 100.0) + (self.width.value / 100.0)
1244-
else:
1245-
wave_sample = self.previous_wave_sample
1246-
elif self.wave_shape.value == WAVE_AIN:
1247-
if rising_edge and not self.skip_this_step:
1248-
wave_sample = CV_INS["AIN"].percent() * self.amplitude.value / 100.0
1249-
else:
1250-
wave_sample = self.previous_wave_sample
1251-
elif self.wave_shape.value == WAVE_KNOB:
1252-
if rising_edge and not self.skip_this_step:
1253-
wave_sample = CV_INS["KNOB"].percent() * self.amplitude.value / 100.0
1254-
else:
1255-
wave_sample = self.previous_wave_sample
1256-
elif self.wave_shape.value == WAVE_SQUARE:
1257-
wave_sample = wave_sample * self.square_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1258-
elif self.wave_shape.value == WAVE_TRIANGLE:
1259-
wave_sample = wave_sample * self.triangle_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1260-
elif self.wave_shape.value == WAVE_SIN:
1261-
wave_sample = wave_sample * self.sine_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1262-
elif self.wave_shape.value == WAVE_ADSR:
1263-
wave_sample = wave_sample * self.adsr_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1264-
elif self.wave_shape.value == WAVE_TURING:
1265-
wave_sample = self.turing_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1266-
else:
1267-
wave_sample = 0.0
1268-
1269-
self.previous_wave_sample = wave_sample
1270-
out_volts = wave_sample * MAX_OUTPUT_VOLTAGE
1271-
1272-
if self.quantizer.mapped_value is not None:
1273-
(out_volts, note) = self.quantizer.mapped_value.quantize(out_volts, self.root.value)
1274-
1275-
if wave_position == ticks_per_note - 1:
1276-
if self.next_e_pattern:
1277-
# if we just finished a waveform and we have a new euclidean pattern, start it
1278-
# this will always line up with the current beat, but may be rotated relative to
1279-
# other patterns currently playing.
1280-
# rather than do a lot of math, treat this as a feature that if you change patterns
1281-
# while playing, the new pattern starts right away instead of waiting for for the
1282-
# end of (a potentially long, slow) pattern to finish
1283-
self.e_position = 0
1284-
self.e_pattern = self.next_e_pattern
1285-
self.next_e_pattern = None
1286-
else:
1287-
# if we've reached end of the euclidean pattern start it again
1288-
self.e_position = self.e_position + 1
1289-
if self.e_position >= len(self.e_pattern):
1290-
self.e_position = 0
1216+
out_volts = self.wave_gen()
12911217

12921218
# If the clock modifier was changed, apply the new value now
12931219
if self.clock_mod_dirty:
12941220
self.change_clock_mod()
12951221

12961222
self.out_volts = out_volts
12971223

1224+
@micropython.native
1225+
def wave_gen(self):
1226+
"""Calculates the output voltage for the output channel.
1227+
1228+
@return The desired output voltage to be applied
1229+
"""
1230+
if self.wave_counter % 2 == 0:
1231+
# first half of the swing; if swing < 50% this is short, otherwise long
1232+
swing_amt = self.swing.value / 100.0
1233+
else:
1234+
# second half of the swing; if swing < 50% this is long, otherwise short
1235+
swing_amt = (100 - self.swing.value) / 100.0
1236+
ticks_per_note = round(2 * MasterClock.PPQN / self.real_clock_mod * swing_amt)
1237+
if ticks_per_note == 0:
1238+
# we're swinging SO HARD that one beat is squashed out of existence!
1239+
# move immediately to the other beat
1240+
self.e_position = self.e_position + 1
1241+
if self.e_position >= len(self.e_pattern):
1242+
self.e_position = 0
1243+
ticks_per_note = round(2 * MasterClock.PPQN / self.real_clock_mod)
1244+
1245+
e_step = self.e_pattern[self.e_position]
1246+
wave_position = self.clock.elapsed_pulses % ticks_per_note
1247+
# are we starting a new repeat of the pattern?
1248+
rising_edge = (wave_position == int(self.phase.value * ticks_per_note / 100.0)) and e_step
1249+
# determine if we should skip this sample playback
1250+
if rising_edge:
1251+
self.skip_this_step = random.randint(0, 100) < self.skip.value
1252+
self.wave_counter += 1
1253+
1254+
wave_sample = int(e_step) * int (not self.skip_this_step)
1255+
if self.wave_shape.value == WAVE_RANDOM:
1256+
if rising_edge and not self.skip_this_step:
1257+
wave_sample = random.random() * (self.amplitude.value / 100.0) + (self.width.value / 100.0)
1258+
else:
1259+
wave_sample = self.previous_wave_sample
1260+
elif self.wave_shape.value == WAVE_AIN:
1261+
if rising_edge and not self.skip_this_step:
1262+
wave_sample = CV_INS["AIN"].percent() * self.amplitude.value / 100.0
1263+
else:
1264+
wave_sample = self.previous_wave_sample
1265+
elif self.wave_shape.value == WAVE_KNOB:
1266+
if rising_edge and not self.skip_this_step:
1267+
wave_sample = CV_INS["KNOB"].percent() * self.amplitude.value / 100.0
1268+
else:
1269+
wave_sample = self.previous_wave_sample
1270+
elif self.wave_shape.value == WAVE_SQUARE:
1271+
wave_sample = wave_sample * self.square_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1272+
elif self.wave_shape.value == WAVE_TRIANGLE:
1273+
wave_sample = wave_sample * self.triangle_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1274+
elif self.wave_shape.value == WAVE_SIN:
1275+
wave_sample = wave_sample * self.sine_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1276+
elif self.wave_shape.value == WAVE_ADSR:
1277+
wave_sample = wave_sample * self.adsr_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1278+
elif self.wave_shape.value == WAVE_TURING:
1279+
wave_sample = self.turing_wave(wave_position, ticks_per_note) * (self.amplitude.value / 100.0)
1280+
else:
1281+
wave_sample = 0.0
1282+
1283+
self.previous_wave_sample = wave_sample
1284+
out_volts = wave_sample * MAX_OUTPUT_VOLTAGE
1285+
1286+
if self.quantizer.mapped_value is not None:
1287+
(out_volts, note) = self.quantizer.mapped_value.quantize(out_volts, self.root.value)
1288+
1289+
if wave_position == ticks_per_note - 1:
1290+
if self.next_e_pattern:
1291+
# if we just finished a waveform and we have a new euclidean pattern, start it
1292+
# this will always line up with the current beat, but may be rotated relative to
1293+
# other patterns currently playing.
1294+
# rather than do a lot of math, treat this as a feature that if you change patterns
1295+
# while playing, the new pattern starts right away instead of waiting for for the
1296+
# end of (a potentially long, slow) pattern to finish
1297+
self.e_position = 0
1298+
self.e_pattern = self.next_e_pattern
1299+
self.next_e_pattern = None
1300+
else:
1301+
# if we've reached end of the euclidean pattern start it again
1302+
self.e_position = self.e_position + 1
1303+
if self.e_position >= len(self.e_pattern):
1304+
self.e_position = 0
1305+
1306+
return out_volts
1307+
12981308
@micropython.native
12991309
def apply(self):
13001310
"""Apply the calculated voltage to the output channel

0 commit comments

Comments
 (0)