Skip to content
← All project notes

HARDWARE + SOFTWARE + MUSIC / FIELD NOTES 02

Audio streamer

MILA*

Personal audio streamer · In development

A music project that brings together my interest in computers, practical problem-solving and everyday listening. MILA* combines existing hardware with an interface I can shape around my own needs.

MILA* playing a Fink album, with source and DAC formats above an album-grouped queue
Player — album playback, source and DAC formats, and queue · 23 October 2026 · Click to enlarge

From frustration to a project

I listen to music every day, with a large personal library of hi-res FLAC files alongside internet radio and streaming. The streamers I used frustrated me: slow menus when browsing larger collections, occasional connection drops, and limited ways to adapt the system. I also wanted direct control over audio processing — ensuring bit-perfect delivery for high-resolution files, avoiding unwanted resampling, and verifying what the DAC actually receives.

I set out to build a true all-rounder: a dedicated player that unites high-resolution local playback, internet radio, and streaming without compromise. Rather than keeping my main computer running, I looked at the hardware I already had: a Raspberry Pi 5, touch display, fast NVMe disk for local audio storage, USB DAC and linear power supply. I put my requirements on paper and began shaping a streamer around them.

The goal was straightforward: make an all-rounder player that handles high-resolution FLAC albums effortlessly, keeps radio and streaming within easy reach, and remains completely responsive and transparent in how it behaves.

One interface for everyday listening

The Player brings playback controls together with the queue, favourites and recently played or added content. Source filters let me move between local music, radio and streaming without switching to a different interface.

The built-in touch display is the main control surface. The same web interface can also be opened from a phone or computer on the local network. Playback stays on the streamer; those other devices act as remote controls.

MILA* mobile player with album artwork, playback controls, track list and bottom navigation
Mobile view — playback controls and album tracks · 23 October 2026 · Click to enlarge

A library I can explore

Navigating a large collection of hi-res FLAC files requires an interface that stays swift and intuitive. Local music can be browsed by album, artist, genre or folder, supported by search, sorting and alphabet navigation. High-speed NVMe storage on the Pi keeps album art and metadata loading instantly.

I want browsing to feel connected to listening: inspect an album, choose a track, return to the collection and manage the queue without losing my place.

MILA* local music library with album artwork and browsing controls
Library — albums, artists, folders and persistent playback controls · Click to enlarge

Radio without the clutter

The radio view separates my own station collection from discovery. It brings together saved stations, search, recently played content and filters for country, genre and quality. Personal streams can also be added.

Reliable background listening is a central development goal. When a stream or connection fails, the interface should explain what happened and provide a clear way to recover. Long listening sessions and recovery checks are part of the remaining validation.

MILA* My Stations with saved radio stations, discovery filters and the persistent mini-player
Radio — saved stations, discovery and the mini-player · 18 October 2026 · Click to enlarge

Streaming and audio control

Qobuz browsing is integrated through Lyrion Music Server. AirPlay, Spotify Connect and Bluetooth are also part of the receiver work, with individual support and validation tracked during development.

The main playback path uses Lyrion Music Server → Squeezelite → USB DAC. My aim is to avoid unnecessary resampling and digital volume changes for supported content. The interface distinguishes source quality from the format currently reported at the DAC output.

That distinction matters: an output shown as 32-bit does not turn a compressed radio stream into higher-quality source material. The format display supports investigation; it is not, by itself, proof of bit-perfect reproduction.

MILA* full-screen Now Playing view with BEAK album artwork, playback controls and separate source and DAC format labels
Now Playing — full-screen listening view · 18 October 2026 · Click to enlarge

Settings that belong with the player

Appearance, audio and services, music storage, and system maintenance are organised into four sections. The project includes theme and display options, meters, device information and user-data backup tools. Sensitive system actions use protected controls.

Screensavers and visual details are part of the experience, but they share the same design language as the listening and browsing screens.

MILA* settings organised into four sections
Settings — appearance, audio, storage and maintenance · Click to enlarge
MILA* system update screen listing available packages and protected update controls
System updates — available packages and update controls · 22 October 2026 · Click to enlarge

