Close
0%
0%

RPDeck

A USB Volume mixer/macro pad

Similar projects worth following
228 views
0 followers
(Project description is a work in progress)
A DIY USB Volume controller and macro pad, powered by an RP2040. Features 2 rotary encoders, an OLED display, and 3(?) macro buttons. This device can individually control the volume of Windows applications.

(Project description is a work in progress)
A DIY USB Volume controller and macro pad, powered by an ATmega32U4. On my computer I usually have a few programs outputting audio at the same time; Discord, Spotify, and a video game for example. My keyboard runs on QMK and has a rotary encoder for volume control, but only controls the master volume. I downloaded EarTrumpet, a volume mixer that replaces the default Windows volume control. It works well, but I still need to get to the task bar to use it. This is an extremely minor inconvenience, but I had some pro micros laying around and decided to try making a custom solution. This device can (hopefully) individually select an application and control its volume, and has 3 (or more/less) buttons that can be customized to run macros. This project is inspired by, and (most likely) builds off of code found in the similar projects I came across, Maxmix (https://maxmixproject.com/) and deej (https://github.com/omriharel/deej).

  • 3: CircuitPython

    neatloaf7a day ago 0 comments

    I have decided to switch to CircuitPython for creating the device firmware. I initially wanted to use QMK since I had spent a few days learning it to configure the Adafruit Macropad. However, I figured that most of the loafdeck (name WIP) functions won't be keycodes so there isn't a pressing reason for me to use QMK. One QoL improvement is the ability to import local .bmp images directly into bitmap objects, rather than needing to export, convert to byte array, and paste into firmware. This can be done either through the displayio or adafruit_imageload libraries.  I've begun trying to teach myself how to make 1-bit pixel art and uploading iterations of the screen art work will be more streamlined now. 

    I am using the Adafruit_displayio_ssd1306 library to display images and text. The displayio.TileGrid class is helpful for using sprite sheets, which will reduce the number of image files needed to be uploaded. A sprite sheet of arbitrary size can be uploaded as a "grid," and each grid can be split into "tiles" for easily calling the image you want. As a simple test, I went in GIMP to create an image with twice the height of my oled dimensions, 128x128 in this case. The top 128x64 of the image is one screen state, and the bottom half is a second screen state. I import the bitmap as a 1x2 tile grid, with each tile being the size of the screen. In circuit python, you can easily switch between which tile is being shown on the display. This is a very rudimentary test as grids and tiles can be any size and located anywhere on the screen. 

    Another good feature of displayio are the palette and pixel_map features, specifically being able to designate specific colors as transparent. This was useful for me as I was trying to create sprites for the left hand and right hand of the screen separately. The sprites I was using took up the whole screen, so the sprites would draw over each other rather than showing something on both halves of the screen. Setting black to transparent allows for this to work, although I may look into having smaller tiles instead. 

    Serial communication is handled by the usb_cdc library. The rp2040 actually has 2 serial ports available, with one disabled by default. The normally used serial port, identified as usb_cdc.console, is typically used for the REPL. This port would be usable for two way communications, but data can be interrupted and only one program can access the port at a time. I am experimenting with the usb_cdc.data port which is normally disabled, so is unaffected by the REPL data stream. I have gotten the device to output a message to serial if the first encoder is turned one direction. I used PuTTY to confirm the device was sending serial data that could be read. 

    I am very inexperienced with circuitpython and python in general, but I have attached my test code for reference. I pieced it together by taking from the few examples available and trying to decipher the documentation. I figure for someone with as little knowledge about (circuit)Python as I had 24 hours ago (no knowledge), this example could be helpful for starting projects that require two-way communication and updating a display accordingly.

    import board
    import rotaryio
    import digitalio
    from adafruit_hid.keyboard import Keyboard
    from adafruit_hid.keycode import Keycode
    import usb_hid
    import time
    import displayio
    import busio
    from adafruit_displayio_ssd1306 import SSD1306
    from adafruit_display_text import label
    import terminalio
    import usb_cdc
    import adafruit_imageload
    
    #create object named 'serial' connected to the unused serial data port
    serial = usb_cdc.data
    
    # Release any existing displays
    displayio.release_displays()
    
    # Initialize I2C
    i2c = busio.I2C(scl=board.GP3, sda=board.GP2)
    
    # Create the display bus
    display_bus = displayio.I2CDisplay(i2c, device_address=0x3C)
    
    # Create the SSD1306 display object
    display = SSD1306(display_bus, width=128, height=64)
    
    # Create a display group 'splash'
    splash = displayio.Group()
    ...
    Read more »

  • 2: QMK

    neatloaf74 days ago 0 comments

    I recently picked up an Adafruit macropad kit and have been learning to use QMK. After reading through the documentation, I learned of the Raw HID feature that allows for two-way HID reporting with the host. I figured QMK is already so feature rich and somewhat easy to create firmware with, so I will be trying to use QMK for this project. 

    I will be trying to implement some sort of image-based indicator for the sound level along with its numerical value, sort of like how the windows volume mixer tray icon works. I also hope to incorporate a few application icons such as for spotify or discord. I have decided to switch to the RP2040 as the much larger flash memory should help me avoid any memory issues down the line. My code for the firmware probably not be well optimized given my lack of code experience. 

    The way I have been drawing to the Adafruit macropad OLED is using byte arrays, which works  since I only have 2 layers for now. I imagine the volume indicator image will have 4-5 different states depending on volume level and mute status. I'll assume for now about 4 different unique sound icons (spotify, discord, games, and master volume). That is alot of permutations for what images can be shown on the screen and that doesn't include all the text descriptors. I believe QMK allows for writing characters directly to the screen, so hopefully I can populate the images first and then draw the text on after. 

    The oled is 128x64, so about a 8200 length byte array. However, HID reports are only 32 bytes in length I believe. Sending a whole byte array to draw to the OLED would take a minimum of 256 reports. I've read that the report rate reaches about 1kHz with the rp2040. It sounds like it could be potentially slow to update if you are quickly switching through apps, so I will probably have all the image arrays baked into the firmware. I am hoping to have arrays for the application logo on the left of the screen and arrays for the volume level image on the right, and combine the two before drawing to the screen. Lastly I will draw the application name and volume level. 

    The app switching encoder can either be mapped null in the keymap and instead directly send HID reports, or I could map them to hot keys that the windows application will be listening for. Outgoing HID reports would be pretty simple, probably only needing one or two bytes of information to update the windows application. 

    Volume control will be through QMK standard key codes. Switching output devices is taken care of with the windows app called SoundSwitch which I have mapped to a hot key already. 

    Incoming HID reports will be a little more complex. The windows app will need to report information on the current volume level, mute status, and selected application. Volume level and mute can be 3 bytes in the report. As for selected application, I can either send the name over, or have a precompiled list of applications in the firmware and just send a number associated with the application. I could also do a combination of the two; on startup, have the windows app report names of all applications configured and store them on the RP2040 and associate each application name to a number. Having a preset list is the simplest, but would require reflashing the board each time a new application (probably a new game) is configured in the windows application.

    The windows application will probably give me the most trouble. At the least I need to monitor volume level and mute status for what application is currently selected. There will need to be a way to filter out any applications I don't want to control. I believe windows has an API with this functionality but I'll need to do more research. 

    While I wait for the RP2040 to arrive, I am using a pro micro to test out building firmware from scratch. 

    It was sort of a headache but I at least got the oled and encoders working. The static image took up a not insignificant amount of...

    Read more »

  • Log 1: Design parameters, early prototyping

    neatloaf701/09/2024 at 00:16 0 comments

    Before I flesh out the physical design, I am going to establish some design parameters so I (hopefully) don't add too many features that I'll never use, and to see if what I want to make can be bought somewhere for cheaper. The Adafruit MacroPad kit runs 50 dollars as of right now, so I am hoping I can keep my design under that price. I was thinking about buying the Adafruit kit for this project, but couldn't justify having 12 switches for what ultimately amounts to being a fancy volume knob. I made a rough sketch of the features I want, with a little wiggle room for additional functions down the road.

    This is a poorly drawn out representation of the functions I would like to implement. At the very least the OLED will report the current application and its volume level. It would be nice to show the previous and next applications that can be scrolled to, and animate the application names scrolling. What would be cool to add is a little speaker icon that shows the relative volume level, sort of like what you'd see from the Windows volume icon in the task bar tray. Maybe it also does a little volume increase/decrease animation when changing the volume. If memory becomes an issue I will probably switch to an RP2040 based board. 

    I was thinking of using two rotary encoders with a push button for controlling the app selection and volume. The push button on the volume control knob will be a mute, but I am not sure exactly what to use the other encoder push button for. I don't want the project to be too large physically, so I am thinking of only including 2 or 3 macro buttons, and using the remaining encoder push button to swap between button profiles. If I do go this route, I'll need the OLED to also report what button profile it is on. For the macro buttons I'll use some cherry-MX profile switches that I have extras of. I have an extra set of keycaps not being used, but it might be nice to buy some PBT blanks.

    When looking at the Maxmix and the deej, they both use a separate windows application to interface with the arduino. I will have to learn how to write, or at least modify windows applications. Functionality wise, I think the maxmix software is pretty complete in regards to the features I want. YaMoef's fork of deej is also similar to how I'd approach building off the deej software.

    For now, I am going to learn how to use the OLED screen and look at the code of the other two projects I mentioned earlier. When I first came up with this idea I didn't anticipate needing to write software, but I suppose this is an easy project to learn on.

View all 3 project logs

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates