-
-
Save gbraad/73870ba44249f4fef859dd91de5edc06 to your computer and use it in GitHub Desktop.
Music sequencer for the BBC micro:bit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# MUSIC SEQUENCER by Darryl Sloan (30/11/2017) | |
# Step 1: press A to toggle the first note of the desired scale, then B to select. | |
# Step 2: press A to toggle the time signature (3/4, 4/4 or 5/4), then B to select. | |
# Step 3: press A to toggle the desired number of patterns (1 to 4), then B to select. | |
# Press A to move the range of notes selected. Press B to randomise the selected notes. | |
# The direction of tilt determines which scale the random notes conform to: | |
# Left = minor; right = major; forward = minor pentatonic; backward = major pentatonic. | |
# While holding A during the first note of the sequence, tilting up/down increases/decreases the tempo, | |
# tilting left/right selects a lower/higher octave. | |
# While holding A, tap B to show the notes in English for transcription purposes. | |
from microbit import * | |
import music | |
import random | |
octave = 3 | |
tempo_adjust = 90 | |
music.set_tempo(bpm = tempo_adjust) | |
selection = 0 | |
pattern = 0 | |
all_notes = ("C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B") | |
major = (0, 2, 4, 5, 7, 9, 11) | |
minor = (0, 2, 3, 5, 7, 8, 10) | |
major_pent = (0, 2, 4, 7, 9) | |
minor_pent = (0, 3, 5, 7, 10) | |
scale_major = ["", "", "", "", "", "", ""] | |
scale_minor = ["", "", "", "", "", "", ""] | |
scale_major_pent = ["", "", "", "", ""] | |
scale_minor_pent = ["", "", "", "", ""] | |
# User selects scale | |
scale = 0 | |
display.scroll("Scale") | |
while True: | |
display.show(all_notes[scale]) | |
if button_a.was_pressed(): | |
scale += 1 | |
if scale == 12: | |
scale = 0 | |
if button_b.was_pressed(): | |
break | |
for i in range(7): | |
scale_major[i] = all_notes[major[i]] | |
scale_minor[i] = all_notes[minor[i]] | |
for i in range(5): | |
scale_major_pent[i] = all_notes[major_pent[i]] | |
scale_minor_pent[i] = all_notes[minor_pent[i]] | |
notes = scale_major | |
# User selects time signature | |
beat = 4 | |
display.scroll("Beat") | |
while True: | |
display.show(str(beat)) | |
if button_a.was_pressed(): | |
beat += 1 | |
if beat == 6: | |
beat = 3 | |
riff_length = beat*4 | |
if button_b.was_pressed(): | |
break | |
# User selects quantity of patterns | |
patterns = 1 | |
display.scroll("Patterns") | |
while True: | |
display.show(str(patterns)) | |
if button_a.was_pressed(): | |
patterns += 1 | |
if patterns == 5: | |
patterns = 1 | |
if button_b.was_pressed(): | |
break | |
# Load example riff | |
sequence = [] | |
default = [all_notes[scale]+"4"] | |
for i in range(beat-1): | |
default += [all_notes[scale]+"3"] | |
for i in range(patterns*4): | |
sequence += default | |
while True: | |
x, y = 0, 0 | |
for i in range(riff_length): | |
# Refresh display | |
display.clear() | |
display.set_pixel(pattern, 4, 9) | |
for highlight in range(beat): | |
display.set_pixel(highlight, selection, 5) | |
display.set_pixel(x, y, 9) | |
# User reveals notes in English | |
if button_a.is_pressed() and button_b.was_pressed(): | |
for p in range(patterns): | |
text = "" | |
for q in range(8): | |
display.show(str(p+1)) | |
sleep(200) | |
display.clear() | |
sleep(200) | |
for j in range(riff_length): | |
text += sequence[j+(pattern*riff_length)]+" " | |
display.scroll(text) | |
# User adjusts octave or tempo | |
if i == 0 and button_a.is_pressed(): | |
if accelerometer.get_x() < 0 and abs(accelerometer.get_y()) < abs(accelerometer.get_x()) and octave > 1: | |
octave -= 1 | |
if accelerometer.get_x() > 0 and abs(accelerometer.get_y()) < abs(accelerometer.get_x()) and octave < 6: | |
octave += 1 | |
if accelerometer.get_y() < 0 and abs(accelerometer.get_x()) < abs(accelerometer.get_y()) and tempo_adjust < 200: | |
tempo_adjust += 10 | |
if accelerometer.get_y() > 0 and abs(accelerometer.get_x()) < abs(accelerometer.get_y()) and tempo_adjust > 60: | |
tempo_adjust -= 10 | |
music.set_tempo(bpm = tempo_adjust) | |
# User changes current selection | |
if button_a.was_pressed(): | |
selection += 1 | |
if selection == 4: | |
selection = 0 | |
# User randomises selected notes | |
if button_b.was_pressed(): | |
if accelerometer.get_x() < 0 and abs(accelerometer.get_y()) < abs(accelerometer.get_x()): | |
notes = scale_minor | |
if accelerometer.get_x() > 0 and abs(accelerometer.get_y()) < abs(accelerometer.get_x()): | |
notes = scale_major | |
if accelerometer.get_y() < 0 and abs(accelerometer.get_x()) < abs(accelerometer.get_y()): | |
notes = scale_minor_pent | |
if accelerometer.get_y() > 0 and abs(accelerometer.get_x()) < abs(accelerometer.get_y()): | |
notes = scale_major_pent | |
for r in range(selection*beat, selection*beat+beat): | |
sequence[r+(pattern*riff_length)] = random.choice(notes)+str(random.randint(octave, octave+1)) | |
# Play current note | |
music.play(sequence[i+(pattern*riff_length)]+":1") | |
# Move playhead forward by 1 | |
x += 1 | |
if x == beat: | |
x = 0 | |
y += 1 | |
if y == 4: | |
y = 0 | |
# Move pattern forward by 1 | |
if x == 0 and y == 0: | |
pattern += 1 | |
if pattern == patterns: | |
pattern = 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment