diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio/tracker.cc | 175 | ||||
| -rw-r--r-- | src/audio/tracker.h | 3 | ||||
| -rw-r--r-- | src/generated/music_data.cc | 299 | ||||
| -rw-r--r-- | src/tests/test_tracker.cc | 47 |
4 files changed, 285 insertions, 239 deletions
diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc index 8f3da38..cb97f23 100644 --- a/src/audio/tracker.cc +++ b/src/audio/tracker.cc @@ -7,13 +7,23 @@ static uint32_t g_last_trigger_idx = 0; +// Active pattern instance tracking +struct ActivePattern { + uint16_t pattern_id; + float start_music_time; // When this pattern was triggered (music time) + uint32_t next_event_idx; // Next event to trigger within this pattern + bool active; +}; + +static ActivePattern g_active_patterns[MAX_SPECTROGRAMS]; + struct ManagedSpectrogram { int synth_id; float* data; bool active; }; -// Simple pool for dynamic spectrograms +// Simple pool for dynamic spectrograms (now for individual notes) static ManagedSpectrogram g_spec_pool[MAX_SPECTROGRAMS]; static int g_next_pool_slot = 0; // Round-robin allocation @@ -24,6 +34,14 @@ void tracker_init() { g_spec_pool[i].synth_id = -1; g_spec_pool[i].data = nullptr; g_spec_pool[i].active = false; + g_active_patterns[i].active = false; + } +} + +void tracker_reset() { + g_last_trigger_idx = 0; + for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { + g_active_patterns[i].active = false; } } @@ -41,81 +59,118 @@ static int get_free_pool_slot() { return slot; } -void tracker_update(float time_sec) { - while (g_last_trigger_idx < g_tracker_score.num_triggers) { - const TrackerPatternTrigger& trigger = - g_tracker_score.triggers[g_last_trigger_idx]; +static int get_free_pattern_slot() { + for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { + if (!g_active_patterns[i].active) + return i; + } + return -1; // No free slots +} - if (trigger.time_sec > time_sec) - break; +// Helper to trigger a single note event +static void trigger_note_event(const TrackerEvent& event) { + std::vector<float> note_data; + int note_frames = 0; + + // Load or generate the note spectrogram + AssetId aid = g_tracker_sample_assets[event.sample_id]; + if (aid != AssetId::ASSET_LAST_ID) { + size_t size; + const uint8_t* data = GetAsset(aid, &size); + if (data && size >= sizeof(SpecHeader)) { + const SpecHeader* header = (const SpecHeader*)data; + note_frames = header->num_frames; + const float* src_spectral_data = + (const float*)(data + sizeof(SpecHeader)); + note_data.assign(src_spectral_data, + src_spectral_data + (size_t)note_frames * DCT_SIZE); + } + } else { + const NoteParams& params = g_tracker_samples[event.sample_id]; + note_data = generate_note_spectrogram(params, ¬e_frames); + } - const TrackerPattern& pattern = g_tracker_patterns[trigger.pattern_id]; + if (note_frames > 0) { + const int slot = get_free_pool_slot(); - int dest_num_frames = 0; - std::vector<float> pattern_data; + // Clean up old data in this slot if reusing + if (g_spec_pool[slot].synth_id != -1) { + synth_unregister_spectrogram(g_spec_pool[slot].synth_id); + g_spec_pool[slot].synth_id = -1; + } + if (g_spec_pool[slot].data != nullptr) { + delete[] g_spec_pool[slot].data; + g_spec_pool[slot].data = nullptr; + } - float beat_to_sec = 60.0f / g_tracker_score.bpm; + // Allocate and register new note + g_spec_pool[slot].data = new float[note_data.size()]; + memcpy(g_spec_pool[slot].data, note_data.data(), + note_data.size() * sizeof(float)); - for (uint32_t i = 0; i < pattern.num_events; ++i) { - const TrackerEvent& event = pattern.events[i]; + Spectrogram spec; + spec.spectral_data_a = g_spec_pool[slot].data; + spec.spectral_data_b = g_spec_pool[slot].data; + spec.num_frames = note_frames; - std::vector<float> note_data; - int note_frames = 0; + g_spec_pool[slot].synth_id = synth_register_spectrogram(&spec); + g_spec_pool[slot].active = true; + + synth_trigger_voice(g_spec_pool[slot].synth_id, event.volume, event.pan); + } +} - AssetId aid = g_tracker_sample_assets[event.sample_id]; - if (aid != AssetId::ASSET_LAST_ID) { - size_t size; - const uint8_t* data = GetAsset(aid, &size); - if (data && size >= sizeof(SpecHeader)) { - const SpecHeader* header = (const SpecHeader*)data; - note_frames = header->num_frames; - const float* src_spectral_data = - (const float*)(data + sizeof(SpecHeader)); - note_data.assign(src_spectral_data, - src_spectral_data + (size_t)note_frames * DCT_SIZE); - } - } else { - const NoteParams& params = g_tracker_samples[event.sample_id]; - note_data = generate_note_spectrogram(params, ¬e_frames); - } +void tracker_update(float music_time_sec) { + // Step 1: Process new pattern triggers + while (g_last_trigger_idx < g_tracker_score.num_triggers) { + const TrackerPatternTrigger& trigger = + g_tracker_score.triggers[g_last_trigger_idx]; - if (note_frames > 0) { - int frame_offset = - (int)(event.beat * beat_to_sec * 32000.0f / DCT_SIZE); - paste_spectrogram(pattern_data, &dest_num_frames, note_data, - note_frames, frame_offset); - } + if (trigger.time_sec > music_time_sec) + break; + + // Add this pattern to active patterns list + const int slot = get_free_pattern_slot(); + if (slot != -1) { + g_active_patterns[slot].pattern_id = trigger.pattern_id; + g_active_patterns[slot].start_music_time = trigger.time_sec; + g_active_patterns[slot].next_event_idx = 0; + g_active_patterns[slot].active = true; } - if (dest_num_frames > 0) { - const int slot = get_free_pool_slot(); + g_last_trigger_idx++; + } - // Clean up old data in this slot if reusing - if (g_spec_pool[slot].synth_id != -1) { - synth_unregister_spectrogram(g_spec_pool[slot].synth_id); - g_spec_pool[slot].synth_id = -1; - } - if (g_spec_pool[slot].data != nullptr) { - delete[] g_spec_pool[slot].data; - g_spec_pool[slot].data = nullptr; - } + // Step 2: Update all active patterns and trigger individual events + const float beat_duration = 60.0f / g_tracker_score.bpm; + + for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { + if (!g_active_patterns[i].active) + continue; - // Allocate and register new pattern - g_spec_pool[slot].data = new float[pattern_data.size()]; - memcpy(g_spec_pool[slot].data, pattern_data.data(), - pattern_data.size() * sizeof(float)); + ActivePattern& active = g_active_patterns[i]; + const TrackerPattern& pattern = g_tracker_patterns[active.pattern_id]; - Spectrogram spec; - spec.spectral_data_a = g_spec_pool[slot].data; - spec.spectral_data_b = g_spec_pool[slot].data; - spec.num_frames = dest_num_frames; + // Calculate elapsed beats since pattern started + const float elapsed_music_time = music_time_sec - active.start_music_time; + const float elapsed_beats = elapsed_music_time / beat_duration; - g_spec_pool[slot].synth_id = synth_register_spectrogram(&spec); - g_spec_pool[slot].active = true; + // Trigger all events that have passed their beat time + while (active.next_event_idx < pattern.num_events) { + const TrackerEvent& event = pattern.events[active.next_event_idx]; - synth_trigger_voice(g_spec_pool[slot].synth_id, 1.0f, 0.0f); + if (event.beat > elapsed_beats) + break; // This event hasn't reached its time yet + + // Trigger this event as an individual voice + trigger_note_event(event); + + active.next_event_idx++; } - g_last_trigger_idx++; + // If all events have been triggered, mark pattern as complete + if (active.next_event_idx >= pattern.num_events) { + active.active = false; + } } } diff --git a/src/audio/tracker.h b/src/audio/tracker.h index 49fcd3c..e6d479a 100644 --- a/src/audio/tracker.h +++ b/src/audio/tracker.h @@ -41,4 +41,5 @@ extern const uint32_t g_tracker_patterns_count; extern const TrackerScore g_tracker_score; void tracker_init(); -void tracker_update(float time_sec); +void tracker_update(float music_time_sec); +void tracker_reset(); // Reset tracker state (for tests/seeking) diff --git a/src/generated/music_data.cc b/src/generated/music_data.cc index 73ed992..a37d9c0 100644 --- a/src/generated/music_data.cc +++ b/src/generated/music_data.cc @@ -7,54 +7,30 @@ const NoteParams g_tracker_samples[] = { { 0 }, // ASSET_KICK_1 (ASSET) { 0 }, // ASSET_KICK_2 (ASSET) - { 0 }, // ASSET_KICK_3 (ASSET) { 0 }, // ASSET_SNARE_1 (ASSET) - { 0 }, // ASSET_SNARE_2 (ASSET) { 0 }, // ASSET_SNARE_3 (ASSET) - { 0 }, // ASSET_SNARE_4 (ASSET) { 0 }, // ASSET_HIHAT_1 (ASSET) { 0 }, // ASSET_HIHAT_2 (ASSET) - { 0 }, // ASSET_HIHAT_3 (ASSET) - { 0 }, // ASSET_HIHAT_4 (ASSET) { 0 }, // ASSET_CRASH_1 (ASSET) - { 0 }, // ASSET_RIDE_1 (ASSET) - { 0 }, // ASSET_SPLASH_1 (ASSET) { 0 }, // ASSET_BASS_1 (ASSET) - { 0 }, // ASSET_SYNTH_BASS_1 (ASSET) { 82.4f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // E2 { 98.0f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // G2 - { 110.0f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // A2 - { 123.5f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // B2 { 329.6f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // E4 { 392.0f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // G4 { 493.9f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // B4 - { 587.3f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // D5 - { 659.3f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // E5 { 440.0f, 0.50f, 1.0f, 0.01f, 0.0f, 0.0f, 0.0f, 3, 0.6f, 0.0f, 0.0f }, // A4 }; -const uint32_t g_tracker_samples_count = 26; +const uint32_t g_tracker_samples_count = 14; const AssetId g_tracker_sample_assets[] = { AssetId::ASSET_KICK_1, AssetId::ASSET_KICK_2, - AssetId::ASSET_KICK_3, AssetId::ASSET_SNARE_1, - AssetId::ASSET_SNARE_2, AssetId::ASSET_SNARE_3, - AssetId::ASSET_SNARE_4, AssetId::ASSET_HIHAT_1, AssetId::ASSET_HIHAT_2, - AssetId::ASSET_HIHAT_3, - AssetId::ASSET_HIHAT_4, AssetId::ASSET_CRASH_1, - AssetId::ASSET_RIDE_1, - AssetId::ASSET_SPLASH_1, AssetId::ASSET_BASS_1, - AssetId::ASSET_SYNTH_BASS_1, - AssetId::ASSET_LAST_ID, - AssetId::ASSET_LAST_ID, - AssetId::ASSET_LAST_ID, - AssetId::ASSET_LAST_ID, AssetId::ASSET_LAST_ID, AssetId::ASSET_LAST_ID, AssetId::ASSET_LAST_ID, @@ -63,177 +39,174 @@ const AssetId g_tracker_sample_assets[] = { AssetId::ASSET_LAST_ID, }; -static const TrackerEvent PATTERN_EVENTS_rock_beat[] = { +static const TrackerEvent PATTERN_EVENTS_kick_basic[] = { { 0.0f, 0, 1.0f, 0.0f }, - { 1.0f, 5, 0.9f, 0.1f }, { 2.0f, 0, 1.0f, 0.0f }, - { 2.5f, 0, 0.7f, -0.1f }, - { 3.0f, 5, 0.9f, 0.1f }, + { 2.5f, 1, 0.7f, -0.2f }, }; -static const TrackerEvent PATTERN_EVENTS_double_kick[] = { - { 0.0f, 2, 1.0f, 0.0f }, - { 0.5f, 1, 0.8f, -0.2f }, - { 1.0f, 6, 0.9f, 0.2f }, - { 1.5f, 2, 0.7f, 0.1f }, - { 2.0f, 2, 1.0f, 0.0f }, - { 2.5f, 1, 0.8f, -0.2f }, - { 3.0f, 6, 0.9f, 0.2f }, - { 3.5f, 2, 0.6f, 0.1f }, +static const TrackerEvent PATTERN_EVENTS_snare_basic[] = { + { 1.0f, 2, 0.9f, 0.1f }, + { 3.0f, 2, 0.9f, 0.1f }, }; -static const TrackerEvent PATTERN_EVENTS_hihat_8th[] = { - { 0.0f, 8, 0.6f, -0.3f }, - { 0.5f, 7, 0.4f, 0.3f }, - { 1.0f, 8, 0.6f, -0.3f }, - { 1.5f, 7, 0.4f, 0.3f }, - { 2.0f, 8, 0.6f, -0.3f }, - { 2.5f, 7, 0.4f, 0.3f }, - { 3.0f, 8, 0.6f, -0.3f }, - { 3.5f, 7, 0.4f, 0.3f }, +static const TrackerEvent PATTERN_EVENTS_hihat_stressed[] = { + { 0.0f, 5, 0.8f, -0.3f }, + { 0.5f, 4, 0.4f, 0.3f }, + { 1.0f, 5, 0.8f, -0.3f }, + { 1.5f, 4, 0.4f, 0.3f }, + { 2.0f, 5, 0.8f, -0.3f }, + { 2.5f, 4, 0.4f, 0.3f }, + { 3.0f, 5, 0.8f, -0.3f }, + { 3.5f, 4, 0.4f, 0.3f }, }; -static const TrackerEvent PATTERN_EVENTS_hihat_16th[] = { - { 0.0f, 9, 0.7f, -0.4f }, - { 0.2f, 7, 0.3f, 0.4f }, - { 0.5f, 9, 0.6f, -0.2f }, - { 0.8f, 7, 0.3f, 0.2f }, - { 1.0f, 9, 0.7f, -0.4f }, - { 1.2f, 7, 0.3f, 0.4f }, - { 1.5f, 9, 0.6f, -0.2f }, - { 1.8f, 7, 0.3f, 0.2f }, - { 2.0f, 9, 0.7f, -0.4f }, - { 2.2f, 7, 0.3f, 0.4f }, - { 2.5f, 9, 0.6f, -0.2f }, - { 2.8f, 7, 0.3f, 0.2f }, - { 3.0f, 9, 0.7f, -0.4f }, - { 3.2f, 7, 0.3f, 0.4f }, - { 3.5f, 9, 0.6f, -0.2f }, - { 3.8f, 7, 0.3f, 0.2f }, -}; -static const TrackerEvent PATTERN_EVENTS_ride_pattern[] = { - { 0.0f, 12, 0.6f, 0.5f }, - { 0.5f, 12, 0.5f, -0.3f }, - { 1.0f, 12, 0.6f, 0.5f }, - { 1.5f, 12, 0.5f, -0.3f }, - { 2.0f, 12, 0.6f, 0.5f }, - { 2.5f, 12, 0.5f, -0.3f }, - { 3.0f, 12, 0.7f, 0.5f }, - { 3.5f, 12, 0.5f, -0.3f }, -}; -static const TrackerEvent PATTERN_EVENTS_crash_accent[] = { - { 0.0f, 11, 0.9f, 0.0f }, +static const TrackerEvent PATTERN_EVENTS_kick_dense[] = { + { 0.0f, 0, 1.0f, 0.0f }, + { 0.5f, 1, 0.6f, -0.2f }, + { 1.0f, 0, 1.0f, 0.0f }, + { 1.5f, 1, 0.6f, 0.2f }, + { 2.0f, 0, 1.0f, 0.0f }, + { 2.5f, 1, 0.6f, -0.2f }, + { 3.0f, 0, 1.0f, 0.0f }, + { 3.5f, 1, 0.6f, 0.2f }, }; -static const TrackerEvent PATTERN_EVENTS_splash_accent[] = { - { 0.0f, 13, 0.8f, 0.3f }, +static const TrackerEvent PATTERN_EVENTS_snare_dense[] = { + { 0.5f, 3, 0.7f, 0.0f }, + { 1.0f, 2, 0.9f, 0.1f }, + { 1.5f, 3, 0.7f, 0.0f }, + { 2.5f, 3, 0.7f, 0.0f }, + { 3.0f, 2, 0.9f, 0.1f }, + { 3.5f, 3, 0.7f, 0.0f }, }; -static const TrackerEvent PATTERN_EVENTS_snare_fill[] = { - { 0.0f, 4, 0.6f, -0.4f }, - { 0.2f, 4, 0.6f, -0.2f }, - { 0.5f, 4, 0.7f, 0.0f }, - { 0.8f, 5, 0.8f, 0.2f }, - { 1.0f, 5, 0.8f, 0.4f }, - { 1.2f, 6, 0.9f, 0.2f }, - { 1.5f, 6, 0.9f, 0.0f }, - { 1.8f, 6, 0.9f, -0.2f }, +static const TrackerEvent PATTERN_EVENTS_crash[] = { + { 0.0f, 6, 0.9f, 0.0f }, }; -static const TrackerEvent PATTERN_EVENTS_power_riff[] = { - { 0.0f, 16, 0.8f, -0.5f }, - { 0.5f, 16, 0.6f, -0.5f }, - { 1.0f, 17, 0.8f, -0.3f }, - { 1.5f, 17, 0.6f, -0.3f }, - { 2.0f, 18, 0.8f, 0.3f }, - { 2.5f, 18, 0.6f, 0.3f }, - { 3.0f, 19, 0.8f, 0.5f }, - { 3.5f, 19, 0.6f, 0.5f }, +static const TrackerEvent PATTERN_EVENTS_bass_e[] = { + { 0.0f, 8, 0.9f, 0.0f }, + { 1.0f, 8, 0.7f, 0.0f }, + { 2.0f, 8, 0.9f, 0.0f }, + { 2.5f, 8, 0.6f, 0.0f }, + { 3.0f, 8, 0.7f, 0.0f }, }; -static const TrackerEvent PATTERN_EVENTS_lead_melody[] = { - { 0.0f, 20, 0.7f, 0.0f }, - { 0.5f, 21, 0.6f, 0.1f }, - { 1.0f, 22, 0.7f, -0.1f }, - { 1.5f, 23, 0.6f, 0.2f }, - { 2.0f, 24, 0.8f, -0.2f }, - { 2.5f, 23, 0.6f, 0.1f }, - { 3.0f, 22, 0.7f, 0.0f }, - { 3.5f, 25, 0.6f, -0.1f }, +static const TrackerEvent PATTERN_EVENTS_bass_eg[] = { + { 0.0f, 8, 0.9f, 0.0f }, + { 1.0f, 8, 0.7f, 0.0f }, + { 2.0f, 9, 0.9f, 0.0f }, + { 3.0f, 9, 0.7f, 0.0f }, }; -static const TrackerEvent PATTERN_EVENTS_bass_line[] = { - { 0.0f, 16, 0.9f, 0.0f }, - { 1.0f, 16, 0.8f, 0.0f }, - { 2.0f, 16, 0.9f, 0.0f }, - { 2.5f, 16, 0.7f, 0.0f }, - { 3.0f, 17, 0.9f, 0.0f }, +static const TrackerEvent PATTERN_EVENTS_melody_em[] = { + { 0.0f, 10, 0.7f, 0.0f }, + { 0.5f, 11, 0.6f, 0.1f }, + { 1.0f, 12, 0.7f, -0.1f }, + { 2.0f, 13, 0.6f, 0.0f }, + { 2.5f, 11, 0.6f, 0.1f }, + { 3.0f, 10, 0.7f, 0.0f }, }; const TrackerPattern g_tracker_patterns[] = { - { PATTERN_EVENTS_rock_beat, 5, 4.0f }, // rock_beat - { PATTERN_EVENTS_double_kick, 8, 4.0f }, // double_kick - { PATTERN_EVENTS_hihat_8th, 8, 4.0f }, // hihat_8th - { PATTERN_EVENTS_hihat_16th, 16, 4.0f }, // hihat_16th - { PATTERN_EVENTS_ride_pattern, 8, 4.0f }, // ride_pattern - { PATTERN_EVENTS_crash_accent, 1, 4.0f }, // crash_accent - { PATTERN_EVENTS_splash_accent, 1, 4.0f }, // splash_accent - { PATTERN_EVENTS_snare_fill, 8, 4.0f }, // snare_fill - { PATTERN_EVENTS_power_riff, 8, 4.0f }, // power_riff - { PATTERN_EVENTS_lead_melody, 8, 4.0f }, // lead_melody - { PATTERN_EVENTS_bass_line, 5, 4.0f }, // bass_line + { PATTERN_EVENTS_kick_basic, 3, 4.0f }, // kick_basic + { PATTERN_EVENTS_snare_basic, 2, 4.0f }, // snare_basic + { PATTERN_EVENTS_hihat_stressed, 8, 4.0f }, // hihat_stressed + { PATTERN_EVENTS_kick_dense, 8, 4.0f }, // kick_dense + { PATTERN_EVENTS_snare_dense, 6, 4.0f }, // snare_dense + { PATTERN_EVENTS_crash, 1, 4.0f }, // crash + { PATTERN_EVENTS_bass_e, 5, 4.0f }, // bass_e + { PATTERN_EVENTS_bass_eg, 4, 4.0f }, // bass_eg + { PATTERN_EVENTS_melody_em, 6, 4.0f }, // melody_em }; -const uint32_t g_tracker_patterns_count = 11; +const uint32_t g_tracker_patterns_count = 9; static const TrackerPatternTrigger SCORE_TRIGGERS[] = { { 0.0f, 5 }, - { 0.0f, 2 }, { 0.0f, 0 }, - { 2.0f, 2 }, + { 0.0f, 1 }, + { 0.0f, 2 }, { 2.0f, 0 }, + { 2.0f, 1 }, + { 2.0f, 2 }, { 4.0f, 5 }, - { 4.0f, 2 }, { 4.0f, 0 }, - { 4.0f, 10 }, - { 6.0f, 2 }, + { 4.0f, 1 }, + { 4.0f, 2 }, { 6.0f, 0 }, - { 6.0f, 10 }, - { 8.0f, 6 }, - { 8.0f, 3 }, + { 6.0f, 1 }, + { 6.0f, 2 }, + { 8.0f, 5 }, + { 8.0f, 0 }, { 8.0f, 1 }, - { 8.0f, 10 }, - { 8.0f, 9 }, - { 10.0f, 3 }, + { 8.0f, 2 }, + { 10.0f, 5 }, + { 10.0f, 0 }, { 10.0f, 1 }, - { 10.0f, 10 }, - { 10.0f, 9 }, - { 12.0f, 5 }, - { 12.0f, 4 }, + { 10.0f, 2 }, + { 10.0f, 6 }, + { 12.0f, 0 }, { 12.0f, 1 }, - { 12.0f, 8 }, - { 14.0f, 4 }, + { 12.0f, 2 }, + { 12.0f, 6 }, + { 14.0f, 0 }, { 14.0f, 1 }, - { 14.0f, 8 }, - { 16.0f, 7 }, + { 14.0f, 2 }, + { 14.0f, 6 }, + { 16.0f, 5 }, { 16.0f, 3 }, - { 17.0f, 6 }, - { 17.0f, 2 }, - { 17.0f, 0 }, - { 17.0f, 10 }, - { 18.0f, 5 }, + { 16.0f, 4 }, + { 16.0f, 2 }, + { 16.0f, 6 }, { 18.0f, 3 }, - { 18.0f, 1 }, - { 18.0f, 10 }, - { 18.0f, 9 }, + { 18.0f, 4 }, + { 18.0f, 2 }, + { 18.0f, 7 }, + { 20.0f, 5 }, { 20.0f, 3 }, - { 20.0f, 1 }, - { 20.0f, 10 }, - { 20.0f, 8 }, - { 22.0f, 7 }, + { 20.0f, 4 }, + { 20.0f, 2 }, + { 20.0f, 6 }, { 22.0f, 3 }, - { 23.0f, 5 }, - { 23.0f, 0 }, - { 23.0f, 10 }, - { 25.0f, 5 }, + { 22.0f, 4 }, + { 22.0f, 2 }, + { 22.0f, 6 }, + { 24.0f, 3 }, + { 24.0f, 4 }, + { 24.0f, 2 }, + { 24.0f, 7 }, + { 26.0f, 5 }, + { 26.0f, 0 }, + { 26.0f, 1 }, + { 26.0f, 2 }, + { 26.0f, 6 }, + { 28.0f, 0 }, + { 28.0f, 1 }, + { 28.0f, 2 }, + { 28.0f, 7 }, + { 30.0f, 5 }, + { 30.0f, 0 }, + { 30.0f, 1 }, + { 30.0f, 2 }, + { 30.0f, 6 }, + { 30.0f, 8 }, + { 32.0f, 0 }, + { 32.0f, 1 }, + { 32.0f, 2 }, + { 32.0f, 7 }, + { 32.0f, 8 }, + { 34.0f, 0 }, + { 34.0f, 1 }, + { 34.0f, 2 }, + { 34.0f, 6 }, + { 34.0f, 8 }, + { 36.0f, 5 }, + { 36.0f, 0 }, + { 36.0f, 1 }, + { 36.0f, 2 }, + { 36.0f, 7 }, + { 36.0f, 8 }, + { 38.0f, 5 }, }; const TrackerScore g_tracker_score = { - SCORE_TRIGGERS, 49, 120.0f + SCORE_TRIGGERS, 85, 120.0f }; // Resource usage analysis: -// Maximum simultaneous pattern triggers: 5 -// Recommended MAX_VOICES: 10 (current: see synth.h) -// Recommended MAX_SPECTROGRAMS: 10 (current: see synth.h) +// Maximum simultaneous pattern triggers: 6 +// Recommended MAX_VOICES: 12 (current: see synth.h) +// Recommended MAX_SPECTROGRAMS: 12 (current: see synth.h) diff --git a/src/tests/test_tracker.cc b/src/tests/test_tracker.cc index ea1debd..7ef7172 100644 --- a/src/tests/test_tracker.cc +++ b/src/tests/test_tracker.cc @@ -24,25 +24,42 @@ void test_tracker_pattern_triggering() { synth_init(); tracker_init(); - // Test 1: Trigger patterns at 0.0f + // At time 0.0f, 4 patterns are triggered: + // - crash (1 event at beat 0.0) + // - kick_basic (events at beat 0.0, 2.0, 2.5) + // - snare_basic (events at beat 1.0, 3.0) + // - hihat_stressed (events at beat 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5) + // With the new 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); - printf("Actual active voice count: %d\n", synth_get_active_voice_count()); - // Expect 4 voices (one for each pattern triggered at 0.0f: - // crash, kick_basic, snare_basic, hihat_stressed) - assert(synth_get_active_voice_count() == 4); + printf("Actual active voice count at 0.0f: %d\n", + synth_get_active_voice_count()); + // Expect 3 voices: crash (beat 0.0), kick_basic (beat 0.0), hihat_stressed + // (beat 0.0) + assert(synth_get_active_voice_count() == 3); - // Test 2: Advance time slightly - tracker_update(0.1f); + // 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); + printf("Actual active voice count at 0.25f: %d\n", + synth_get_active_voice_count()); + // Expect 4 voices (3 previous + 1 new hihat) assert(synth_get_active_voice_count() == 4); - // Test 3: Advance further, no new triggers until 4.0f - tracker_update(3.0f); - // Voices from 0.0f triggers might have ended, but new ones haven't started. - // synth_get_active_voice_count might drop if previous voices ended. - // For this test, we assume voices triggered at 0.0f are still active for a - // short duration. A more robust test would check for specific spectrograms or - // mock synth. For now, we expect voices to still be somewhat active or new - // ones to be triggered if there's overlap + // Test 3: At music_time = 0.5f (beat 1.0), snare event triggers + tracker_update(0.5f); + printf("Actual active voice count at 0.5f: %d\n", + synth_get_active_voice_count()); + // Expect 6 voices (4 previous + snare + hihat at beat 1.0) + assert(synth_get_active_voice_count() == 6); + + // Test 4: Advance further to 2.0f (beat 4.0), new pattern triggers at 2.0f + tracker_update(2.0f); + printf("Actual active voice count at 2.0f: %d\n", + synth_get_active_voice_count()); + // Multiple events have triggered by now assert(synth_get_active_voice_count() > 0); printf("Tracker pattern triggering test PASSED\n"); |
