What Timbre taught me about Windows audio and working with coding agents
Shared control buffers, missing processing, and a failed service handoff made us test Timbre at several levels. Here is how we kept the claims tied to the evidence.
Building Timbre taught me to ask several questions every time we changed an audio control.
Did the app write the right setting? Did the processor receive it? Did the audio change? Did the test leave the machine in its original state?
Those questions sounded similar at first. Our experiments gave each one a separate answer.
Timbre is my Windows control app for an EPOS B20 microphone and GSX 300 sound card. I am building it with coding agents to keep the hardware useful and to learn how its interfaces work. The first post covers how the project started. These are the lessons from taking it apart.
Follow the whole audio path
My GSX 300 initially produced sound through a generic USB audio installation, but the EPOS processor was missing from its endpoints. That explained why some controls could look plausible while the expected effects were absent.
Windows audio has several layers. The endpoint is the microphone or playback destination an application sees. The driver exposes the device to Windows. An Audio Processing Object, or APO, can supply software effects such as EQ and reverb in the audio path. Microsoft documents this in its APO architecture guide.
For Timbre, Windows volume and mute, USB sidetone controls, and settings for the installed processor became separate responsibilities. Learning how to send a device command does not reproduce an effect implemented in the PC's processor.
Repairing the driver binding and rebooting made the EPOS processing path available on my GSX. After that, listening and measurement could answer questions that control readback alone could not.
Recover the layout one change at a time
Part of the control interface is a shared memory mapping. Windows allows processes to view the same mapped data, including mappings backed by the system page file. Microsoft's file mapping documentation describes that mechanism.
In this system we investigated a 4096-byte mapped view containing settings. It is a control structure; the microphone recording is not stored in that buffer.
We captured the state, changed one control in Gaming Suite, captured it again, and compared the bytes. Gate levels, enable switches, and EQ gains had different encodings. We cross-checked changes against additional captures and local inspection of the installed software.
A capture also taught us to be careful about assuming that one UI action means one field changed. One vendor action reapplied cached gate and filter values as well as the control I was moving. The exact diff mattered more than the label on the button.
Recovered offsets became documented evidence and regression fixtures. Unknown layouts, invalid values, and ambiguous device identities cause refusal. We preserve fields we have not established ownership of.
Shared settings require coordination
The mapping sits alongside a named mutex and event. The mutex coordinates access; the event signals a settings update.
That made changing an EQ band a small transaction: validate the current layout and expected state, acquire the existing lock, change only the fields requested, signal the update, and check the result.
Other software can change those same settings. A stale edit should be rejected. If something fails after a partial update, restoration must avoid overwriting a newer change made by another controller. Those cases became explicit regression checks.
This changed how I thought about the interface. A slider belongs to the app, but the state it controls is shared with other processes.
Check the audio separately
We kept three kinds of evidence separate.
- Offline tests exercise encoding, device isolation, stale edits, failure handling, and restoration using reviewed captures and simulated transports.
- Control checks confirm that a live change reaches the expected fields and returns to the starting values.
- Audio checks ask whether a specific change affects the stream, with listening and numerical measurements recorded separately.
For a playback experiment, we generated a 1 kHz tone and measured flat EQ, a +6 dB setting, and flat again through Windows loopback capture. The observed change was about +6.002 dB, and the baseline returned. We also checked interruptions, clipping, invalid samples, and preservation of unrelated settings. The playback research notes record the details.
That establishes a reversible EQ response at the measured point on this setup. It does not establish a full frequency response or calibrated virtual surround.
The same discipline applies to microphone gate tests. A quiet, unstable, or interrupted input is inconclusive. We save numerical evidence and discard the samples rather than saving recordings.
Recovery was part of the result
The clearest lesson came while experimenting with GSX initialization after temporarily stopping vendor support at a controlled Windows Audio boundary.
The helper created fresh shared objects, the settings checks passed, and playback EQ produced the expected measured change. Then we released the helper. The GSX interface disappeared even though the vendor services were running again.
We recorded the overall run as failed. The audio result was useful, but the experiment had not completed recovery.
The investigation showed why checking the service status was insufficient. We needed to observe the current vendor process holding all three GSX objects before releasing our helper. The corrected runner waits for that ownership. In the successful local rerun, the wait took 4.62 seconds.
After release, independent read-only captures found the complete GSX and B20 buffers equal to their baselines, the controls unchanged, services running, and no remaining helper. The initialization notes retain both the failed handoff and the corrected run.
That is a bounded recovery result on my PC. Cold boot, managed reconnect, an installed replacement service, and independence from the EPOS driver or processor are still separate milestones.
Give the next agent something it can verify
Agents helped inspect interfaces, compare captures, implement adapters, and build repeatable checks. Their work was easier to trust when the task had a concrete question and an observable result.
A useful loop emerged: make a small claim, gather evidence, implement the smallest supported change, test the failure paths, and record the remaining boundary. Hardware experiments stayed opt-in. Normal test runs used fixtures and demo adapters.
We kept failed reports instead of rewriting them after a fix. We separated protocol notes, user guides, validation, and future work. We documented provenance for reviewed fixtures and excluded vendor binaries and personal state from the repository.
That record matters for maintenance. A future session should be able to follow a control back to its evidence, reproduce the offline checks, and see which live behavior still needs testing.
The work is available in Timbre on GitHub, with an overview on the project page and a dated validation status. It is a useful app on my setup and an ongoing investigation. Keeping both of those descriptions accurate is part of the work.