summaryrefslogtreecommitdiff
path: root/src/tests/test_mock_backend.cc
blob: 9173bb2dc20b4812f613144de124e3f537733e87 (plain)
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// This file is part of the 64k demo project.
// It tests the MockAudioBackend implementation.
// Verifies event recording, time tracking, and synth integration.

#include "audio/mock_audio_backend.h"
#include "audio/audio.h"
#include "audio/synth.h"
#include <assert.h>
#include <stdio.h>
#include <cmath>

#if !defined(STRIP_ALL)

void test_event_recording() {
  MockAudioBackend backend;

  // Initially no events
  assert(backend.get_events().size() == 0);
  assert(backend.get_current_time() == 0.0f);

  // Simulate voice trigger
  backend.on_voice_triggered(0.5f, 3, 0.75f, -0.25f);

  // Verify event recorded
  const auto& events = backend.get_events();
  assert(events.size() == 1);
  assert(events[0].timestamp_sec == 0.5f);
  assert(events[0].spectrogram_id == 3);
  assert(events[0].volume == 0.75f);
  assert(events[0].pan == -0.25f);

  // Record multiple events
  backend.on_voice_triggered(1.0f, 5, 1.0f, 0.0f);
  backend.on_voice_triggered(1.5f, 3, 0.5f, 0.5f);

  assert(backend.get_events().size() == 3);
  assert(events[1].timestamp_sec == 1.0f);
  assert(events[2].timestamp_sec == 1.5f);

  // Clear events
  backend.clear_events();
  assert(backend.get_events().size() == 0);

  printf("Event recording test PASSED\n");
}

void test_time_tracking() {
  MockAudioBackend backend;

  // Test manual time advance
  assert(backend.get_current_time() == 0.0f);

  backend.advance_time(0.5f);
  assert(backend.get_current_time() == 0.5f);

  backend.advance_time(1.0f);
  assert(backend.get_current_time() == 1.5f);

  // Test time setting
  backend.set_time(10.0f);
  assert(backend.get_current_time() == 10.0f);

  printf("Time tracking test PASSED\n");
}

void test_frame_rendering() {
  MockAudioBackend backend;

  // Simulate frame rendering (32000 Hz sample rate)
  // 1 second = 32000 frames
  backend.on_frames_rendered(16000); // 0.5 seconds
  assert(std::abs(backend.get_current_time() - 0.5f) < 0.001f);

  backend.on_frames_rendered(16000); // Another 0.5 seconds
  assert(std::abs(backend.get_current_time() - 1.0f) < 0.001f);

  backend.on_frames_rendered(32000); // 1 second
  assert(std::abs(backend.get_current_time() - 2.0f) < 0.001f);

  printf("Frame rendering test PASSED\n");
}

void test_synth_integration() {
  MockAudioBackend backend;
  audio_set_backend(&backend);

  synth_init();

  // Create dummy spectrogram
  float data[DCT_SIZE * 10] = {0};
  data[0] = 100.0f; // DC component

  Spectrogram spec = {data, data, 10};
  int spec_id = synth_register_spectrogram(&spec);
  assert(spec_id >= 0);

  // Trigger voice - should be recorded at time 0
  synth_trigger_voice(spec_id, 0.8f, -0.3f);

  // Verify event recorded
  const auto& events = backend.get_events();
  assert(events.size() == 1);
  assert(events[0].timestamp_sec == 0.0f); // Before any rendering
  assert(events[0].spectrogram_id == spec_id);
  assert(events[0].volume == 0.8f);
  assert(events[0].pan == -0.3f);

  // Render some frames to advance time
  float output[1024] = {0};
  synth_render(output, 512); // ~0.016 sec at 32kHz

  // Verify synth updated its time
  // (Note: synth time is internal, mock doesn't track it from render)

  // Trigger another voice after rendering
  synth_trigger_voice(spec_id, 1.0f, 0.5f);

  assert(events.size() == 2);
  // Second trigger should have timestamp > 0
  assert(events[1].timestamp_sec > 0.0f);
  assert(events[1].timestamp_sec < 0.02f); // ~512 frames = ~0.016 sec

  printf("Synth integration test PASSED\n");
}

void test_multiple_voices() {
  MockAudioBackend backend;
  audio_set_backend(&backend);

  synth_init();

  // Create multiple spectrograms
  float data1[DCT_SIZE * 5] = {0};
  float data2[DCT_SIZE * 5] = {0};
  float data3[DCT_SIZE * 5] = {0};

  Spectrogram spec1 = {data1, data1, 5};
  Spectrogram spec2 = {data2, data2, 5};
  Spectrogram spec3 = {data3, data3, 5};

  int id1 = synth_register_spectrogram(&spec1);
  int id2 = synth_register_spectrogram(&spec2);
  int id3 = synth_register_spectrogram(&spec3);

  // Trigger multiple voices at once
  synth_trigger_voice(id1, 1.0f, -1.0f);
  synth_trigger_voice(id2, 0.5f, 0.0f);
  synth_trigger_voice(id3, 0.75f, 1.0f);

  // Verify all recorded
  const auto& events = backend.get_events();
  assert(events.size() == 3);

  // Verify each has correct properties
  assert(events[0].spectrogram_id == id1);
  assert(events[1].spectrogram_id == id2);
  assert(events[2].spectrogram_id == id3);

  assert(events[0].volume == 1.0f);
  assert(events[1].volume == 0.5f);
  assert(events[2].volume == 0.75f);

  assert(events[0].pan == -1.0f);
  assert(events[1].pan == 0.0f);
  assert(events[2].pan == 1.0f);

  printf("Multiple voices test PASSED\n");
}

void test_audio_render_silent_integration() {
  MockAudioBackend backend;
  audio_set_backend(&backend);

  audio_init();
  synth_init();

  // Create a spectrogram
  float data[DCT_SIZE * 5] = {0};
  Spectrogram spec = {data, data, 5};
  int spec_id = synth_register_spectrogram(&spec);

  // Trigger at t=0
  synth_trigger_voice(spec_id, 1.0f, 0.0f);

  // Simulate 2 seconds of silent rendering (seek/fast-forward)
  audio_render_silent(2.0f);

  // Verify backend time advanced via on_frames_rendered
  const float expected_time = 2.0f;
  const float actual_time = backend.get_current_time();
  assert(std::abs(actual_time - expected_time) < 0.01f); // 10ms tolerance

  audio_shutdown();

  printf("audio_render_silent integration test PASSED\n");
}

#endif /* !defined(STRIP_ALL) */

int main() {
#if !defined(STRIP_ALL)
  printf("Running MockAudioBackend tests...\n");
  test_event_recording();
  test_time_tracking();
  test_frame_rendering();
  test_synth_integration();
  test_multiple_voices();
  test_audio_render_silent_integration();
  printf("All MockAudioBackend tests PASSED\n");
  return 0;
#else
  printf("MockAudioBackend tests skipped (STRIP_ALL enabled)\n");
  return 0;
#endif /* !defined(STRIP_ALL) */
}