From 798fc6d471a70ed930e5b1fc084818cb337ca5b1 Mon Sep 17 00:00:00 2001 From: skal Date: Thu, 5 Feb 2026 19:13:34 +0100 Subject: feat(audio): Implement AudioEngine and SpectrogramResourceManager (Task #56 Phase 1) Implements Phase 1 of the audio lifecycle refactor to eliminate initialization order dependencies between synth and tracker. New Components: 1. SpectrogramResourceManager (src/audio/spectrogram_resource_manager.{h,cc}) - Centralized resource loading and ownership - Lazy loading: resources registered but not loaded until needed - Handles both asset spectrograms and procedural notes - Clear ownership: assets borrowed, procedurals owned - Optional cache eviction under DEMO_ENABLE_CACHE_EVICTION flag 2. AudioEngine (src/audio/audio_engine.{h,cc}) - Unified audio subsystem manager - Single initialization point eliminates order dependencies - Manages synth, tracker, and resource manager lifecycle - Timeline seeking API for debugging (!STRIP_ALL) - Clean API: init(), shutdown(), reset(), seek() Features: - Lazy loading strategy with manual preload API - Reset functionality for timeline seeking - Zero impact on production builds - Debug-only seeking support Testing: - Comprehensive test suite (test_audio_engine.cc) - Tests lifecycle, resource loading, reset, seeking - All 20 tests passing (100% pass rate) Bug Fixes: - Fixed infinite recursion in AudioEngine::tracker_reset() Integration: - Added to CMakeLists.txt audio library - No changes to existing code (backward compatible) Binary Size Impact: ~700 bytes (within budget) Next: Phase 2 (Test Migration) - Update existing tests to use AudioEngine Co-Authored-By: Claude Sonnet 4.5 --- src/audio/spectrogram_resource_manager.h | 74 ++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/audio/spectrogram_resource_manager.h (limited to 'src/audio/spectrogram_resource_manager.h') diff --git a/src/audio/spectrogram_resource_manager.h b/src/audio/spectrogram_resource_manager.h new file mode 100644 index 0000000..97196d1 --- /dev/null +++ b/src/audio/spectrogram_resource_manager.h @@ -0,0 +1,74 @@ +// This file is part of the 64k demo project. +// SpectrogramResourceManager: Centralized resource loading and ownership. +// Handles both asset spectrograms and procedurally generated notes. + +#pragma once + +#include "audio/gen.h" +#include "audio/synth.h" +#include "generated/assets.h" +#include "util/asset_manager.h" +#include + +// Maximum number of unique spectrogram resources +constexpr int MAX_SPECTROGRAM_RESOURCES = 256; + +class SpectrogramResourceManager { + public: + // Lifecycle + void init(); + void shutdown(); // Frees all owned memory + void reset(); // Clear state but keep registrations + + // Metadata registration (no loading yet, just bookkeeping) + void register_asset(int sample_id, AssetId asset_id); + void register_procedural(int sample_id, const NoteParams& params); + + // Lazy loading API (loads on first access if not cached) + const Spectrogram* get_or_load(int sample_id); + + // Explicit pre-warming (for timeline seeking) + void preload(int sample_id); + void preload_range(int start_id, int end_id); + + // Query API + const Spectrogram* get_spectrogram(int sample_id) const; + bool is_loaded(int sample_id) const; + int get_loaded_count() const; + +#if defined(DEMO_ENABLE_CACHE_EVICTION) + // Cache management (optional, compile-time flag) + void release(int sample_id); + void release_all(); + void try_evict_lru(float current_time); +#endif /* defined(DEMO_ENABLE_CACHE_EVICTION) */ + + private: + enum ResourceState { + UNREGISTERED = 0, // No metadata registered + REGISTERED, // Metadata registered, not loaded yet + LOADED, // Fully loaded and ready +#if defined(DEMO_ENABLE_CACHE_EVICTION) + EVICTED // Was loaded, now evicted +#endif + }; + + struct Resource { + Spectrogram spec; + float* owned_data; // nullptr if asset (not owned), allocated if procedural + AssetId asset_id; // ASSET_LAST_ID if procedural + NoteParams proc_params; + ResourceState state; + +#if defined(DEMO_ENABLE_CACHE_EVICTION) + float last_access_time; +#endif + }; + + // Load implementation + void load_asset(Resource* resource); + void load_procedural(Resource* resource); + + Resource resources_[MAX_SPECTROGRAM_RESOURCES]; + int loaded_count_ = 0; +}; -- cgit v1.2.3