From 5d2ec00c0179d1ee1b07883511d34dac272c680f Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 2 Feb 2026 22:05:50 +0100 Subject: feat: Integrate tracker system and update project context documentation - Implemented the basic tracker system with runtime support (tracker.h, tracker.cc). - Added a sample music track file (assets/music.track). - Created a tracker compiler tool (tools/tracker_compiler.cc) to generate music data. - Updated CMakeLists.txt to build the tracker compiler and integrate generated data. - Updated GEMINI.md to reflect new file locations and project context. --- src/audio/tracker.cc | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/audio/tracker.h | 42 +++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 src/audio/tracker.cc create mode 100644 src/audio/tracker.h (limited to 'src/audio') diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc new file mode 100644 index 0000000..0b57ce3 --- /dev/null +++ b/src/audio/tracker.cc @@ -0,0 +1,95 @@ +// 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++; + } +} diff --git a/src/audio/tracker.h b/src/audio/tracker.h new file mode 100644 index 0000000..d97b483 --- /dev/null +++ b/src/audio/tracker.h @@ -0,0 +1,42 @@ +// This file is part of the 64k demo project. +// It defines the tracker system for music composition. + +#pragma once + +#include "audio/gen.h" +#include + +struct TrackerEvent { + float beat; + uint16_t sample_id; + float volume; + float pan; +}; + +struct TrackerPattern { + const TrackerEvent* events; + uint32_t num_events; + float num_beats; +}; + +struct TrackerPatternTrigger { + float time_sec; + uint16_t pattern_id; + // Modifiers could be added here +}; + +struct TrackerScore { + const TrackerPatternTrigger* triggers; + uint32_t num_triggers; + float bpm; +}; + +// Global music data generated by tracker_compiler +extern const NoteParams g_tracker_samples[]; +extern const uint32_t g_tracker_samples_count; +extern const TrackerPattern g_tracker_patterns[]; +extern const uint32_t g_tracker_patterns_count; +extern const TrackerScore g_tracker_score; + +void tracker_init(); +void tracker_update(float time_sec); -- cgit v1.2.3