summaryrefslogtreecommitdiff
path: root/src/audio/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio/backend')
-rw-r--r--src/audio/backend/jittered_audio_backend.cc6
-rw-r--r--src/audio/backend/jittered_audio_backend.h1
-rw-r--r--src/audio/backend/miniaudio_backend.cc34
-rw-r--r--src/audio/backend/miniaudio_backend.h5
-rw-r--r--src/audio/backend/mock_audio_backend.cc6
-rw-r--r--src/audio/backend/mock_audio_backend.h1
-rw-r--r--src/audio/backend/silent_backend.cc5
-rw-r--r--src/audio/backend/silent_backend.h1
-rw-r--r--src/audio/backend/wav_dump_backend.cc6
-rw-r--r--src/audio/backend/wav_dump_backend.h1
10 files changed, 50 insertions, 16 deletions
diff --git a/src/audio/backend/jittered_audio_backend.cc b/src/audio/backend/jittered_audio_backend.cc
index 0c1c4a6..973a474 100644
--- a/src/audio/backend/jittered_audio_backend.cc
+++ b/src/audio/backend/jittered_audio_backend.cc
@@ -115,4 +115,10 @@ float JitteredAudioBackend::get_realtime_peak() {
return 0.0f;
}
+void JitteredAudioBackend::get_callback_state(double* out_time,
+ int64_t* out_samples) {
+ *out_time = 0.0;
+ *out_samples = 0;
+}
+
#endif /* !defined(STRIP_ALL) */
diff --git a/src/audio/backend/jittered_audio_backend.h b/src/audio/backend/jittered_audio_backend.h
index 8bda4c7..13feee0 100644
--- a/src/audio/backend/jittered_audio_backend.h
+++ b/src/audio/backend/jittered_audio_backend.h
@@ -20,6 +20,7 @@ class JitteredAudioBackend : public AudioBackend {
void start() override;
void shutdown() override;
float get_realtime_peak() override;
+ void get_callback_state(double* out_time, int64_t* out_samples) override;
// Control simulation
void set_jitter_amount(float jitter_ms); // Random jitter in ms (default: 5ms)
diff --git a/src/audio/backend/miniaudio_backend.cc b/src/audio/backend/miniaudio_backend.cc
index ffa0852..26194c9 100644
--- a/src/audio/backend/miniaudio_backend.cc
+++ b/src/audio/backend/miniaudio_backend.cc
@@ -13,6 +13,10 @@
// Updated in audio_callback when samples are read from ring buffer
volatile float MiniaudioBackend::realtime_peak_ = 0.0f;
+// Smooth playback time interpolation
+volatile double MiniaudioBackend::last_callback_time_ = 0.0;
+volatile int64_t MiniaudioBackend::last_callback_samples_ = 0;
+
// Static callback for miniaudio (C API requirement)
void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput,
const void* pInput,
@@ -140,6 +144,12 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput,
const int actually_read = ring_buffer->read(fOutput, samples_to_read);
+ // Update smooth playback time tracking (absolute time, no epoch needed)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ last_callback_time_ = ts.tv_sec + ts.tv_nsec / 1e9;
+ last_callback_samples_ = ring_buffer->get_total_read();
+
#if defined(DEBUG_LOG_RING_BUFFER)
if (actually_read < samples_to_read) {
DEBUG_RING_BUFFER(
@@ -150,22 +160,8 @@ void MiniaudioBackend::audio_callback(ma_device* pDevice, void* pOutput,
}
#endif /* defined(DEBUG_LOG_RING_BUFFER) */
- // Measure peak of samples being played RIGHT NOW (real-time sync)
- // This ensures visual effects trigger at the same moment audio is heard
- float frame_peak = 0.0f;
- for (int i = 0; i < actually_read; ++i) {
- frame_peak = fmaxf(frame_peak, fabsf(fOutput[i]));
- }
-
- // Exponential averaging: instant attack, fast decay
- // Decay rate of 0.5 gives ~500ms decay time for 120 BPM music
- // (At 128ms callbacks: 0.5^3.9 ≈ 0.07 after ~500ms = 1 beat)
- // TODO: Make decay rate configurable based on BPM from tracker/MainSequence
- if (frame_peak > realtime_peak_) {
- realtime_peak_ = frame_peak; // Attack: instant
- } else {
- realtime_peak_ *= 0.5f; // Decay: 50% per callback
- }
+ // Peak calculation moved to audio_get_realtime_peak() for RMS-based measurement
+ // (uses ring buffer peek for accurate time-windowed RMS)
}
#if defined(DEBUG_LOG_AUDIO)
@@ -285,3 +281,9 @@ void MiniaudioBackend::shutdown() {
float MiniaudioBackend::get_realtime_peak() {
return realtime_peak_;
}
+
+void MiniaudioBackend::get_callback_state(double* out_time,
+ int64_t* out_samples) {
+ *out_time = last_callback_time_;
+ *out_samples = last_callback_samples_;
+}
diff --git a/src/audio/backend/miniaudio_backend.h b/src/audio/backend/miniaudio_backend.h
index eb9019c..435496c 100644
--- a/src/audio/backend/miniaudio_backend.h
+++ b/src/audio/backend/miniaudio_backend.h
@@ -18,6 +18,7 @@ class MiniaudioBackend : public AudioBackend {
void start() override;
void shutdown() override;
float get_realtime_peak() override;
+ void get_callback_state(double* out_time, int64_t* out_samples) override;
// Get the underlying miniaudio device (for internal use)
ma_device* get_device() {
@@ -32,6 +33,10 @@ class MiniaudioBackend : public AudioBackend {
// Updated in audio_callback when samples are read from ring buffer
static volatile float realtime_peak_;
+ // Smooth playback time interpolation (updated in callback)
+ static volatile double last_callback_time_; // Absolute CLOCK_MONOTONIC time
+ static volatile int64_t last_callback_samples_;
+
// Static callback required by miniaudio C API
static void audio_callback(ma_device* pDevice, void* pOutput,
const void* pInput, ma_uint32 frameCount);
diff --git a/src/audio/backend/mock_audio_backend.cc b/src/audio/backend/mock_audio_backend.cc
index 068d8a3..60be429 100644
--- a/src/audio/backend/mock_audio_backend.cc
+++ b/src/audio/backend/mock_audio_backend.cc
@@ -30,6 +30,12 @@ float MockAudioBackend::get_realtime_peak() {
return 0.5f;
}
+void MockAudioBackend::get_callback_state(double* out_time,
+ int64_t* out_samples) {
+ *out_time = (double)current_time_sec_;
+ *out_samples = (int64_t)(current_time_sec_ * kSampleRate * 2);
+}
+
void MockAudioBackend::on_voice_triggered(float timestamp, int spectrogram_id,
float volume, float pan) {
// Record the event with the timestamp provided by synth
diff --git a/src/audio/backend/mock_audio_backend.h b/src/audio/backend/mock_audio_backend.h
index 55e89c5..e998909 100644
--- a/src/audio/backend/mock_audio_backend.h
+++ b/src/audio/backend/mock_audio_backend.h
@@ -29,6 +29,7 @@ class MockAudioBackend : public AudioBackend {
void start() override;
void shutdown() override;
float get_realtime_peak() override;
+ void get_callback_state(double* out_time, int64_t* out_samples) override;
// Event recording hooks
void on_voice_triggered(float timestamp, int spectrogram_id, float volume,
diff --git a/src/audio/backend/silent_backend.cc b/src/audio/backend/silent_backend.cc
index 6615eff..d6e1b19 100644
--- a/src/audio/backend/silent_backend.cc
+++ b/src/audio/backend/silent_backend.cc
@@ -32,6 +32,11 @@ float SilentBackend::get_realtime_peak() {
return test_peak_;
}
+void SilentBackend::get_callback_state(double* out_time, int64_t* out_samples) {
+ *out_time = 0.0;
+ *out_samples = 0;
+}
+
void SilentBackend::on_voice_triggered(float timestamp, int spectrogram_id,
float volume, float pan) {
// Track voice triggers for testing
diff --git a/src/audio/backend/silent_backend.h b/src/audio/backend/silent_backend.h
index 2d52858..c3942da 100644
--- a/src/audio/backend/silent_backend.h
+++ b/src/audio/backend/silent_backend.h
@@ -22,6 +22,7 @@ class SilentBackend : public AudioBackend {
void start() override;
void shutdown() override;
float get_realtime_peak() override;
+ void get_callback_state(double* out_time, int64_t* out_samples) override;
// Test inspection interface
bool is_initialized() const {
diff --git a/src/audio/backend/wav_dump_backend.cc b/src/audio/backend/wav_dump_backend.cc
index 7427fa9..67f639f 100644
--- a/src/audio/backend/wav_dump_backend.cc
+++ b/src/audio/backend/wav_dump_backend.cc
@@ -114,6 +114,12 @@ float WavDumpBackend::get_realtime_peak() {
return 0.0f;
}
+void WavDumpBackend::get_callback_state(double* out_time,
+ int64_t* out_samples) {
+ *out_time = 0.0;
+ *out_samples = 0;
+}
+
void WavDumpBackend::write_wav_header(FILE* file, uint32_t num_samples) {
// WAV file header structure
// Reference: http://soundfile.sapp.org/doc/WaveFormat/
diff --git a/src/audio/backend/wav_dump_backend.h b/src/audio/backend/wav_dump_backend.h
index de445d6..b59d406 100644
--- a/src/audio/backend/wav_dump_backend.h
+++ b/src/audio/backend/wav_dump_backend.h
@@ -23,6 +23,7 @@ class WavDumpBackend : public AudioBackend {
void start() override;
void shutdown() override;
float get_realtime_peak() override;
+ void get_callback_state(double* out_time, int64_t* out_samples) override;
// Set output filename (call before init())
void set_output_file(const char* filename);