Internal · OI-Frame
The Signal Chain and the Update Loop
What the frame is made of and where its delay comes from — and the exact steps to change the software and get that change onto the machine.
01 · The chain today
A microphone hears the room. A Raspberry Pi turns that sound into 45 numbers, draws them as a small picture, and sends the picture out over HDMI. A NovaStar controller reads one corner of that picture and pushes it down an Ethernet cable to a receiving card in the LED cabinet, which drives the panels over HUB75.
Every stage below is a real part with a real part number, taken from the machine and from the repository — not from a plan.
Figure 1 · The chain, with where the time goes Open full size · print A3 landscape ↗
Two things in that picture are worth saying out loud. The Pi sends a full 1920 × 1080 signal but only paints a 320 × 540 corner of it, because the NovaStar reads from the top-left and does not scale — the other 92 % of the frame is black and thrown away. And the software is one Electron application drawing 45 circles onto a plain canvas, with hardware acceleration off. It hits every refresh anyway.
02 · Where the delay comes from
Sound reaches the light in roughly 175 to 220 milliseconds. Almost all of that is the chain itself, and the one part we control is already turned down as far as it goes.
The smoothing control called inertia is set to 0 on this frame. Even there it is not free: the code keeps a 30 millisecond floor, deliberately, so a cell can never snap instantly and flicker. Turned up to its 0.45 default that floor becomes 255 ms, and at maximum 530 ms — so inertia is by far the biggest lever in the system, and we are already sitting at the fast end of it.
| Stage | Delay | Where the number comes from |
|---|---|---|
| Microphone capture buffer | 10–25 ms | Standard for a class-compliant USB device. No latency hint is set in the code, so this is device-dependent and unmeasured. |
| FFT window | ~43 ms | 4096 points at 48 kHz spans 85 ms of audio; the effective delay is roughly the middle of that window. Analyser smoothing is explicitly set to zero. |
| Waiting for the next frame | ~8 ms | Half a frame at 60 Hz, on average. |
| Drawing 45 circles | under 1 ms | Measured as hitting every vsync, even with hardware acceleration off. |
| Compositor and HDMI scan-out | 33–50 ms | Two to three frames at 60 Hz. Standard, not measured here. |
| NovaStar chain | 50–67 ms | NovaStar's own model: sender 1 frame + receiving card 2 frames + driver chip 0–1 frame = 3–4 frames. |
| Inertia, as set today | +30 ms | Set to 0, its minimum. The 30 ms is a floor built into the code so cells cannot snap and flicker. At the 0.45 default this would be 255 ms; at 1.0, 530 ms. |
| Microphone to light, today | ≈175–220 ms | Sum of the above. |
Two honest caveats. NovaStar publishes no latency figure for the TB40 at all — the words "latency" and "delay" appear nowhere in its specification. The 3–4 frame figure is NovaStar's general model for an LED chain, applied to our parts. And nobody has ever measured this frame end to end; every number above is either a constant read out of our code or a published vendor model.
One thing worth trying
Our A5s Plus is on NovaStar's list of receiving cards that support low latency mode, and the driver chips in our panels have the built-in memory that mode requires. Ticking "enable receiving card low latency" in NovaLCT should remove one frame — about 17 ms — for the cost of a checkbox. It cannot be combined with Genlock, and it limits each port to 512 pixels wide, neither of which affects us. [Likely — worth testing, not yet tried.]
03 · Changing the software
All the work happens on the Windows machine, in one folder. There is one branch, main, no review process and no build server. You edit, you build, you copy it over. That simplicity is deliberate — it means one person can carry a change from idea to wall in about ten minutes.
The tool that does the editing is Claude Code, running inside VS Code. You do not need to read or write any code yourself. You describe the change in ordinary language, it finds the right files, makes the edit, and shows you what it touched before anything is built.
- Open the project. Start VS Code, then File → Open Folder →
C:\Users\Armin Seltz\Git\OI-Frame. Everything — the app, the documents, the Pi's configuration — lives in that one folder. - Open Claude Code from the sidebar. Carry on in an existing conversation if you are continuing something, or start a new one for an unrelated change. A fresh conversation for a fresh topic gives better results, because it is not carrying yesterday's context.
- Say what you want, in plain words. "Make the circles fade out more slowly when the music stops." "Add a second row of cells." It will ask if something is ambiguous, then make the change and explain what it did.
- Ask it to bump the version and write the changelog. Both matter more than they look. The version number lives in one line of one file and ends up in the name of the file you send to the Pi — and the Pi decides whether a build is new by looking at that name. Ship twice with the same number and the second one is silently ignored. The changelog is how anyone later works out what a version actually contains; it has been skipped once and that version is still a blank in the record.
- Ask it to run the file check. A one-second scan for invisible corruption in the files the app serves. It exists because a single stray byte once made the phone page render completely blank, while the desktop, the server and every other test passed happily.
- Ask it to commit and push. This is the save point. If a change turns out badly, having it committed is what makes going back easy.
None of these steps needs a terminal. Ask for them in the conversation and Claude runs them, shows you the output, and tells you if something failed.
04 · Getting the change onto the Pi
The Raspberry Pi has no keyboard, no mouse and no screen of its own — it only drives the wall. There are two ways to reach it, and the first one needs no computer skills at all.
The USB stick — the way anyone can do it
Copy one file onto the stick. Push the stick into the Pi. Wait. Pull it out.
- Build the file. One command turns the project into a single compressed file. Ask Claude Code to do it — the only thing worth knowing is that it makes two versions, one for a normal PC and one for the Pi, and the Pi's is the one marked arm64. The wrong one fails in a way that explains nothing.
- Copy it into the
installerfolder on the stick labelled OI-FRAME. That is the only folder that matters and the only stick that works. - Eject the stick properly — the Windows "safely remove" — so the copy is genuinely finished and not still sitting in memory.
- Push it into the Pi. Nothing else. No reboot, no keyboard, no laptop. Plugging the stick in is the instruction.
- Wait for the wall. It goes black and comes back showing the new version number. Measured on the real machine: twelve seconds. Then pull the stick out.
Afterwards there is a file called update-log.txt on the stick, with one line per attempt saying what happened. It is written by the Pi and read back on your laptop, and it is the only feedback that leaves the room with you.
Going back is the same act as going forward. Put the older file in installer, delete the newer one, and plug the stick in again — the stick decides which build runs.
Over the network — the developer path
The same thing can be done from the Windows machine across the network, and that is how a developer works, because it needs no walking. One thing is worth knowing about it: the Pi does not accept passwords. It only accepts a key, and exactly one computer's key is registered today. A different computer cannot connect at all until its key is added — no password will help.
If that computer is ever lost, the way back in is connect.raspberrypi.com. The Pi is signed in to Raspberry Pi's own service, so that page gives a working terminal on it from any browser, with no key at all. Add the new computer's key from there and normal access resumes.
This is the reason the stick exists. The network path is faster for someone who already has access, and completely closed to someone who does not.
Figure 2 · The update loop Open full size · print A3 landscape ↗
05 · Glossary
- arm64
- The processor family the Raspberry Pi uses. A build for a normal PC (
x64) will not run on it, and the mistake is silent. - field
- The 45 numbers the software produces from the sound — one per circle, each between 0 and 1. It is the seam between listening and drawing.
- FFT
- Fast Fourier Transform. The maths that splits a sound into how much of each pitch it contains. Ours looks at 4096 samples at a time, about 85 ms of audio.
- frame
- One picture. At 60 Hz a frame lasts 16.7 ms, which is the unit LED people quote delays in.
- HUB75
- The standard ribbon-cable connection between a receiving card and an LED panel.
- inertia
- Our smoothing control. Higher means the light follows the music more slowly. Set to 0 on this frame; the default is 0.45, the maximum 1.0.
- NovaLCT
- NovaStar's Windows configuration tool for controllers and receiving cards. Where the low-latency setting lives.
- Pi Connect
- Raspberry Pi's own remote-access service. This Pi is signed in to it, so a browser at connect.raspberrypi.com gives a terminal on the machine without needing a key first.
- receiving card
- The board inside the LED cabinet that turns the Ethernet signal into panel signals. Ours is an A5s Plus.
- SSH
- Opening a command line on another computer over the network. The Pi allows it by key only — passwords are switched off.
- SSH key
- A matched pair of files that replaces a password. The secret half never leaves your computer; the public half is registered on the Pi. One is registered today.
- SCP
- Copying a file to another computer over the same connection SSH uses. Same door, different use.
- service
- A program Linux starts at boot and restarts if it stops. The frame is one, which is why updating it ends with "restart the service" rather than "open the app".
- vsync
- Waiting for the screen's next refresh before showing a new picture. It costs a little delay and prevents tearing.