From d3a609fad91744c45f6bc59b625a26f8870e271d Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Feb 2026 21:28:40 +0100 Subject: docs: Archive historical documentation (26 files → doc/archive/) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved completed/historical docs to doc/archive/ for cleaner context: Archived (26 files): - Analysis docs: variable tempo, audio architecture, build optimization - Handoff docs: 6 agent handoff documents - Debug reports: shadows, peak meter, timing fixes - Task summaries and planning docs Kept (16 files): - Essential: AI_RULES, HOWTO, CONTRIBUTING, CONTEXT_MAINTENANCE - Active subsystems: 3D, ASSET_SYSTEM, TRACKER, SEQUENCE - Current work: MASKING_SYSTEM, SPECTRAL_BRUSH_EDITOR Updated COMPLETED.md with archive index for easy reference. --- doc/archive/AUDIO_LIFECYCLE_REFACTOR.md | 105 ++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 doc/archive/AUDIO_LIFECYCLE_REFACTOR.md (limited to 'doc/archive/AUDIO_LIFECYCLE_REFACTOR.md') diff --git a/doc/archive/AUDIO_LIFECYCLE_REFACTOR.md b/doc/archive/AUDIO_LIFECYCLE_REFACTOR.md new file mode 100644 index 0000000..f5e0045 --- /dev/null +++ b/doc/archive/AUDIO_LIFECYCLE_REFACTOR.md @@ -0,0 +1,105 @@ +# Audio System Architecture + +## Problem Statement + +The legacy audio system had a fragile initialization order dependency: `tracker_init()` had to be called after `synth_init()` because the synth would clear all registered spectrograms. This was brittle, non-obvious, and made testing difficult, as tests needed to respect this internal implementation detail. + +## Implemented Solution: The AudioEngine + +To solve this, the audio system was refactored into a unified, lifecycle-managed architecture centered around two new classes: `AudioEngine` and `SpectrogramResourceManager`. This design eliminates initialization-order dependencies and provides clear ownership of resources. + +### Architecture Overview + +The final architecture separates responsibilities into distinct, manageable components: + +``` + ┌─────────────────┐ + │ AudioEngine │ + │ (Facade) │ + └────────┬────────┘ + │ + ┌─────────────────┼─────────────────┐ + │ │ │ + ┌──────▼──────┐ ┌─────▼──────┐ ┌─────▼────────┐ + │ Synth │ │ Tracker │ │ Resource │ + │ │ │ │ │ Manager │ + │ (Playback) │ │ (Sequence) │ │ (Loading) │ + └─────────────┘ └────────────┘ └──────┬───────┘ + │ + ┌──────────┼──────────┐ + │ │ + ┌──────▼──────┐ ┌──────▼──────┐ + │ AssetManager│ │ Procedural │ + │ (Assets) │ │ Generator │ + └─────────────┘ └─────────────┘ +``` + +### 1. AudioEngine + +The `AudioEngine` acts as a high-level facade for the entire audio subsystem. It is the single entry point for initialization, updates, and shutdown. + +**Responsibilities:** +- Manages the lifecycle of the `Synth`, `Tracker`, and `SpectrogramResourceManager`. +- Guarantees the correct initialization order internally. +- Provides a unified API for updating the audio state (`update()`) and seeking (`seek()`). +- Abstracts away the complexity of resource loading and synth registration. + +**Before (Fragile Initialization):** +```cpp +// In main.cc or tests +synth_init(); +tracker_init(); +// ... +tracker_update(music_time); +``` + +**After (Robust Initialization):** +```cpp +// In main.cc or tests +#include "audio/audio_engine.h" + +AudioEngine g_audio_engine; +g_audio_engine.init(); +// ... +g_audio_engine.update(music_time); +``` + +### 2. SpectrogramResourceManager + +This class centralizes all resource loading and memory management for spectrograms, for both binary assets and procedurally generated notes. + +**Responsibilities:** +- **Loading:** Handles loading `.spec` files from the `AssetManager` and generating procedural spectrograms from `NoteParams`. +- **Ownership:** Enforces clear memory ownership rules. It *borrows* pointers to static assets but *owns* the memory for any generated procedural spectrograms, which it frees upon shutdown. +- **Lazy Loading & Caching:** Resources are not loaded when the application starts. Instead, their metadata is registered. The actual data is loaded on-demand the first time a sample is needed. Once loaded, it is cached for future use. This results in faster startup times and more efficient memory usage. + +--- + +## Lazy Loading and Pre-warming Strategy + +The system uses a lazy-loading approach to minimize startup delay and memory footprint. + +**Workflow:** +1. **`AudioEngine::init()`**: The resource manager is initialized, but no samples are loaded. +2. **`AudioEngine::load_music_data()`**: The tracker score is parsed, and metadata for all required samples (both asset-based and procedural) is *registered* with the `SpectrogramResourceManager`. No data is loaded at this stage. +3. **`AudioEngine::update()`**: During the main loop, the tracker identifies which samples will be needed in the near future (a 1-2 second lookahead window). It then asks the resource manager to "pre-warm" these samples, loading them into the cache just before they are needed. +4. **Triggering a sample**: When a tracker event fires, the `AudioEngine` requests the sample from the resource manager. Since it was pre-warmed, it's a fast cache hit. The engine then ensures the spectrogram is registered with the low-level synth and triggers the voice. + +**Benefits:** +- **Fast Startup:** The application doesn't pay the cost of loading all audio assets up front. +- **No Stutter:** Pre-warming ensures that samples are already in memory when they need to be played, preventing stutter caused by load-on-trigger. +- **Memory Efficient:** Only the samples that are actively being used or are coming up soon are held in memory. + +--- + +## Timeline Seeking & Scrubbing (For Debugging) + +A key feature enabled by this refactor is robust timeline seeking, which is invaluable for development and debugging. The `AudioEngine::seek()` method (`#if !defined(STRIP_ALL)`) allows jumping to any point in the demo timeline. + +**`seek(target_time)` Process:** +1. **Reset:** The synth and tracker states are completely reset, clearing all active voices and pattern states. +2. **State Reconstruction:** The tracker re-scans the musical score from the beginning up to `target_time` to determine which patterns should be active. +3. **Pre-warming:** The resource manager pre-loads all samples needed for the time range around `target_time`. +4. **Ready:** The audio system is now in the exact state it would have been if the demo had run normally up to `target_time`, ready for playback to resume. + +This allows developers to instantly jump to a specific scene to debug audio or visual issues without having to watch the demo from the start. -- cgit v1.2.3