diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-02 22:05:50 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-02 22:05:50 +0100 |
| commit | 5d2ec00c0179d1ee1b07883511d34dac272c680f (patch) | |
| tree | bdb50394baa8c5df1ac64e39a9560b0d5d8e0fcc /src/audio | |
| parent | 4fc02a8d2acf1eafce36c1348261890d54b8b5b5 (diff) | |
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.
Diffstat (limited to 'src/audio')
| -rw-r--r-- | src/audio/tracker.cc | 95 | ||||
| -rw-r--r-- | src/audio/tracker.h | 42 |
2 files changed, 137 insertions, 0 deletions
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 <vector> + +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<float> 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<float> 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 <cstdint> + +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); |
