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
    led.on()
    sleep_us(int(0.9 * usec))     # Play for a number of usec
    pwm.duty_u16(0)               # Stop playing for gap between notes
    led.off()
    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

Comments

2 Responses to “MicroPython MIDI mayhem (kinda)”

  1. Walt Ribeiro Avatar
    Walt Ribeiro

    Your work with UMidiParser is so helpful. For me, the USec isn’t quantized evenly between eighth notes and sixteenth notes. Did you have a workaround for this?

    Here’s a video showing what’s happening:

    https://youtu.be/eIUn4sx_A7w?si=MbOJHgPe3COg9b2r

  2. scruss Avatar

    glad you got this worked out, Walt: seems that your input file wasn’t properly quantized

Leave a Reply

Your email address will not be published. Required fields are marked *