summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio/audio.cc18
-rw-r--r--src/audio/audio.h11
-rw-r--r--src/audio/tracker.cc75
-rw-r--r--src/audio/tracker.h2
-rw-r--r--src/main.cc43
-rw-r--r--src/tests/test_spectool.cc9
-rw-r--r--src/tests/test_tracker.cc27
7 files changed, 81 insertions, 104 deletions
diff --git a/src/audio/audio.cc b/src/audio/audio.cc
index e4abbf8..ad324c0 100644
--- a/src/audio/audio.cc
+++ b/src/audio/audio.cc
@@ -3,6 +3,7 @@
// Implementation uses miniaudio for cross-platform support.
#include "audio.h"
+#include "util/asset_manager.h"
#if !defined(DEMO_BUILD_TOOLS)
#define MA_NO_FLAC
@@ -16,6 +17,23 @@
#include <stdio.h>
+int register_spec_asset(AssetId id) {
+ size_t size;
+ const uint8_t* data = GetAsset(id, &size);
+ if (!data || size < sizeof(SpecHeader))
+ return -1;
+
+ const SpecHeader* header = (const SpecHeader*)data;
+ const float* spectral_data = (const float*)(data + sizeof(SpecHeader));
+
+ Spectrogram spec;
+ spec.spectral_data_a = spectral_data;
+ spec.spectral_data_b = spectral_data; // No double-buffer for static assets
+ spec.num_frames = header->num_frames;
+
+ return synth_register_spectrogram(&spec);
+}
+
static ma_device g_device;
void audio_data_callback(ma_device* pDevice, void* pOutput, const void* pInput,
diff --git a/src/audio/audio.h b/src/audio/audio.h
index 24db18f..a1ddb44 100644
--- a/src/audio/audio.h
+++ b/src/audio/audio.h
@@ -3,6 +3,15 @@
// Includes initialization, shutdown, and frame updates.
#pragma once
+#include "generated/assets.h"
+#include <cstdint>
+
+struct SpecHeader {
+ char magic[4];
+ int32_t version;
+ int32_t dct_size;
+ int32_t num_frames;
+};
void audio_init();
void audio_start(); // Starts the audio device callback
@@ -11,3 +20,5 @@ void audio_render_silent(float duration_sec); // Fast-forwards audio state
#endif /* !defined(STRIP_ALL) */
void audio_update();
void audio_shutdown();
+
+int register_spec_asset(AssetId id);
diff --git a/src/audio/tracker.cc b/src/audio/tracker.cc
index 9f9263d..5d99a45 100644
--- a/src/audio/tracker.cc
+++ b/src/audio/tracker.cc
@@ -1,8 +1,7 @@
-// This file is part of the 64k demo project.
-// It implements the tracker runtime logic.
-
#include "tracker.h"
+#include "audio.h"
#include "audio/synth.h"
+#include "util/asset_manager.h"
#include <cstring>
#include <vector>
@@ -31,9 +30,6 @@ static int get_free_pool_slot() {
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;
}
@@ -45,10 +41,8 @@ void tracker_update(float time_sec) {
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;
@@ -56,39 +50,54 @@ void tracker_update(float time_sec) {
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];
-
+
+ std::vector<float> note_data;
int note_frames = 0;
- std::vector<float> note_data =
- generate_note_spectrogram(params, &note_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);
- }
+ 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, &note_frames);
+ }
- // 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;
+ 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 (dest_num_frames > 0) {
+ int slot = get_free_pool_slot();
+ if (slot != -1) {
+ 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));
+ 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;
+ 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;
+ 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);
+ 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
index d97b483..49fcd3c 100644
--- a/src/audio/tracker.h
+++ b/src/audio/tracker.h
@@ -4,6 +4,7 @@
#pragma once
#include "audio/gen.h"
+#include "generated/assets.h"
#include <cstdint>
struct TrackerEvent {
@@ -34,6 +35,7 @@ struct TrackerScore {
// Global music data generated by tracker_compiler
extern const NoteParams g_tracker_samples[];
extern const uint32_t g_tracker_samples_count;
+extern const AssetId g_tracker_sample_assets[];
extern const TrackerPattern g_tracker_patterns[];
extern const uint32_t g_tracker_patterns_count;
extern const TrackerScore g_tracker_score;
diff --git a/src/main.cc b/src/main.cc
index 97732da..7114460 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -19,30 +19,6 @@
#define SPEC_FRAMES 16
-struct SpecHeader {
- char magic[4];
- int32_t version;
- int32_t dct_size;
- int32_t num_frames;
-};
-
-int register_spec_asset(AssetId id) {
- size_t size;
- const uint8_t* data = GetAsset(id, &size);
- if (!data || size < sizeof(SpecHeader))
- return -1;
-
- const SpecHeader* header = (const SpecHeader*)data;
- const float* spectral_data = (const float*)(data + sizeof(SpecHeader));
-
- Spectrogram spec;
- spec.spectral_data_a = spectral_data;
- spec.spectral_data_b = spectral_data; // No double-buffer for static assets
- spec.num_frames = header->num_frames;
-
- return synth_register_spectrogram(&spec);
-}
-
static float* g_spec_buffer_a[SPEC_FRAMES * DCT_SIZE] = {0};
static float* g_spec_buffer_b[SPEC_FRAMES * DCT_SIZE] = {0};
@@ -107,10 +83,6 @@ int main(int argc, char** argv) {
synth_init();
tracker_init();
- int kick_id = register_spec_asset(AssetId::ASSET_KICK_1);
- int snare_id = register_spec_asset(AssetId::ASSET_SNARE_1);
- int hihat_id = register_spec_asset(AssetId::ASSET_HIHAT_1);
-
// Still keep the dynamic tone for bass (can be integrated into tracker too)
const float* g_spec_buffer_a = generate_tone(nullptr, 110.0f); // A2
const float* g_spec_buffer_b = generate_tone(nullptr, 110.0f);
@@ -130,21 +102,6 @@ int main(int argc, char** argv) {
const int step = beat_count % 16;
- // Kick on 1, 9, 11, 14...
- if (step == 0 || step == 8 || step == 10 || step == 13) {
- synth_trigger_voice(kick_id, 0.6f, 0.0f);
- }
-
- // Snare on 4, 12
- if (step == 4 || step == 12) {
- synth_trigger_voice(snare_id, 0.48f, step & 8 ? -1.0f : 1.0f);
- }
-
- // Hihat on every offbeat
- if (step % 2 == 1) {
- synth_trigger_voice(hihat_id, 0.3f, 0.3f);
- }
-
// Bass pattern
if (step % 4 == 0) {
float* back_buffer = synth_begin_update(bass_id);
diff --git a/src/tests/test_spectool.cc b/src/tests/test_spectool.cc
index 37a74b7..984322a 100644
--- a/src/tests/test_spectool.cc
+++ b/src/tests/test_spectool.cc
@@ -11,14 +11,7 @@
#include "miniaudio.h"
-// Redefine SpecHeader to avoid including spectool internals if possible,
-// but for an E2E test we need to know the format.
-struct SpecHeader {
- char magic[4];
- int32_t version;
- int32_t dct_size;
- int32_t num_frames;
-};
+// struct SpecHeader { ... } -> now in audio.h
void generate_test_wav(const char* path, int duration_seconds) {
ma_encoder_config config =
diff --git a/src/tests/test_tracker.cc b/src/tests/test_tracker.cc
index 95e746b..ad84163 100644
--- a/src/tests/test_tracker.cc
+++ b/src/tests/test_tracker.cc
@@ -25,28 +25,15 @@ void test_tracker_pattern_triggering() {
synth_init();
tracker_init();
- // Need a minimal set of samples for generation
- // These values should match what's expected by the music.track file
- // For testing purposes, we define dummy data here. In a real scenario,
- // we'd rely on the generated g_tracker_samples, g_tracker_patterns, etc.
- // This test focuses on the logic of tracker_update, not the full audio generation pipeline.
-
- // Assuming g_tracker_score, g_tracker_patterns, and g_tracker_samples are available globally
- // after tracker_compiler has run.
-
- // Test 1: No triggers initially, active voices should be 0
+ // Test 1: Trigger patterns at 0.0f
tracker_update(0.0f);
- assert(synth_get_active_voice_count() == 2); // Expect 2 voices (one for each pattern triggered at 0.0f)
-
- // Test 2: Advance time to first trigger (0.0f in music.track for drum_loop and hihat_roll)
- // In our dummy music.track, there are two patterns triggered at 0.0f
- // Each pattern has multiple events which trigger voices.
- tracker_update(0.1f); // Advance just past the 0.0f trigger point
+ printf("Actual active voice count: %d\n", synth_get_active_voice_count());
+ // Expect 3 voices (one for each pattern triggered at 0.0f: drum_loop, hihat_roll, em_melody)
+ assert(synth_get_active_voice_count() == 3);
- // The exact number of voices depends on the music.track content.
- // For the given music.track, two patterns are triggered at 0.0f.
- // Each pattern registers one spectrogram and triggers one voice.
- assert(synth_get_active_voice_count() == 2);
+ // Test 2: Advance time slightly
+ tracker_update(0.1f);
+ assert(synth_get_active_voice_count() == 3);
// Test 3: Advance further, no new triggers until 4.0f
tracker_update(3.0f);