6.6 KiB
micro-tuner
An instrument tuner assistant, built to be run on the Microbit V2. Portable and Practical!
Background
Selecting a project for this course was itself small challenge and lead to a slightly later start then I would have otherwise planned.
Alternatives
Since I thought a lot about it, I may as well mention what the alternatives may have been
- Reverse engineering, or augmenting the firmware of my DEFCON30 badge
- Adding sound output capabilities to my recent BSides badge, possibly with my piezoelectric buzzer (discussed briefy in the notebook)
- An undetermined project, perhaps reverse engineering or adding to a small FM receiver board I have, but know little about (Chip MEGA328P)
- Sound oriented project involving other small devices I own like arduinos, raspberry pi's, and my newly aquired adafruit featherboard RP2040. Notably, the new Pi 5 no longer has a 3.5mm audio port, and it would be interesting to try to build a DAC in code with GPIO output, to not need an external USB DAC.
- Understanding/Experimenting with sound tricks like Dolby Pro Logic
- Buying an SDR and exploring the various ways sounds is encoded and transmitted in practical radio applications. Learning the law, and getting an amateur radio license
I hope to work on many of these some day soon, but feel free to share these with any future students looking for ideas
Decision
I chose to create an instrument tuner device with my microbit-v2 from the previous embedded rust course. Compared to the other ideas, this project is both tangible and flexible. It can be broken into different levels of goals and there are different layers of abstraction I can choose from with this approach.
Goals
Primary Goals (MVP)
- The microbit shall be able to play any reference note (tone mode). The reference note will be displayed on the LED matrix, and the touch button shall play the note when touched. The A and B buttons will allow the choosing of different reference notes.
- In an alternative mode (listen mode), the microbit shall be able to identify the note heard by the microphone. Likewise, this note should also be displayed
- Portable / can run on a battery (this should just work)
Stretch Goals
- In the listen mode, if the note heard is close to a reference note, some feedback should be given (up or down arrow, etc.)
- Building on the above point to set a "target" note and provide appropriate feedback
- Avoid to some extent, sound abstraction the microbit package provides and build/interpret my own frequencies
Fun ideas (Stretch ++)
- Interfacing with the dragontail and breadboard to do some cool stuff:
- Using the analog dial resistor to assist with chaning notes
- Using an external LED for more interesting feedback
- Printing some data to an external display
- Interfacing some pins to a USB adapter -> MIDI adapter -> My MIDI keyboard, to instantly choose a reference note
- Parallel implemention in rust, and comparing the performance
Source Code Overview
Although I already have experience interfacing with the various capabilities of this device with rust, I initially decided to go with python for this project. I want to compare the experience of both, and also have the ability to take advantage of more abstractions if I choose to. However, after making significant progress building tone mode in micropy
, I came to find that micropy (and the microbit package) do not generally allow API access to the raw data samples of the microphone pins. They only seem to expose 256 values of sound intensity. This makes rust appear much more feasible for listen mode, and the scope of this project has changed to now implement only tone mode in python, and listen mode in rust.
It should also be possible to flash a python application with some compiled rust, using a package like PyO3
. If I have time, I will look into that.
Python
main.py
This application (tone mode) works relatively well. Ultimetly, I decided to rely on microbits music.play()
function which takes a note name as a parameter. In this regard much of the sound theory efforts are abstracted away, and there was more focus on the music and computers. The application works as follow
- On start, note A4 / Midi key 69 is selected.
- Pressing A selects the next note down; Pressing B selects the next note up
- The selected note and octave will wrap around on both ends (0 and 128)
- The root note (letter portion) is always rendered using all pixels except the last column
- If a flat note is selected, the bottom pixel of the last column is dimly lit.
- The current octave is expressed in a little-endian binary fashion with 4 pixels, top-down in the last column (not to conflict with the flat flag)
- Pressing A and B together was intended to switch to and from listen mode (not implemented as explained above)
Rust
src/main.rs
Much of the code for this feature has beeen written, but some critical pieces remain. Some repositories were consulted, including
mb2-template
: Configurations and common packagesmicrobit-spectrum
: This seems to be one of the only code examples of grabbing raw audio samples with the microbit microphone in rust
Building/ Running - Python
It seems that many python microbit developers use a highly abstracted web-based IDE. I attempted to avoid that. These methods are tested only on my local debian-based linux machine, so your results may vary
Dependencies
pip install microbit-3
pip install uflash
IDE support
The microbit package does not seem to include the necessary stubs/tooltips for graceful IDE development. I found the micro:bit Python VS Code extension helpful. Follow its instructions
Flashing
uflash main.py # Optional paramter for device port like /dev/ttyACM0 if not found automatically
Serial (for console output)
screen /dev/ttyACM0 115200 # You may have a different port
Building/ Running - Rust
Dependencies
rustup target add thumbv7em-none-eabihf
rustup component add llvm-tools
cargo install cargo-binutils
cargo install probe-run
cargo install cargo-embed
Flashing
cargo embed --release
Testing
More time should be allocated to write tests, as well as perform user acceptence testing
Demo
Tone Mode
Listen Mode
Not Yet Ready