My role and how I work

My background is in hardware, quality control and failure analysis, and I run MILA* the same way. I lead the project: I define the requirements, decide how it should behave, test every change on the real device and decide what is released. AI coding assistants write much of the implementation under that direction. Directing that work and verifying the result is a skill in its own right.

The playback foundation comes from Lyrion and Squeezelite; my application connects the sources, controls and device functions into a coherent experience.

The work is iterative: notice a problem, reproduce it, investigate the cause, make a change and check the result. The examples below follow that pattern. I am also using the project to deepen my understanding of Python after completing my Java studies.

Development example · 01

Keeping favourites consistent

01 / Problem
A single action could add the same favourite twice. A slow response could also arrive after a newer change and bring an older list back into view.
02 / Investigation
The development review found that two list views shared the same underlying collection. It also identified places where older responses could still overwrite current favourites.
03 / Change
The lists were separated, and newer confirmed changes now take priority over earlier responses. An uncertain operation is reported rather than automatically repeated.
04 / Check
Targeted automated checks covered duplicate additions, late responses and confirmed changes. The documented update was installed and the Favourites view was inspected on the Pi. Longer use and simultaneous-client checks remain part of ongoing validation.

Development example · 02

Commands that only looked successful

01 / Problem
Play, Pause and Next could fail without the interface saying so. Rejected commands were silently ignored, and an error-shaped reply from the music server could be read as a success.
02 / Investigation
The review followed a command from the touch button through the backend to Lyrion's JSON-RPC interface. A missing result was being turned into an empty "success". A response lost on the network also says nothing about whether the command actually ran.
03 / Change
Every command now ends in one of three outcomes: confirmed, rejected or unknown. An unknown outcome shows a warning that the command may already have run. Commands are deliberately not repeated automatically: repeating a Play/Pause toggle could undo a command that had in fact succeeded.
04 / Check
New automated cases covered rejected, malformed and lost responses. The update was installed with a fresh backup; the music server kept running and the player reported playback before and after the installation.

Development example · 03

A lost connection without false alarms

01 / Problem
When the interface lost contact with the player, the screen simply kept showing the last known state, with no sign that it might be out of date.
02 / Investigation
Status polling already handled timeouts and late responses correctly, so the gap was feedback, not data. The real question was which failures should count: a single slow reply or a browser tab in the background should not raise an alarm.
03 / Change
Two consecutive failed status checks now show a quiet notice that the status is unavailable and that the player is showing the last known playback. When contact returns, a short recovery message appears and then disappears. The notice never restarts or repeats anything, so it cannot interrupt playback.
04 / Check
Five new automated cases covered an outage, recovery, single failures and a hidden page. On the Pi the notice stays hidden during normal polling; its appearance was reviewed in an isolated preview. I have not yet caused a real network fault on the device to see it there.

These examples show the approach I bring from quality control: work through the cause, document the change and check the result, including saying clearly what has not been checked yet.

Testing and releases

MILA* runs on a device I listen to every day, so a change is only finished once it has been checked.

The rollback path is covered by targeted tests; a controlled rollback on real hardware is still on the list.

Hardware & foundation

Photographs of my listening setup, with the touch display, DAC, linear power supply and speakers. Backgrounds have been softened for presentation.

MILA listening setup viewed from the front, with touch display, DAC, linear power supply and speakers
My listening setup — front view · Click to enlarge
Component Role
Raspberry Pi 5 Dedicated computer running the streamer
NVMe disk Local music storage
Topping E50 USB DAC Audio output
10-inch touch display Built-in control interface
Dedicated linear power supply DAC power
Edifier MR5 speakers My listening setup

Software: Raspberry Pi OS · Lyrion Music Server · Squeezelite · Python · HTML/CSS/JavaScript

Current state

MILA* is a working personal prototype in active development. The current focus is stable listening, recovery after interruptions and consistent behaviour across screen sizes. Some integrations and workflows still need refinement and real-world validation before a stable release.

The source code is in a private repository. I am happy to walk through it, the tests and the release history in a conversation.