Introduction: E-Ink Desk Screen to Show Activated Equalizers
Idea
The idea is to use an e-paper screen to see at any time which equalizers are currently being applied by my PC to the output audio. Depending on the use (video editing, music, films, etc.), the correct equalizer can be quickly added or removed.
This makes it easier to use and prevents accidental switching of equalizers that are already in the desired state.
The aim is to display the current total EQ as a line on a two-color E-Ink screen and to fill the change to the neutral EQ with color.
Disclaimer
This project and code is nowhere near polished nor perfect. To implement this, at least some knowledge of python, serial communication and embedded programming is needed. But since I managed to get to this state aswell, don't let yourself be discouraged either if you lack some of the requirements ;)
Concept
Equalizer APO is used to control audio output. This program allows for applying various parametric and graphic equalizers to the entire audio stream of the PC. Embedding room mode corrections, such as those created by REW, is also possible.
To change the equalizer depending on the task or consumed medium with a button press, an Akai USB MIDI controller is used, which triggers windowless Python scripts (.pyw) via the MIDI-Mixer program.
These Python scripts search the config file (config.txt) of the equalizer using regex for the line with the corresponding EQ and checks whether it is active or inactive. This line is then deactivated or activated in the toggle behavior. The action performed is also output as a Windows notification.
This also works without a screen that displays the current EQ status. However, it often happens that the corresponding EQ has already been set and the button on the MIDI controller has to be pressed again to undo the action. That's when I noticed a two-color E-ink screen that can be plugged into a Raspberry Pi Pico as a hat.
config.txt:
# Room correction EQ created with REW and measurements
Include: 17.01.24 20-20000 9db_max_boost.txt
# PA-EQ
# GraphicEQ: 19 6.5; 25..................................; 10000 2.8; 12500 3; 16000 3.3; 19999 3.5
# LowShelf
# Filter: ON LSC Fc 161.08 Hz Gain 4.5 dB Q 0.6694
# HighShelf
# Filter: ON HSC Fc 4920.74 Hz Gain 1 dB Q 0.6706
# LernHighCut
# Filter: ON HSC Fc 700 Hz Gain -2.2 dB Q 0.6703
# BassReduction
# Filter: ON LSC Fc 110.17 Hz Gain -2.3 dB Q 0.6706
# Harman Listening Curve:
GraphicEQ: 31.5 6; 40 5.9; 50 5.5; 63 4.9; 80 3.7; 100 2.5; 125 1.3; 160 0.6; 200 0.2; 250 0; 1000 -1; 32000 -3
Headless Python Script (Bass-Boost example):
from win10toast import ToastNotifier
import regex as re
from time import sleep
announced = False
search_pat = re.compile(r"#\sLernHighCut")
notification = ""
toast = ToastNotifier()
with open("C:/Program Files/EqualizerAPO/config/config.txt", "r+") as conf:
conf_text = conf.read().splitlines()
for i, line in enumerate(conf_text):
if announced:
if line[0] == "#":
conf_text[i] = line[1:].strip()
notification = "Enabled High-Cut ¯¯¯¯¯¯¯¯\_______"
else:
conf_text[i] = "# " + line.strip()
notification = "Disabled High-Cut ----------------"
announced = False
break
if search_pat.match(line):
announced = True
if notification != "":
conf.seek(0)
conf.truncate(0)
conf.write("\n".join(conf_text))
else:
notification = "Filter not found!"
toast.show_toast(
"Equalizer",
notification,
duration=3,
icon_path="C:/Users/Leo/AppData/Roaming/midi-mixer-app/eq.ico",
threaded=True)
while toast.notification_active():
sleep(0.1)
The Python script first loads the modules for Windows notifications and regex.
After opening config.txt, it iterates through the lines until the regular expression for the title of the bass boost ("#LowShelf") matches. The subsequent line must accordingly be the filter.
Then, it checks if the filter is deactivated (with #) or activated (without #). Next, the line is manipulated to change to its opposite.
Now, a Windows toast notification is displayed, informing of the made change.
Supplies
Electronics
- Raspberry Pi Pico
- 2.66" E-Paper E-Ink Display Module (B) For Raspberry Pi Pico, 296×152
- Micro-USB Cable
Tools
- 3D printer + filament
Step 1: Casing
I decided to use a 3D-printed housing for the prototype. Unfortunately, it is not really aesthetically pleasing, but it is very flexible in terms of design and use.
However, a wooden housing is planned for the future.
The files are attached, nothing special to note here. The design is so simple that I printed it with 0.26 mm layer thickness to finish faster.
For easy post-processing, the support structures can be activated, to support the cable input opening.
Step 2: Software
In order to achieve the goal of graphical representation, the individual Python scripts are supplemented by a self-written module (see graph_gen.py). Within this module, all active equalizers are read in, mathematically applied to a zero matrix and this matrix is then plotted as an equalizer graph in the corresponding resolution. For a boost to the flat EQ (with room correction), the area in between is filled in red. If the EQ reduces the volume in relation to the flat EQ, the area is filled in gray. In the e-paper, this corresponds to a checkerboard pattern due to dithering.
The rendering process must be split into two individual images for the e-paper display. One for the red pixels and one for the black pixels. Both images are stored in one-dimensional arrays with one-bit color depth (i.e. black / white) for simple serial transmission and then sent via the specified port.
On the other side is the Raspberry Pi Pico. This contains code written in C (see main.c) to wait for the transmission of the two bitmaps at the serial input. These are transferred by Python as byte arrays. As the division into black and red bitmaps takes place on the Pi Pico, both byte arrays are output together. After successful transmission, these are output to the display via the Waveshare E-Paper Library.
If the transmission is only partial or faulty, the Pico resets itself and falls back into a loop waiting for serial data. As a keepalive heartbeat, the built-in LED is toggled after each loop.
Attachments
Step 3: Making It Work
For commissioning, only the EQ adjustment scripts need to be extended to include the integration of the EQ plot module:
import graph_gen
.
.
.
graph_gen.main()
The standoffs supplied are used to secure the electronics in the housing. Alternatively, normal screws of the appropriate thickness and thread pitch can of course also be used.
Now everything should work. As soon as a part of the equalizer of Equalizer-APO is activated or deactivated via USB-MIDI-Controller, the display on the E-Ink display on the desk is automatically adjusted and allows a quick change between different settings.