summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-07 08:30:50 +0100
committerskal <pascal.massimino@gmail.com>2026-02-07 08:30:50 +0100
commit99d35e10bd44d546312c1b74d3b0b13c663ccbd1 (patch)
treec364784b64f3b075eba67c0472d7bda68e339fe9
parentbc924828cebaf049cdda9488b113f8b3b8a8a0d9 (diff)
feat(test_demo): Add fine-grained peak logging at frame resolution
Adds --log-peaks-fine option to log audio peaks at every frame (~60 Hz) instead of just at beat boundaries, enabling millisecond-resolution synchronization analysis. Features: - --log-peaks-fine flag for per-frame logging - Logs ~960 samples over 16 seconds (vs 32 for beat-aligned) - Header indicates logging mode (beat-aligned vs fine) - Frame number instead of beat number in fine mode - Updated gnuplot command (using column 2 for time) Use cases: - Millisecond-resolution synchronization debugging - Frame-level timing jitter detection - Audio envelope analysis (attack/decay characteristics) - Sub-beat artifact identification Example usage: build/test_demo --log-peaks peaks.txt --log-peaks-fine The fine mode provides approximately 16.67ms resolution (60 Hz) compared to 500ms resolution (beat boundaries at 120 BPM). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
-rw-r--r--src/test_demo.cc33
-rw-r--r--test_demo_README.md62
2 files changed, 80 insertions, 15 deletions
diff --git a/src/test_demo.cc b/src/test_demo.cc
index 1664f7c..5f36e30 100644
--- a/src/test_demo.cc
+++ b/src/test_demo.cc
@@ -28,11 +28,14 @@ static void print_usage(const char* prog_name) {
printf(" --resolution WxH Set window resolution (e.g., 1024x768)\n");
printf(" --tempo Enable tempo variation test mode\n");
printf(" (alternates between acceleration and deceleration)\n");
- printf(" --log-peaks FILE Log audio peaks to FILE for gnuplot visualization\n");
+ printf(" --log-peaks FILE Log audio peaks at each beat (32 samples for 16s)\n");
+ printf(" --log-peaks-fine Log at each frame for fine analysis (~960 samples)\n");
+ printf(" (use with --log-peaks for millisecond resolution)\n");
printf("\nExamples:\n");
printf(" %s --fullscreen\n", prog_name);
printf(" %s --resolution 1024x768 --tempo\n", prog_name);
printf(" %s --log-peaks peaks.txt\n", prog_name);
+ printf(" %s --log-peaks peaks.txt --log-peaks-fine\n", prog_name);
printf("\nControls:\n");
printf(" ESC Exit the demo\n");
printf(" F Toggle fullscreen\n");
@@ -47,6 +50,7 @@ int main(int argc, char** argv) {
int width = 1280;
int height = 720;
const char* log_peaks_file = nullptr;
+ bool log_peaks_fine = false;
#if !defined(STRIP_ALL)
for (int i = 1; i < argc; ++i) {
@@ -66,6 +70,8 @@ int main(int argc, char** argv) {
}
} else if (strcmp(argv[i], "--log-peaks") == 0 && i + 1 < argc) {
log_peaks_file = argv[++i];
+ } else if (strcmp(argv[i], "--log-peaks-fine") == 0) {
+ log_peaks_fine = true;
}
}
#else
@@ -131,15 +137,21 @@ int main(int argc, char** argv) {
peak_log = fopen(log_peaks_file, "w");
if (peak_log) {
fprintf(peak_log, "# Audio peak log from test_demo\n");
+ fprintf(peak_log, "# Mode: %s\n", log_peaks_fine ? "fine (per-frame)" : "beat-aligned");
fprintf(peak_log, "# To plot with gnuplot:\n");
- fprintf(peak_log, "# gnuplot -p -e \"set xlabel 'Time (s)'; set ylabel 'Peak'; plot '%s' using 1:3 with lines title 'Raw Peak'\"\n", log_peaks_file);
- fprintf(peak_log, "# Columns: beat_number clock_time raw_peak\n");
+ fprintf(peak_log, "# gnuplot -p -e \"set xlabel 'Time (s)'; set ylabel 'Peak'; plot '%s' using 2:3 with lines title 'Raw Peak'\"\n", log_peaks_file);
+ if (log_peaks_fine) {
+ fprintf(peak_log, "# Columns: frame_number clock_time raw_peak\n");
+ } else {
+ fprintf(peak_log, "# Columns: beat_number clock_time raw_peak\n");
+ }
fprintf(peak_log, "#\n");
} else {
fprintf(stderr, "Warning: Could not open log file '%s'\n", log_peaks_file);
}
}
int last_beat_logged = -1;
+ int frame_number = 0;
#endif
// Main loop
@@ -177,11 +189,18 @@ int main(int argc, char** argv) {
const float beat = fmodf(beat_time, 1.0f);
#if !defined(STRIP_ALL)
- // Log peak at each beat boundary
- if (peak_log && beat_number != last_beat_logged) {
- fprintf(peak_log, "%d %.6f %.6f\n", beat_number, current_time, raw_peak);
- last_beat_logged = beat_number;
+ // Log peak (either per-frame or per-beat)
+ if (peak_log) {
+ if (log_peaks_fine) {
+ // Log every frame for fine-grained analysis
+ fprintf(peak_log, "%d %.6f %.6f\n", frame_number, current_time, raw_peak);
+ } else if (beat_number != last_beat_logged) {
+ // Log only at beat boundaries
+ fprintf(peak_log, "%d %.6f %.6f\n", beat_number, current_time, raw_peak);
+ last_beat_logged = beat_number;
+ }
}
+ frame_number++;
// Debug output every 0.5 seconds
static float last_print_time = -1.0f;
diff --git a/test_demo_README.md b/test_demo_README.md
index f84f972..b8abfc2 100644
--- a/test_demo_README.md
+++ b/test_demo_README.md
@@ -34,7 +34,9 @@ build/test_demo
--fullscreen Run in fullscreen mode
--resolution WxH Set window resolution (e.g., 1024x768)
--tempo Enable tempo variation test mode
- --log-peaks FILE Log audio peaks to FILE for gnuplot visualization
+ --log-peaks FILE Log audio peaks at each beat (32 samples for 16s)
+ --log-peaks-fine Log at each frame for fine analysis (~960 samples)
+ (use with --log-peaks for millisecond resolution)
```
### Examples
@@ -49,16 +51,23 @@ build/test_demo --fullscreen
build/test_demo --resolution 1024x768 --tempo
```
-#### Log audio peaks for analysis
+#### Log audio peaks for analysis (beat-aligned)
```bash
build/test_demo --log-peaks peaks.txt
```
After running, visualize with gnuplot:
```bash
-gnuplot -p -e "set xlabel 'Time (s)'; set ylabel 'Peak'; plot 'peaks.txt' using 1:3 with lines title 'Raw Peak'"
+gnuplot -p -e "set xlabel 'Time (s)'; set ylabel 'Peak'; plot 'peaks.txt' using 2:3 with lines title 'Raw Peak'"
```
+#### Log audio peaks with fine resolution (every frame)
+```bash
+build/test_demo --log-peaks peaks_fine.txt --log-peaks-fine
+```
+
+This logs at ~60 Hz (every frame) instead of every beat, providing millisecond-resolution data for detailed synchronization analysis. Produces ~960 samples for the 16-second demo.
+
## Keyboard Controls
- **ESC**: Exit the demo
@@ -109,12 +118,17 @@ This tests the variable tempo system where music time advances independently of
## Peak Logging Format
-The `--log-peaks` option writes a text file with three columns:
+The `--log-peaks` option writes a text file with three columns.
+
+### Beat-Aligned Mode (default)
+
+Logs once per beat (32 samples for 16 seconds):
```
# Audio peak log from test_demo
+# Mode: beat-aligned
# To plot with gnuplot:
-# gnuplot -p -e "set xlabel 'Time (s)'; set ylabel 'Peak'; plot 'peaks.txt' using 1:3 with lines title 'Raw Peak'"
+# gnuplot -p -e "set xlabel 'Time (s)'; set ylabel 'Peak'; plot 'peaks.txt' using 2:3 with lines title 'Raw Peak'"
# Columns: beat_number clock_time raw_peak
#
0 0.000000 0.850000
@@ -128,12 +142,44 @@ The `--log-peaks` option writes a text file with three columns:
2. **clock_time**: Physical time in seconds
3. **raw_peak**: Audio peak value (0.0-1.0+)
+### Fine-Grained Mode (`--log-peaks-fine`)
+
+Logs at every frame (approximately 960 samples for 16 seconds at 60 Hz):
+
+```
+# Audio peak log from test_demo
+# Mode: fine (per-frame)
+# To plot with gnuplot:
+# gnuplot -p -e "set xlabel 'Time (s)'; set ylabel 'Peak'; plot 'peaks_fine.txt' using 2:3 with lines title 'Raw Peak'"
+# Columns: frame_number clock_time raw_peak
+#
+0 0.000000 0.850000
+1 0.016667 0.845231
+2 0.033333 0.823445
+3 0.050000 0.802891
+...
+```
+
+**Columns:**
+1. **frame_number**: Frame index (0, 1, 2, ...)
+2. **clock_time**: Physical time in seconds (millisecond precision)
+3. **raw_peak**: Audio peak value (0.0-1.0+)
+
**Use Cases:**
-- Verify audio/visual synchronization timing
-- Detect clipping (peak > 1.0)
-- Analyze tempo scaling effects
+
+*Beat-Aligned Mode:*
+- Verify audio/visual synchronization at beat boundaries
+- Detect clipping at specific beats (peak > 1.0)
+- Analyze tempo scaling effects on pattern triggering
- Compare expected vs actual beat times
+*Fine-Grained Mode:*
+- Millisecond-resolution synchronization analysis
+- Detect frame-level timing jitter or drift
+- Analyze audio envelope shape and attack/decay characteristics
+- Debug precise flash-to-audio alignment issues
+- Identify sub-beat audio artifacts or glitches
+
## Files
- **`src/test_demo.cc`**: Main executable (~220 lines)