Day 6 — Learning to Hear

Music, film and traditional theater performances has always been an integral part of my own life, and that of my son Mathias. Here, a 2-year old Mathias is enjoying a listening experience back in 1997. To make a good audiophile, you need to start your ear training as early as possible. He looks like he's an apt pupil!
Day five had left the engine standing in exactly the right shape and stone deaf.
It could walk politely through all nine of its stages and produce no music whatsoever, because every stage was still a hollow placeholder waiting to be filled.
Day six is the day it opened its ears, and I had been looking forward to it for the better part of a week.
Three separate tricks
Hearing, for a thing like this, means three separate things.
The first is working out what key a piece is in — and the engine does it the way a musician half-does it by instinct, listening to which notes ring out most and most often across the whole recording, then holding that fingerprint up against the known shape of all twenty-four major and minor keys and quietly picking the closest match.
The second is finding the pulse: how fast the music is moving, and exactly where each beat falls, so that everything downstream has a grid to pin itself to.
And the third is the one I committed to on the very first day — slowing the audio down without dragging its pitch through the floor. That went in too, properly this time: a shredded run can now be stretched out to a quarter of its speed, a crawl slow enough to read note by note, while sitting at precisely the pitch it was played at. No chipmunks. The day-one promise, finally made good.

Here's my 4-year old son Mathias practicing his DJ skills around new year's eve 1998/1999. He was an excellent DJ already back then, and excellent taste in music. He's probably listening to Kraftwerk's legendary album 'Autobahn'!
Correcting yourself out loud
Then the discipline did its favourite trick again, the one I will never stop being grateful for: it caught the mistakes while they were still cheap.
Before a single line of the hearing was written, the specification went to one of my coding agents that I use for spec writing, audits and Quality Assurance (QA), and came back with two genuine faults.
One was a simple miscount.
The other was more interesting, and more humbling — a decision I had pinned to the wall back on day one had quietly come to contradict the work I was now asking for.
The honest thing, the only thing, is to take it down properly: I wrote a new decision that formally supersedes the old one, stated plainly why, and left the original standing in the record as the history it is.
Here is what that looks like in practice — the old wording, then the correction:
# FOM-ADR-002 — Time-Stretch Strategy (day one, the wrong bit)
- "All detected onset timestamps are divided by the stretch factor before
- being written into tab_data — remapping back to real-time positions.
- The remapping is internal to time_stretch.py and transparent to all
- downstream modules."
# FOM-ADR-005 — Timestamp Remapping Contract (day six, the correction)
Status: Accepted — Supersedes ADR-002 (timestamp remapping clause only)
+ "Timestamp remapping is the caller's responsibility, not time_stretch.py's.
+ time_stretch.py executes before transcription. When it runs, no note onset
+ times exist yet — it has nothing to remap. The orchestration layer (cli.py)
+ divides all transcription onset times by the slow_factor before assembling
+ tab_data.json. Downstream modules consume real-time positions only."
That is the whole point of working this way. You do not get to quietly betray your past self at two in the morning. You correct yourself out loud, in writing, where everyone can see it.
There was one small, stupid, entirely human obstacle in the middle of all this.
The pitch-preserving slowdown leans on a little command-line program — the Rubber Band Library by Particular Programs Ltd, a small audio software company in Harpenden, England — that, it turns out, no package manager on Windows will hand you. Not one.
I went hunting across the wider internet and eventually found it on their website, downloaded it by hand, dropped two files into a folder, and told Windows where to go looking for them.
Ten minutes of nonsense to make the magic work on my own machine, and a note written down for whoever comes after me so they don't lose the same ten minutes. The unglamorous tax you pay on every real project.
In practice, calling it from Python is five lines:
import pyrubberband as pyrb
import soundfile as sf
y, sr = sf.read("guitar_solo.wav")
y_slow = pyrb.time_stretch(y, sr, rate=0.5) # half speed, pitch intact
sf.write("guitar_solo_slow.wav", y_slow, sr)
Rubber Band Library — open source, by Particular Programs Ltd, Harpenden, England. Source on GitHub.
A memory for the machine
And then, with the ears working, I built the thing I told you on day one I would keep mentioning. This is the Living Documentation System — the LDS.

This is what my Fret-O-Matic 'Living Documentation System' looks like. I use 'FOM LDS' as an internal abbreviation.I originally designed the system for my 'Hedda' project (a personal AI assistant running locally on my machine). 'Hedda' is capable of utilizing both locally run LLMs, as well as any and all AI models available online on the internet.It's an insane project, but I built Hedda in just 3 months and it's a full stack web application. I'm thinking of eventually releasing a white label, but Fret-O-Matic has become my #1 priority now.My next Hedda build will actually do my banking tasks for me via my bank's OAuth and public API. 'FOM-LDS' is just a customization of Hedda's LDS system that I built for her.
I built the first version of it from scratch for my other long-running project, Hedda, where the document base was large enough and varied enough to need semantic search: that version runs on SQLite with sqlite-vec, a vector search extension that finds documents by conceptual similarity rather than exact wording.
The Fret-o-Matic version takes a different approach, one better suited to a smaller and tightly structured set of documents: SQLite with FTS5, which is SQLite's own full-text search module, built in, no extra dependencies.
What is the difference between the two methods, you may ask? sqlite-vec answers "what is this conceptually similar to?" FTS5 answers "which documents contain this exact idea?" — and for a project where every decision has a name, every law has a number, and every bug has an ID, that is the faster and more precise tool.
The project had reached the point where it owned enough documents — decisions, specifications, laws, handoffs — that finding a single past ruling meant re-reading the entire pile like a man searching his own pockets in the dark.
The LDS fixes that. You ask it a plain question and it searches every document the project has ever produced simultaneously, ranks the results by relevance, and hands you an answer in under a millisecond.
After every session close it syncs to lds.fret-o-matic.com, the project's live knowledge base.
It is not glamorous and nobody will ever see most of it but me, and it is quietly one of the most valuable things on the whole build. I had it indexing the project's entire history inside an afternoon.
I will be honest about the first time I actually opened it in a browser, which is that it was broken in three different ways at once — the same document showing up four times over, the filters doing nothing, the search confused by the duplicates.
All three were found, written up, and fixed before the evening was out.
By the time I closed the lid, the engine could hear, and the project could remember itself. Two things it could not do that morning. Now it just had to learn to write down what it heard.
Written by Torgrim Nyerrød — May 6, 2026
Discussion (0)
Loading comments…