Major update to sequencer again. Added track toggle and track clear.
This commit is contained in:
parent
cc213eae2f
commit
d30e3ce4ab
1 changed files with 205 additions and 129 deletions
|
@ -12,7 +12,12 @@
|
||||||
# Each track is colour-coded: track 1 is orange, track 2 blue, track 3 is pink,
|
# Each track is colour-coded: track 1 is orange, track 2 blue, track 3 is pink,
|
||||||
# and track 4 is green. Tracks can be selected by pressing and holding the
|
# and track 4 is green. Tracks can be selected by pressing and holding the
|
||||||
# bottom left orange track select key and then tapping one of the four track
|
# bottom left orange track select key and then tapping one of the four track
|
||||||
# keys on the row above.
|
# keys on the row above. The currently focussed track's track select key (on the
|
||||||
|
# second bottom row) is highlighted in a brighter colour.
|
||||||
|
|
||||||
|
# A track can be toggled on or off (no notes are sent from that track, but notes
|
||||||
|
# are not deleted) by tapping the track's track select key. The track select LED
|
||||||
|
# for a track toggled off will not be lit.
|
||||||
|
|
||||||
# The sequencer is started and stopped by tapping the bottom right key, which is
|
# The sequencer is started and stopped by tapping the bottom right key, which is
|
||||||
# red when the sequencer is stopped, and green when it is playing.
|
# red when the sequencer is stopped, and green when it is playing.
|
||||||
|
@ -20,6 +25,10 @@
|
||||||
# The sequencer can be cleared by holding the track selector key (orange, bottom
|
# The sequencer can be cleared by holding the track selector key (orange, bottom
|
||||||
# left) and then holding the start/stop key (red/green, bottom right).
|
# left) and then holding the start/stop key (red/green, bottom right).
|
||||||
|
|
||||||
|
# A single track can be cleared by holding the track selector key, the track
|
||||||
|
# select key (on the second bottom row) for the track you want to clear, and
|
||||||
|
# then holding the start/stop key.
|
||||||
|
|
||||||
# Tempo can be increased or decreased by holding the tempo selector key (blue,
|
# Tempo can be increased or decreased by holding the tempo selector key (blue,
|
||||||
# second from left, on the bottom row) and then tapping blue key on the row
|
# second from left, on the bottom row) and then tapping blue key on the row
|
||||||
# above to shift tempo down, or the pink key to shift it up. Tempo is increased/
|
# above to shift tempo down, or the pink key to shift it up. Tempo is increased/
|
||||||
|
@ -33,12 +42,10 @@
|
||||||
# You'll need to connect Keybow 2040 to a computer running a DAW like Ableton,
|
# You'll need to connect Keybow 2040 to a computer running a DAW like Ableton,
|
||||||
# or other software synth, or to a hardware synth that accepts USB MIDI.
|
# or other software synth, or to a hardware synth that accepts USB MIDI.
|
||||||
|
|
||||||
# Currently, all of the notes are C3 with a velocity of 127.
|
|
||||||
|
|
||||||
# Tracks' notes are sent on MIDI channels 1-4.
|
# Tracks' notes are sent on MIDI channels 1-4.
|
||||||
|
|
||||||
# Drop the keybow2040.py file into your `lib` folder on your `CIRCUITPY` drive,
|
# Drop the keybow2040.py file into your `lib` folder on your `CIRCUITPY` drive,
|
||||||
# and then save this code in the `code.py` file
|
# and then save this code in the `code.py` file.
|
||||||
|
|
||||||
# NOTE! Requires the adafruit_midi CircuitPython library also!
|
# NOTE! Requires the adafruit_midi CircuitPython library also!
|
||||||
|
|
||||||
|
@ -51,6 +58,9 @@ import adafruit_midi
|
||||||
from adafruit_midi.note_off import NoteOff
|
from adafruit_midi.note_off import NoteOff
|
||||||
from adafruit_midi.note_on import NoteOn
|
from adafruit_midi.note_on import NoteOn
|
||||||
|
|
||||||
|
|
||||||
|
## CONSTANTS. Change these to change the look and feel of the sequencer.
|
||||||
|
|
||||||
# These are the key numbers that represent each step in a track (the top two
|
# These are the key numbers that represent each step in a track (the top two
|
||||||
# rows of four keys)
|
# rows of four keys)
|
||||||
TRACK_KEYS = [3, 7, 11, 15, 2, 6, 10, 14]
|
TRACK_KEYS = [3, 7, 11, 15, 2, 6, 10, 14]
|
||||||
|
@ -110,9 +120,9 @@ MAX_BPM = 200
|
||||||
KEY_HOLD_TIME = 0.25
|
KEY_HOLD_TIME = 0.25
|
||||||
|
|
||||||
# LED brightness settings for the track steps.
|
# LED brightness settings for the track steps.
|
||||||
PLAY_BRIGHTNESS = 1.0
|
HIGH_BRIGHTNESS = 1.0
|
||||||
ACTIVE_BRIGHTNESS = 0.2
|
MID_BRIGHTNESS = 0.2
|
||||||
STEP_BRIGHTNESS = 0.05
|
LOW_BRIGHTNESS = 0.05
|
||||||
|
|
||||||
# Start on middle C and a reasonably high velocity.
|
# Start on middle C and a reasonably high velocity.
|
||||||
DEFAULT_NOTE = 60
|
DEFAULT_NOTE = 60
|
||||||
|
@ -121,6 +131,7 @@ MAX_VELOCITY = 127
|
||||||
MAX_NOTE = 127
|
MAX_NOTE = 127
|
||||||
VELOCITY_STEP = 4
|
VELOCITY_STEP = 4
|
||||||
|
|
||||||
|
|
||||||
class Sequencer(Keybow2040):
|
class Sequencer(Keybow2040):
|
||||||
"""
|
"""
|
||||||
Represents the sequencer, with a set of Track instances, which in turn have
|
Represents the sequencer, with a set of Track instances, which in turn have
|
||||||
|
@ -148,6 +159,17 @@ class Sequencer(Keybow2040):
|
||||||
track_key.index = i
|
track_key.index = i
|
||||||
self.track_keys.append(track_key)
|
self.track_keys.append(track_key)
|
||||||
|
|
||||||
|
# These keys select and change the current track.
|
||||||
|
self.track_select_keys = []
|
||||||
|
|
||||||
|
for i in range(len(TRACK_SELECTOR_KEYS)):
|
||||||
|
track_select_key = self.keys[TRACK_SELECTOR_KEYS[i]]
|
||||||
|
track_select_key.rgb = TRACK_COLOURS[i]
|
||||||
|
self.track_select_keys.append(track_select_key)
|
||||||
|
|
||||||
|
self.track_select_keys_held = [False, False, False, False]
|
||||||
|
self.track_select_active = False
|
||||||
|
|
||||||
# Holds the list of tracks, a set of Track instances.
|
# Holds the list of tracks, a set of Track instances.
|
||||||
self.tracks = []
|
self.tracks = []
|
||||||
|
|
||||||
|
@ -189,19 +211,11 @@ class Sequencer(Keybow2040):
|
||||||
# The start stop key.
|
# The start stop key.
|
||||||
self.start_stop = self.keys[START_STOP]
|
self.start_stop = self.keys[START_STOP]
|
||||||
self.start_stop.set_led(*STOP_COLOUR)
|
self.start_stop.set_led(*STOP_COLOUR)
|
||||||
|
self.start_stop_held = False
|
||||||
|
|
||||||
# The track selector key.
|
# The track selector key.
|
||||||
self.track_selector = self.keys[TRACK_SELECTOR]
|
self.track_selector = self.keys[TRACK_SELECTOR]
|
||||||
self.track_selector.set_led(*TRACK_SELECTOR_COLOUR)
|
self.track_selector.set_led(*TRACK_SELECTOR_COLOUR)
|
||||||
self.track_selector_active = False
|
|
||||||
|
|
||||||
# These keys select and change the current track.
|
|
||||||
self.track_select_keys = []
|
|
||||||
|
|
||||||
for i in range(len(TRACK_SELECTOR_KEYS)):
|
|
||||||
track_select_key = self.keys[TRACK_SELECTOR_KEYS[i]]
|
|
||||||
track_select_key.rgb = TRACK_COLOURS[i]
|
|
||||||
self.track_select_keys.append(track_select_key)
|
|
||||||
|
|
||||||
# Set the key hold time for all the keys. A little shorter than the
|
# Set the key hold time for all the keys. A little shorter than the
|
||||||
# default for Keybow. Makes controlling the sequencer a bit more fluid.
|
# default for Keybow. Makes controlling the sequencer a bit more fluid.
|
||||||
|
@ -213,122 +227,121 @@ class Sequencer(Keybow2040):
|
||||||
for key in self.track_keys:
|
for key in self.track_keys:
|
||||||
@self.on_release(key)
|
@self.on_release(key)
|
||||||
def step_select(key):
|
def step_select(key):
|
||||||
if not key.held:
|
if self.tracks[self.current_track].active:
|
||||||
step = self.tracks[self.current_track].steps[key.index]
|
if not key.held:
|
||||||
step.toggle()
|
step = self.tracks[self.current_track].steps[key.index]
|
||||||
if not step.active:
|
step.toggle()
|
||||||
current_note = step.note
|
if not step.active:
|
||||||
self.midi_channels[track.channel].send(NoteOff(current_note, 0))
|
current_note = step.note
|
||||||
step.note = DEFAULT_NOTE
|
self.midi_channels[track.channel].send(NoteOff(current_note, 0))
|
||||||
step.velocity = DEFAULT_VELOCITY
|
step.note = DEFAULT_NOTE
|
||||||
else:
|
step.velocity = DEFAULT_VELOCITY
|
||||||
self.steps_held.remove(key.index)
|
else:
|
||||||
self.note_down.led_off()
|
self.steps_held.remove(key.index)
|
||||||
self.note_up.led_off()
|
self.note_down.led_off()
|
||||||
self.velocity_down.led_off()
|
self.note_up.led_off()
|
||||||
self.velocity_up.led_off()
|
self.velocity_down.led_off()
|
||||||
|
self.velocity_up.led_off()
|
||||||
|
|
||||||
|
self.update_track_select_keys(True)
|
||||||
|
|
||||||
# When step held, toggle on the note and velocity up/down keys.
|
# When step held, toggle on the note and velocity up/down keys.
|
||||||
@self.on_hold(key)
|
@self.on_hold(key)
|
||||||
def step_change(key):
|
def step_change(key):
|
||||||
self.steps_held.append(key.index)
|
if self.tracks[self.current_track].active:
|
||||||
self.note_down.set_led(*NOTE_DOWN_COLOUR)
|
self.steps_held.append(key.index)
|
||||||
self.note_up.set_led(*NOTE_UP_COLOUR)
|
self.note_down.set_led(*NOTE_DOWN_COLOUR)
|
||||||
self.velocity_down.set_led(*VELOCITY_DOWN_COLOUR)
|
self.note_up.set_led(*NOTE_UP_COLOUR)
|
||||||
self.velocity_up.set_led(*VELOCITY_UP_COLOUR)
|
self.velocity_down.set_led(*VELOCITY_DOWN_COLOUR)
|
||||||
|
self.velocity_up.set_led(*VELOCITY_UP_COLOUR)
|
||||||
|
|
||||||
|
self.update_track_select_keys(False)
|
||||||
|
|
||||||
# Attach hold function to track selector key that sets it active and
|
# Attach hold function to track selector key that sets it active and
|
||||||
# lights the track select keys.
|
# lights the track select keys.
|
||||||
@self.on_hold(self.track_selector)
|
@self.on_hold(self.track_selector)
|
||||||
def track_selector_hold(key):
|
def track_selector_hold(key):
|
||||||
self.track_selector_active = True
|
self.track_select_active = True
|
||||||
|
|
||||||
for k in range(len(self.track_select_keys)):
|
for track in self.tracks:
|
||||||
key = self.track_select_keys[k]
|
track.update_track_select_key = True
|
||||||
key.set_led(*TRACK_COLOURS[k])
|
|
||||||
key.led_on()
|
|
||||||
|
|
||||||
# Attach release function to track selector key that sets it inactive
|
# Attach release function to track selector key that sets it inactive
|
||||||
# and turns track select LEDs off.
|
# and turns track select LEDs off.
|
||||||
@self.on_release(self.track_selector)
|
@self.on_release(self.track_selector)
|
||||||
def track_selector_release(key):
|
def track_selector_release(key):
|
||||||
self.track_selector_active = False
|
self.track_select_active = False
|
||||||
|
self.update_track_select_keys(True)
|
||||||
|
|
||||||
for key in self.track_select_keys:
|
# Handles track select/mute, tempo down/up, note down/up.
|
||||||
key.led_off()
|
#
|
||||||
|
# If the tempo selector key (second from left, blue, on the bottom row)
|
||||||
|
# is held, pressing the tempo keys (the left two keys on the second
|
||||||
|
# bottom row, lit blue and pink) shifts the tempo down or up by
|
||||||
|
# 5 bpm each time it is pressed, with a lower limit of 5 BPM and upper
|
||||||
|
# limit of 200 BPM.
|
||||||
|
#
|
||||||
|
# If notes are held, then the four track select keys allow the held
|
||||||
|
# notes MIDI note number to be shifted down/up (track select keys 0
|
||||||
|
# and 1 respectively), or MIDI velocity to be shifted down/up (track
|
||||||
|
# select keys 2 and 3 respectively).
|
||||||
|
#
|
||||||
|
# If the track selector is not held, tapping this track button toggles
|
||||||
|
#the track on/off.
|
||||||
|
for key in self.track_select_keys:
|
||||||
|
|
||||||
# Handles track 0 select, tempo down, note down.
|
@self.on_press(key)
|
||||||
# Pressing the tempo down key shifts the tempo down by
|
def track_select_press(key):
|
||||||
# 5 bpm each time it is pressed, with a lower limit of 5 BPM.
|
index = TRACK_SELECTOR_KEYS.index(key.number)
|
||||||
# If notes are held, then tapping this key decrements the MIDI note
|
if self.track_select_active:
|
||||||
# number by one.
|
self.current_track = index
|
||||||
@self.on_press(self.track_select_keys[0])
|
elif self.tempo_select_active:
|
||||||
def track_select_0_press(key):
|
if index == 0:
|
||||||
if self.track_selector_active:
|
if self.bpm > 5:
|
||||||
self.current_track = 0
|
self.bpm -= 5
|
||||||
elif self.tempo_select_active:
|
elif index == 1:
|
||||||
if self.bpm > 5:
|
if self.bpm < 200:
|
||||||
self.bpm -= 5
|
self.bpm += 5
|
||||||
elif len(self.steps_held):
|
elif len(self.steps_held):
|
||||||
for i in self.steps_held:
|
for i in self.steps_held:
|
||||||
step = self.tracks[self.current_track].steps[i]
|
step = self.tracks[self.current_track].steps[i]
|
||||||
step.last_notes.append(step.note)
|
if index == 0 or index == 1:
|
||||||
step.note_changed = True
|
step.last_notes.append(step.note)
|
||||||
if step.note > 0:
|
step.note_changed = True
|
||||||
step.note -= 1
|
if index == 0:
|
||||||
|
if step.note > 0:
|
||||||
|
step.note -= 1
|
||||||
|
elif index == 1:
|
||||||
|
if step.note < MAX_NOTE:
|
||||||
|
step.note += 1
|
||||||
|
elif index == 2:
|
||||||
|
if step.velocity > 0 + VELOCITY_STEP:
|
||||||
|
step.velocity -= VELOCITY_STEP
|
||||||
|
elif index == 3:
|
||||||
|
if step.velocity <= MAX_VELOCITY - VELOCITY_STEP:
|
||||||
|
step.velocity += VELOCITY_STEP
|
||||||
|
else:
|
||||||
|
self.tracks[index].active = not self.tracks[index].active
|
||||||
|
self.tracks[index].update_track_select_key = True
|
||||||
|
|
||||||
# Handles track 1 select, tempo up, note up.
|
# Handlers to hold held states of track select keys.
|
||||||
# Pressing the tempo up key shifts the tempo up by
|
for key in self.track_select_keys:
|
||||||
# 5 bpm each time it is pressed, with an upper limit of 200 BPM.
|
@self.on_hold(key)
|
||||||
# If notes are held, then tapping this key increments the MIDI note
|
def track_select_key_hold(key):
|
||||||
# number by one.
|
index = TRACK_SELECTOR_KEYS.index(key.number)
|
||||||
@self.on_press(self.track_select_keys[1])
|
self.track_select_keys_held[index] = True
|
||||||
def track_select_1_press(key):
|
|
||||||
if self.track_selector_active:
|
|
||||||
self.current_track = 1
|
|
||||||
elif self.tempo_select_active:
|
|
||||||
if self.bpm < 200:
|
|
||||||
self.bpm += 5
|
|
||||||
elif len(self.steps_held):
|
|
||||||
for i in self.steps_held:
|
|
||||||
step = self.tracks[self.current_track].steps[i]
|
|
||||||
step.last_notes.append(step.note)
|
|
||||||
step.note_changed = True
|
|
||||||
if step.note < MAX_NOTE:
|
|
||||||
step.note += 1
|
|
||||||
|
|
||||||
# Handles track 2 select, velocity down.
|
@self.on_release(key)
|
||||||
# If notes are held, then tapping this key decrements the velocity by
|
def track_select_key_release(key):
|
||||||
# four.
|
index = TRACK_SELECTOR_KEYS.index(key.number)
|
||||||
@self.on_press(self.track_select_keys[2])
|
self.track_select_keys_held[index] = False
|
||||||
def track_select_2_press(key):
|
|
||||||
if self.track_selector_active:
|
|
||||||
self.current_track = 2
|
|
||||||
elif len(self.steps_held):
|
|
||||||
for i in self.steps_held:
|
|
||||||
step = self.tracks[self.current_track].steps[i]
|
|
||||||
if step.velocity > 0 + VELOCITY_STEP:
|
|
||||||
step.velocity -= VELOCITY_STEP
|
|
||||||
|
|
||||||
# Handles track 3 select, velocity up.
|
|
||||||
# If notes are held, then tapping this key increments the velocity by
|
|
||||||
# four.
|
|
||||||
@self.on_press(self.track_select_keys[3])
|
|
||||||
def track_select_3_press(key):
|
|
||||||
if self.track_selector_active:
|
|
||||||
self.current_track = 3
|
|
||||||
elif len(self.steps_held):
|
|
||||||
for i in self.steps_held:
|
|
||||||
step = self.tracks[self.current_track].steps[i]
|
|
||||||
if step.velocity <= MAX_VELOCITY - VELOCITY_STEP:
|
|
||||||
step.velocity += VELOCITY_STEP
|
|
||||||
|
|
||||||
# Attach press function to start/stop key that toggles whether the
|
# Attach press function to start/stop key that toggles whether the
|
||||||
# sequencer is running and toggles its colour between green (running)
|
# sequencer is running and toggles its colour between green (running)
|
||||||
# and red (not running).
|
# and red (not running).
|
||||||
@self.on_press(self.start_stop)
|
@self.on_press(self.start_stop)
|
||||||
def start_stop_toggle(key):
|
def start_stop_toggle(key):
|
||||||
if not self.track_selector_active:
|
if not self.track_select_active:
|
||||||
if self.running:
|
if self.running:
|
||||||
self.running = False
|
self.running = False
|
||||||
key.set_led(*STOP_COLOUR)
|
key.set_led(*STOP_COLOUR)
|
||||||
|
@ -338,13 +351,24 @@ class Sequencer(Keybow2040):
|
||||||
|
|
||||||
# Attach hold function, so that when the track selector key is held and
|
# Attach hold function, so that when the track selector key is held and
|
||||||
# the start/stop key is also held, clear all of the steps on all of the
|
# the start/stop key is also held, clear all of the steps on all of the
|
||||||
# tracks.
|
# tracks. If a track select key is held, then clear just that track.
|
||||||
@self.on_hold(self.start_stop)
|
@self.on_hold(self.start_stop)
|
||||||
def start_stop_hold(key):
|
def start_stop_hold(key):
|
||||||
if self.track_selector_active:
|
self.start_stop_held = True
|
||||||
self.clear_tracks()
|
|
||||||
for track in self.tracks:
|
if self.track_select_active:
|
||||||
track.midi_panic()
|
if not any(self.track_select_keys_held):
|
||||||
|
self.clear_tracks()
|
||||||
|
for track in self.tracks:
|
||||||
|
track.midi_panic()
|
||||||
|
else:
|
||||||
|
for i, state in enumerate(self.track_select_keys_held):
|
||||||
|
if state:
|
||||||
|
self.tracks[i].clear_steps()
|
||||||
|
|
||||||
|
@self.on_release(self.start_stop)
|
||||||
|
def start_stop_release(key):
|
||||||
|
self.start_stop_held = False
|
||||||
|
|
||||||
# Attach hold function that lights the tempo down/up keys when the
|
# Attach hold function that lights the tempo down/up keys when the
|
||||||
# tempo selector key is held.
|
# tempo selector key is held.
|
||||||
|
@ -355,6 +379,7 @@ class Sequencer(Keybow2040):
|
||||||
self.tempo_up.set_led(*TEMPO_UP_COLOUR)
|
self.tempo_up.set_led(*TEMPO_UP_COLOUR)
|
||||||
self.track_select_keys[2].led_off()
|
self.track_select_keys[2].led_off()
|
||||||
self.track_select_keys[3].led_off()
|
self.track_select_keys[3].led_off()
|
||||||
|
self.update_track_select_keys(False)
|
||||||
|
|
||||||
# Attach release function that furns off the tempo down/up LEDs.
|
# Attach release function that furns off the tempo down/up LEDs.
|
||||||
@self.on_release(self.tempo_selector)
|
@self.on_release(self.tempo_selector)
|
||||||
|
@ -362,6 +387,7 @@ class Sequencer(Keybow2040):
|
||||||
self.tempo_select_active = False
|
self.tempo_select_active = False
|
||||||
self.tempo_down.led_off()
|
self.tempo_down.led_off()
|
||||||
self.tempo_up.led_off()
|
self.tempo_up.led_off()
|
||||||
|
self.update_track_select_keys(True)
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Update the superclass (Keybow2040).
|
# Update the superclass (Keybow2040).
|
||||||
|
@ -410,6 +436,13 @@ class Sequencer(Keybow2040):
|
||||||
if this_step.active:
|
if this_step.active:
|
||||||
self.midi_channels[track.channel].send(NoteOn(this_note, this_vel))
|
self.midi_channels[track.channel].send(NoteOn(this_note, this_vel))
|
||||||
|
|
||||||
|
# If track is not active, send note off for last note and this note.
|
||||||
|
else:
|
||||||
|
last_note = track.steps[self.last_step_num].note
|
||||||
|
this_note = track.steps[self.this_step_num].note
|
||||||
|
self.midi_channels[track.channel].send(NoteOff(last_note, 0))
|
||||||
|
self.midi_channels[track.channel].send(NoteOff(this_note, 0))
|
||||||
|
|
||||||
# This step is now the last step!
|
# This step is now the last step!
|
||||||
last_step = this_step
|
last_step = this_step
|
||||||
self.last_step_num = self.this_step_num
|
self.last_step_num = self.this_step_num
|
||||||
|
@ -434,6 +467,11 @@ class Sequencer(Keybow2040):
|
||||||
for track in self.tracks:
|
for track in self.tracks:
|
||||||
track.clear_steps()
|
track.clear_steps()
|
||||||
|
|
||||||
|
def update_track_select_keys(self, state):
|
||||||
|
# Updates all of the track select keys' states in one go.
|
||||||
|
for track in self.tracks:
|
||||||
|
track.update_track_select_key = state
|
||||||
|
|
||||||
|
|
||||||
class Track:
|
class Track:
|
||||||
"""
|
"""
|
||||||
|
@ -451,6 +489,9 @@ class Track:
|
||||||
self.steps = []
|
self.steps = []
|
||||||
self.sequencer = sequencer
|
self.sequencer = sequencer
|
||||||
self.track_keys = self.sequencer.track_keys
|
self.track_keys = self.sequencer.track_keys
|
||||||
|
self.update_track_leds = False
|
||||||
|
self.update_track_select_key = True
|
||||||
|
self.select_key = self.sequencer.track_select_keys[self.index]
|
||||||
|
|
||||||
# For each key in the track, create a Step instance and add to
|
# For each key in the track, create a Step instance and add to
|
||||||
# self.steps.
|
# self.steps.
|
||||||
|
@ -478,6 +519,29 @@ class Track:
|
||||||
else:
|
else:
|
||||||
self.focussed = False
|
self.focussed = False
|
||||||
|
|
||||||
|
r, g, b = TRACK_COLOURS[self.index]
|
||||||
|
|
||||||
|
# Only update these keys if required, as it affects the BPM when
|
||||||
|
# constantly updating them. Light the focussed track in a bright colour.
|
||||||
|
# Turn the LED off for tracks that aren't active.
|
||||||
|
if self.update_track_select_key:
|
||||||
|
if not self.sequencer.track_select_active:
|
||||||
|
if self.active:
|
||||||
|
if not self.focussed:
|
||||||
|
r, g, b = rgb_with_brightness(r, g, b, brightness=LOW_BRIGHTNESS)
|
||||||
|
self.select_key.set_led(r, g, b)
|
||||||
|
else:
|
||||||
|
r, g, b = rgb_with_brightness(r, g, b, brightness=HIGH_BRIGHTNESS)
|
||||||
|
self.select_key.set_led(r, g, b)
|
||||||
|
else:
|
||||||
|
self.select_key.led_off()
|
||||||
|
self.update_track_select_key = False
|
||||||
|
else:
|
||||||
|
r, g, b = rgb_with_brightness(r, g, b, brightness=HIGH_BRIGHTNESS)
|
||||||
|
self.select_key.set_led(r, g, b)
|
||||||
|
self.update_track_select_key = False
|
||||||
|
|
||||||
|
|
||||||
def update_steps(self):
|
def update_steps(self):
|
||||||
# Update a tracks steps.
|
# Update a tracks steps.
|
||||||
for step in self.steps:
|
for step in self.steps:
|
||||||
|
@ -489,6 +553,7 @@ class Track:
|
||||||
step.active = False
|
step.active = False
|
||||||
|
|
||||||
def midi_panic(self):
|
def midi_panic(self):
|
||||||
|
# Send note off messages for every note on this track's channel.
|
||||||
for i in range(128):
|
for i in range(128):
|
||||||
self.sequencer.midi_channels[self.channel].send(NoteOff(i, 0))
|
self.sequencer.midi_channels[self.channel].send(NoteOff(i, 0))
|
||||||
|
|
||||||
|
@ -537,24 +602,27 @@ class Step:
|
||||||
if self.track.focussed:
|
if self.track.focussed:
|
||||||
# Only update the LEDs when the sequencer is running.
|
# Only update the LEDs when the sequencer is running.
|
||||||
if self.sequencer.running:
|
if self.sequencer.running:
|
||||||
# Make an active step that is currently being played full
|
if self.track.active:
|
||||||
# brightness.
|
# Make an active step that is currently being played full
|
||||||
if self.playing and self.active:
|
# brightness.
|
||||||
self.set_led(r, g, b, PLAY_BRIGHTNESS)
|
if self.playing and self.active:
|
||||||
|
self.set_led(r, g, b, HIGH_BRIGHTNESS)
|
||||||
|
|
||||||
# Make an inactive step that is "playing" (the current step)
|
# Make an inactive step that is "playing" (the current step)
|
||||||
# the dimmest brightness, but bright enough to indicate the
|
# the dimmest brightness, but bright enough to indicate the
|
||||||
# step the sequencer is on.
|
# step the sequencer is on.
|
||||||
if self.playing and not self.active:
|
if self.playing and not self.active:
|
||||||
self.set_led(r, g, b, STEP_BRIGHTNESS)
|
self.set_led(r, g, b, LOW_BRIGHTNESS)
|
||||||
|
|
||||||
# Make an active step that is not playing a low-medium
|
# Make an active step that is not playing a low-medium
|
||||||
# brightness to indicate that it is toggled active.
|
# brightness to indicate that it is toggled active.
|
||||||
if not self.playing and self.active:
|
if not self.playing and self.active:
|
||||||
self.set_led(r, g, b, ACTIVE_BRIGHTNESS)
|
self.set_led(r, g, b, MID_BRIGHTNESS)
|
||||||
|
|
||||||
# Turn not playing, not active steps off.
|
# Turn not playing, not active steps off.
|
||||||
if not self.playing and not self.active:
|
if not self.playing and not self.active:
|
||||||
|
self.set_led(0, 0, 0, 0)
|
||||||
|
else:
|
||||||
self.set_led(0, 0, 0, 0)
|
self.set_led(0, 0, 0, 0)
|
||||||
|
|
||||||
# If the sequencer is not running, still show the active steps.
|
# If the sequencer is not running, still show the active steps.
|
||||||
|
@ -564,10 +632,18 @@ class Step:
|
||||||
else:
|
else:
|
||||||
self.set_led(0, 0, 0, 0)
|
self.set_led(0, 0, 0, 0)
|
||||||
|
|
||||||
# Set up Keybow
|
|
||||||
|
def rgb_with_brightness(r, g, b, brightness=1.0):
|
||||||
|
# Allows an RGB value to be altered with a brightness
|
||||||
|
# value from 0.0 to 1.0.
|
||||||
|
r, g, b = (int(c * brightness) for c in (r, g, b))
|
||||||
|
return r, g, b
|
||||||
|
|
||||||
|
|
||||||
|
# Set up Keybow's I2C bus.
|
||||||
i2c = board.I2C()
|
i2c = board.I2C()
|
||||||
|
|
||||||
# Instatiate the sequencer.
|
# Instantiate the sequencer.
|
||||||
sequencer = Sequencer(i2c)
|
sequencer = Sequencer(i2c)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
|
Loading…
Reference in a new issue