Close

Adding Midi NoteOn/NoteOff

A project log for NeoTrellis Explorations

Adafruit NeoTrellis is a 4x4 button+Neopixel array that can be chained on i2c bus. I am exploring its programming and uses.

jerry-isdaleJerry Isdale 07/20/2022 at 02:330 Comments

So far the neotrellis is a somewhat pretty blinkie toy.  We can make it a bit more useful by turning it into a 16 button Midi keypad.  That is having each key send a different Midi Note over USB.  Press and send Midi.NoteOn, Release and send Midi.NoteOff.   A PC (mac etc) application can receive the MIdi data and use it for application control (music synthesizer, video switcher commands, etc).  We did the same thing back in the Astral TV midi controller project that inspired this one.

The new modular design makes it really easy to implement.using the adafruit_midi and usb_midi libraries.  We added a module to our project called neotrellis_midi.py.  It exposes three methods:

A couple module constants let the client application chose the midi channel and notes associated with the 16 keys. Simply edit these values and rerun the application.  A fancier version might read them at runtime from a configuration file.

import   usb_midi
import adafruit_midi
from adafruit_midi.note_on import NoteOn
from adafruit_midi.note_off import NoteOff

# constants for channel, velocity and notes to associate with keys
# caveat: programmers count channels from 0, normal folks count from 1
# you can see difference viewing midi traffic using
#    https://www.kilpatrickaudio.com/apps/midiview/
# we send zero, it receives 0 but prints out 1
#
__midi_channel = 0

# 16 midi notes to associate with keypad by number
__midiNotes = [
    60, 61, 62, 63,
    64, 65, 66, 67,
    68, 69, 70, 71,
    72, 73, 74, 75,
]

__midi = None

def setup_midi():
    global __midi, __midi_channel
    #  MIDI setup as MIDI out device
    print("setup midi out device")
    __midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=__midi_channel)

def send_note_on(idx):
    global __midi
    print("YO send_note_on", idx, __midi)
    if __midi is None:
        print("Midi not defined")
    else:
        print("send midi NoteOn ", idx, __midiNotes[idx], __midi)
        __midi.send(NoteOn(__midiNotes[idx], 120))

def send_note_off(idx):
    global __midi
    if __midi is None:
        print("Midi not defined")
    else:
        __midi.send(NoteOff(__midiNotes[idx], 120))
        print("send midi NoteOff ", idx, __midiNotes[idx])

That's all there is to the midi module. It is pretty simple with more data checking and print statements than real function stuff.  Adding it to the rest of the application is also pretty simple - add four lines to the neotrellis_keypad.py module.

First add the import at the top

import neotrellis_midi

Then in setup_keypad(), call the setup_midi()

neotrellis_midi.setup_midi()

Then down in doKey(), we add lines to send NoteOn and NoteOff.  In the NeoTrellis.EDGE_RISING block, we add

neotrellis_midi.send_note_on(event.number)

and then in the NeoTrellis.EDGE_FALLING block, we add

neotrellis_midi.send_note_off(event.number)

Thats it.   The neotrellis will now send the midi commands.

You can use a midi enabled browser, like Google Chrome, to view MIDI traffic on the MidiView web page https://www.kilpatrickaudio.com/apps/midiview/

It is interesting to note that while we sending data on midi channel 0, the tool reports it as channel 1.  This is because musicians and other normal people count from 1, while programmers start with zero.  It is the 0 index into the array, right?

Anyway the neotrellis has now become a useful midi keypad device.  yay!!

Discussions