MicroPython MIDI mayhem (kinda)

It pleased me to learn about umidiparser – MIDI file parser for Micropython. Could I use my previous adventures in beepy nonsense to turn a simple MIDI file into a terrible squeaky rendition of same? You betcha!

MIDI seems to be absurdly complex. In all the files I looked at, there didn’t seem to be much of a standard in encoding whether the note duration was in the NOTE_ON event or the NOTE_OFF event. Eventually, I managed to fudge a tiny single channel file that had acceptable note durations in the NOTE_OFF events. Here is the file:

I used the same setup as before:

Raspberry Pi Pico with small piezo speaker connected to pins 23 and 26
piezo between pins 26 and 23

With this code:

# extremely crude MicroPython MIDI demo
# MicroPython / Raspberry Pi Pico - scruss, 2022-08
# see https://github.com/bixb922/umidiparser

import umidiparser
from time import sleep_us
from machine import Pin, PWM

# pin 26 - GP20; just the right distance from GND at pin 23
#  to use one of those PC beepers with the 4-pin headers
pwm = PWM(Pin(20))
led = Pin('LED', Pin.OUT)

def play_tone(freq, usec):
    # play RTTL/midi notes, also flash onboard LED
    # original idea thanks to
    #   https://github.com/dhylands/upy-rtttl
    print('freq = {:6.1f} usec = {:6.1f}'.format(freq, usec))
    if freq > 0:
        pwm.freq(int(freq))       # Set frequency
        pwm.duty_u16(32767)       # 50% duty cycle
    sleep_us(int(0.9 * usec))     # Play for a number of usec
    pwm.duty_u16(0)               # Stop playing for gap between notes
    sleep_us(int(0.1 * usec))     # Pause for a number of usec

# map MIDI notes (0-127) to frequencies. Note 69 is 440 Hz ('A4')
freqs = [440 * 2**((float(x) - 69) / 12) for x in range(128)]

for event in umidiparser.MidiFile("lg2.mid", reuse_event_object=True):
    if event.status == umidiparser.NOTE_OFF and event.channel == 0:
        play_tone(freqs[event.note], event.delta_us)

This isn’t be any means a general MIDI parser, but is rather specialized to play monophonic tunes on channel 0. The result is gloriously awful:

apologies to LG

Leave a comment

Your email address will not be published.