// 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 #include #include #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) */ }