adding code for rotary encoder synth
Adding code for ANO rotary encoder synth. Uses synthio, five ANO encoders, five alphanumeric displays and one 8x8 matrix.
This commit is contained in:
parent
774c940bcf
commit
20b3c4a856
1 changed files with 740 additions and 0 deletions
740
ANO_Rotary_Encoder_Synth/code.py
Normal file
740
ANO_Rotary_Encoder_Synth/code.py
Normal file
|
|
@ -0,0 +1,740 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 Liz Clark for Adafruit Industries
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
from random import randint
|
||||||
|
import ulab.numpy as np
|
||||||
|
import board
|
||||||
|
import audiobusio
|
||||||
|
import audiomixer
|
||||||
|
import synthio
|
||||||
|
import simpleio
|
||||||
|
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
||||||
|
from adafruit_ht16k33 import segments
|
||||||
|
from adafruit_ht16k33.matrix import Matrix8x8x2
|
||||||
|
from adafruit_seesaw import seesaw, rotaryio, digitalio
|
||||||
|
|
||||||
|
SAMPLE_RATE = 44100
|
||||||
|
SAMPLE_SIZE = 256
|
||||||
|
VOLUME = 5000
|
||||||
|
|
||||||
|
# waveforms, envelopes and synth setup
|
||||||
|
|
||||||
|
square = np.concatenate((np.ones(SAMPLE_SIZE//2, dtype=np.int16)*VOLUME,np.ones(SAMPLE_SIZE//2,
|
||||||
|
dtype=np.int16)*-VOLUME))
|
||||||
|
sine = np.array(np.sin(np.linspace(0, 4*np.pi, SAMPLE_SIZE, endpoint=False)) * VOLUME,
|
||||||
|
dtype=np.int16)
|
||||||
|
saw = np.linspace(VOLUME, -VOLUME, num=SAMPLE_SIZE, dtype=np.int16)
|
||||||
|
noise = np.array([randint(-VOLUME, VOLUME) for i in range(SAMPLE_SIZE)], dtype=np.int16)
|
||||||
|
|
||||||
|
lfo = synthio.LFO(rate = .5, waveform = sine)
|
||||||
|
|
||||||
|
amp_env0 = synthio.Envelope(attack_time=0.1, decay_time = 0.1, release_time=0.1,
|
||||||
|
attack_level=1, sustain_level=0.05)
|
||||||
|
amp_env1 = synthio.Envelope(attack_time=0.05, decay_time = 0.1, release_time=0.1,
|
||||||
|
attack_level=1, sustain_level=0.05)
|
||||||
|
|
||||||
|
# synth plays the notes
|
||||||
|
synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE)
|
||||||
|
|
||||||
|
# these are the notes
|
||||||
|
synth0 = synthio.Note(frequency = 0.0, envelope=amp_env0, waveform=square, ring_frequency = 0,
|
||||||
|
ring_bend = lfo, ring_waveform = sine)
|
||||||
|
synth1 = synthio.Note(frequency = 0.0, envelope=amp_env1, waveform=sine, ring_frequency = 0,
|
||||||
|
ring_bend = lfo, ring_waveform = sine)
|
||||||
|
synth2 = synthio.Note(frequency = 0.0, envelope=amp_env0, waveform=square, ring_frequency = 0,
|
||||||
|
ring_bend = lfo, ring_waveform = sine)
|
||||||
|
synth3 = synthio.Note(frequency = 0.0, envelope=amp_env1, waveform=sine, ring_frequency = 0,
|
||||||
|
ring_bend = lfo, ring_waveform = sine)
|
||||||
|
|
||||||
|
synths = [synth0, synth1, synth2, synth3]
|
||||||
|
wave_names = ["SQUR", "SINE", "SAW ", "NOIZ"]
|
||||||
|
waveforms = [square, sine, saw, noise]
|
||||||
|
synth0_wave = 0
|
||||||
|
synth1_wave = 1
|
||||||
|
synth2_wave = 0
|
||||||
|
synth3_wave = 1
|
||||||
|
|
||||||
|
# i2s amp setup
|
||||||
|
audio = audiobusio.I2SOut(bit_clock=board.D10, word_select=board.D11, data=board.D9)
|
||||||
|
mixer = audiomixer.Mixer(voice_count=4, sample_rate=SAMPLE_RATE, channel_count=1,
|
||||||
|
bits_per_sample=16, samples_signed=True, buffer_size=2048 )
|
||||||
|
audio.play(mixer)
|
||||||
|
vol_val = 2
|
||||||
|
mixer.voice[0].play(synth)
|
||||||
|
mixer.voice[0].level = 0.3
|
||||||
|
|
||||||
|
# these are the triads, all major
|
||||||
|
c_tones = [130.81, 164.81, 196.00]
|
||||||
|
g_tones = [196.00, 246.94, 293.66]
|
||||||
|
d_tones = [146.83, 185.00, 220.00]
|
||||||
|
a_tones = [220.00, 277.18, 329.63]
|
||||||
|
e_tones = [164.81, 207.65, 246.94]
|
||||||
|
b_tones = [246.94, 311.13, 369.99]
|
||||||
|
fsharp_tones = [185.00, 233.08, 277.18]
|
||||||
|
csharp_tones = [138.59, 174.61, 207.65]
|
||||||
|
aflat_tones = [207.65, 261.63, 311.13]
|
||||||
|
eflat_tones = [155.56, 196.00, 233.08]
|
||||||
|
bflat_tones = [233.08, 293.66, 349.23]
|
||||||
|
f_tones = [174.61, 220.00, 261.63]
|
||||||
|
|
||||||
|
# names for the alphanumeric displays
|
||||||
|
chord_names = ["Cmaj", "Gmaj", "Dmaj", "Amaj", "Emaj", "Bmaj",
|
||||||
|
"F#ma", "C#ma", "Abma", "Ebma", "Bbma", "Fmaj"]
|
||||||
|
chords = [c_tones, g_tones, d_tones, a_tones, e_tones, b_tones, fsharp_tones, csharp_tones,
|
||||||
|
aflat_tones, eflat_tones, bflat_tones, f_tones]
|
||||||
|
|
||||||
|
# i2c setup
|
||||||
|
i2c = board.I2C()
|
||||||
|
# the encoders
|
||||||
|
seesaw0 = seesaw.Seesaw(i2c, addr=0x49)
|
||||||
|
seesaw1 = seesaw.Seesaw(i2c, addr=0x4A)
|
||||||
|
seesaw2 = seesaw.Seesaw(i2c, addr=0x4B)
|
||||||
|
seesaw3 = seesaw.Seesaw(i2c, addr=0x4C)
|
||||||
|
menu_seesaw = seesaw.Seesaw(i2c, addr=0x4D)
|
||||||
|
# the alphanumeric displays
|
||||||
|
display0 = segments.Seg14x4(i2c, address=0x70)
|
||||||
|
display1 = segments.Seg14x4(i2c, address=0x71)
|
||||||
|
display2 = segments.Seg14x4(i2c, address=0x72)
|
||||||
|
display3 = segments.Seg14x4(i2c, address=0x73)
|
||||||
|
menu_display = segments.Seg14x4(i2c, address=0x74)
|
||||||
|
# the matrix
|
||||||
|
matrix0 = Matrix8x8x2(i2c, address=0x75)
|
||||||
|
|
||||||
|
seesaws = [seesaw0, seesaw1, seesaw2, seesaw3, menu_seesaw]
|
||||||
|
buttons0 = []
|
||||||
|
buttons1 = []
|
||||||
|
buttons2 = []
|
||||||
|
buttons3 = []
|
||||||
|
menu_buttons = []
|
||||||
|
button0_states = []
|
||||||
|
button1_states = []
|
||||||
|
button2_states = []
|
||||||
|
button3_states = []
|
||||||
|
menu_states = []
|
||||||
|
button0_names = ["Select", "Up", "Left", "Down", "Right"]
|
||||||
|
|
||||||
|
# setup the buttons on all of the encoders
|
||||||
|
for i in range(1, 6):
|
||||||
|
seesaw0.pin_mode(i, seesaw0.INPUT_PULLUP)
|
||||||
|
seesaw1.pin_mode(i, seesaw1.INPUT_PULLUP)
|
||||||
|
seesaw2.pin_mode(i, seesaw2.INPUT_PULLUP)
|
||||||
|
seesaw3.pin_mode(i, seesaw3.INPUT_PULLUP)
|
||||||
|
menu_seesaw.pin_mode(i, menu_seesaw.INPUT_PULLUP)
|
||||||
|
buttons0.append(digitalio.DigitalIO(seesaw0, i))
|
||||||
|
buttons1.append(digitalio.DigitalIO(seesaw1, i))
|
||||||
|
buttons2.append(digitalio.DigitalIO(seesaw2, i))
|
||||||
|
buttons3.append(digitalio.DigitalIO(seesaw3, i))
|
||||||
|
menu_buttons.append(digitalio.DigitalIO(menu_seesaw, i))
|
||||||
|
button0_states.append(False)
|
||||||
|
button1_states.append(False)
|
||||||
|
button2_states.append(False)
|
||||||
|
button3_states.append(False)
|
||||||
|
menu_states.append(False)
|
||||||
|
|
||||||
|
# make all of the encoders
|
||||||
|
encoder0 = rotaryio.IncrementalEncoder(seesaw0)
|
||||||
|
last_position0 = 0
|
||||||
|
encoder1 = rotaryio.IncrementalEncoder(seesaw1)
|
||||||
|
last_position1 = 0
|
||||||
|
encoder2 = rotaryio.IncrementalEncoder(seesaw2)
|
||||||
|
last_position2 = 0
|
||||||
|
encoder3 = rotaryio.IncrementalEncoder(seesaw3)
|
||||||
|
last_position3 = 0
|
||||||
|
menu_enc = rotaryio.IncrementalEncoder(menu_seesaw)
|
||||||
|
last_menuPosition = 0
|
||||||
|
|
||||||
|
# Python Implementation of Björklund's Algorithm by Brian House
|
||||||
|
# MIT License 2011
|
||||||
|
# https://github.com/brianhouse/bjorklund
|
||||||
|
|
||||||
|
def bjorklund(steps, pulses):
|
||||||
|
steps = int(steps)
|
||||||
|
pulses = int(pulses)
|
||||||
|
if pulses > steps:
|
||||||
|
raise ValueError
|
||||||
|
pattern = []
|
||||||
|
counts = []
|
||||||
|
remainders = []
|
||||||
|
divisor = steps - pulses
|
||||||
|
remainders.append(pulses)
|
||||||
|
level = 0
|
||||||
|
while True:
|
||||||
|
counts.append(divisor // remainders[level])
|
||||||
|
remainders.append(divisor % remainders[level])
|
||||||
|
divisor = remainders[level]
|
||||||
|
level = level + 1
|
||||||
|
if remainders[level] <= 1:
|
||||||
|
break
|
||||||
|
counts.append(divisor)
|
||||||
|
|
||||||
|
def build(level):
|
||||||
|
if level == -1:
|
||||||
|
pattern.append(0)
|
||||||
|
elif level == -2:
|
||||||
|
pattern.append(1)
|
||||||
|
else:
|
||||||
|
for _ in range(0, counts[level]):
|
||||||
|
build(level - 1)
|
||||||
|
if remainders[level] != 0:
|
||||||
|
build(level - 2)
|
||||||
|
|
||||||
|
build(level)
|
||||||
|
p = pattern.index(1)
|
||||||
|
pattern = pattern[p:] + pattern[0:p]
|
||||||
|
return pattern
|
||||||
|
|
||||||
|
# using ticks for time tracking
|
||||||
|
clock = ticks_ms()
|
||||||
|
|
||||||
|
# default BPM
|
||||||
|
bpm = 120
|
||||||
|
|
||||||
|
# beat divison
|
||||||
|
beat_div = [15, 30, 60, 120, 240]
|
||||||
|
beat_index = 2
|
||||||
|
beat_names = ["1/16", "1/8 ", "1/4 ", "1/2 ", "HOLE"]
|
||||||
|
delay = int((beat_div[beat_index] / bpm) * 1000)
|
||||||
|
|
||||||
|
# variables for euclidean
|
||||||
|
c0 = 0
|
||||||
|
c1 = 0
|
||||||
|
c2 = 0
|
||||||
|
c3 = 0
|
||||||
|
r0 = 0
|
||||||
|
r1 = 0
|
||||||
|
r2 = 0
|
||||||
|
r3 = 0
|
||||||
|
last_r0 = 0
|
||||||
|
last_r1 = 0
|
||||||
|
last_r2 = 0
|
||||||
|
last_r3 = 0
|
||||||
|
|
||||||
|
euclid0_steps = 8
|
||||||
|
euclid0_pulses = 4
|
||||||
|
euclid1_steps = 8
|
||||||
|
euclid1_pulses = 4
|
||||||
|
euclid2_steps = 8
|
||||||
|
euclid2_pulses = 4
|
||||||
|
euclid3_steps = 8
|
||||||
|
euclid3_pulses = 4
|
||||||
|
|
||||||
|
rhythm0 = bjorklund(euclid0_steps, euclid0_pulses)
|
||||||
|
rhythm1 = bjorklund(euclid1_steps, euclid1_pulses)
|
||||||
|
rhythm2 = bjorklund(euclid2_steps, euclid2_pulses)
|
||||||
|
rhythm3 = bjorklund(euclid3_steps, euclid3_pulses)
|
||||||
|
|
||||||
|
# read buttons to update Euclidean rhythms
|
||||||
|
# pylint: disable=too-many-branches
|
||||||
|
def read_buttons(button_array, button_states, euc, e_step, e_pulse, the_step):
|
||||||
|
for b in range(5):
|
||||||
|
if not button_array[b].value and button_states[b] is False:
|
||||||
|
button_states[b] = True
|
||||||
|
if button0_names[b] == "Select":
|
||||||
|
e_step = 8
|
||||||
|
e_pulse = 4
|
||||||
|
if the_step >= e_step:
|
||||||
|
the_step = 0
|
||||||
|
elif button0_names[b] == "Up":
|
||||||
|
if e_step > 16:
|
||||||
|
e_step = 16
|
||||||
|
else:
|
||||||
|
e_step += 1
|
||||||
|
elif button0_names[b] == "Down":
|
||||||
|
if e_step < 1:
|
||||||
|
e_step = 1
|
||||||
|
else:
|
||||||
|
e_step -= 1
|
||||||
|
if the_step >= e_step:
|
||||||
|
the_step = 0
|
||||||
|
elif button0_names[b] == "Left":
|
||||||
|
e_pulse -= 1
|
||||||
|
e_pulse = max(e_pulse, 1)
|
||||||
|
else:
|
||||||
|
e_pulse += 1
|
||||||
|
e_pulse = min(e_pulse, e_step)
|
||||||
|
euc = bjorklund(e_step, e_pulse)
|
||||||
|
if button_array[b].value and button_states[b] is True:
|
||||||
|
button_states[b] = False
|
||||||
|
if button0_names[b] in ("Select", "Up", "Down"):
|
||||||
|
matrix0.fill(matrix0.LED_OFF)
|
||||||
|
draw_steps(euclid0_steps, 0)
|
||||||
|
draw_steps(euclid1_steps, 2)
|
||||||
|
draw_steps(euclid2_steps, 4)
|
||||||
|
draw_steps(euclid3_steps, 6)
|
||||||
|
return euc, e_step, e_pulse, the_step
|
||||||
|
|
||||||
|
# play euclidean rhythms and update matrix
|
||||||
|
def play_euclidean(this_synth, n, the_rhythm, rhythm_count, last_count, c, matrix_slot):
|
||||||
|
if last_count <= 7:
|
||||||
|
matrix0[matrix_slot, last_count] = matrix0.LED_GREEN
|
||||||
|
else:
|
||||||
|
c -= 1
|
||||||
|
matrix0[matrix_slot + 1, (last_count - last_count) + c] = matrix0.LED_GREEN
|
||||||
|
c += 1
|
||||||
|
|
||||||
|
if the_rhythm[rhythm_count] == 1:
|
||||||
|
this_synth.frequency = n[randint(0, 2)]
|
||||||
|
synth.press(this_synth)
|
||||||
|
if rhythm_count <= 7:
|
||||||
|
matrix0[matrix_slot, rhythm_count] = matrix0.LED_RED
|
||||||
|
else:
|
||||||
|
matrix0[matrix_slot + 1, (rhythm_count - rhythm_count) + c] = matrix0.LED_RED
|
||||||
|
c += 1
|
||||||
|
else:
|
||||||
|
synth.release(this_synth)
|
||||||
|
if rhythm_count > 7:
|
||||||
|
c += 1
|
||||||
|
last_count = rhythm_count
|
||||||
|
|
||||||
|
rhythm_count += 1
|
||||||
|
if rhythm_count >= len(the_rhythm):
|
||||||
|
rhythm_count = 0
|
||||||
|
if rhythm_count == 1:
|
||||||
|
c = 0
|
||||||
|
return rhythm_count, last_count, c
|
||||||
|
|
||||||
|
# initial matrix draw
|
||||||
|
def draw_steps(euc_steps, col):
|
||||||
|
dif = 0
|
||||||
|
for m in range(euc_steps):
|
||||||
|
if m <= 7:
|
||||||
|
matrix0[col, m] = matrix0.LED_GREEN
|
||||||
|
else:
|
||||||
|
matrix0[col + 1, (m - m) + dif] = matrix0.LED_GREEN
|
||||||
|
dif += 1
|
||||||
|
draw_steps(euclid0_steps, 0)
|
||||||
|
draw_steps(euclid1_steps, 2)
|
||||||
|
draw_steps(euclid2_steps, 4)
|
||||||
|
draw_steps(euclid3_steps, 6)
|
||||||
|
|
||||||
|
# clocks for playing euclidean and reading menu encoder
|
||||||
|
enc_clock = ticks_ms()
|
||||||
|
menu_clock = ticks_ms()
|
||||||
|
|
||||||
|
# the modes menu
|
||||||
|
modes = ["PLAY", "EUC ", "BPM ", "BEAT", "ADSR", "WAVE", "RING", "LFO ", "VOL "]
|
||||||
|
mode_index = 0
|
||||||
|
mode = modes[mode_index]
|
||||||
|
menu_display.print(f" {mode}")
|
||||||
|
|
||||||
|
# default chords
|
||||||
|
chord0_sel = 0
|
||||||
|
chord1_sel = 1
|
||||||
|
chord2_sel = 0
|
||||||
|
chord3_sel = 1
|
||||||
|
|
||||||
|
display0.print(chord_names[chord0_sel])
|
||||||
|
display1.print(chord_names[chord1_sel])
|
||||||
|
display2.print(chord_names[chord2_sel])
|
||||||
|
display3.print(chord_names[chord3_sel])
|
||||||
|
|
||||||
|
# arrays of individual buttons
|
||||||
|
|
||||||
|
select_buttons = [buttons0[0], buttons1[0], buttons2[0], buttons3[0]]
|
||||||
|
left_buttons = [buttons0[2], buttons1[2], buttons2[2], buttons3[2]]
|
||||||
|
right_buttons = [buttons0[4], buttons1[4], buttons2[4], buttons3[4]]
|
||||||
|
select_states = [button0_states[0], button1_states[0], button2_states[0], button3_states[0]]
|
||||||
|
left_states = [button0_states[2], button1_states[2], button2_states[2], button3_states[2]]
|
||||||
|
right_states = [button0_states[4], button1_states[4], button2_states[4], button3_states[4]]
|
||||||
|
select_index = 0
|
||||||
|
left_index = 0
|
||||||
|
right_index = 0
|
||||||
|
|
||||||
|
# adsr mode
|
||||||
|
adsr_names = ["A", "D", "S", "R"]
|
||||||
|
|
||||||
|
synth_adsr_indexes = [0, 0, 0, 0]
|
||||||
|
|
||||||
|
adsr_properties = [0, 1, 4, 2]
|
||||||
|
|
||||||
|
adsr0_values = [amp_env0.attack_time, amp_env0.decay_time,
|
||||||
|
amp_env0.sustain_level, amp_env0.release_time]
|
||||||
|
adsr1_values = [amp_env1.attack_time, amp_env1.decay_time,
|
||||||
|
amp_env1.sustain_level, amp_env1.release_time]
|
||||||
|
adsr2_values = [amp_env0.attack_time, amp_env0.decay_time,
|
||||||
|
amp_env0.sustain_level, amp_env0.release_time]
|
||||||
|
adsr3_values = [amp_env1.attack_time, amp_env1.decay_time,
|
||||||
|
amp_env1.sustain_level, amp_env1.release_time]
|
||||||
|
|
||||||
|
all_adsr_values = [adsr0_values, adsr1_values, adsr2_values, adsr3_values]
|
||||||
|
|
||||||
|
adsr0_val = int(simpleio.map_range(amp_env0.attack_time, 0.0, 1.0, 0, 19))
|
||||||
|
|
||||||
|
adsr1_val = int(simpleio.map_range(amp_env0.decay_time, 0.0, 1.0, 0, 19))
|
||||||
|
|
||||||
|
adsr2_val = int(simpleio.map_range(amp_env0.sustain_level, 0.0, 1.0, 0, 19))
|
||||||
|
|
||||||
|
adsr3_val = int(simpleio.map_range(amp_env0.release_time, 0.0, 1.0, 0, 19))
|
||||||
|
|
||||||
|
clock_stretch = False
|
||||||
|
|
||||||
|
ring0_val = 0
|
||||||
|
ring1_val = 0
|
||||||
|
ring2_val = 0
|
||||||
|
ring3_val = 0
|
||||||
|
|
||||||
|
lfo_val = 0
|
||||||
|
|
||||||
|
# used to play/pause
|
||||||
|
play_states = [True, True, True, True]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# rotary encoder reading
|
||||||
|
if ticks_diff(ticks_ms(), enc_clock) >= 100:
|
||||||
|
position0 = encoder0.position
|
||||||
|
position1 = encoder1.position
|
||||||
|
position2 = encoder2.position
|
||||||
|
position3 = encoder3.position
|
||||||
|
menuPosition = menu_enc.position
|
||||||
|
# menu changes mode
|
||||||
|
if menuPosition != last_menuPosition:
|
||||||
|
if menuPosition > last_menuPosition:
|
||||||
|
mode_index = (mode_index + 1) % len(modes)
|
||||||
|
else:
|
||||||
|
mode_index = (mode_index - 1) % len(modes)
|
||||||
|
if mode in ("EUC ", "ADSR"):
|
||||||
|
clock_stretch = True
|
||||||
|
if mode in ("PLAY", "BPM ", "BEAT", "WAVE") and clock_stretch:
|
||||||
|
clock = ticks_ms()
|
||||||
|
clock_stretch = False
|
||||||
|
mode = modes[mode_index]
|
||||||
|
menu_display.print(f" {mode}")
|
||||||
|
last_menuPosition = menuPosition
|
||||||
|
# encoder functionality depends on mode
|
||||||
|
# encoder 0 has most functionality
|
||||||
|
if position0 != last_position0:
|
||||||
|
if position0 > last_position0:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord0_sel = (chord0_sel + 1) % len(chords)
|
||||||
|
display0.print(chord_names[chord0_sel])
|
||||||
|
elif mode == "BEAT":
|
||||||
|
beat_index = (beat_index + 1) % 5
|
||||||
|
delay = int((beat_div[beat_index] / bpm) * 1000)
|
||||||
|
display0.print(f" {beat_names[beat_index]}")
|
||||||
|
elif mode == "BPM ":
|
||||||
|
bpm += 1
|
||||||
|
delay = int((beat_div[beat_index] / bpm) * 1000)
|
||||||
|
display0.print(f" {bpm}")
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr0_val = (adsr0_val + 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr0_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[0][synth_adsr_indexes[0]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[0][0],
|
||||||
|
decay_time = all_adsr_values[0][1],
|
||||||
|
release_time=all_adsr_values[0][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[0][2])
|
||||||
|
synth0.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth0_wave = (synth0_wave + 1) % len(wave_names)
|
||||||
|
synth0.waveform = waveforms[synth0_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring0_val = (ring0_val + 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring0_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth0.ring_frequency = mapped_val
|
||||||
|
elif mode == "LFO ":
|
||||||
|
lfo_val = (lfo_val + 1) % 10
|
||||||
|
mapped_val = simpleio.map_range(lfo_val, 0, 9, 0.0, 5.0)
|
||||||
|
lfo.rate = mapped_val
|
||||||
|
elif mode == "VOL ":
|
||||||
|
vol_val = (vol_val + 1) % 10
|
||||||
|
mapped_val = simpleio.map_range(vol_val, 0, 9, 0.0, 1.0)
|
||||||
|
mixer.voice[0].level = mapped_val
|
||||||
|
else:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord0_sel = (chord0_sel - 1) % len(chords)
|
||||||
|
display0.print(chord_names[chord0_sel])
|
||||||
|
elif mode == "BEAT":
|
||||||
|
beat_index = (beat_index - 1) % 5
|
||||||
|
delay = int((beat_div[beat_index] / bpm) * 1000)
|
||||||
|
display0.print(f" {beat_names[beat_index]}")
|
||||||
|
elif mode == "BPM ":
|
||||||
|
bpm -= 1
|
||||||
|
display0.print(f" {bpm}")
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr0_val = (adsr0_val - 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr0_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[0][synth_adsr_indexes[0]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[0][0],
|
||||||
|
decay_time = all_adsr_values[0][1],
|
||||||
|
release_time=all_adsr_values[0][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[0][2])
|
||||||
|
synth0.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth0_wave = (synth0_wave - 1) % len(wave_names)
|
||||||
|
synth0.waveform = waveforms[synth0_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring0_val = (ring0_val - 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring0_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth0.ring_frequency = mapped_val
|
||||||
|
elif mode == "LFO ":
|
||||||
|
lfo_val = (lfo_val - 1) % 10
|
||||||
|
mapped_val = simpleio.map_range(lfo_val, 0, 9, 0.0, 5.0)
|
||||||
|
lfo.rate = mapped_val
|
||||||
|
elif mode == "VOL ":
|
||||||
|
vol_val = (vol_val - 1) % 10
|
||||||
|
mapped_val = simpleio.map_range(vol_val, 0, 9, 0.0, 1.0)
|
||||||
|
mixer.voice[0].level = mapped_val
|
||||||
|
last_position0 = position0
|
||||||
|
if position1 != last_position1:
|
||||||
|
if position1 > last_position1:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord1_sel = (chord1_sel + 1) % len(chords)
|
||||||
|
display1.print(chord_names[chord1_sel])
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr1_val = (adsr1_val + 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr1_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[1][synth_adsr_indexes[1]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[1][0],
|
||||||
|
decay_time = all_adsr_values[1][1],
|
||||||
|
release_time=all_adsr_values[1][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[1][2])
|
||||||
|
synth1.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth1_wave = (synth1_wave + 1) % len(wave_names)
|
||||||
|
synth1.waveform = waveforms[synth1_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring1_val = (ring1_val + 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring1_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth1.ring_frequency = mapped_val
|
||||||
|
else:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord1_sel = (chord1_sel - 1) % len(chords)
|
||||||
|
display1.print(chord_names[chord1_sel])
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr1_val = (adsr1_val - 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr1_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[1][synth_adsr_indexes[1]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[1][0],
|
||||||
|
decay_time = all_adsr_values[1][1],
|
||||||
|
release_time=all_adsr_values[1][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[1][2])
|
||||||
|
synth1.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth1_wave = (synth1_wave - 1) % len(wave_names)
|
||||||
|
synth1.waveform = waveforms[synth1_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring1_val = (ring1_val - 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring1_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth1.ring_frequency = mapped_val
|
||||||
|
last_position1 = position1
|
||||||
|
if position2 != last_position2:
|
||||||
|
if position2 > last_position2:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord2_sel = (chord2_sel + 1) % len(chords)
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr2_val = (adsr2_val + 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr2_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[2][synth_adsr_indexes[2]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[2][0],
|
||||||
|
decay_time = all_adsr_values[2][1],
|
||||||
|
release_time=all_adsr_values[2][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[2][2])
|
||||||
|
synth2.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth2_wave = (synth2_wave + 1) % len(wave_names)
|
||||||
|
synth2.waveform = waveforms[synth2_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring2_val = (ring2_val + 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring2_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth2.ring_frequency = mapped_val
|
||||||
|
else:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord2_sel = (chord2_sel - 1) % len(chords)
|
||||||
|
display2.print(chord_names[chord2_sel])
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr2_val = (adsr2_val - 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr2_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[2][synth_adsr_indexes[2]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[2][0],
|
||||||
|
decay_time = all_adsr_values[2][1],
|
||||||
|
release_time=all_adsr_values[2][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[2][2])
|
||||||
|
synth2.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth2_wave = (synth2_wave - 1) % len(wave_names)
|
||||||
|
synth2.waveform = waveforms[synth2_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring2_val = (ring2_val - 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring2_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth2.ring_frequency = mapped_val
|
||||||
|
last_position2 = position2
|
||||||
|
if position3 != last_position3:
|
||||||
|
if position3 > last_position3:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord3_sel = (chord3_sel + 1) % len(chords)
|
||||||
|
display3.print(chord_names[chord3_sel])
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr3_val = (adsr3_val + 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr3_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[3][synth_adsr_indexes[3]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[3][0],
|
||||||
|
decay_time = all_adsr_values[3][1],
|
||||||
|
release_time=all_adsr_values[3][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[3][2])
|
||||||
|
synth3.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth3_wave = (synth3_wave + 1) % len(wave_names)
|
||||||
|
synth3.waveform = waveforms[synth3_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring3_val = (ring3_val + 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring3_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth3.ring_frequency = mapped_val
|
||||||
|
else:
|
||||||
|
if mode == "PLAY":
|
||||||
|
chord3_sel = (chord3_sel - 1) % len(chords)
|
||||||
|
display3.print(chord_names[chord3_sel])
|
||||||
|
elif mode == "ADSR":
|
||||||
|
adsr3_val = (adsr3_val - 1) % 20
|
||||||
|
mapped_val = simpleio.map_range(adsr3_val, 0, 19, 0.0, 1.0)
|
||||||
|
all_adsr_values[3][synth_adsr_indexes[3]] = mapped_val
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[3][0],
|
||||||
|
decay_time = all_adsr_values[3][1],
|
||||||
|
release_time=all_adsr_values[3][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[3][2])
|
||||||
|
synth3.envelope = the_env
|
||||||
|
elif mode == "WAVE":
|
||||||
|
synth3_wave = (synth3_wave - 1) % len(wave_names)
|
||||||
|
synth3.waveform = waveforms[synth3_wave]
|
||||||
|
elif mode == "RING":
|
||||||
|
ring3_val = (ring3_val - 1) % 25
|
||||||
|
mapped_val = simpleio.map_range(ring3_val, 0, 24, 0.0, 220.0)
|
||||||
|
synth3.ring_frequency = mapped_val
|
||||||
|
last_position3 = position3
|
||||||
|
enc_clock = ticks_add(enc_clock, 100)
|
||||||
|
|
||||||
|
# synth plays based on ticks timing
|
||||||
|
if ticks_diff(ticks_ms(), clock) >= delay:
|
||||||
|
if play_states[0] is True:
|
||||||
|
r0, last_r0, c0 = play_euclidean(synth0, chords[chord0_sel],
|
||||||
|
rhythm0, r0, last_r0, c0, 0)
|
||||||
|
if play_states[1] is True:
|
||||||
|
r1, last_r1, c1 = play_euclidean(synth1, chords[chord1_sel],
|
||||||
|
rhythm1, r1, last_r1, c1, 2)
|
||||||
|
if play_states[2] is True:
|
||||||
|
r2, last_r2, c2 = play_euclidean(synth2, chords[chord2_sel],
|
||||||
|
rhythm2, r2, last_r2, c2, 4)
|
||||||
|
if play_states[3] is True:
|
||||||
|
r3, last_r3, c3 = play_euclidean(synth3, chords[chord3_sel],
|
||||||
|
rhythm3, r3, last_r3, c3, 6)
|
||||||
|
clock = ticks_add(clock, delay)
|
||||||
|
# in PLAY select button controls play/pause
|
||||||
|
if mode == "PLAY":
|
||||||
|
for i in range(4):
|
||||||
|
if not select_buttons[i].value and select_states[i] is False:
|
||||||
|
select_states[i] = True
|
||||||
|
if play_states[i] is True:
|
||||||
|
synth.release(synths[i])
|
||||||
|
play_states[i] = False
|
||||||
|
else:
|
||||||
|
play_states[i] = True
|
||||||
|
if select_buttons[i].value and select_states[i] is True:
|
||||||
|
select_states[i] = False
|
||||||
|
display0.print(chord_names[chord0_sel])
|
||||||
|
display1.print(chord_names[chord1_sel])
|
||||||
|
display2.print(chord_names[chord2_sel])
|
||||||
|
display3.print(chord_names[chord3_sel])
|
||||||
|
# EUC menu select resets cycle count
|
||||||
|
elif mode == "EUC ":
|
||||||
|
if not menu_buttons[0].value and menu_states[0] is False:
|
||||||
|
r0 = 0
|
||||||
|
r1 = 0
|
||||||
|
r2 = 0
|
||||||
|
r3 = 0
|
||||||
|
menu_states[0] = True
|
||||||
|
if menu_buttons[0].value and menu_states[0] is True:
|
||||||
|
menu_states[0] = False
|
||||||
|
rhythm0, euclid0_steps, euclid0_pulses, r0 = read_buttons(buttons0, button0_states,
|
||||||
|
rhythm0, euclid0_steps,
|
||||||
|
euclid0_pulses, r0)
|
||||||
|
rhythm1, euclid1_steps, euclid1_pulses, r1 = read_buttons(buttons1, button1_states,
|
||||||
|
rhythm1, euclid1_steps,
|
||||||
|
euclid1_pulses, r1)
|
||||||
|
rhythm2, euclid2_steps, euclid2_pulses, r2 = read_buttons(buttons2, button2_states,
|
||||||
|
rhythm2, euclid2_steps,
|
||||||
|
euclid2_pulses, r2)
|
||||||
|
rhythm3, euclid3_steps, euclid3_pulses, r3 = read_buttons(buttons3, button3_states,
|
||||||
|
rhythm3, euclid3_steps,
|
||||||
|
euclid3_pulses, r3)
|
||||||
|
display0.print(f" {euclid0_pulses}")
|
||||||
|
display1.print(f" {euclid1_pulses}")
|
||||||
|
display2.print(f" {euclid2_pulses}")
|
||||||
|
display3.print(f" {euclid3_pulses}")
|
||||||
|
# BPM is adjusted
|
||||||
|
elif mode == "BPM ":
|
||||||
|
if not select_buttons[0].value and select_states[0] is False:
|
||||||
|
bpm = 120
|
||||||
|
select_states[0] = True
|
||||||
|
if select_buttons[0].value and select_states[0] is True:
|
||||||
|
select_states[0] = False
|
||||||
|
display0.print(f" {bpm}")
|
||||||
|
display1.print(" ")
|
||||||
|
display2.print(" ")
|
||||||
|
display3.print(" ")
|
||||||
|
# beat division is changed
|
||||||
|
elif mode == "BEAT":
|
||||||
|
if not select_buttons[0].value and select_states[0] is False:
|
||||||
|
beat_names[beat_index] = 2
|
||||||
|
select_states[0] = True
|
||||||
|
if select_buttons[0].value and select_states[0] is True:
|
||||||
|
select_states[0] = False
|
||||||
|
display0.print(f" {beat_names[beat_index]}")
|
||||||
|
display1.print(" ")
|
||||||
|
display2.print(" ")
|
||||||
|
display3.print(" ")
|
||||||
|
# adsr for each voice
|
||||||
|
elif mode == "ADSR":
|
||||||
|
for i in range(4):
|
||||||
|
if not left_buttons[i].value and left_states[i] is False:
|
||||||
|
synth_adsr_indexes[i] = (synth_adsr_indexes[i] - 1) % 4
|
||||||
|
left_states[i] = True
|
||||||
|
the_synth = synths[i]
|
||||||
|
if left_buttons[i].value and left_states[i] is True:
|
||||||
|
left_states[i] = False
|
||||||
|
if not right_buttons[i].value and right_states[i] is False:
|
||||||
|
synth_adsr_indexes[i] = (synth_adsr_indexes[i] + 1) % 4
|
||||||
|
right_states[i] = True
|
||||||
|
if right_buttons[i].value and right_states[i] is True:
|
||||||
|
right_states[i] = False
|
||||||
|
if not select_buttons[i].value and select_states[i] is False:
|
||||||
|
the_synth = synths[i]
|
||||||
|
all_adsr_values[i][0] = 0.1
|
||||||
|
all_adsr_values[i][1] = 0.1
|
||||||
|
all_adsr_values[i][3] = 0.1
|
||||||
|
all_adsr_values[i][2] = 0.05
|
||||||
|
the_env = synthio.Envelope(attack_time=all_adsr_values[i][0],
|
||||||
|
decay_time = all_adsr_values[i][1],
|
||||||
|
release_time=all_adsr_values[i][3],
|
||||||
|
attack_level=1, sustain_level=all_adsr_values[i][2])
|
||||||
|
the_synth.envelope = the_env
|
||||||
|
select_states[i] = True
|
||||||
|
if select_buttons[i].value and select_states[i] is True:
|
||||||
|
select_states[i] = False
|
||||||
|
# pylint: disable=line-too-long
|
||||||
|
display0.print(f"{adsr_names[synth_adsr_indexes[0]]}{synth0.envelope[adsr_properties[synth_adsr_indexes[0]]]:.2f}")
|
||||||
|
display1.print(f"{adsr_names[synth_adsr_indexes[1]]}{synth1.envelope[adsr_properties[synth_adsr_indexes[1]]]:.2f}")
|
||||||
|
display2.print(f"{adsr_names[synth_adsr_indexes[2]]}{synth2.envelope[adsr_properties[synth_adsr_indexes[2]]]:.2f}")
|
||||||
|
display3.print(f"{adsr_names[synth_adsr_indexes[3]]}{synth3.envelope[adsr_properties[synth_adsr_indexes[3]]]:.2f}")
|
||||||
|
# change waveform
|
||||||
|
elif mode == "WAVE":
|
||||||
|
display0.print(f" {wave_names[synth0_wave]}")
|
||||||
|
display1.print(f" {wave_names[synth1_wave]}")
|
||||||
|
display2.print(f" {wave_names[synth2_wave]}")
|
||||||
|
display3.print(f" {wave_names[synth3_wave]}")
|
||||||
|
# adjust ring modulation
|
||||||
|
elif mode == "RING":
|
||||||
|
display0.print(f" {synth0.ring_frequency:.1f}")
|
||||||
|
display1.print(f" {synth1.ring_frequency:.1f}")
|
||||||
|
display2.print(f" {synth2.ring_frequency:.1f}")
|
||||||
|
display3.print(f" {synth3.ring_frequency:.1f}")
|
||||||
|
# adjust lfo rate used for ring modulation
|
||||||
|
elif mode == "LFO ":
|
||||||
|
display0.print("RATE")
|
||||||
|
display1.print(f" {lfo.rate:.1f}")
|
||||||
|
display2.print(" ")
|
||||||
|
display3.print(" ")
|
||||||
|
# overall volume 0.0 - 1.0
|
||||||
|
elif mode == "VOL ":
|
||||||
|
display0.print(f" {mixer.voice[0].level:.1f}")
|
||||||
|
display1.print(" ")
|
||||||
|
display2.print(" ")
|
||||||
|
display3.print(" ")
|
||||||
Loading…
Reference in a new issue