// This file is part of the 64k demo project. // It implements the tracker runtime logic. #include "tracker.h" #include "audio/synth.h" #include static uint32_t g_last_trigger_idx = 0; struct ManagedSpectrogram { int synth_id; float* data; bool active; }; // Simple pool for dynamic spectrograms static ManagedSpectrogram g_spec_pool[MAX_SPECTROGRAMS]; void tracker_init() { g_last_trigger_idx = 0; for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { g_spec_pool[i].synth_id = -1; g_spec_pool[i].data = nullptr; g_spec_pool[i].active = false; } } static int get_free_pool_slot() { for (int i = 0; i < MAX_SPECTROGRAMS; ++i) { if (!g_spec_pool[i].active) return i; } // If no free slot, find one where the synth voice is inactive // (In a real implementation, we'd check if any voice is still using this) // For now, just wrap around or return -1 return -1; } 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]; if (trigger.time_sec > time_sec) break; // Trigger pattern! const TrackerPattern& pattern = g_tracker_patterns[trigger.pattern_id]; // Generate spectrogram for the pattern int dest_num_frames = 0; std::vector pattern_data; float beat_to_sec = 60.0f / g_tracker_score.bpm; for (uint32_t i = 0; i < pattern.num_events; ++i) { const TrackerEvent& event = pattern.events[i]; const NoteParams& params = g_tracker_samples[event.sample_id]; int note_frames = 0; std::vector note_data = generate_note_spectrogram(params, ¬e_frames); 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); } // Register with synth int slot = get_free_pool_slot(); if (slot != -1) { // Clean up old if needed if (g_spec_pool[slot].synth_id != -1) { synth_unregister_spectrogram(g_spec_pool[slot].synth_id); delete[] g_spec_pool[slot].data; } g_spec_pool[slot].data = new float[pattern_data.size()]; memcpy(g_spec_pool[slot].data, pattern_data.data(), pattern_data.size() * sizeof(float)); 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; 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, 1.0f, 0.0f); } g_last_trigger_idx++; } }