summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/test_tracker.cc27
-rw-r--r--src/tests/test_tracker_timing.cc72
-rw-r--r--src/tests/test_variable_tempo.cc101
-rw-r--r--src/tests/test_wav_dump.cc13
4 files changed, 123 insertions, 90 deletions
diff --git a/src/tests/test_tracker.cc b/src/tests/test_tracker.cc
index 9285728..ae06c5e 100644
--- a/src/tests/test_tracker.cc
+++ b/src/tests/test_tracker.cc
@@ -1,6 +1,7 @@
// This file is part of the 64k demo project.
// It tests the core functionality of the audio tracker engine.
+#include "audio/audio_engine.h"
#include "audio/gen.h"
#include "audio/synth.h"
#include "audio/tracker.h"
@@ -16,14 +17,15 @@ extern const uint32_t g_tracker_patterns_count;
extern const TrackerScore g_tracker_score;
void test_tracker_init() {
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
printf("Tracker init test PASSED\n");
+ engine.shutdown();
}
void test_tracker_pattern_triggering() {
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// At time 0.0f, 3 patterns are triggered:
// - crash (1 event at beat 0.0)
@@ -32,28 +34,29 @@ void test_tracker_pattern_triggering() {
// With event-based triggering, only events at beat 0.0 trigger immediately.
// Test 1: At music_time = 0.0f, events at beat 0.0 trigger
- tracker_update(0.0f);
+ engine.update(0.0f);
// Expect 3 voices: crash (beat 0.0), kick (beat 0.0), hihat (beat 0.0)
- assert(synth_get_active_voice_count() == 3);
+ assert(engine.get_active_voice_count() == 3);
// Test 2: At music_time = 0.25f (beat 0.5 @ 120 BPM), hihat event triggers
// beat_duration = 60.0f / 120.0f = 0.5s per beat
// beat 0.5 = 0.25s
- tracker_update(0.25f);
+ engine.update(0.25f);
// Expect 4 voices (3 previous + 1 hihat at beat 0.5)
- assert(synth_get_active_voice_count() == 4);
+ assert(engine.get_active_voice_count() == 4);
// Test 3: At music_time = 0.5f (beat 1.0), hihat event triggers
- tracker_update(0.5f);
+ engine.update(0.5f);
// Expect 5 voices (4 previous + 1 hihat at beat 1.0)
- assert(synth_get_active_voice_count() == 5);
+ assert(engine.get_active_voice_count() == 5);
// Test 4: Advance to 2.0f - new patterns trigger at time 2.0f
- tracker_update(2.0f);
+ engine.update(2.0f);
// Many events have triggered by now
- assert(synth_get_active_voice_count() > 5);
+ assert(engine.get_active_voice_count() > 5);
printf("Tracker pattern triggering test PASSED\n");
+ engine.shutdown();
}
int main() {
diff --git a/src/tests/test_tracker_timing.cc b/src/tests/test_tracker_timing.cc
index cf2519d..2f39a16 100644
--- a/src/tests/test_tracker_timing.cc
+++ b/src/tests/test_tracker_timing.cc
@@ -2,19 +2,20 @@
// It tests tracker timing and synchronization using MockAudioBackend.
// Verifies pattern triggers occur at correct times with proper BPM scaling.
-#include "audio/mock_audio_backend.h"
#include "audio/audio.h"
+#include "audio/audio_engine.h"
+#include "audio/mock_audio_backend.h"
#include "audio/synth.h"
#include "audio/tracker.h"
#include <assert.h>
-#include <stdio.h>
#include <cmath>
+#include <stdio.h>
#if !defined(STRIP_ALL)
// Helper: Check if a timestamp exists in events within tolerance
static bool has_event_at_time(const std::vector<VoiceTriggerEvent>& events,
- float expected_time, float tolerance = 0.001f) {
+ float expected_time, float tolerance = 0.001f) {
for (const auto& evt : events) {
if (std::abs(evt.timestamp_sec - expected_time) < tolerance) {
return true;
@@ -25,7 +26,7 @@ static bool has_event_at_time(const std::vector<VoiceTriggerEvent>& events,
// Helper: Count events at a specific time
static int count_events_at_time(const std::vector<VoiceTriggerEvent>& events,
- float expected_time, float tolerance = 0.001f) {
+ float expected_time, float tolerance = 0.001f) {
int count = 0;
for (const auto& evt : events) {
if (std::abs(evt.timestamp_sec - expected_time) < tolerance) {
@@ -36,8 +37,9 @@ static int count_events_at_time(const std::vector<VoiceTriggerEvent>& events,
}
// Helper: Get all unique timestamps in events
-static std::vector<float> get_unique_timestamps(
- const std::vector<VoiceTriggerEvent>& events, float tolerance = 0.001f) {
+static std::vector<float>
+get_unique_timestamps(const std::vector<VoiceTriggerEvent>& events,
+ float tolerance = 0.001f) {
std::vector<float> timestamps;
for (const auto& evt : events) {
bool found = false;
@@ -60,11 +62,11 @@ void test_basic_event_recording() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Trigger at t=0.0 (should trigger initial patterns)
- tracker_update(0.0f);
+ engine.update(0.0f);
const auto& events = backend.get_events();
printf(" Events triggered at t=0.0: %zu\n", events.size());
@@ -77,6 +79,7 @@ void test_basic_event_recording() {
assert(evt.timestamp_sec < 0.1f); // Within 100ms of start
}
+ engine.shutdown();
printf(" ✓ Basic event recording works\n");
}
@@ -86,21 +89,21 @@ void test_progressive_triggering() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Update at t=0
- tracker_update(0.0f);
+ engine.update(0.0f);
const size_t events_at_0 = backend.get_events().size();
printf(" Events at t=0.0: %zu\n", events_at_0);
// Update at t=1.0
- tracker_update(1.0f);
+ engine.update(1.0f);
const size_t events_at_1 = backend.get_events().size();
printf(" Events at t=1.0: %zu\n", events_at_1);
// Update at t=2.0
- tracker_update(2.0f);
+ engine.update(2.0f);
const size_t events_at_2 = backend.get_events().size();
printf(" Events at t=2.0: %zu\n", events_at_2);
@@ -108,6 +111,7 @@ void test_progressive_triggering() {
assert(events_at_1 >= events_at_0);
assert(events_at_2 >= events_at_1);
+ engine.shutdown();
printf(" ✓ Events accumulate over time\n");
}
@@ -117,12 +121,12 @@ void test_simultaneous_triggers() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Clear and update to first trigger point
backend.clear_events();
- tracker_update(0.0f);
+ engine.update(0.0f);
const auto& events = backend.get_events();
if (events.size() == 0) {
@@ -155,6 +159,8 @@ void test_simultaneous_triggers() {
} else {
printf(" ℹ Only one event at t=0.0, cannot verify simultaneity\n");
}
+
+ engine.shutdown();
}
void test_timing_monotonicity() {
@@ -163,12 +169,12 @@ void test_timing_monotonicity() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Update through several time points
for (float t = 0.0f; t <= 5.0f; t += 0.5f) {
- tracker_update(t);
+ engine.update(t);
}
const auto& events = backend.get_events();
@@ -179,6 +185,7 @@ void test_timing_monotonicity() {
assert(events[i].timestamp_sec >= events[i - 1].timestamp_sec);
}
+ engine.shutdown();
printf(" ✓ All timestamps monotonically increasing\n");
}
@@ -189,8 +196,8 @@ void test_seek_simulation() {
audio_set_backend(&backend);
audio_init();
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Simulate seeking to t=3.0s by rendering silent audio
// This should trigger all patterns in range [0, 3.0]
@@ -200,10 +207,10 @@ void test_seek_simulation() {
float t = 0.0f;
const float step = 0.1f;
while (t <= seek_target) {
- tracker_update(t);
+ engine.update(t);
// Simulate audio rendering
float dummy_buffer[512 * 2];
- synth_render(dummy_buffer, 512);
+ engine.render(dummy_buffer, 512);
t += step;
}
@@ -220,6 +227,7 @@ void test_seek_simulation() {
assert(evt.timestamp_sec <= seek_target + 0.5f);
}
+ engine.shutdown();
audio_shutdown();
printf(" ✓ Seek simulation works correctly\n");
@@ -231,12 +239,12 @@ void test_timestamp_clustering() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Update through the first 4 seconds
for (float t = 0.0f; t <= 4.0f; t += 0.1f) {
- tracker_update(t);
+ engine.update(t);
}
const auto& events = backend.get_events();
@@ -254,6 +262,7 @@ void test_timestamp_clustering() {
}
}
+ engine.shutdown();
printf(" ✓ Timestamp clustering analyzed\n");
}
@@ -264,11 +273,11 @@ void test_render_integration() {
audio_set_backend(&backend);
audio_init();
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
// Trigger some patterns
- tracker_update(0.0f);
+ engine.update(0.0f);
const size_t events_before = backend.get_events().size();
// Render 1 second of silent audio
@@ -280,12 +289,13 @@ void test_render_integration() {
assert(backend_time >= 0.9f && backend_time <= 1.1f);
// Trigger more patterns after time advance
- tracker_update(1.0f);
+ engine.update(1.0f);
const size_t events_after = backend.get_events().size();
printf(" Events before: %zu, after: %zu\n", events_before, events_after);
assert(events_after >= events_before);
+ engine.shutdown();
audio_shutdown();
printf(" ✓ audio_render_silent integration works\n");
diff --git a/src/tests/test_variable_tempo.cc b/src/tests/test_variable_tempo.cc
index 3deb97e..533f398 100644
--- a/src/tests/test_variable_tempo.cc
+++ b/src/tests/test_variable_tempo.cc
@@ -2,13 +2,13 @@
// It tests variable tempo system with music_time scaling.
// Verifies 2x speed-up and 2x slow-down reset tricks.
-#include "audio/mock_audio_backend.h"
#include "audio/audio.h"
-#include "audio/synth.h"
+#include "audio/audio_engine.h"
+#include "audio/mock_audio_backend.h"
#include "audio/tracker.h"
#include <assert.h>
-#include <stdio.h>
#include <cmath>
+#include <stdio.h>
#if !defined(STRIP_ALL)
@@ -19,7 +19,7 @@ static float calc_physical_time(float music_time, float tempo_scale) {
// Helper: Simulate music time advancement
static float advance_music_time(float current_music_time, float dt,
- float tempo_scale) {
+ float tempo_scale) {
return current_music_time + (dt * tempo_scale);
}
@@ -29,8 +29,10 @@ void test_basic_tempo_scaling() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
// Test 1: Normal tempo (1.0x)
{
@@ -40,9 +42,9 @@ void test_basic_tempo_scaling() {
// Simulate 1 second of physical time
for (int i = 0; i < 10; ++i) {
- float dt = 0.1f; // 100ms physical steps
+ float dt = 0.1f; // 100ms physical steps
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
// After 1 second physical time at 1.0x tempo:
@@ -54,7 +56,7 @@ void test_basic_tempo_scaling() {
// Test 2: Fast tempo (2.0x)
{
backend.clear_events();
- tracker_init(); // Reset tracker
+ engine.reset(); // Reset engine
float music_time = 0.0f;
float tempo_scale = 2.0f;
@@ -62,7 +64,7 @@ void test_basic_tempo_scaling() {
for (int i = 0; i < 10; ++i) {
float dt = 0.1f;
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
// After 1 second physical time at 2.0x tempo:
@@ -74,7 +76,7 @@ void test_basic_tempo_scaling() {
// Test 3: Slow tempo (0.5x)
{
backend.clear_events();
- synth_init();
+ engine.reset();
float music_time = 0.0f;
float tempo_scale = 0.5f;
@@ -82,7 +84,7 @@ void test_basic_tempo_scaling() {
for (int i = 0; i < 10; ++i) {
float dt = 0.1f;
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
// After 1 second physical time at 0.5x tempo:
@@ -91,6 +93,7 @@ void test_basic_tempo_scaling() {
assert(std::abs(music_time - 0.5f) < 0.01f);
}
+ engine.shutdown();
printf(" ✓ Basic tempo scaling works correctly\n");
}
@@ -100,30 +103,32 @@ void test_2x_speedup_reset_trick() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
// Scenario: Accelerate to 2.0x, then reset to 1.0x
float music_time = 0.0f;
float tempo_scale = 1.0f;
float physical_time = 0.0f;
- const float dt = 0.1f; // 100ms steps
+ const float dt = 0.1f; // 100ms steps
// Phase 1: Accelerate from 1.0x to 2.0x over 5 seconds
printf(" Phase 1: Accelerating 1.0x → 2.0x\n");
for (int i = 0; i < 50; ++i) {
physical_time += dt;
- tempo_scale = 1.0f + (physical_time / 5.0f); // Linear acceleration
+ tempo_scale = 1.0f + (physical_time / 5.0f); // Linear acceleration
tempo_scale = fminf(tempo_scale, 2.0f);
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
printf(" After 5s physical: tempo=%.2fx, music_time=%.3f\n", tempo_scale,
music_time);
- assert(tempo_scale >= 1.99f); // Should be at 2.0x
+ assert(tempo_scale >= 1.99f); // Should be at 2.0x
// Record state before reset
const float music_time_before_reset = music_time;
@@ -137,7 +142,7 @@ void test_2x_speedup_reset_trick() {
for (int i = 0; i < 20; ++i) {
physical_time += dt;
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
printf(" After reset + 2s: tempo=%.2fx, music_time=%.3f\n", tempo_scale,
@@ -148,6 +153,7 @@ void test_2x_speedup_reset_trick() {
printf(" Music time delta: %.3f (expected ~2.0)\n", music_time_delta);
assert(std::abs(music_time_delta - 2.0f) < 0.1f);
+ engine.shutdown();
printf(" ✓ 2x speed-up reset trick verified\n");
}
@@ -157,8 +163,10 @@ void test_2x_slowdown_reset_trick() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
// Scenario: Decelerate to 0.5x, then reset to 1.0x
float music_time = 0.0f;
@@ -171,16 +179,16 @@ void test_2x_slowdown_reset_trick() {
printf(" Phase 1: Decelerating 1.0x → 0.5x\n");
for (int i = 0; i < 50; ++i) {
physical_time += dt;
- tempo_scale = 1.0f - (physical_time / 10.0f); // Linear deceleration
+ tempo_scale = 1.0f - (physical_time / 10.0f); // Linear deceleration
tempo_scale = fmaxf(tempo_scale, 0.5f);
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
printf(" After 5s physical: tempo=%.2fx, music_time=%.3f\n", tempo_scale,
music_time);
- assert(tempo_scale <= 0.51f); // Should be at 0.5x
+ assert(tempo_scale <= 0.51f); // Should be at 0.5x
// Record state before reset
const float music_time_before_reset = music_time;
@@ -193,7 +201,7 @@ void test_2x_slowdown_reset_trick() {
for (int i = 0; i < 20; ++i) {
physical_time += dt;
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
printf(" After reset + 2s: tempo=%.2fx, music_time=%.3f\n", tempo_scale,
@@ -204,6 +212,7 @@ void test_2x_slowdown_reset_trick() {
printf(" Music time delta: %.3f (expected ~2.0)\n", music_time_delta);
assert(std::abs(music_time_delta - 2.0f) < 0.1f);
+ engine.shutdown();
printf(" ✓ 2x slow-down reset trick verified\n");
}
@@ -213,8 +222,10 @@ void test_pattern_density_swap() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
// Simulate: sparse pattern → accelerate → reset + dense pattern
float music_time = 0.0f;
@@ -224,7 +235,7 @@ void test_pattern_density_swap() {
printf(" Phase 1: Sparse pattern, normal tempo\n");
for (float t = 0.0f; t < 3.0f; t += 0.1f) {
music_time += 0.1f * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
const size_t sparse_events = backend.get_events().size();
printf(" Events during sparse phase: %zu\n", sparse_events);
@@ -234,7 +245,7 @@ void test_pattern_density_swap() {
tempo_scale = 2.0f;
for (float t = 0.0f; t < 2.0f; t += 0.1f) {
music_time += 0.1f * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
const size_t events_at_2x = backend.get_events().size() - sparse_events;
printf(" Additional events during 2.0x: %zu\n", events_at_2x);
@@ -249,7 +260,7 @@ void test_pattern_density_swap() {
const size_t events_before_reset_phase = backend.get_events().size();
for (float t = 0.0f; t < 2.0f; t += 0.1f) {
music_time += 0.1f * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
}
const size_t events_after_reset = backend.get_events().size();
@@ -259,6 +270,7 @@ void test_pattern_density_swap() {
// Verify patterns triggered throughout
assert(backend.get_events().size() > 0);
+ engine.shutdown();
printf(" ✓ Pattern density swap points verified\n");
}
@@ -268,14 +280,16 @@ void test_continuous_acceleration() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
float music_time = 0.0f;
float tempo_scale = 0.5f;
float physical_time = 0.0f;
- const float dt = 0.05f; // 50ms steps for smoother curve
+ const float dt = 0.05f; // 50ms steps for smoother curve
// Accelerate from 0.5x to 2.0x over 10 seconds
printf(" Accelerating 0.5x → 2.0x over 10 seconds\n");
@@ -285,12 +299,12 @@ void test_continuous_acceleration() {
for (int i = 0; i < 200; ++i) {
physical_time += dt;
- float progress = physical_time / 10.0f; // 0.0 to 1.0
+ float progress = physical_time / 10.0f; // 0.0 to 1.0
tempo_scale = min_tempo + progress * (max_tempo - min_tempo);
tempo_scale = fmaxf(min_tempo, fminf(max_tempo, tempo_scale));
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
// Log at key points
if (i % 50 == 0) {
@@ -305,12 +319,14 @@ void test_continuous_acceleration() {
assert(tempo_scale >= 1.99f);
// Verify music_time progressed correctly
- // Integral of (0.5 + 1.5t/10) from 0 to 10 = 0.5*10 + 1.5*10²/(2*10) = 5 + 7.5 = 12.5
+ // Integral of (0.5 + 1.5t/10) from 0 to 10 = 0.5*10 + 1.5*10²/(2*10) = 5
+ // + 7.5 = 12.5
const float expected_music_time = 12.5f;
printf(" Expected music_time: %.3f, actual: %.3f\n", expected_music_time,
music_time);
assert(std::abs(music_time - expected_music_time) < 0.5f);
+ engine.shutdown();
printf(" ✓ Continuous acceleration verified\n");
}
@@ -320,8 +336,10 @@ void test_oscillating_tempo() {
MockAudioBackend backend;
audio_set_backend(&backend);
- synth_init();
- tracker_init();
+ AudioEngine engine;
+ engine.init();
+ engine.load_music_data(&g_tracker_score, g_tracker_samples,
+ g_tracker_sample_assets, g_tracker_samples_count);
float music_time = 0.0f;
float physical_time = 0.0f;
@@ -336,7 +354,7 @@ void test_oscillating_tempo() {
float tempo_scale = 1.0f + 0.2f * sinf(physical_time * 2.0f);
music_time += dt * tempo_scale;
- tracker_update(music_time);
+ engine.update(music_time);
if (i % 25 == 0) {
printf(" t=%.2fs: tempo=%.3fx, music_time=%.3f\n", physical_time,
@@ -344,14 +362,15 @@ void test_oscillating_tempo() {
}
}
- // After oscillation, music_time should be approximately equal to physical_time
- // (since average tempo is 1.0x)
+ // After oscillation, music_time should be approximately equal to
+ // physical_time (since average tempo is 1.0x)
printf(" Final: physical_time=%.2fs, music_time=%.3f (expected ~%.2f)\n",
physical_time, music_time, physical_time);
// Allow some tolerance for integral error
assert(std::abs(music_time - physical_time) < 0.5f);
+ engine.shutdown();
printf(" ✓ Oscillating tempo verified\n");
}
diff --git a/src/tests/test_wav_dump.cc b/src/tests/test_wav_dump.cc
index f350330..c68578b 100644
--- a/src/tests/test_wav_dump.cc
+++ b/src/tests/test_wav_dump.cc
@@ -2,8 +2,7 @@
// Regression test for WAV dump backend to prevent format mismatches.
#include "audio/audio.h"
-#include "audio/synth.h"
-#include "audio/tracker.h"
+#include "audio/audio_engine.h"
#include "audio/wav_dump_backend.h"
#include <assert.h>
#include <stdio.h>
@@ -42,21 +41,23 @@ void test_wav_format_matches_live_audio() {
// Initialize audio system (calls synth_init internally)
audio_init();
- // Initialize tracker AFTER audio_init to ensure spectrograms stay registered
- tracker_init();
+ // Initialize AudioEngine (replaces direct synth_init/tracker_init)
+ AudioEngine engine;
+ engine.init();
// Manually trigger some audio for testing
- tracker_update(0.0f); // Trigger patterns at t=0
+ engine.update(0.0f); // Trigger patterns at t=0
// Render short duration (1 second = 60 updates @ 60Hz)
for (int i = 0; i < 60; ++i) {
float t = i / 60.0f;
- tracker_update(t);
+ engine.update(t);
// Simulate audio render (WavDumpBackend will handle this in start())
}
audio_start(); // This triggers the actual WAV rendering
+ engine.shutdown();
audio_shutdown();
// Read and verify WAV header