from microbit import * import music # Constants note_names: list[str] = [ "C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B", ] max_octave: int = 8 max_midi_note: int = 127 images_set = { "A": Image("09900:" "90090:" "99990:" "90090:" "90090"), "B": Image("99900:" "90090:" "99900:" "90090:" "99900"), "C": Image("09990:" "90000:" "90000:" "90000:" "09990"), "D": Image("99900:" "90090:" "90090:" "90090:" "99900"), "E": Image("99990:" "90000:" "99900:" "90000:" "99990"), "F": Image("99990:" "90000:" "99900:" "90000:" "90000"), "G": Image("09990:" "90000:" "90990:" "90090:" "09990"), } # Logic control loop: bool = True tone: bool = False midi_key: int = 69 tone_mode: bool = True # Fetch the base image for the note letter from the global dictionary, # Then embellish it with the octave pattern (in binary) and potential flat flag # Flat flag goes in the bottom right pixel at partial brightness, and binary octave pattern goes from top right down def get_image(note_letter: str, octave: int) -> Image: base_letter = note_letter[0] base_img = images_set[base_letter] if len(note_letter) > 1 and note_letter[1] == "b": base_img.set_pixel(4, 4, 2) else: base_img.set_pixel(4, 4, 0) binary_big_e: str = bin(octave)[2:] binary_little_e = "".join( reversed(list(binary_big_e)) ) # one cannot simply [::-1] in micropy bit_length = len(binary_little_e) for i in range(4): if i < bit_length and binary_little_e[i] == "1": base_img.set_pixel(4, i, 6) else: base_img.set_pixel(4, i, 0) return base_img # Example: get_note(69) -> ("A", 4) def get_note(key: int) -> tuple: return ((note_names[key % 12]), ((key // 12) - 1)) # Logic controller for the speaker. Decides when to start and stop, and looks up which note to play def manage_tone(midi_key): global tone if pin_logo.is_touched() and tone == False: note = get_note(midi_key) print(str(note[0]), str(note[1])) music.play(str(note[0]) + str(note[1]) + ":4", wait=False, loop=True) tone = True elif pin_logo.is_touched() == False and tone == True: music.stop() tone = False # Logic controller for the display def manage_display(midi_key): note = get_note(midi_key) note_letter = note[0] octave = note[1] display.show(get_image(note_letter, octave), wait=False, loop=True) def log(): note = get_note(midi_key) print(midi_key, "-", note[0], "[", note[1], "]") # Logic for "tone mode" - Pick a note and play it def tone_mode_controller(): global midi_key input = (button_a.was_pressed(), button_b.was_pressed()) update = False if input == (False, False): pass elif input == (True, False): update = True midi_key = (midi_key - 1) % max_midi_note elif input == (False, True): update = True midi_key = (midi_key + 1) % max_midi_note else: pass if update: log() manage_display(midi_key) manage_tone(midi_key) # Stub logic for listen mode. See README.md for elaboration def listen_mode_controller(): # mic_in = pin5.get_pull() # mic_run = pin20.get_analog_period_microseconds() display.show(Image.CONFUSED) # Main Program Logic. Run the display once before looping manage_display(midi_key) while loop: if button_a.is_pressed() and button_b.is_pressed(): tone_mode = not tone_mode sleep(100) if tone_mode: tone_mode_controller() else: listen_mode_controller() sleep(100)