Skip to content

SpacemannFinn/Mishmann

Repository files navigation

📻 Mishmann Player | Hippocratic License HL3-FULL

A tactile, screen-first MP3 player for the Radxa Zero, built around an ILI9488 480×320 IPS SPI display and a five-button physical interface. No touchscreen, no menus-within-menus — just music.

Licensed under the Hippocratic License HL3-FULL.

📖 Project Overview

The Mishmann Player takes inspiration from classic tape decks like the 1979 Sony Walkman TPS-L2 and rebuilds the idea on modern embedded hardware. It runs headless on a Radxa Zero, drives its display over SPI, and is controlled entirely through five tactile buttons: play/pause, next, previous, volume up, and volume down.

The interface is drawn dynamically rather than skinned: colors are extracted from each track's album art, animated cassette spools spin during playback, and a split-screen library view lets you browse artists and albums without ever touching a settings page.

✨ Key Features

  • Dynamic HSV palette engine — Extracts dominant colors from embedded album art and scales hue, saturation, and value to produce a dark background with a high-contrast complementary accent. Every album gets its own theme, automatically.
  • Mechanical cassette spools — Twin rotating spools mimic tape hubs. All 36 rotation frames are pre-rendered into RAM at boot, giving a smooth 25 fps spin during playback without SPI bottlenecks.
  • Split-screen library — A 44 px text list on the left, a live "deck preview" on the right with metadata and an album-art collage (a 50/50 vertical split for two albums, a 2×2 grid for three or four).
  • See-through volume HUD — Volume changes appear as a translucent overlay alpha-composited onto the album art. When the HUD hides, the original backdrop slice is restored exactly — no ghosting.
  • Phone-assisted Wi-Fi setup & web portal — If no network is found at boot, the player starts a Walkman Setup hotspot and walks you through connecting from your phone. The mobile-friendly web console handles track uploads (MP3, FLAC, M4A, and more) and Wi-Fi configuration.
  • MusicBrainz auto-tagging — A background thread fills in missing genre tags via the MusicBrainz API whenever Wi-Fi is available, writing them back to the files with mutagen without interrupting playback.
  • Boot diagnosticsboot.py verifies the SPI display, GPIO lines, backlight PWM, PulseAudio pipeline, and music directories before launch, showing a pass/fail checklist on screen.

📸 Interface Screenshots

1. Diagnostic Boot Checks (boot.py)

Diagnostic Boot Checks Screen

A terminal-style checklist on a dark slate background with real-time pass/fail markers for each hardware interface.

2. Playback Display

Playback Now Playing Screen

Album art with an 8 px drop shadow and 2 px border, twin spinning spools below, and track title and timer rendered in the extracted accent color.

3. Split-View Library

Split View Library Screen

The selected row highlights in the dynamic theme color on the left; the right pane shows a collage preview and genre for the selected artist.

📂 System Architecture

The software runs as a cluster of lightweight, decoupled Python threads communicating via D-Bus and NetworkManager signals:

               +--------------------------------+
               |            boot.py             |
               |  (Initializes & self-checks)   |
               +---------------+----------------+
                               |
                               v
               +--------------------------------+
               |        music_player.py         | <------+
               |   (Primary UI and state loop)  |        |
               +-------+--------------+---------+        |
                       |              |                  |
(Controls audio stream)|              | (BlueZ D-Bus)    | (Signals rescan)
                       v              v                  |
               +---------------+ +----+---------+        |
               | GStreamer API | | bt_manager.py |        |
               +---------------+ +--------------+        |
                                                         |
               +--------------------------------+        |
               |        upload_server.py        | -------+
               |  (Flask server & Wi-Fi Setup)  |
               +---------------+----------------+
                               |
         (Polls Wi-Fi)         v
               +---------------+
               | genre_fill.py | (MusicBrainz thread)
               +---------------+
  • boot.py — Diagnostic manager. Verifies critical interfaces before playback; on failure it draws an on-screen warning and halts safely instead of failing silently.
  • music_player.py — Core runtime. Handles SPI address windowing, in-memory PIL rendering, spool animation, and button input.
  • bt_manager.py — Native D-Bus Bluetooth driver. Talks directly to bluetoothd for scans, pairing, connections, and trust — no shell subprocesses.
  • upload_server.py — Multi-threaded Flask portal. Uses nmcli to bring up the Walkman Setup hotspot when needed, and serves the uploader, library management, and Wi-Fi configuration pages.
  • genre_fill.py — Asynchronous tagging daemon. Queries the MusicBrainz API (respecting its 1 request/second policy) and writes genres back into file metadata via mutagen.

