diff --git a/README.md b/README.md index 270f357..90d11d9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,44 @@ -# keybow2040-circuitpython -CircuitPython library for the Pimoroni Keybow 2040 +# Keybow 2040 CircuitPython + +This CircuitPython library is for the RP2040-powered Keybow 2040 from Pimoroni, +a 16-key mini mechanical keyboard with RGB backlit keys. Find out more about +Keybow 2040 at the link below. + +[Keybow 2040 at pimoroni.com](https://shop.pimoroni.com/products/keybow-2040). + +![Keybow 2040 with backlit keys on marble background](keybow-2040-github-1.jpg) + +The library abstracts away most of the complexity of having to check pin states, +and interact with the IS31FL3731 LED driver library, and exposes classes for +individual keys and the whole Keybow (a collection of Key instances). + +## Getting started quickly! + +You'll need to grab the latest version of Adafruit's Keybow 2040-flavoured +CircuitPython, from the link below. + +[Adafruit CircuitPython for Keybow 2040](https://circuitpython.org/board/pimoroni_keybow2040/) + +Unplug your Keybow 2040's USB-C cable, press and hold the button on the top edge +of Keybow 2040 while plugging the USB-C cable back into your computer to mount +it as a drive (it should show up as `RPI-RP2` or something similar). + +Drag and drop the `xxxxxxxx.uf2` file that you downloaded onto the drive and it +should reboot and load the CircuitPython firmware. The drive should now show up +as `CIRCUITPY`. + +The Adafruit IS31FL3731 LED driver library for CircuitPython is a prequisite for +this Keybow 2040 library, so you'll need to download it from GitHub at the link +below, and then drop the `adafruit_is31fl3731` folder into the `lib` folder on +your `CIRCUITPY` drive. + +[Adafruit IS31FL3731 CircuitPython library](https://github.com/adafruit/Adafruit_CircuitPython_IS31FL3731) + +Finally, drop the `keybow2040.py` file from this library into the `lib` folder +on your `CIRCUITPY` drive also, and you're all set! + +Pick one of the [examples](examples) (I'd suggest the +[reactive.press.py](examples/reactive-press.py) example to begin), copy the +code, and save it in the `code.py` file on your `CIRCUITPY` drive using your +favourite text editor. As soon as you save the `code.py` file, or make any other +changes, then it should load up and run the code! \ No newline at end of file diff --git a/examples/midi-arp.py b/examples/midi-arp.py new file mode 100644 index 0000000..1fcec41 --- /dev/null +++ b/examples/midi-arp.py @@ -0,0 +1,117 @@ +# SPDX-FileCopyrightText: 2021 Sandy Macdonald +# +# SPDX-License-Identifier: MIT + +# Demonstrates how to send MIDI notes by attaching handler functions to key +# presses with decorators. + +# You'll need to connect Keybow 2040 to a computer running a DAW like Ableton, +# or other software synth, or to a hardware synth that accepts USB MIDI. + +# NOTE! Requires the adafruit_midi CircuitPython library! + +import time +import board +import random +from keybow2040 import Keybow2040 + +import usb_midi +import adafruit_midi +from adafruit_midi.note_off import NoteOff +from adafruit_midi.note_on import NoteOn + +# Set up Keybow +i2c = board.I2C() +keybow = Keybow2040(i2c) +keys = keybow.keys + +# Set USB MIDI up on channel 0. +midi = adafruit_midi.MIDI(midi_out=usb_midi.ports[1], out_channel=5) + +# The colour to set the keys when pressed. +rgb = (255, 50, 0) + +# MIDI velocity. +start_note = 60 +velocity = 127 + +# Arpeggio style: +# 0 = up +# 1 = down +# 2 = up down +arp_style = 2 + +if arp_style == 0 or arp_style == 2: + direction = 1 +elif arp_style == 1: + direction = -1 + +last_played = None +last_pressed = [] +speed = 5 + +# Loop through keys and attach decorators. +for key in keys: + # If pressed, turn on LED. + @keybow.on_press(key) + def press_handler(key): + key.set_led(*rgb) + + # If released, turn off LED. + @keybow.on_release(key) + def release_handler(key): + key.set_led(0, 0, 0) + +while True: + # Always remember to call keybow.update()! + keybow.update() + + if keybow.any_pressed(): + pressed = keybow.get_pressed() + + if pressed != last_pressed: + notes = [start_note + k for k in pressed] + last_pressed = pressed + + if arp_style == 0 or arp_style == 2: + this_note = 0 + elif arp_style == 1: + this_note = len(notes) - 1 + + midi.send(NoteOn(notes[this_note], velocity)) + print(notes[this_note]) + + last_played = time.monotonic() + elapsed = 0 + last_note = this_note + this_note += direction + + else: + if notes != []: + elapsed = time.monotonic() - last_played + + if elapsed > 1 / speed: + if this_note == len(notes) and direction == 1: + this_note = 0 + elif this_note < 0: + this_note = len(notes) - 1 + + midi.send(NoteOff(notes[last_note], 0)) + midi.send(NoteOn(notes[this_note], velocity)) + print(notes[this_note]) + + last_played = time.monotonic() + last_note = this_note + + if arp_style == 2 and this_note == len(notes) -1: + direction = -1 + elif arp_style == 2 and this_note == 0: + direction = 1 + + this_note += direction + + elif len(last_pressed) and keybow.none_pressed(): + for note in range(128): + midi.send(NoteOff(note, 0)) + + last_pressed = [] \ No newline at end of file diff --git a/keybow-2040-github-1.jpg b/keybow-2040-github-1.jpg new file mode 100644 index 0000000..5ac58e4 Binary files /dev/null and b/keybow-2040-github-1.jpg differ