1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
// This file is part of the 64k demo project.
// It tests the ring buffer under jittered consumption (stress test).
#include <stdio.h>
#if !defined(STRIP_ALL)
#include "audio/audio.h"
#include "audio/jittered_audio_backend.h"
#include "audio/synth.h"
#include "audio/tracker.h"
#include <assert.h>
#include <chrono>
#include <thread>
void test_jittered_audio_basic() {
printf("Test: Basic jittered audio consumption...\n");
// Initialize audio system
synth_init();
tracker_init();
// Set up jittered backend with realistic parameters
// At 32kHz, 10ms = 320 samples = 160 frames (stereo)
// Jitter of ±5ms means 5-15ms intervals, or 80-240 frames
JitteredAudioBackend jittered_backend;
jittered_backend.set_base_interval(10.0f); // 10ms base interval
jittered_backend.set_jitter_amount(5.0f); // ±5ms jitter
jittered_backend.set_chunk_size_range(
80, 240); // Realistic chunk sizes for 5-15ms
audio_set_backend(&jittered_backend);
audio_init();
// Start audio thread
audio_start();
assert(jittered_backend.is_running());
// Simulate main loop for 0.5 seconds (quick stress test)
const float total_time = 0.5f;
const float dt = 1.0f / 60.0f; // 60fps
float music_time = 0.0f;
for (float t = 0.0f; t < total_time; t += dt) {
music_time += dt; // Normal tempo
// Update tracker and fill buffer
tracker_update(music_time);
audio_render_ahead(music_time, dt);
// Sleep to simulate frame time
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
// Stop audio
audio_shutdown();
// Check results
const int frames_consumed = jittered_backend.get_total_frames_consumed();
const int underruns = jittered_backend.get_underrun_count();
printf(" Frames consumed: %d\n", frames_consumed);
printf(" Underruns: %d\n", underruns);
// Should have consumed roughly 0.5 seconds worth of audio
// At 32kHz stereo: 0.5 seconds = 16000 samples = 8000 frames
assert(frames_consumed > 4000); // At least 0.25 seconds (8000 samples)
assert(frames_consumed < 12000); // At most 0.75 seconds (24000 samples)
// Underruns are acceptable in this test, but shouldn't be excessive
assert(underruns < 20); // Less than 20 underruns in 0.5 seconds
printf(" ✓ Basic jittered audio consumption PASSED\n");
}
void test_jittered_audio_with_acceleration() {
printf("Test: Jittered audio with tempo acceleration...\n");
// Initialize audio system
synth_init();
tracker_init();
// Set up jittered backend with aggressive settings for stress test
// At 32kHz, 15ms = 480 samples = 240 frames (stereo)
// Jitter of ±10ms means 5-25ms intervals, or 80-400 frames
JitteredAudioBackend jittered_backend;
jittered_backend.set_base_interval(15.0f); // Slower consumption
jittered_backend.set_jitter_amount(10.0f); // High jitter
jittered_backend.set_chunk_size_range(80, 400); // Realistic stress test range
audio_set_backend(&jittered_backend);
audio_init();
// Start audio thread
audio_start();
// Simulate acceleration scenario (similar to real demo)
const float total_time = 3.0f;
const float dt = 1.0f / 60.0f;
float music_time = 0.0f;
float physical_time = 0.0f;
for (int frame = 0; frame < 180; ++frame) { // 3 seconds @ 60fps
physical_time = frame * dt;
// Variable tempo (accelerate from 1.5-3s)
float tempo_scale = 1.0f;
if (physical_time >= 1.5f && physical_time < 3.0f) {
const float progress = (physical_time - 1.5f) / 1.5f;
tempo_scale = 1.0f + progress * 1.0f; // 1.0 → 2.0
}
music_time += dt * tempo_scale;
// Update tracker and fill buffer
tracker_update(music_time);
audio_render_ahead(music_time, dt);
// Sleep to simulate frame time
std::this_thread::sleep_for(std::chrono::milliseconds(16));
// Progress indicator (every 30 frames for shorter test)
if (frame % 30 == 0) {
printf(
" Frame %d: music_time=%.2fs, tempo=%.2fx, consumed=%d frames, "
"underruns=%d\r",
frame, music_time, tempo_scale,
jittered_backend.get_total_frames_consumed(),
jittered_backend.get_underrun_count());
fflush(stdout);
}
}
printf("\n");
// Stop audio
audio_shutdown();
// Check results
const int frames_consumed = jittered_backend.get_total_frames_consumed();
const int underruns = jittered_backend.get_underrun_count();
printf(" Total frames consumed: %d\n", frames_consumed);
printf(" Total underruns: %d\n", underruns);
// Should have consumed roughly 3.75 seconds worth of audio
// (3 seconds physical time with acceleration 1.0x → 2.0x)
// At 32kHz stereo: 3.75 seconds = 120000 samples = 60000 frames
assert(frames_consumed > 40000); // At least 2.5 seconds (80000 samples)
assert(frames_consumed < 80000); // At most 5 seconds (160000 samples)
// During acceleration with jitter, some underruns are expected but not
// excessive
assert(underruns < 60); // Less than 60 underruns in 3 seconds
printf(" ✓ Jittered audio with acceleration PASSED\n");
}
int main() {
printf("Running Jittered Audio Backend tests...\n\n");
test_jittered_audio_basic();
test_jittered_audio_with_acceleration();
printf("\n✅ All Jittered Audio Backend tests PASSED\n");
return 0;
}
#else
int main() {
printf("Jittered Audio Backend tests skipped (STRIP_ALL enabled)\n");
return 0;
}
#endif /* !defined(STRIP_ALL) */
|