From ca8acd5e7c0556bee7cb21f5ff280c5fd1f47801 Mon Sep 17 00:00:00 2001 From: skal Date: Wed, 20 May 2026 23:12:08 +0200 Subject: fix: audio & effects cleanup — dead code removal, simplifications MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/audio/audio_engine.cc | 7 +- src/audio/spectrogram_resource_manager.cc | 89 +++++++++-- src/audio/spectrogram_resource_manager.h | 3 + src/audio/tracker.cc | 241 +++++------------------------- src/audio/tracker.h | 6 +- src/effects/peak_meter_effect.cc | 19 +-- src/effects/peak_meter_effect.h | 6 +- src/effects/rotating_cube_effect.cc | 15 +- src/effects/rotating_cube_effect.h | 6 +- src/tests/audio/test_audio_engine.cc | 33 ++-- 10 files changed, 157 insertions(+), 268 deletions(-) diff --git a/src/audio/audio_engine.cc b/src/audio/audio_engine.cc index c184324..1d6659d 100644 --- a/src/audio/audio_engine.cc +++ b/src/audio/audio_engine.cc @@ -13,7 +13,7 @@ void AudioEngine::init() { // Initialize in correct order (synth first, then tracker) synth_init(); resource_mgr_.init(); - tracker_init(); + tracker_init(&resource_mgr_); // Initialize sample-to-synth-id mapping for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { @@ -48,8 +48,8 @@ void AudioEngine::reset() { } synth_init(); // Re-init synth (clears all state) - ::tracker_init(); // Re-register all spectrograms (synth slots now clean) resource_mgr_.reset(); + ::tracker_init(&resource_mgr_); // Re-register all spectrograms // Clear sample-to-synth mapping for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { @@ -171,7 +171,8 @@ void AudioEngine::seek(float target_time) { synth_init(); // 2. Re-init tracker: re-registers all spectrograms with now-clean synth slots - ::tracker_init(); + resource_mgr_.reset(); + ::tracker_init(&resource_mgr_); // 3. Clear sample-to-synth mapping (will be re-registered on demand) for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { diff --git a/src/audio/spectrogram_resource_manager.cc b/src/audio/spectrogram_resource_manager.cc index c0fb0a3..f182869 100644 --- a/src/audio/spectrogram_resource_manager.cc +++ b/src/audio/spectrogram_resource_manager.cc @@ -3,11 +3,17 @@ #include "spectrogram_resource_manager.h" #include "audio/audio.h" +#include "audio/dct.h" #include "procedural/generator.h" #include "util/debug.h" #include #include +#if !defined(STRIP_ALL) +#include "audio/mp3_sample.h" +#include "audio/window.h" +#endif + void SpectrogramResourceManager::init() { for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { resources_[i].owned_data = nullptr; @@ -32,10 +38,13 @@ void SpectrogramResourceManager::shutdown() { } void SpectrogramResourceManager::reset() { - // Clear state but keep registrations (useful for seeking) - // Don't free memory, just mark as unloaded + // Clear state and free owned memory, keep registrations for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { if (resources_[i].state == LOADED) { + if (resources_[i].owned_data) { + delete[] resources_[i].owned_data; + resources_[i].owned_data = nullptr; + } resources_[i].state = REGISTERED; } } @@ -50,7 +59,9 @@ void SpectrogramResourceManager::register_asset(int sample_id, Resource& resource = resources_[sample_id]; resource.asset_id = asset_id; - resource.state = REGISTERED; + if (resource.state == UNREGISTERED) { + resource.state = REGISTERED; + } #if defined(DEBUG_LOG_ASSETS) DEBUG_ASSETS("[ResourceMgr] Registered asset sample_id=%d, asset_id=%d\n", @@ -67,7 +78,9 @@ void SpectrogramResourceManager::register_procedural(int sample_id, Resource& resource = resources_[sample_id]; resource.asset_id = AssetId::ASSET_LAST_ID; // Mark as procedural resource.proc_params = params; - resource.state = REGISTERED; + if (resource.state == UNREGISTERED) { + resource.state = REGISTERED; + } #if defined(DEBUG_LOG_ASSETS) DEBUG_ASSETS("[ResourceMgr] Registered procedural sample_id=%d, freq=%.2f\n", @@ -184,12 +197,19 @@ void SpectrogramResourceManager::try_evict_lru(float current_time) { void SpectrogramResourceManager::load_asset(Resource* resource) { size_t size; const uint8_t* data = GetAsset(resource->asset_id, &size); + if (data == nullptr || size == 0) { + return; + } - if (data == nullptr || size < sizeof(SpecHeader)) { -#if defined(DEBUG_LOG_ASSETS) - DEBUG_ASSETS("[ResourceMgr ERROR] Failed to load asset %d\n", - (int)resource->asset_id); +#if !defined(STRIP_ALL) + // MP3 assets: decode to spectrogram via OLA analysis + if (GetAssetType(resource->asset_id) == AssetType::MP3) { + load_mp3(resource, data, size); + return; + } #endif + + if (size < sizeof(SpecHeader)) { return; } @@ -201,12 +221,57 @@ void SpectrogramResourceManager::load_asset(Resource* resource) { resource->spec.num_frames = header->num_frames; resource->spec.version = header->version; resource->owned_data = nullptr; // Asset data is not owned +} -#if defined(DEBUG_LOG_ASSETS) - DEBUG_ASSETS("[ResourceMgr] Loaded asset %d: %d frames\n", - (int)resource->asset_id, header->num_frames); -#endif +#if !defined(STRIP_ALL) +void SpectrogramResourceManager::load_mp3(Resource* resource, + const uint8_t* data, size_t size) { + Mp3Decoder* dec = mp3_open(data, size); + if (!dec) + return; + + float window[DCT_SIZE]; + hann_window_512(window); + + std::vector spec_data; + float pcm_buf[DCT_SIZE]; + float pcm_chunk[DCT_SIZE]; + float dct_chunk[DCT_SIZE]; + + memset(pcm_buf, 0, sizeof(pcm_buf)); + + for (;;) { + memmove(pcm_buf, pcm_buf + OLA_HOP_SIZE, OLA_HOP_SIZE * sizeof(float)); + const int decoded = mp3_decode(dec, OLA_HOP_SIZE, pcm_buf + OLA_HOP_SIZE); + if (decoded < OLA_HOP_SIZE) { + memset(pcm_buf + OLA_HOP_SIZE + decoded, 0, + (OLA_HOP_SIZE - decoded) * sizeof(float)); + } + + for (int i = 0; i < DCT_SIZE; ++i) + pcm_chunk[i] = pcm_buf[i] * window[i]; + fdct_512(pcm_chunk, dct_chunk); + spec_data.insert(spec_data.end(), dct_chunk, dct_chunk + DCT_SIZE); + + if (decoded == 0) + break; + } + + mp3_close(dec); + if (spec_data.empty()) + return; + + const int num_frames = (int)(spec_data.size() / DCT_SIZE); + resource->owned_data = new float[spec_data.size()]; + memcpy(resource->owned_data, spec_data.data(), + spec_data.size() * sizeof(float)); + + resource->spec.spectral_data_a = resource->owned_data; + resource->spec.spectral_data_b = resource->owned_data; + resource->spec.num_frames = num_frames; + resource->spec.version = SPEC_VERSION_V2_OLA; } +#endif void SpectrogramResourceManager::load_procedural(Resource* resource) { int note_frames = 0; diff --git a/src/audio/spectrogram_resource_manager.h b/src/audio/spectrogram_resource_manager.h index 45faa37..687f91e 100644 --- a/src/audio/spectrogram_resource_manager.h +++ b/src/audio/spectrogram_resource_manager.h @@ -68,6 +68,9 @@ class SpectrogramResourceManager { // Load implementation void load_asset(Resource* resource); void load_procedural(Resource* resource); +#if !defined(STRIP_ALL) + void load_mp3(Resource* resource, const uint8_t* data, size_t size); +#endif Resource resources_[MAX_SPECTROGRAM_RESOURCES]; int loaded_count_ = 0; diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc index a511a62..e634333 100644 --- a/src/audio/tracker.cc +++ b/src/audio/tracker.cc @@ -1,5 +1,6 @@ #include "tracker.h" #include "audio.h" +#include "audio/spectrogram_resource_manager.h" #include "audio/synth.h" #include "ring_buffer.h" #include "util/asset_manager.h" @@ -7,13 +8,6 @@ #include "util/fatal_error.h" #include #include -#include - -#if !defined(STRIP_ALL) -#include "audio/dct.h" -#include "audio/mp3_sample.h" -#include "audio/window.h" -#endif // !defined(STRIP_ALL) static uint32_t g_last_trigger_idx = 0; @@ -27,201 +21,76 @@ struct ActivePattern { static ActivePattern g_active_patterns[MAX_SPECTROGRAMS]; -struct ManagedSpectrogram { - int synth_id; - float* data; - bool active; -}; - -// Simple pool for dynamic spectrograms (now for individual notes) -static ManagedSpectrogram g_spec_pool[MAX_SPECTROGRAMS]; -static int g_next_pool_slot = 0; // Round-robin allocation - // CACHE: Pre-registered synth_ids for all samples (indexed by sample_id) -// This eliminates redundant spectrogram generation and registration -static int g_sample_synth_cache[256]; // Max 256 unique samples -static bool g_cache_initialized = false; - -// Forward declarations -static int get_free_pool_slot(); - -#if !defined(STRIP_ALL) -// Decode an in-memory MP3 blob to a heap-allocated spectrogram (caller owns). -// Uses OLA analysis: 512-sample Hann window, OLA_HOP_SIZE advance per frame. -// Returns nullptr on error. Sets *out_num_frames to frame count. -static float* convert_mp3_to_spectrogram(const uint8_t* data, size_t size, - int* out_num_frames) { - *out_num_frames = 0; - Mp3Decoder* dec = mp3_open(data, size); - if (!dec) - return nullptr; - - float window[DCT_SIZE]; - hann_window_512(window); - - std::vector spec_data; - float pcm_buf[DCT_SIZE]; - float pcm_chunk[DCT_SIZE]; - float dct_chunk[DCT_SIZE]; - - // Sliding-window OLA analysis: advance OLA_HOP_SIZE samples per frame. - // First iteration: pcm_buf is zero-initialized (silence before signal start). - memset(pcm_buf, 0, sizeof(pcm_buf)); - - for (;;) { - // Slide left by OLA_HOP_SIZE; fill right half with new samples. - memmove(pcm_buf, pcm_buf + OLA_HOP_SIZE, OLA_HOP_SIZE * sizeof(float)); - const int decoded = mp3_decode(dec, OLA_HOP_SIZE, pcm_buf + OLA_HOP_SIZE); - if (decoded < OLA_HOP_SIZE) { - memset(pcm_buf + OLA_HOP_SIZE + decoded, 0, - (OLA_HOP_SIZE - decoded) * sizeof(float)); - } +static int g_sample_synth_cache[MAX_SPECTROGRAM_RESOURCES]; - // Window + DCT the current 512-sample frame. - for (int i = 0; i < DCT_SIZE; ++i) - pcm_chunk[i] = pcm_buf[i] * window[i]; - fdct_512(pcm_chunk, dct_chunk); - spec_data.insert(spec_data.end(), dct_chunk, dct_chunk + DCT_SIZE); - - if (decoded == 0) - break; +static int get_free_pattern_slot() { + for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { + if (!g_active_patterns[i].active) + return i; } - - mp3_close(dec); - if (spec_data.empty()) - return nullptr; - - const int num_frames = (int)(spec_data.size() / DCT_SIZE); - float* result = new float[spec_data.size()]; - memcpy(result, spec_data.data(), spec_data.size() * sizeof(float)); - *out_num_frames = num_frames; - return result; + return -1; // No free slots } -#endif // !defined(STRIP_ALL) -void tracker_init() { +void tracker_init(SpectrogramResourceManager* resource_mgr) { g_last_trigger_idx = 0; - g_next_pool_slot = 0; - - // Free any previously allocated generated note data to prevent leaks. - // Must run before the pool is zeroed (relies on .active/.data still set). - if (g_cache_initialized) { - for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { - if (g_spec_pool[i].data != nullptr && g_spec_pool[i].active) { - delete[] g_spec_pool[i].data; - } - } - } for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { - g_spec_pool[i].synth_id = -1; - g_spec_pool[i].data = nullptr; - g_spec_pool[i].active = false; g_active_patterns[i].active = false; } - // Initialize sample cache - { - for (int i = 0; i < 256; ++i) { - g_sample_synth_cache[i] = -1; - } + for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { + g_sample_synth_cache[i] = -1; + } - // Pre-register all unique samples (assets + generated notes) - for (uint32_t sid = 0; sid < g_tracker_samples_count; ++sid) { - AssetId aid = g_tracker_sample_assets[sid]; + // Pre-register all unique samples (assets + generated notes) + for (uint32_t sid = 0; sid < g_tracker_samples_count; ++sid) { + AssetId aid = g_tracker_sample_assets[sid]; + if (resource_mgr) { + // Unified path: register metadata, load eagerly, register with synth + if (aid != AssetId::ASSET_LAST_ID) { + resource_mgr->register_asset(sid, aid); + } else { + resource_mgr->register_procedural(sid, g_tracker_samples[sid]); + } + const Spectrogram* spec = resource_mgr->get_or_load(sid); + if (spec) { + g_sample_synth_cache[sid] = synth_register_spectrogram(spec); + } + } else { + // Legacy path (no resource manager — standalone tests) if (aid != AssetId::ASSET_LAST_ID) { - // ASSET sample: Load once and cache size_t size; const uint8_t* data = GetAsset(aid, &size); #if !defined(STRIP_ALL) if (data && size > 0 && GetAssetType(aid) == AssetType::MP3) { - int num_frames = 0; - float* spec_data = - convert_mp3_to_spectrogram(data, size, &num_frames); - if (spec_data && num_frames > 0) { - const int slot = get_free_pool_slot(); - g_spec_pool[slot].data = spec_data; - g_spec_pool[slot].active = true; - Spectrogram spec; - spec.spectral_data_a = spec_data; - spec.spectral_data_b = spec_data; - spec.num_frames = num_frames; - spec.version = SPEC_VERSION_V2_OLA; - g_sample_synth_cache[sid] = synth_register_spectrogram(&spec); - g_spec_pool[slot].synth_id = g_sample_synth_cache[sid]; - } - } else + continue; // MP3 requires resource manager + } #else if (data != nullptr && GetAssetType(aid) == AssetType::MP3) { - continue; // MP3 decoding not available in STRIP_ALL builds + continue; } #endif - if (data && size >= sizeof(SpecHeader)) { + if (data && size >= sizeof(SpecHeader)) { const SpecHeader* header = (const SpecHeader*)data; - const int note_frames = header->num_frames; - const float* spectral_data = - (const float*)(data + sizeof(SpecHeader)); - Spectrogram spec; - spec.spectral_data_a = spectral_data; - spec.spectral_data_b = spectral_data; - spec.num_frames = note_frames; + spec.spectral_data_a = (const float*)(data + sizeof(SpecHeader)); + spec.spectral_data_b = spec.spectral_data_a; + spec.num_frames = header->num_frames; spec.version = header->version; - - g_sample_synth_cache[sid] = synth_register_spectrogram(&spec); - -#if defined(DEBUG_LOG_TRACKER) - if (g_sample_synth_cache[sid] == -1) { - DEBUG_TRACKER( - "[TRACKER INIT] Failed to cache asset sample_id=%d (aid=%d)\n", - sid, (int)aid); - } -#endif /* defined(DEBUG_LOG_TRACKER) */ - } - } else { - // GENERATED note: Generate once and cache - const NoteParams& params = g_tracker_samples[sid]; - int note_frames = 0; - std::vector note_data = - generate_note_spectrogram(params, ¬e_frames); - - if (note_frames > 0) { - // Allocate persistent storage for this note - const int slot = get_free_pool_slot(); - g_spec_pool[slot].data = new float[note_data.size()]; - memcpy(g_spec_pool[slot].data, note_data.data(), - note_data.size() * sizeof(float)); - - Spectrogram spec; - spec.spectral_data_a = g_spec_pool[slot].data; - spec.spectral_data_b = g_spec_pool[slot].data; - spec.num_frames = note_frames; - spec.version = SPEC_VERSION_V1; - g_sample_synth_cache[sid] = synth_register_spectrogram(&spec); - g_spec_pool[slot].synth_id = g_sample_synth_cache[sid]; - g_spec_pool[slot].active = true; // Mark as permanently allocated - -#if defined(DEBUG_LOG_TRACKER) - if (g_sample_synth_cache[sid] == -1) { - DEBUG_TRACKER( - "[TRACKER INIT] Failed to cache generated sample_id=%d " - "(freq=%.2f)\n", - sid, params.base_freq); - } -#endif /* defined(DEBUG_LOG_TRACKER) */ } } + // Note: procedural notes without resource_mgr are not supported + // (requires std::vector allocation — use resource_mgr path) } - - g_cache_initialized = true; + } #if defined(DEBUG_LOG_TRACKER) - DEBUG_TRACKER("[TRACKER INIT] Cached %d unique samples\n", - g_tracker_samples_count); -#endif /* defined(DEBUG_LOG_TRACKER) */ - } + DEBUG_TRACKER("[TRACKER INIT] Cached %d unique samples\n", + g_tracker_samples_count); +#endif // Validate that all pattern events are sorted by unit_time // (required for early-exit optimization in tracker_update) @@ -247,36 +116,6 @@ void tracker_reset() { } } -static int get_free_pool_slot() { - // Try to find an inactive slot first (unused slots) - for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { - if (!g_spec_pool[i].active) - return i; - } - - // If all slots are active, reuse the oldest one (round-robin) - // Clean up the old slot before reuse - const int slot = g_next_pool_slot; - g_next_pool_slot = (g_next_pool_slot + 1) % MAX_SPECTROGRAMS; - - if (g_spec_pool[slot].synth_id >= 0) { - synth_unregister_spectrogram(g_spec_pool[slot].synth_id); - } - delete[] g_spec_pool[slot].data; - g_spec_pool[slot].data = nullptr; - g_spec_pool[slot].synth_id = -1; - g_spec_pool[slot].active = false; - return slot; -} - -static int get_free_pattern_slot() { - for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { - if (!g_active_patterns[i].active) - return i; - } - return -1; // No free slots -} - // Helper to trigger a single note event (OPTIMIZED with caching) // start_offset_samples: How many samples into the future to trigger (for // sample-accurate timing) diff --git a/src/audio/tracker.h b/src/audio/tracker.h index f471bd8..a96a801 100644 --- a/src/audio/tracker.h +++ b/src/audio/tracker.h @@ -7,6 +7,8 @@ #include "generated/assets.h" #include +class SpectrogramResourceManager; + struct TrackerEvent { float unit_time; // Unit-less time within pattern (0.0 to pattern.unit_length) uint16_t sample_id; @@ -44,6 +46,8 @@ extern const TrackerPattern g_tracker_patterns[]; extern const uint32_t g_tracker_patterns_count; extern const TrackerScore g_tracker_score; -void tracker_init(); +// Initialize tracker. If resource_mgr is provided, spectrograms are loaded +// through it (unified ownership). If nullptr, tracker manages its own storage. +void tracker_init(SpectrogramResourceManager* resource_mgr = nullptr); void tracker_update(double music_time_sec, double dt_music_sec); void tracker_reset(); // Reset tracker state (for tests/seeking) diff --git a/src/effects/peak_meter_effect.cc b/src/effects/peak_meter_effect.cc index c2ef42e..8956e32 100644 --- a/src/effects/peak_meter_effect.cc +++ b/src/effects/peak_meter_effect.cc @@ -9,8 +9,7 @@ PeakMeter::PeakMeter(const GpuContext& ctx, const std::vector& inputs, const std::vector& outputs, float start_time, float end_time) - : Effect(ctx, inputs, outputs, start_time, end_time), pipeline_(nullptr), - bind_group_(nullptr) { + : Effect(ctx, inputs, outputs, start_time, end_time) { HEADLESS_RETURN_IF_NULL(ctx_.device); const char* shader_main = R"( @@ -58,15 +57,8 @@ PeakMeter::PeakMeter(const GpuContext& ctx, std::string shader_code = ShaderComposer::Get().Compose({"common_uniforms"}, shader_main); - pipeline_ = create_post_process_pipeline( - ctx_.device, WGPUTextureFormat_RGBA8Unorm, shader_code.c_str()); -} - -PeakMeter::~PeakMeter() { - if (bind_group_) - wgpuBindGroupRelease(bind_group_); - if (pipeline_) - wgpuRenderPipelineRelease(pipeline_); + pipeline_.set(create_post_process_pipeline( + ctx_.device, WGPUTextureFormat_RGBA8Unorm, shader_code.c_str())); } void PeakMeter::render(WGPUCommandEncoder encoder, @@ -75,9 +67,10 @@ void PeakMeter::render(WGPUCommandEncoder encoder, WGPUTextureView input_view = nodes.get_view(input_nodes_[0]); WGPUTextureView output_view = nodes.get_view(output_nodes_[0]); - pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view, + pp_update_bind_group(ctx_.device, pipeline_.get(), + bind_group_.get_address(), input_view, uniforms_buffer_.get(), {nullptr, 0}); - run_fullscreen_pass(encoder, pipeline_, bind_group_, output_view, + run_fullscreen_pass(encoder, pipeline_.get(), bind_group_.get(), output_view, WGPULoadOp_Load); } diff --git a/src/effects/peak_meter_effect.h b/src/effects/peak_meter_effect.h index 1f19ed6..b822efd 100644 --- a/src/effects/peak_meter_effect.h +++ b/src/effects/peak_meter_effect.h @@ -4,18 +4,18 @@ #pragma once #include "gpu/effect.h" #include "gpu/uniform_helper.h" +#include "gpu/wgpu_resource.h" class PeakMeter : public Effect { public: PeakMeter(const GpuContext& ctx, const std::vector& inputs, const std::vector& outputs, float start_time, float end_time); - ~PeakMeter() override; void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, NodeRegistry& nodes) override; private: - WGPURenderPipeline pipeline_; - WGPUBindGroup bind_group_; + RenderPipeline pipeline_; + BindGroup bind_group_; }; diff --git a/src/effects/rotating_cube_effect.cc b/src/effects/rotating_cube_effect.cc index 82f90c5..000d177 100644 --- a/src/effects/rotating_cube_effect.cc +++ b/src/effects/rotating_cube_effect.cc @@ -84,7 +84,7 @@ RotatingCube::RotatingCube(const GpuContext& ctx, pipeline_desc.multisample.mask = 0xFFFFFFFF; pipeline_desc.fragment = &fragment; - pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc); + pipeline_.set(wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc)); wgpuShaderModuleRelease(shader_module); wgpuPipelineLayoutRelease(pipeline_layout); @@ -103,17 +103,10 @@ RotatingCube::RotatingCube(const GpuContext& ctx, .entryCount = 2, .entries = entries, }; - bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc); + bind_group_.set(wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc)); wgpuBindGroupLayoutRelease(bgl); } -RotatingCube::~RotatingCube() { - if (bind_group_) - wgpuBindGroupRelease(bind_group_); - if (pipeline_) - wgpuRenderPipelineRelease(pipeline_); -} - void RotatingCube::declare_nodes(NodeRegistry& registry) { // Declare depth buffer node registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1); @@ -201,8 +194,8 @@ void RotatingCube::render(WGPUCommandEncoder encoder, WGPURenderPassEncoder pass = wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc); - wgpuRenderPassEncoderSetPipeline(pass, pipeline_); - wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr); + wgpuRenderPassEncoderSetPipeline(pass, pipeline_.get()); + wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_.get(), 0, nullptr); wgpuRenderPassEncoderDraw(pass, 36, 1, 0, 0); // 36 vertices for cube wgpuRenderPassEncoderEnd(pass); wgpuRenderPassEncoderRelease(pass); diff --git a/src/effects/rotating_cube_effect.h b/src/effects/rotating_cube_effect.h index fb321fa..0aa1469 100644 --- a/src/effects/rotating_cube_effect.h +++ b/src/effects/rotating_cube_effect.h @@ -6,6 +6,7 @@ #include "gpu/effect.h" #include "gpu/gpu.h" #include "gpu/uniform_helper.h" +#include "gpu/wgpu_resource.h" #include "util/mini_math.h" class RotatingCube : public Effect { @@ -13,7 +14,6 @@ class RotatingCube : public Effect { RotatingCube(const GpuContext& ctx, const std::vector& inputs, const std::vector& outputs, float start_time, float end_time); - ~RotatingCube() override; void declare_nodes(NodeRegistry& registry) override; void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params, @@ -44,8 +44,8 @@ class RotatingCube : public Effect { }; static_assert(sizeof(ObjectData) == 160, "ObjectData size mismatch"); - WGPURenderPipeline pipeline_ = nullptr; - WGPUBindGroup bind_group_ = nullptr; + RenderPipeline pipeline_; + BindGroup bind_group_; GpuBuffer uniform_buffer_; GpuBuffer object_buffer_; float rotation_ = 0.0f; diff --git a/src/tests/audio/test_audio_engine.cc b/src/tests/audio/test_audio_engine.cc index 767ee15..98c6aa7 100644 --- a/src/tests/audio/test_audio_engine.cc +++ b/src/tests/audio/test_audio_engine.cc @@ -34,13 +34,12 @@ void test_audio_engine_music_loading() { fixture.load_music(&g_tracker_score, g_tracker_samples, g_tracker_sample_assets, g_tracker_samples_count); - // Verify resource manager was initialized (samples registered but not loaded - // yet) + // Verify resource manager was initialized SpectrogramResourceManager* res_mgr = fixture.engine().get_resource_manager(); assert(res_mgr != nullptr); - // Initially, no samples should be loaded (lazy loading) - assert(res_mgr->get_loaded_count() == 0); + // After load_music_data, samples are registered (may be eagerly loaded + // by tracker_init if already initialized) printf(" ✓ Music data loaded: %u samples registered\n", g_tracker_samples_count); @@ -59,18 +58,13 @@ void test_audio_engine_manual_resource_loading() { g_tracker_sample_assets, g_tracker_samples_count); SpectrogramResourceManager* res_mgr = fixture.engine().get_resource_manager(); - const int initial_loaded = res_mgr->get_loaded_count(); - assert(initial_loaded == 0); // No samples loaded yet - - // Manually preload first few samples - res_mgr->preload(0); - res_mgr->preload(1); - const int after_preload = res_mgr->get_loaded_count(); - printf(" Samples loaded after manual preload: %d\n", after_preload); - assert(after_preload == 2); // Should have 2 samples loaded + // After init + load_music, tracker_init eagerly loads all samples + const int initial_loaded = res_mgr->get_loaded_count(); + printf(" Samples eagerly loaded by tracker_init: %d\n", initial_loaded); + assert(initial_loaded > 0); // Samples loaded eagerly at init - // Verify samples are accessible + // Verify first samples are accessible const Spectrogram* spec0 = res_mgr->get_spectrogram(0); const Spectrogram* spec1 = res_mgr->get_spectrogram(1); @@ -91,12 +85,8 @@ void test_audio_engine_reset() { SpectrogramResourceManager* res_mgr = fixture.engine().get_resource_manager(); - // Manually load some samples - res_mgr->preload(0); - res_mgr->preload(1); - const int loaded_before_reset = res_mgr->get_loaded_count(); - assert(loaded_before_reset == 2); + assert(loaded_before_reset > 0); // Reset engine fixture.engine().reset(); @@ -104,11 +94,12 @@ void test_audio_engine_reset() { // After reset, state should be cleared assert(fixture.engine().get_active_voice_count() == 0); - // Resources should be marked as unloaded (but memory not freed) + // After reset, tracker re-initializes and reloads samples eagerly const int loaded_after_reset = res_mgr->get_loaded_count(); printf(" Loaded count before reset: %d, after reset: %d\n", loaded_before_reset, loaded_after_reset); - assert(loaded_after_reset == 0); + // Samples are re-loaded by tracker_init after reset + assert(loaded_after_reset == loaded_before_reset); printf(" ✓ AudioEngine reset test passed\n"); } -- cgit v1.2.3