Microbit Choir
WIP - Early experiment in creating a choir for three or more microbits.
Code
from microbit import *
import radio
import music
def separate_note(note):
return note.split(":")
def note_to_midi(note):
note_map = {
"C": 0,
"C#": 1,
"D": 2,
"D#": 3,
"E": 4,
"F": 5,
"F#": 6,
"G": 7,
"G#": 8,
"A": 9,
"A#": 10,
"B": 11,
}
# Extract the note and octave from the input
if len(note) == 2:
note_name = note[0]
octave = int(note[1])
elif len(note) == 3:
note_name = note[:2]
octave = int(note[2])
else:
raise ValueError("Invalid note format")
# Calculate the MIDI value
midi_value = note_map[note_name] + (octave + 1) * 12
return midi_value
def midi_to_note_name(midi_value):
note_names = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
note_name = note_names[midi_value % 12]
octave = (midi_value // 12) - 1
return "{}{}".format(note_name, octave)
def is_rest(note):
return note == "R" or note == "r"
def harmonize(note, interval):
parts = separate_note(note)
if is_rest(parts[0]):
return note
root = note_to_midi(parts[0])
harmony = root + interval
harmony_note = midi_to_note_name(harmony)
if len(parts) == 2:
return "{}:{}".format(harmony_note, parts[1])
return harmony_note
def harmonize_all(notes, interval):
if interval == 0:
return notes
harmonized = []
for note in notes:
harmony = harmonize(note, interval)
harmonized.append(harmony)
return notes
def encode_notes_message(notes):
commalist = ",".join(score)
return "NOTES={}".format(commalist)
def decode_notes_message(message):
_, notes = message.split("=")
return notes.split(",")
# notes are
score = ["C4:4", "D4:4", "E4:4", "F4:4", "G4:4", "A4:4", "B4:4"]
# choir leader
leader = False
# position = 0
# harmonizer
semi_tones = 0
display.scroll("Harmony")
radio.on()
while True:
wallpaper = Image.SQUARE if leader else Image.MUSIC_CROTCHET
display.show(wallpaper)
if accelerometer.was_gesture("shake"):
leader = not leader
if leader:
# send out notes
# send out go signal
if button_a.was_pressed():
# upload
display.show(Image.ARROW_N)
message = encode_notes_message(score)
radio.send(message)
sleep(2000)
if button_b.was_pressed():
display.show(Image.ARROW_N)
message = "PLAY"
radio.send(message)
sleep(2000)
else:
# harmonizer
if button_a.was_pressed():
semi_tones = max(0, semi_tones - 1)
if button_b.was_pressed():
semi_tones = min(semi_tones + 1, 12)
# is this a set of notes?
# is this a control signal
message = radio.receive()
if message:
# download
display.show(Image.ARROW_S)
if message.startswith("NOTES"):
score = decode_notes_message(message)
elif message.startswith("PLAY"):
harmony = harmonize_all(score, semi_tones)
music.play(harmony)
# print(harmonize('C5', 12))