diff options
Diffstat (limited to 'src/audio')
| -rw-r--r-- | src/audio/audio.cc | 29 | ||||
| -rw-r--r-- | src/audio/audio_backend.h | 5 | ||||
| -rw-r--r-- | src/audio/audio_engine.cc | 23 | ||||
| -rw-r--r-- | src/audio/audio_engine.h | 18 | ||||
| -rw-r--r-- | src/audio/jittered_audio_backend.cc | 28 | ||||
| -rw-r--r-- | src/audio/jittered_audio_backend.h | 22 | ||||
| -rw-r--r-- | src/audio/miniaudio_backend.cc | 100 | ||||
| -rw-r--r-- | src/audio/miniaudio_backend.h | 4 | ||||
| -rw-r--r-- | src/audio/mock_audio_backend.cc | 2 | ||||
| -rw-r--r-- | src/audio/mock_audio_backend.h | 16 | ||||
| -rw-r--r-- | src/audio/ring_buffer.cc | 37 | ||||
| -rw-r--r-- | src/audio/ring_buffer.h | 22 | ||||
| -rw-r--r-- | src/audio/spectrogram_resource_manager.cc | 27 | ||||
| -rw-r--r-- | src/audio/spectrogram_resource_manager.h | 16 | ||||
| -rw-r--r-- | src/audio/synth.cc | 38 | ||||
| -rw-r--r-- | src/audio/synth.h | 8 | ||||
| -rw-r--r-- | src/audio/tracker.cc | 41 | ||||
| -rw-r--r-- | src/audio/tracker.h | 2 |
18 files changed, 264 insertions, 174 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc index 0407fb3..b00d416 100644 --- a/src/audio/audio.cc +++ b/src/audio/audio.cc @@ -21,7 +21,7 @@ static AudioRingBuffer g_ring_buffer; // Maximum size: one chunk (533 frames @ 60fps = 1066 samples stereo) #define MAX_PENDING_SAMPLES 2048 static float g_pending_buffer[MAX_PENDING_SAMPLES]; -static int g_pending_samples = 0; // How many samples are waiting to be written +static int g_pending_samples = 0; // How many samples are waiting to be written // Global backend pointer for audio abstraction static AudioBackend* g_audio_backend = nullptr; @@ -59,7 +59,8 @@ int register_spec_asset(AssetId id) { void audio_init() { // Note: synth_init() must be called separately before using audio system. - // In production code, use AudioEngine::init() which manages initialization order. + // In production code, use AudioEngine::init() which manages initialization + // order. // Clear pending buffer g_pending_samples = 0; @@ -83,21 +84,22 @@ void audio_start() { void audio_render_ahead(float music_time, float dt) { // Target: maintain look-ahead buffer - const float target_lookahead = - (float)RING_BUFFER_LOOKAHEAD_MS / 1000.0f; + const float target_lookahead = (float)RING_BUFFER_LOOKAHEAD_MS / 1000.0f; // Render in small chunks to keep synth time synchronized with tracker // Chunk size: one frame's worth of audio (~16.6ms @ 60fps) const int chunk_frames = (int)(dt * RING_BUFFER_SAMPLE_RATE); const int chunk_samples = chunk_frames * RING_BUFFER_CHANNELS; - if (chunk_frames <= 0) return; + if (chunk_frames <= 0) + return; // Keep rendering small chunks until buffer is full enough while (true) { // First, try to flush any pending samples from previous partial writes if (g_pending_samples > 0) { - const int written = g_ring_buffer.write(g_pending_buffer, g_pending_samples); + const int written = + g_ring_buffer.write(g_pending_buffer, g_pending_samples); if (written > 0) { // Some or all samples were written @@ -119,16 +121,19 @@ void audio_render_ahead(float music_time, float dt) { } // If still have pending samples, buffer is full - wait for consumption - if (g_pending_samples > 0) break; + if (g_pending_samples > 0) + break; } // Check current buffer state const int buffered_samples = g_ring_buffer.available_read(); const float buffered_time = - (float)buffered_samples / (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); + (float)buffered_samples / + (RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS); // Stop if buffer is full enough - if (buffered_time >= target_lookahead) break; + if (buffered_time >= target_lookahead) + break; // Check available space and render chunk that fits const int available_space = g_ring_buffer.available_write(); @@ -139,7 +144,8 @@ void audio_render_ahead(float music_time, float dt) { // Determine how much we can actually render // Render the smaller of: desired chunk size OR available space - const int actual_samples = (available_space < chunk_samples) ? available_space : chunk_samples; + const int actual_samples = + (available_space < chunk_samples) ? available_space : chunk_samples; const int actual_frames = actual_samples / RING_BUFFER_CHANNELS; // Allocate temporary buffer (stereo) @@ -172,7 +178,8 @@ void audio_render_ahead(float music_time, float dt) { delete[] temp_buffer; // If we couldn't write everything, stop and retry next frame - if (written < actual_samples) break; + if (written < actual_samples) + break; } } diff --git a/src/audio/audio_backend.h b/src/audio/audio_backend.h index 4a2b7fb..940e2b2 100644 --- a/src/audio/audio_backend.h +++ b/src/audio/audio_backend.h @@ -8,7 +8,8 @@ // Production uses MiniaudioBackend, tests use MockAudioBackend class AudioBackend { public: - virtual ~AudioBackend() {} + virtual ~AudioBackend() { + } // Initialize backend resources virtual void init() = 0; @@ -26,7 +27,7 @@ class AudioBackend { // volume: Voice volume (0.0 - 1.0) // pan: Pan position (-1.0 left, 0.0 center, 1.0 right) virtual void on_voice_triggered(float timestamp, int spectrogram_id, - float volume, float pan) { + float volume, float pan) { // Default implementation does nothing (production path) (void)timestamp; (void)spectrogram_id; diff --git a/src/audio/audio_engine.cc b/src/audio/audio_engine.cc index 184e4aa..6d2ee92 100644 --- a/src/audio/audio_engine.cc +++ b/src/audio/audio_engine.cc @@ -3,8 +3,8 @@ #include "audio_engine.h" #include "util/debug.h" -#include <cstring> #include <algorithm> +#include <cstring> void AudioEngine::init() { if (initialized_) { @@ -48,7 +48,7 @@ void AudioEngine::reset() { return; } - synth_init(); // Re-init synth (clears all state) + synth_init(); // Re-init synth (clears all state) tracker_reset(); resource_mgr_.reset(); @@ -65,9 +65,9 @@ void AudioEngine::reset() { } void AudioEngine::load_music_data(const TrackerScore* score, - const NoteParams* samples, - const AssetId* sample_assets, - uint32_t sample_count) { + const NoteParams* samples, + const AssetId* sample_assets, + uint32_t sample_count) { // Register sample metadata (lazy loading - don't load yet!) for (uint32_t i = 0; i < sample_count; ++i) { if (sample_assets[i] != AssetId::ASSET_LAST_ID) { @@ -118,7 +118,9 @@ void AudioEngine::trigger_sample(int sample_id, float volume, float pan) { const int synth_id = get_or_register_synth_id(sample_id); if (synth_id == -1) { #if defined(DEBUG_LOG_AUDIO) - DEBUG_AUDIO("[AudioEngine ERROR] Failed to register sample_id=%d with synth\n", sample_id); + DEBUG_AUDIO( + "[AudioEngine ERROR] Failed to register sample_id=%d with synth\n", + sample_id); #endif return; } @@ -148,7 +150,8 @@ int AudioEngine::get_or_register_synth_id(int sample_id) { sample_to_synth_id_[sample_id] = synth_id; #if defined(DEBUG_LOG_AUDIO) - DEBUG_AUDIO("[AudioEngine] Registered sample_id=%d → synth_id=%d\n", sample_id, synth_id); + DEBUG_AUDIO("[AudioEngine] Registered sample_id=%d → synth_id=%d\n", + sample_id, synth_id); #endif return synth_id; @@ -161,7 +164,8 @@ void AudioEngine::seek(float target_time) { } #if defined(DEBUG_LOG_AUDIO) - DEBUG_AUDIO("[AudioEngine] Seeking to t=%.3fs (from t=%.3fs)\n", target_time, current_time_); + DEBUG_AUDIO("[AudioEngine] Seeking to t=%.3fs (from t=%.3fs)\n", target_time, + current_time_); #endif // 1. Reset synth state (clear all active voices) @@ -203,7 +207,8 @@ void AudioEngine::prewarm_for_time_range(float start_time, float end_time) { // and pattern data to determine which samples will be needed. #if defined(DEBUG_LOG_AUDIO) - DEBUG_AUDIO("[AudioEngine] Pre-warming samples for t=%.2f-%.2f\n", start_time, end_time); + DEBUG_AUDIO("[AudioEngine] Pre-warming samples for t=%.2f-%.2f\n", start_time, + end_time); #endif } diff --git a/src/audio/audio_engine.h b/src/audio/audio_engine.h index ef3c163..95761ad 100644 --- a/src/audio/audio_engine.h +++ b/src/audio/audio_engine.h @@ -14,13 +14,11 @@ class AudioEngine { // Lifecycle void init(); void shutdown(); - void reset(); // Clear all state (for seeking/rewinding) + void reset(); // Clear all state (for seeking/rewinding) // Music data loading - void load_music_data(const TrackerScore* score, - const NoteParams* samples, - const AssetId* sample_assets, - uint32_t sample_count); + void load_music_data(const TrackerScore* score, const NoteParams* samples, + const AssetId* sample_assets, uint32_t sample_count); // Update loop void update(float music_time); @@ -28,7 +26,9 @@ class AudioEngine { #if !defined(STRIP_ALL) // Timeline seeking (debugging only) void seek(float target_time); - float get_time() const { return current_time_; } + float get_time() const { + return current_time_; + } #endif /* !defined(STRIP_ALL) */ // Synth interface (delegates to internal synth) @@ -39,7 +39,9 @@ class AudioEngine { void tracker_reset(); // Resource access - SpectrogramResourceManager* get_resource_manager() { return &resource_mgr_; } + SpectrogramResourceManager* get_resource_manager() { + return &resource_mgr_; + } private: // Trigger a sample (loads resource if needed, registers with synth) @@ -51,7 +53,7 @@ class AudioEngine { #if !defined(STRIP_ALL) // Seeking support void prewarm_for_time_range(float start_time, float end_time); - void update_silent(float music_time); // Update without triggering audio + void update_silent(float music_time); // Update without triggering audio #endif SpectrogramResourceManager resource_mgr_; diff --git a/src/audio/jittered_audio_backend.cc b/src/audio/jittered_audio_backend.cc index 5561c11..8742aba 100644 --- a/src/audio/jittered_audio_backend.cc +++ b/src/audio/jittered_audio_backend.cc @@ -13,14 +13,9 @@ #include <thread> JitteredAudioBackend::JitteredAudioBackend() - : running_(false), - should_stop_(false), - jitter_ms_(5.0f), - base_interval_ms_(10.0f), - min_chunk_frames_(256), - max_chunk_frames_(1024), - total_frames_consumed_(0), - underrun_count_(0) { + : running_(false), should_stop_(false), jitter_ms_(5.0f), + base_interval_ms_(10.0f), min_chunk_frames_(256), max_chunk_frames_(1024), + total_frames_consumed_(0), underrun_count_(0) { } JitteredAudioBackend::~JitteredAudioBackend() { @@ -32,7 +27,8 @@ void JitteredAudioBackend::init() { } void JitteredAudioBackend::start() { - if (running_.load()) return; + if (running_.load()) + return; should_stop_.store(false); running_.store(true); @@ -42,7 +38,8 @@ void JitteredAudioBackend::start() { } void JitteredAudioBackend::shutdown() { - if (!running_.load()) return; + if (!running_.load()) + return; should_stop_.store(true); @@ -61,20 +58,23 @@ void JitteredAudioBackend::set_base_interval(float interval_ms) { base_interval_ms_ = interval_ms; } -void JitteredAudioBackend::set_chunk_size_range(int min_frames, int max_frames) { +void JitteredAudioBackend::set_chunk_size_range(int min_frames, + int max_frames) { min_chunk_frames_ = min_frames; max_chunk_frames_ = max_frames; } void JitteredAudioBackend::audio_thread_loop() { AudioRingBuffer* ring_buffer = audio_get_ring_buffer(); - if (ring_buffer == nullptr) return; + if (ring_buffer == nullptr) + return; // Random number generator for jitter std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<float> jitter_dist(-jitter_ms_, jitter_ms_); - std::uniform_int_distribution<int> chunk_dist(min_chunk_frames_, max_chunk_frames_); + std::uniform_int_distribution<int> chunk_dist(min_chunk_frames_, + max_chunk_frames_); while (!should_stop_.load()) { // Calculate jittered wait time @@ -88,7 +88,7 @@ void JitteredAudioBackend::audio_thread_loop() { // Random chunk size const int chunk_frames = chunk_dist(gen); - const int chunk_samples = chunk_frames * 2; // Stereo + const int chunk_samples = chunk_frames * 2; // Stereo // Read from ring buffer float* temp_buffer = new float[chunk_samples]; diff --git a/src/audio/jittered_audio_backend.h b/src/audio/jittered_audio_backend.h index e0ce9d7..c246c48 100644 --- a/src/audio/jittered_audio_backend.h +++ b/src/audio/jittered_audio_backend.h @@ -21,14 +21,22 @@ class JitteredAudioBackend : public AudioBackend { void shutdown() override; // Control simulation - void set_jitter_amount(float jitter_ms); // Random jitter in ms (default: 5ms) - void set_base_interval(float interval_ms); // Base interval between reads (default: 10ms) - void set_chunk_size_range(int min_frames, int max_frames); // Variable chunk sizes + void set_jitter_amount(float jitter_ms); // Random jitter in ms (default: 5ms) + void set_base_interval( + float interval_ms); // Base interval between reads (default: 10ms) + void set_chunk_size_range(int min_frames, + int max_frames); // Variable chunk sizes // Query state - int get_total_frames_consumed() const { return total_frames_consumed_.load(); } - int get_underrun_count() const { return underrun_count_.load(); } - bool is_running() const { return running_.load(); } + int get_total_frames_consumed() const { + return total_frames_consumed_.load(); + } + int get_underrun_count() const { + return underrun_count_.load(); + } + bool is_running() const { + return running_.load(); + } private: void audio_thread_loop(); @@ -45,7 +53,7 @@ class JitteredAudioBackend : public AudioBackend { // Statistics std::atomic<int> total_frames_consumed_; - std::atomic<int> underrun_count_; // How many times buffer was empty + std::atomic<int> underrun_count_; // How many times buffer was empty }; #endif /* !defined(STRIP_ALL) */ diff --git a/src/audio/miniaudio_backend.cc b/src/audio/miniaudio_backend.cc index c2db268..baaf9bb 100644 --- a/src/audio/miniaudio_backend.cc +++ b/src/audio/miniaudio_backend.cc @@ -7,12 +7,12 @@ #include "ring_buffer.h" #include "util/debug.h" #include <stdio.h> -#include <stdlib.h> // for abort() +#include <stdlib.h> // for abort() // Static callback for miniaudio (C API requirement) void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, - const void* pInput, - ma_uint32 frameCount) { + const void* pInput, + ma_uint32 frameCount) { (void)pInput; #if defined(DEBUG_LOG_AUDIO) @@ -33,25 +33,30 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, double now = ts.tv_sec + ts.tv_nsec / 1000000000.0; if (timing_initialized) { - double delta = (now - last_time) * 1000.0; // ms + double delta = (now - last_time) * 1000.0; // ms double expected = ((double)frameCount / pDevice->sampleRate) * 1000.0; double jitter = delta - expected; // Enhanced logging: Log first 20 callbacks in detail, then periodic summary if (callback_number <= 20 || callback_number % 50 == 0) { - const double elapsed_by_frames = (double)total_frames_requested / pDevice->sampleRate * 1000.0; - const double elapsed_by_time = now * 1000.0; // Convert to ms - DEBUG_AUDIO("[CB#%llu] frameCount=%u, Delta=%.2fms, Expected=%.2fms, Jitter=%.2fms, " - "TotalFrames=%llu (%.1fms), TotalTime=%.1fms, Drift=%.2fms\n", - callback_number, frameCount, delta, expected, jitter, - total_frames_requested, elapsed_by_frames, elapsed_by_time, - elapsed_by_time - elapsed_by_frames); + const double elapsed_by_frames = + (double)total_frames_requested / pDevice->sampleRate * 1000.0; + const double elapsed_by_time = now * 1000.0; // Convert to ms + DEBUG_AUDIO( + "[CB#%llu] frameCount=%u, Delta=%.2fms, Expected=%.2fms, " + "Jitter=%.2fms, " + "TotalFrames=%llu (%.1fms), TotalTime=%.1fms, Drift=%.2fms\n", + callback_number, frameCount, delta, expected, jitter, + total_frames_requested, elapsed_by_frames, elapsed_by_time, + elapsed_by_time - elapsed_by_frames); } // Detect large timing anomalies (>5ms off from expected) if (fabs(jitter) > 5.0) { - DEBUG_AUDIO("[TIMING ANOMALY] CB#%llu Delta=%.2fms, Expected=%.2fms, Jitter=%.2fms\n", - callback_number, delta, expected, jitter); + DEBUG_AUDIO( + "[TIMING ANOMALY] CB#%llu Delta=%.2fms, Expected=%.2fms, " + "Jitter=%.2fms\n", + callback_number, delta, expected, jitter); } } last_time = now; @@ -81,8 +86,10 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, if (pDevice->sampleRate != 32000) { static int rate_warning = 0; if (rate_warning++ == 0) { - DEBUG_AUDIO("WARNING: Device sample rate is %u, not 32000! Resampling may occur.\n", - pDevice->sampleRate); + DEBUG_AUDIO( + "WARNING: Device sample rate is %u, not 32000! Resampling may " + "occur.\n", + pDevice->sampleRate); } } #endif /* defined(DEBUG_LOG_AUDIO) */ @@ -91,14 +98,15 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, // BOUNDS CHECK: Sanity check on frameCount if (frameCount > 8192 || frameCount == 0) { - fprintf(stderr, "AUDIO CALLBACK ERROR: frameCount=%u (unreasonable!)\n", frameCount); + fprintf(stderr, "AUDIO CALLBACK ERROR: frameCount=%u (unreasonable!)\n", + frameCount); abort(); } // Read from ring buffer instead of calling synth directly AudioRingBuffer* ring_buffer = audio_get_ring_buffer(); if (ring_buffer != nullptr) { - const int samples_to_read = (int)frameCount * 2; // Stereo + const int samples_to_read = (int)frameCount * 2; // Stereo #if defined(DEBUG_LOG_RING_BUFFER) // Track buffer level and detect drops @@ -108,20 +116,24 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, if (available < min_available) { min_available = available; DEBUG_RING_BUFFER("[BUFFER] CB#%llu NEW MIN: available=%d (%.1fms)\n", - callback_number, available, (float)available / (32000.0f * 2.0f) * 1000.0f); + callback_number, available, + (float)available / (32000.0f * 2.0f) * 1000.0f); } // Log buffer state for first 20 callbacks and periodically if (callback_number <= 20 || callback_number % 50 == 0) { - DEBUG_RING_BUFFER("[BUFFER] CB#%llu requested=%d, available=%d (%.1fms), min=%d\n", - callback_number, samples_to_read, available, - (float)available / (32000.0f * 2.0f) * 1000.0f, min_available); + DEBUG_RING_BUFFER( + "[BUFFER] CB#%llu requested=%d, available=%d (%.1fms), min=%d\n", + callback_number, samples_to_read, available, + (float)available / (32000.0f * 2.0f) * 1000.0f, min_available); } // CRITICAL: Verify we have enough samples if (available < samples_to_read) { - DEBUG_RING_BUFFER("[BUFFER UNDERRUN] CB#%llu requested=%d, available=%d, SHORT=%d\n", - callback_number, samples_to_read, available, samples_to_read - available); + DEBUG_RING_BUFFER( + "[BUFFER UNDERRUN] CB#%llu requested=%d, available=%d, SHORT=%d\n", + callback_number, samples_to_read, available, + samples_to_read - available); } #endif /* defined(DEBUG_LOG_RING_BUFFER) */ @@ -129,8 +141,11 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput, #if defined(DEBUG_LOG_RING_BUFFER) if (actually_read < samples_to_read) { - DEBUG_RING_BUFFER("[PARTIAL READ] CB#%llu requested=%d, got=%d, padded=%d with silence\n", - callback_number, samples_to_read, actually_read, samples_to_read - actually_read); + DEBUG_RING_BUFFER( + "[PARTIAL READ] CB#%llu requested=%d, got=%d, padded=%d with " + "silence\n", + callback_number, samples_to_read, actually_read, + samples_to_read - actually_read); } #endif /* defined(DEBUG_LOG_RING_BUFFER) */ } @@ -171,8 +186,8 @@ void MiniaudioBackend::init() { config.performanceProfile = ma_performance_profile_conservative; // Let Core Audio choose the period size based on conservative profile - config.periodSizeInFrames = 0; // 0 = let backend decide - config.periods = 0; // 0 = let backend decide based on performance profile + config.periodSizeInFrames = 0; // 0 = let backend decide + config.periods = 0; // 0 = let backend decide based on performance profile config.dataCallback = MiniaudioBackend::audio_callback; config.pUserData = this; @@ -187,23 +202,34 @@ void MiniaudioBackend::init() { DEBUG_AUDIO("\n=== MINIAUDIO DEVICE CONFIGURATION ===\n"); DEBUG_AUDIO(" Sample rate: %u (requested: 32000)\n", device_.sampleRate); DEBUG_AUDIO(" Channels: %u (requested: 2)\n", device_.playback.channels); - DEBUG_AUDIO(" Format: %d (requested: %d, f32=%d)\n", - device_.playback.format, config.playback.format, ma_format_f32); + DEBUG_AUDIO(" Format: %d (requested: %d, f32=%d)\n", device_.playback.format, + config.playback.format, ma_format_f32); DEBUG_AUDIO(" Period size: %u frames (%.1fms at %uHz)\n", device_.playback.internalPeriodSizeInFrames, - (float)device_.playback.internalPeriodSizeInFrames / device_.sampleRate * 1000.0f, + (float)device_.playback.internalPeriodSizeInFrames / + device_.sampleRate * 1000.0f, device_.sampleRate); - DEBUG_AUDIO(" Periods: %u (buffer multiplier)\n", device_.playback.internalPeriods); - DEBUG_AUDIO(" Backend: %s\n", ma_get_backend_name(device_.pContext->backend)); + DEBUG_AUDIO(" Periods: %u (buffer multiplier)\n", + device_.playback.internalPeriods); + DEBUG_AUDIO(" Backend: %s\n", + ma_get_backend_name(device_.pContext->backend)); DEBUG_AUDIO(" Total buffer size: %u frames (%.2fms) [period * periods]\n", - device_.playback.internalPeriodSizeInFrames * device_.playback.internalPeriods, - (float)(device_.playback.internalPeriodSizeInFrames * device_.playback.internalPeriods) / device_.sampleRate * 1000.0f); + device_.playback.internalPeriodSizeInFrames * + device_.playback.internalPeriods, + (float)(device_.playback.internalPeriodSizeInFrames * + device_.playback.internalPeriods) / + device_.sampleRate * 1000.0f); // Calculate expected callback interval if (device_.playback.internalPeriodSizeInFrames > 0) { - const float expected_callback_ms = (float)device_.playback.internalPeriodSizeInFrames / device_.sampleRate * 1000.0f; - DEBUG_AUDIO(" Expected callback interval: %.2fms (based on period size)\n", expected_callback_ms); - DEBUG_AUDIO(" WARNING: If actual callback interval differs, audio corruption may occur!\n"); + const float expected_callback_ms = + (float)device_.playback.internalPeriodSizeInFrames / + device_.sampleRate * 1000.0f; + DEBUG_AUDIO(" Expected callback interval: %.2fms (based on period size)\n", + expected_callback_ms); + DEBUG_AUDIO( + " WARNING: If actual callback interval differs, audio corruption may " + "occur!\n"); } DEBUG_AUDIO("======================================\n\n"); fflush(stderr); diff --git a/src/audio/miniaudio_backend.h b/src/audio/miniaudio_backend.h index d46a0c5..82c7b76 100644 --- a/src/audio/miniaudio_backend.h +++ b/src/audio/miniaudio_backend.h @@ -19,7 +19,9 @@ class MiniaudioBackend : public AudioBackend { void shutdown() override; // Get the underlying miniaudio device (for internal use) - ma_device* get_device() { return &device_; } + ma_device* get_device() { + return &device_; + } private: ma_device device_; diff --git a/src/audio/mock_audio_backend.cc b/src/audio/mock_audio_backend.cc index 3f5a57a..33ed35a 100644 --- a/src/audio/mock_audio_backend.cc +++ b/src/audio/mock_audio_backend.cc @@ -25,7 +25,7 @@ void MockAudioBackend::shutdown() { } void MockAudioBackend::on_voice_triggered(float timestamp, int spectrogram_id, - float volume, float pan) { + float volume, float pan) { // Record the event with the timestamp provided by synth VoiceTriggerEvent event; event.timestamp_sec = timestamp; diff --git a/src/audio/mock_audio_backend.h b/src/audio/mock_audio_backend.h index 963d9cb..a4ee36d 100644 --- a/src/audio/mock_audio_backend.h +++ b/src/audio/mock_audio_backend.h @@ -38,12 +38,20 @@ class MockAudioBackend : public AudioBackend { const std::vector<VoiceTriggerEvent>& get_events() const { return recorded_events_; } - void clear_events() { recorded_events_.clear(); } + void clear_events() { + recorded_events_.clear(); + } // Manual time control for deterministic testing - void advance_time(float delta_sec) { current_time_sec_ += delta_sec; } - void set_time(float time_sec) { current_time_sec_ = time_sec; } - float get_current_time() const { return current_time_sec_; } + void advance_time(float delta_sec) { + current_time_sec_ += delta_sec; + } + void set_time(float time_sec) { + current_time_sec_ = time_sec; + } + float get_current_time() const { + return current_time_sec_; + } // Sample rate used for frame-to-time conversion static const int kSampleRate = 32000; diff --git a/src/audio/ring_buffer.cc b/src/audio/ring_buffer.cc index ab51d6b..b30ebbb 100644 --- a/src/audio/ring_buffer.cc +++ b/src/audio/ring_buffer.cc @@ -4,14 +4,12 @@ #include "ring_buffer.h" #include "util/debug.h" #include <algorithm> +#include <cstdio> // for fprintf() +#include <cstdlib> // for abort() #include <cstring> -#include <cstdlib> // for abort() -#include <cstdio> // for fprintf() AudioRingBuffer::AudioRingBuffer() - : capacity_(RING_BUFFER_CAPACITY_SAMPLES), - write_pos_(0), - read_pos_(0), + : capacity_(RING_BUFFER_CAPACITY_SAMPLES), write_pos_(0), read_pos_(0), total_read_(0) { memset(buffer_, 0, sizeof(buffer_)); } @@ -25,7 +23,7 @@ int AudioRingBuffer::available_write() const { const int read = read_pos_.load(std::memory_order_acquire); if (write >= read) { - return capacity_ - (write - read) - 1; // -1 to avoid full/empty ambiguity + return capacity_ - (write - read) - 1; // -1 to avoid full/empty ambiguity } else { return read - write - 1; } @@ -65,7 +63,8 @@ int AudioRingBuffer::write(const float* samples, int count) { // Write in one chunk // BOUNDS CHECK if (write < 0 || write + to_write > capacity_) { - fprintf(stderr, "BOUNDS ERROR in write(): write=%d, to_write=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in write(): write=%d, to_write=%d, capacity=%d\n", write, to_write, capacity_); abort(); } @@ -75,7 +74,9 @@ int AudioRingBuffer::write(const float* samples, int count) { // Write in two chunks (wrap around) // BOUNDS CHECK - first chunk if (write < 0 || write + space_to_end > capacity_) { - fprintf(stderr, "BOUNDS ERROR in write() chunk1: write=%d, space_to_end=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in write() chunk1: write=%d, space_to_end=%d, " + "capacity=%d\n", write, space_to_end, capacity_); abort(); } @@ -83,7 +84,8 @@ int AudioRingBuffer::write(const float* samples, int count) { const int remainder = to_write - space_to_end; // BOUNDS CHECK - second chunk if (remainder < 0 || remainder > capacity_) { - fprintf(stderr, "BOUNDS ERROR in write() chunk2: remainder=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in write() chunk2: remainder=%d, capacity=%d\n", remainder, capacity_); abort(); } @@ -114,7 +116,8 @@ int AudioRingBuffer::read(float* samples, int count) { // Read in one chunk // BOUNDS CHECK if (read < 0 || read + to_read > capacity_) { - fprintf(stderr, "BOUNDS ERROR in read(): read=%d, to_read=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in read(): read=%d, to_read=%d, capacity=%d\n", read, to_read, capacity_); abort(); } @@ -124,7 +127,9 @@ int AudioRingBuffer::read(float* samples, int count) { // Read in two chunks (wrap around) // BOUNDS CHECK - first chunk if (read < 0 || read + space_to_end > capacity_) { - fprintf(stderr, "BOUNDS ERROR in read() chunk1: read=%d, space_to_end=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in read() chunk1: read=%d, space_to_end=%d, " + "capacity=%d\n", read, space_to_end, capacity_); abort(); } @@ -132,7 +137,8 @@ int AudioRingBuffer::read(float* samples, int count) { const int remainder = to_read - space_to_end; // BOUNDS CHECK - second chunk if (remainder < 0 || remainder > capacity_) { - fprintf(stderr, "BOUNDS ERROR in read() chunk2: remainder=%d, capacity=%d\n", + fprintf(stderr, + "BOUNDS ERROR in read() chunk2: remainder=%d, capacity=%d\n", remainder, capacity_); abort(); } @@ -148,9 +154,10 @@ int AudioRingBuffer::read(float* samples, int count) { #if defined(DEBUG_LOG_RING_BUFFER) // UNDERRUN DETECTED static int underrun_count = 0; - if (++underrun_count % 10 == 1) { // Log every 10th underrun - DEBUG_RING_BUFFER("UNDERRUN #%d: requested=%d, available=%d, filling %d with silence\n", - underrun_count, count, to_read, count - to_read); + if (++underrun_count % 10 == 1) { // Log every 10th underrun + DEBUG_RING_BUFFER( + "UNDERRUN #%d: requested=%d, available=%d, filling %d with silence\n", + underrun_count, count, to_read, count - to_read); } #endif /* defined(DEBUG_LOG_RING_BUFFER) */ memset(samples + to_read, 0, (count - to_read) * sizeof(float)); diff --git a/src/audio/ring_buffer.h b/src/audio/ring_buffer.h index 6375161..b19c1ea 100644 --- a/src/audio/ring_buffer.h +++ b/src/audio/ring_buffer.h @@ -14,8 +14,10 @@ #define RING_BUFFER_LOOKAHEAD_MS 400 #define RING_BUFFER_SAMPLE_RATE 32000 #define RING_BUFFER_CHANNELS 2 -#define RING_BUFFER_CAPACITY_SAMPLES \ - ((RING_BUFFER_LOOKAHEAD_MS * RING_BUFFER_SAMPLE_RATE * RING_BUFFER_CHANNELS) / 1000) +#define RING_BUFFER_CAPACITY_SAMPLES \ + ((RING_BUFFER_LOOKAHEAD_MS * RING_BUFFER_SAMPLE_RATE * \ + RING_BUFFER_CHANNELS) / \ + 1000) class AudioRingBuffer { public: @@ -32,20 +34,22 @@ class AudioRingBuffer { int read(float* samples, int count); // Query buffer state - int available_write() const; // Samples that can be written - int available_read() const; // Samples that can be read + int available_write() const; // Samples that can be written + int available_read() const; // Samples that can be read // Get total samples consumed (for timing) - int64_t get_total_read() const { return total_read_.load(std::memory_order_acquire); } + int64_t get_total_read() const { + return total_read_.load(std::memory_order_acquire); + } // Clear buffer (for seeking) void clear(); private: float buffer_[RING_BUFFER_CAPACITY_SAMPLES]; - int capacity_; // Total capacity in samples + int capacity_; // Total capacity in samples - std::atomic<int> write_pos_; // Write position (0 to capacity-1) - std::atomic<int> read_pos_; // Read position (0 to capacity-1) - std::atomic<int64_t> total_read_; // Total samples read (for playback time) + std::atomic<int> write_pos_; // Write position (0 to capacity-1) + std::atomic<int> read_pos_; // Read position (0 to capacity-1) + std::atomic<int64_t> total_read_; // Total samples read (for playback time) }; diff --git a/src/audio/spectrogram_resource_manager.cc b/src/audio/spectrogram_resource_manager.cc index dbed09e..30939e0 100644 --- a/src/audio/spectrogram_resource_manager.cc +++ b/src/audio/spectrogram_resource_manager.cc @@ -42,7 +42,8 @@ void SpectrogramResourceManager::reset() { loaded_count_ = 0; } -void SpectrogramResourceManager::register_asset(int sample_id, AssetId asset_id) { +void SpectrogramResourceManager::register_asset(int sample_id, + AssetId asset_id) { if (sample_id < 0 || sample_id >= MAX_SPECTROGRAM_RESOURCES) { return; } @@ -57,13 +58,14 @@ void SpectrogramResourceManager::register_asset(int sample_id, AssetId asset_id) #endif } -void SpectrogramResourceManager::register_procedural(int sample_id, const NoteParams& params) { +void SpectrogramResourceManager::register_procedural(int sample_id, + const NoteParams& params) { if (sample_id < 0 || sample_id >= MAX_SPECTROGRAM_RESOURCES) { return; } Resource& resource = resources_[sample_id]; - resource.asset_id = AssetId::ASSET_LAST_ID; // Mark as procedural + resource.asset_id = AssetId::ASSET_LAST_ID; // Mark as procedural resource.proc_params = params; resource.state = REGISTERED; @@ -83,7 +85,7 @@ const Spectrogram* SpectrogramResourceManager::get_or_load(int sample_id) { // Already loaded? if (resource.state == LOADED) { #if defined(DEMO_ENABLE_CACHE_EVICTION) - resource.last_access_time = 0.0f; // TODO: Get actual time + resource.last_access_time = 0.0f; // TODO: Get actual time #endif return &resource.spec; } @@ -113,7 +115,8 @@ void SpectrogramResourceManager::preload_range(int start_id, int end_id) { } } -const Spectrogram* SpectrogramResourceManager::get_spectrogram(int sample_id) const { +const Spectrogram* +SpectrogramResourceManager::get_spectrogram(int sample_id) const { if (sample_id < 0 || sample_id >= MAX_SPECTROGRAM_RESOURCES) { return nullptr; } @@ -164,7 +167,8 @@ void SpectrogramResourceManager::try_evict_lru(float current_time) { float oldest_time = current_time; for (int i = 0; i < MAX_SPECTROGRAM_RESOURCES; ++i) { - if (resources_[i].state == LOADED && resources_[i].last_access_time < oldest_time) { + if (resources_[i].state == LOADED && + resources_[i].last_access_time < oldest_time) { oldest_time = resources_[i].last_access_time; lru_id = i; } @@ -183,7 +187,8 @@ void SpectrogramResourceManager::load_asset(Resource* resource) { 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); + DEBUG_ASSETS("[ResourceMgr ERROR] Failed to load asset %d\n", + (int)resource->asset_id); #endif return; } @@ -194,7 +199,7 @@ void SpectrogramResourceManager::load_asset(Resource* resource) { resource->spec.spectral_data_a = spectral_data; resource->spec.spectral_data_b = spectral_data; resource->spec.num_frames = header->num_frames; - resource->owned_data = nullptr; // Asset data is not owned + resource->owned_data = nullptr; // Asset data is not owned #if defined(DEBUG_LOG_ASSETS) DEBUG_ASSETS("[ResourceMgr] Loaded asset %d: %d frames\n", @@ -204,7 +209,8 @@ void SpectrogramResourceManager::load_asset(Resource* resource) { void SpectrogramResourceManager::load_procedural(Resource* resource) { int note_frames = 0; - std::vector<float> note_data = generate_note_spectrogram(resource->proc_params, ¬e_frames); + std::vector<float> note_data = + generate_note_spectrogram(resource->proc_params, ¬e_frames); if (note_frames <= 0 || note_data.empty()) { #if defined(DEBUG_LOG_ASSETS) @@ -215,7 +221,8 @@ void SpectrogramResourceManager::load_procedural(Resource* resource) { // Allocate persistent storage resource->owned_data = new float[note_data.size()]; - memcpy(resource->owned_data, note_data.data(), note_data.size() * sizeof(float)); + memcpy(resource->owned_data, note_data.data(), + note_data.size() * sizeof(float)); resource->spec.spectral_data_a = resource->owned_data; resource->spec.spectral_data_b = resource->owned_data; diff --git a/src/audio/spectrogram_resource_manager.h b/src/audio/spectrogram_resource_manager.h index 97196d1..45faa37 100644 --- a/src/audio/spectrogram_resource_manager.h +++ b/src/audio/spectrogram_resource_manager.h @@ -17,8 +17,8 @@ class SpectrogramResourceManager { public: // Lifecycle void init(); - void shutdown(); // Frees all owned memory - void reset(); // Clear state but keep registrations + 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); @@ -45,18 +45,18 @@ class SpectrogramResourceManager { private: enum ResourceState { - UNREGISTERED = 0, // No metadata registered - REGISTERED, // Metadata registered, not loaded yet - LOADED, // Fully loaded and ready + 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 + 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 + float* owned_data; // nullptr if asset (not owned), allocated if procedural + AssetId asset_id; // ASSET_LAST_ID if procedural NoteParams proc_params; ResourceState state; diff --git a/src/audio/synth.cc b/src/audio/synth.cc index 617ff2f..ada46fd 100644 --- a/src/audio/synth.cc +++ b/src/audio/synth.cc @@ -28,7 +28,7 @@ struct Voice { float time_domain_buffer[DCT_SIZE]; int buffer_pos; - float fractional_pos; // Fractional sample position for tempo scaling + float fractional_pos; // Fractional sample position for tempo scaling const volatile float* active_spectral_data; }; @@ -47,7 +47,7 @@ static float g_tempo_scale = 1.0f; // Playback speed multiplier #if !defined(STRIP_ALL) static float g_elapsed_time_sec = 0.0f; // Tracks elapsed time for event hooks -#endif /* !defined(STRIP_ALL) */ +#endif /* !defined(STRIP_ALL) */ void synth_init() { memset(&g_synth_data, 0, sizeof(g_synth_data)); @@ -72,22 +72,23 @@ int synth_register_spectrogram(const Spectrogram* spec) { #if defined(DEBUG_LOG_SYNTH) // VALIDATION: Check spectrogram pointer and data if (spec == nullptr) { - DEBUG_SYNTH( "[SYNTH ERROR] Null spectrogram pointer\n"); + DEBUG_SYNTH("[SYNTH ERROR] Null spectrogram pointer\n"); return -1; } if (spec->spectral_data_a == nullptr || spec->spectral_data_b == nullptr) { - DEBUG_SYNTH( "[SYNTH ERROR] Null spectral data pointers\n"); + DEBUG_SYNTH("[SYNTH ERROR] Null spectral data pointers\n"); return -1; } if (spec->num_frames <= 0 || spec->num_frames > 10000) { - DEBUG_SYNTH( "[SYNTH ERROR] Invalid num_frames=%d (must be 1-10000)\n", - spec->num_frames); + DEBUG_SYNTH("[SYNTH ERROR] Invalid num_frames=%d (must be 1-10000)\n", + spec->num_frames); return -1; } // VALIDATION: Check spectral data isn't all zeros (common corruption symptom) bool all_zero = true; const float* data = spec->spectral_data_a; - const int samples_to_check = (spec->num_frames > 10) ? 10 * DCT_SIZE : spec->num_frames * DCT_SIZE; + const int samples_to_check = + (spec->num_frames > 10) ? 10 * DCT_SIZE : spec->num_frames * DCT_SIZE; for (int j = 0; j < samples_to_check; ++j) { if (data[j] != 0.0f) { all_zero = false; @@ -95,8 +96,9 @@ int synth_register_spectrogram(const Spectrogram* spec) { } } if (all_zero) { - DEBUG_SYNTH( "[SYNTH WARNING] Spectrogram appears to be all zeros (num_frames=%d)\n", - spec->num_frames); + DEBUG_SYNTH( + "[SYNTH WARNING] Spectrogram appears to be all zeros (num_frames=%d)\n", + spec->num_frames); } #endif @@ -157,8 +159,8 @@ void synth_trigger_voice(int spectrogram_id, float volume, float pan) { if (spectrogram_id < 0 || spectrogram_id >= MAX_SPECTROGRAMS || !g_synth_data.spectrogram_registered[spectrogram_id]) { #if defined(DEBUG_LOG_SYNTH) - DEBUG_SYNTH( "[SYNTH ERROR] Invalid spectrogram_id=%d in trigger_voice\n", - spectrogram_id); + DEBUG_SYNTH("[SYNTH ERROR] Invalid spectrogram_id=%d in trigger_voice\n", + spectrogram_id); #endif return; } @@ -166,12 +168,13 @@ void synth_trigger_voice(int spectrogram_id, float volume, float pan) { #if defined(DEBUG_LOG_SYNTH) // VALIDATION: Check volume and pan ranges if (volume < 0.0f || volume > 2.0f) { - DEBUG_SYNTH( "[SYNTH WARNING] Unusual volume=%.2f for spectrogram_id=%d\n", - volume, spectrogram_id); + DEBUG_SYNTH("[SYNTH WARNING] Unusual volume=%.2f for spectrogram_id=%d\n", + volume, spectrogram_id); } if (pan < -1.0f || pan > 1.0f) { - DEBUG_SYNTH( "[SYNTH WARNING] Invalid pan=%.2f (clamping) for spectrogram_id=%d\n", - pan, spectrogram_id); + DEBUG_SYNTH( + "[SYNTH WARNING] Invalid pan=%.2f (clamping) for spectrogram_id=%d\n", + pan, spectrogram_id); pan = (pan < -1.0f) ? -1.0f : 1.0f; } #endif @@ -191,7 +194,8 @@ void synth_trigger_voice(int spectrogram_id, float volume, float pan) { v.total_spectral_frames = g_synth_data.spectrograms[spectrogram_id].num_frames; v.buffer_pos = DCT_SIZE; // Force IDCT on first render - v.fractional_pos = 0.0f; // Initialize fractional position for tempo scaling + v.fractional_pos = + 0.0f; // Initialize fractional position for tempo scaling v.active_spectral_data = g_synth_data.active_spectrogram_data[spectrogram_id]; @@ -200,7 +204,7 @@ void synth_trigger_voice(int spectrogram_id, float volume, float pan) { AudioBackend* backend = audio_get_backend(); if (backend != nullptr) { backend->on_voice_triggered(g_elapsed_time_sec, spectrogram_id, volume, - pan); + pan); } #endif /* !defined(STRIP_ALL) */ diff --git a/src/audio/synth.h b/src/audio/synth.h index 77b1878..cb0d1df 100644 --- a/src/audio/synth.h +++ b/src/audio/synth.h @@ -17,8 +17,9 @@ // - With caching: MAX_SPECTROGRAMS = 32 provides 2.3x headroom // // Memory cost: 32 slots × 48 bytes = 1.5KB (down from 12KB with 256 slots) -#define MAX_VOICES 48 // Per tracker_compiler: required=24, recommended=48 -#define MAX_SPECTROGRAMS 32 // Current track: 14 unique, 32 provides comfortable headroom +#define MAX_VOICES 48 // Per tracker_compiler: required=24, recommended=48 +#define MAX_SPECTROGRAMS \ + 32 // Current track: 14 unique, 32 provides comfortable headroom struct Spectrogram { const float* spectral_data_a; // Front buffer @@ -39,7 +40,8 @@ void synth_commit_update(int spectrogram_id); void synth_trigger_voice(int spectrogram_id, float volume, float pan); void synth_render(float* output_buffer, int num_frames); -void synth_set_tempo_scale(float tempo_scale); // Set playback speed (1.0 = normal) +void synth_set_tempo_scale( + float tempo_scale); // Set playback speed (1.0 = normal) int synth_get_active_voice_count(); float synth_get_output_peak(); diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc index 5e30281..7ad5a67 100644 --- a/src/audio/tracker.cc +++ b/src/audio/tracker.cc @@ -30,7 +30,7 @@ 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 int g_sample_synth_cache[256]; // Max 256 unique samples static bool g_cache_initialized = false; // Forward declarations @@ -80,7 +80,8 @@ void tracker_init() { 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)); + const float* spectral_data = + (const float*)(data + sizeof(SpecHeader)); Spectrogram spec; spec.spectral_data_a = spectral_data; @@ -91,8 +92,9 @@ void tracker_init() { #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); + DEBUG_TRACKER( + "[TRACKER INIT] Failed to cache asset sample_id=%d (aid=%d)\n", + sid, (int)aid); } #endif /* defined(DEBUG_LOG_TRACKER) */ } @@ -100,7 +102,8 @@ void tracker_init() { // GENERATED note: Generate once and cache const NoteParams& params = g_tracker_samples[sid]; int note_frames = 0; - std::vector<float> note_data = generate_note_spectrogram(params, ¬e_frames); + std::vector<float> note_data = + generate_note_spectrogram(params, ¬e_frames); if (note_frames > 0) { // Allocate persistent storage for this note @@ -116,12 +119,14 @@ void tracker_init() { 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 + 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); + DEBUG_TRACKER( + "[TRACKER INIT] Failed to cache generated sample_id=%d " + "(freq=%.2f)\n", + sid, params.base_freq); } #endif /* defined(DEBUG_LOG_TRACKER) */ } @@ -131,7 +136,8 @@ void tracker_init() { g_cache_initialized = true; #if defined(DEBUG_LOG_TRACKER) - DEBUG_TRACKER( "[TRACKER INIT] Cached %d unique samples\n", g_tracker_samples_count); + DEBUG_TRACKER("[TRACKER INIT] Cached %d unique samples\n", + g_tracker_samples_count); #endif /* defined(DEBUG_LOG_TRACKER) */ } } @@ -170,18 +176,18 @@ static void trigger_note_event(const TrackerEvent& event) { #if defined(DEBUG_LOG_TRACKER) // VALIDATION: Check sample_id bounds if (event.sample_id >= g_tracker_samples_count) { - DEBUG_TRACKER( "[TRACKER ERROR] Invalid sample_id=%d (max=%d)\n", - event.sample_id, g_tracker_samples_count - 1); + DEBUG_TRACKER("[TRACKER ERROR] Invalid sample_id=%d (max=%d)\n", + event.sample_id, g_tracker_samples_count - 1); return; } // VALIDATION: Check volume and pan ranges if (event.volume < 0.0f || event.volume > 2.0f) { - DEBUG_TRACKER( "[TRACKER WARNING] Unusual volume=%.2f for sample_id=%d\n", - event.volume, event.sample_id); + DEBUG_TRACKER("[TRACKER WARNING] Unusual volume=%.2f for sample_id=%d\n", + event.volume, event.sample_id); } if (event.pan < -1.0f || event.pan > 1.0f) { - DEBUG_TRACKER( "[TRACKER WARNING] Invalid pan=%.2f for sample_id=%d\n", - event.pan, event.sample_id); + DEBUG_TRACKER("[TRACKER WARNING] Invalid pan=%.2f for sample_id=%d\n", + event.pan, event.sample_id); } #endif /* defined(DEBUG_LOG_TRACKER) */ @@ -190,8 +196,9 @@ static void trigger_note_event(const TrackerEvent& event) { #if defined(DEBUG_LOG_TRACKER) if (cached_synth_id == -1) { - DEBUG_TRACKER( "[TRACKER ERROR] No cached synth_id for sample_id=%d (init failed?)\n", - event.sample_id); + DEBUG_TRACKER( + "[TRACKER ERROR] No cached synth_id for sample_id=%d (init failed?)\n", + event.sample_id); return; } #endif /* defined(DEBUG_LOG_TRACKER) */ diff --git a/src/audio/tracker.h b/src/audio/tracker.h index e6d479a..336f77f 100644 --- a/src/audio/tracker.h +++ b/src/audio/tracker.h @@ -42,4 +42,4 @@ extern const TrackerScore g_tracker_score; void tracker_init(); void tracker_update(float music_time_sec); -void tracker_reset(); // Reset tracker state (for tests/seeking) +void tracker_reset(); // Reset tracker state (for tests/seeking) |