🛠️ Hardware & Pinout

Built for the Radxa Zero using the Linux kernel GPIO character device API (gpiod) and spidev.

  RADXA ZERO 40-PIN HEADER
        +---------+
  3V3   |  1   2  |   5V
  SDA0  |  3   4  |   5V
  SCL0  |  5   6  |   GND
  ...   |  .   .  |   ...
* LINE1 | 11  12  |   ...         * LINE1  = Data/Command (DC)
* LINE2 | 13  14  |   GND         * LINE2  = Play/Pause Button
  ...   | .   .   |   ...
* LINE4 | 16  17  |   3V3         * LINE4  = Previous Button
  ...   | .   18  | * LINE10      * LINE10 = Backlight PWM
* MOSI  | 19  20  | * LINE20      * MOSI   = SPI MOSI / LINE20 = Next Button
* LINE8 | 21  22  |   ...         * LINE8  = Reset (RST)
* SCLK  | 23  24  | * CS0         * SCLK   = SPI SCLK / CS0 = SPI CS0
  GND   | 25  26  |   ...
  ...   | .   .   |   ...
* LINE11| 29  30  |   GND         * LINE11 = Volume Up Button
* LINE12| 31  32  |   ...         * LINE12 = Volume Down Button
        +---------+

Pinout Table

Hardware Component Device Pin / Label Radxa Zero Header Pin Line Number (gpiochip3)
ILI9488 Display SPI MOSI Pin 19 (GPIOC_1) — (Hardware SPI)
SPI SCLK Pin 23 (GPIOC_3) — (Hardware SPI)
SPI CS0 Pin 24 (GPIOC_4) — (Hardware SPI)
Data / Command (DC) Pin 11 (GPIOA_1) Line 1
Reset (RST) Pin 21 (GPIOA_8) Line 8
Backlight PWM Pin 18 (GPIOB_10) Line 10 (PWM Channel 0)
Tactile Buttons Play / Pause Pin 13 (GPIOA_2) Line 2
Next Track Pin 38 (GPIOA_20) Line 20
Previous Track Pin 16 (GPIOA_4) Line 4
Volume Up Pin 29 (GPIOA_11) Line 11
Volume Down Pin 31 (GPIOA_12) Line 12

⚙️ Installation & Running

1. System Dependencies

The player needs GStreamer, GLib, PulseAudio, and Python bindings for D-Bus and GPIO access. On a Radxa Zero running Debian/Ubuntu:

sudo apt update
sudo apt install python3-pip python3-dbus python3-gi python3-flask python3-mutagen python3-pil
sudo apt install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-pulseaudio

2. Clone & Configure

git clone https://github.com/SpacemannFinn/Mishmann.git
cd Mishmann

# Create the music directory
mkdir -p /home/rock/music

Note: The upload server drives NetworkManager via nmcli to create hotspots and join networks, so the user running the player needs the appropriate permissions or sudo privileges.

3. Launch

Start the full player platform with diagnostic checks:

python3 boot.py

To run it automatically at boot, install the included systemd unit:

sudo cp mishmann-player.service /etc/systemd/system/
sudo systemctl enable --now mishmann-player

🩺 Troubleshooting

Symptom Root Cause Resolution
Boot hangs at "Display & GPIO" SPI device node or GPIO lines locked Check whether /dev/spidev3.0 is busy: sudo lsof /dev/spidev*, then kill conflicting Python instances
Audio fails or plays with static PulseAudio sink misconfigured Check routing with pactl list sinks and make sure the GStreamer audio sink matches your active PulseAudio sink
Wi-Fi scan returns an empty list Single-radio chip in AP mode Single-antenna modules can't scan while hosting a hotspot. Use the web GUI's Manual Connection Card to enter the SSID/password directly
D-Bus interface exceptions bluetoothd not running sudo systemctl status bluetooth, and confirm the bindings import cleanly: python3 -c "import dbus"

📄 License

This project is licensed under the Hippocratic License HL3-FULL. See the LICENSE file for details.

About

Python code and wiring diagram for an MP3 player made with a radxa zero 3W

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages