ETH Price: $4,644.33 (-0.38%)

Input Data Messages (IDM)

Decentralized communication on Ethereum.

Filter by:
29,936 IDM
Age:30D
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6IjI3YjNjMDZiLWY0NGItNGY1Yi1iNDcxLTg3YTdjNWM3MTBlYiIsIm9yZGVySWRlbnRpZmllciI6IjQwM2VlZDcxLWRjNDctNGE3My04YmY2LTc1M2E5MDc4MWQ5YSIsImlhdCI6MTc1NTY1MjA2M30.-AL-BYjhk0gxa9585wcE6uoC8AhzPbXcDuORcAtM0o8------END MEMO------
at txn 0xe6b0b67883eb0153a384c75b6da195300623d7de5b875ec7cfdf404545c369dd Aug-20-2025 01:08:23 AM UTC (26 days ago)
data:,{"targetChain":"10143","targetAddress":"0x3e0854B443ff1c2599c8E6A4F18446fA92a66B17","action":"gas_deposit"}
at txn 0x25d41757068953b914f22e3b6faf27a624c9275093f3614f71a1c57ded400d9e Aug-20-2025 01:07:11 AM UTC (26 days ago)
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6Ijc5N2NmMGU3LWU5MDgtNDhjZi04NWFhLTY5OGI3OWRmYWVmMCIsIm9yZGVySWRlbnRpZmllciI6ImQ4MzBmZTM4LWY5MTUtNDFiMy05NmY3LWQ3MzZmZjM0YzJmOSIsImlhdCI6MTc1NTY1MTQxOH0.RbZKbLJVugWNP9OIZVJl47B096MJ4pwjcUy7PIdMxow------END MEMO------
at txn 0xc6aa7076f6cb8fa339ac2296c7047be17decba042bcde2ba07a414b4e735bf23 Aug-20-2025 12:57:59 AM UTC (26 days ago)

{"BlockHash":"0x44d36d6c26ebe70302e4fc3ca17cfaf179561046424057a5ca90b0b1519117df","Sender":"5GCc8penY3wGsmaq8ZgeTW7TgEfN76tZGvAnUZ2ZqmMbPWqj","Nonce":3892,"Commitment":"0x250b0c60f7313e4294546f5eaa8ecba08a056f76aae506e916e8711e6b045ed0"}
at txn 0xabaa602e23c734cd0c80338f216b669de6a08ef15fd1d3854aaef120ea0894c1 Aug-20-2025 12:52:11 AM UTC (26 days ago)
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6IjIzNjQxZWRhLWRjYzgtNDY0NS04MjIyLTZmMGJkY2FmNGQ4YyIsIm9yZGVySWRlbnRpZmllciI6IjdmYmRmNTg4LTI5ZGYtNGI0OC05MzdmLWI1NmE2YTQyODM0ZSIsImlhdCI6MTc1NTY1MDg2Nn0.89f6fv_xb47htYbyBcwhVCEp3jywE-vvWHCN3wlVPGI------END MEMO------
at txn 0x3145129dfaded9c849b0fc17a5d354f0328ecccfa4fa0964616314739e1ad63b Aug-20-2025 12:49:23 AM UTC (26 days ago)
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6ImExZDM1OGFkLTBlNmEtNGM2OC1iZmEwLWRlZDlkYTkzZTBmMSIsIm9yZGVySWRlbnRpZmllciI6IjA1OTJjMDk2LTNiMmQtNDU5MC04NzQyLWNjMmQyNzc0YjFlNyIsImlhdCI6MTc1NTY1MDg5M30.ILZ09U4mghN49aer0HAwh5wvTTjIwp-i_m76Af7T08w------END MEMO------
at txn 0xff8c45d59ab570af9fdc4a1aeb1ede62fda403397e9d0ee6a5290ef76f649ea3 Aug-20-2025 12:48:35 AM UTC (26 days ago)

||FILE:src/wav_reader.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
#include <SDL.h>
#include "include/visual_types.h"

// WAV file header structure
typedef struct {
char riff[4]; // "RIFF"
uint32_t chunk_size; // File size - 8
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
uint32_t fmt_size; // Format chunk size
uint16_t audio_format; // Audio format (1 = PCM)
uint16_t num_channels; // Number of channels
uint32_t sample_rate; // Sample rate
uint32_t byte_rate; // Byte rate
uint16_t block_align; // Block align
uint16_t bits_per_sample; // Bits per sample
char data[4]; // "data"
uint32_t data_size; // Data size
} wav_header_t;

// Audio analysis data
typedef struct {
int16_t *samples; // Raw audio samples (stereo interleaved)
uint32_t sample_count; // Total samples (left + right)
uint32_t sample_rate; // Sample rate (44100)
uint16_t channels; // Number of channels (2 for stereo)
uint16_t bits_per_sample; // Bits per sample (16)

// Analysis data
float *rms_levels; // RMS levels per video frame
uint32_t num_frames; // Number of video frames
float duration_sec; // Total duration in seconds
float bpm; // Detected BPM (if available)
} audio_data_t;

static audio_data_t audio_data = {0};
static bool audio_loaded = false;
static SDL_AudioDeviceID audio_device = 0;
static uint32_t audio_position = 0; // Current playback position in samples
static uint32_t loop_point_samples = 0; // Where to loop back to (before delay tail)
static uint32_t musical_content_samples = 0; // Length of actual musical content

// Audio callback function for SDL2 with seamless looping
static void audio_callback(void *userdata, Uint8 *stream, int len) {
(void)userdata; // Unused

if (!audio_loaded) {
memset(stream, 0, len);
return;
}

int samples_needed = len / sizeof(int16_t);
int16_t *output = (int16_t *)stream;

for (int i = 0; i < samples_needed; i++) {
if (audio_position < musical_content_samples) {
// Normal playback of musical content
output[i] = audio_data.samples[audio_position];
audio_position++;
} else {
// Loop back to the beginning when musical content ends
audio_position = loop_point_samples;
output[i] = audio_data.samples[audio_position];
audio_position++;
}
}
}

// Load WAV file and extract audio data
bool load_wav_file(const char *filename) {
FILE *file = fopen(filename, "rb");
if (!file) {
printf("Error: Could not open WAV file: %s\n", filename);
return false;
}

wav_header_t header;
size_t read_bytes = fread(&header, sizeof(header), 1, file);
if (read_bytes != 1) {
printf("Error: Could not read WAV header\n");
fclose(file);
return false;
}

// Validate WAV header
if (strncmp(header.riff, "RIFF", 4) != 0 ||
strncmp(header.wave, "WAVE", 4) != 0 ||
strncmp(header.fmt, "fmt ", 4) != 0 ||
strncmp(header.data, "data", 4) != 0) {
printf("Error: Invalid WAV file format\n");
fclose(file);
return false;
}

// Store audio parameters
audio_data.sample_rate = header.sample_rate;
audio_data.channels = header.num_channels;
audio_data.bits_per_sample = header.bits_per_sample;
audio_data.sample_count = header.data_size / (header.bits_per_sample / 8);
audio_data.duration_sec = (float)audio_data.sample_count / header.num_channels / header.sample_rate;

printf("WAV Info: %d Hz, %d channels, %d bits, %.2f seconds\n",
audio_data.sample_rate, audio_data.channels,
audio_data.bits_per_sample, audio_data.duration_sec);

// Only support 16-bit stereo for now
if (header.bits_per_sample != 16 || header.num_channels != 2) {
printf("Error: Only 16-bit stereo WAV files supported\n");
fclose(file);
return false;
}

// Allocate memory for samples
audio_data.samples = malloc(header.data_size);
if (!audio_data.samples) {
printf("Error: Could not allocate memory for audio samples\n");
fclose(file);
return false;
}

// Read audio data
read_bytes = fread(audio_data.samples, header.data_size, 1, file);
if (read_bytes != 1) {
printf("Error: Could not read audio data\n");
free(audio_data.samples);
fclose(file);
return false;
}

fclose(file);

// Calculate RMS levels per video frame
audio_data.num_frames = (uint32_t)(audio_data.duration_sec * VIS_FPS);
audio_data.rms_levels = malloc(audio_data.num_frames * sizeof(float));
if (!audio_data.rms_levels) {
printf("Error: Could not allocate memory for RMS levels\n");
free(audio_data.samples);
return false;
}

// Calculate RMS for each video frame
uint32_t samples_per_frame = audio_data.sample_rate / VIS_FPS;
for (uint32_t frame = 0; frame < audio_data.num_frames; frame++) {
uint32_t start_sample = frame * samples_per_frame * audio_data.channels;
uint32_t end_sample = start_sample + samples_per_frame * audio_data.channels;

if (end_sample > audio_data.sample_count) {
end_sample = audio_data.sample_count;
}

// Calculate RMS for this frame
float sum_squares = 0.0f;
uint32_t sample_count = 0;

for (uint32_t i = start_sample; i < end_sample; i++) {
float sample = audio_data.samples[i] / 32768.0f; // Normalize to -1.0 to 1.0
sum_squares += sample * sample;
sample_count++;
}

if (sample_count > 0) {
audio_data.rms_levels[frame] = sqrtf(sum_squares / sample_count);
} else {
audio_data.rms_levels[frame] = 0.0f;
}
}

// Try to extract BPM from filename (our audio system outputs BPM info)
audio_data.bpm = 120.0f; // Default fallback

printf("Audio analysis complete: %d frames, %.3f avg RMS\n",
audio_data.num_frames, audio_data.rms_levels[0]);

// Initialize SDL audio for playback
if (SDL_WasInit(SDL_INIT_AUDIO) == 0) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
printf("Warning: Could not initialize SDL audio: %s\n", SDL_GetError());
audio_loaded = true;
return true; // Continue without audio playback
}
}

SDL_AudioSpec want, have;
want.freq = audio_data.sample_rate;
want.format = AUDIO_S16SYS;
want.channels = audio_data.channels;
want.samples = 4096;
want.callback = audio_callback;
want.userdata = NULL;

audio_device = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
if (audio_device == 0) {
printf("Warning: Could not open audio device: %s\n", SDL_GetError());
audio_loaded = true;
return true; // Continue without audio playback
}

printf("Audio playback initialized: %d Hz, %d channels\n", have.freq, have.channels);

// Calculate musical content length based on BPM and structure
// Our audio system generates 8 bars of music, but let's use a more conservative estimate
// The delay tail is probably the last 1.5-2 seconds, so loop the first ~7.5 seconds
float musical_duration = audio_data.duration_sec * 0.8f; // Use 80% of total duration

musical_content_samples = (uint32_t)(musical_duration * audio_data.sample_rate * audio_data.channels);

// Make sure we don't exceed the actual audio length
if (musical_content_samples > audio_data.sample_count) {
musical_content_samples = audio_data.sample_count;
}

loop_point_samples = 0; // Loop back to the very beginning

printf("Musical content: %.2f seconds (%d samples), Full audio: %.2f seconds\n",
musical_duration, musical_content_samples, audio_data.duration_sec);
printf("Will loop musical content, letting delay tail ring through naturally\n");

audio_loaded = true;
return true;
}

// Get RMS level for a specific frame (with looping)
float get_audio_rms_for_frame(int frame) {
if (!audio_loaded || audio_data.num_frames == 0) {
return 0.0f;
}

// Calculate how many frames represent the musical content
float musical_duration = (float)musical_content_samples / audio_data.sample_rate / audio_data.channels;
int musical_frames = (int)(musical_duration * VIS_FPS);

if (musical_frames > 0 && musical_frames < (int)audio_data.num_frames) {
// Loop only the musical content frames
int looped_frame = frame % musical_frames;
return audio_data.rms_levels[looped_frame];
} else {
// Fallback to full audio loop
int looped_frame = frame % audio_data.num_frames;
return audio_data.rms_levels[looped_frame];
}
}

// Get current audio time for frame
float get_audio_time_for_frame(int frame) {
if (!audio_loaded) return 0.0f;
return frame / (float)VIS_FPS;
}

// Get total duration
float get_audio_duration(void) {
return audio_loaded ? audio_data.duration_sec : 0.0f;
}

// Get BPM
float get_audio_bpm(void) {
return audio_loaded ? audio_data.bpm : 120.0f;
}

// Check if we've reached the end of the audio
bool is_audio_finished(int frame) {
if (!audio_loaded) return false;
return frame >= (int)audio_data.num_frames;
}

// Get max RMS for normalization
float get_max_rms(void) {
if (!audio_loaded) return 1.0f;

float max_rms = 0.0f;
for (uint32_t i = 0; i < audio_data.num_frames; i++) {
if (audio_data.rms_levels[i] > max_rms) {
max_rms = audio_data.rms_levels[i];
}
}
return max_rms > 0.0f ? max_rms : 1.0f;
}

// Start audio playback
void start_audio_playback(void) {
if (audio_device != 0) {
audio_position = 0; // Reset to beginning
SDL_PauseAudioDevice(audio_device, 0); // Start playback
printf("Audio playback started\n");
}
}

// Stop audio playback
void stop_audio_playback(void) {
if (audio_device != 0) {
SDL_PauseAudioDevice(audio_device, 1); // Pause playback
printf("Audio playback stopped\n");
}
}

// Get current playback position in seconds
float get_playback_position(void) {
if (!audio_loaded || audio_data.sample_rate == 0) return 0.0f;
return (float)audio_position / audio_data.channels / audio_data.sample_rate;
}

// Cleanup audio data
void cleanup_audio_data(void) {
if (audio_device != 0) {
SDL_CloseAudioDevice(audio_device);
audio_device = 0;
}

if (audio_loaded) {
free(audio_data.samples);
free(audio_data.rms_levels);
memset(&audio_data, 0, sizeof(audio_data));
audio_loaded = false;
}
}

// Print audio analysis info
void print_audio_info(void) {
if (!audio_loaded) {
printf("No audio loaded\n");
return;
}

printf("=== Audio Analysis ===\n");
printf("Duration: %.2f seconds\n", audio_data.duration_sec);
printf("Sample Rate: %d Hz\n", audio_data.sample_rate);
printf("Channels: %d\n", audio_data.channels);
printf("Video Frames: %d\n", audio_data.num_frames);
printf("Max RMS: %.3f\n", get_max_rms());
printf("BPM: %.1f\n", audio_data.bpm);
printf("=====================\n");
}
||ENDFILE||
||FILE:extract.py||
#!/usr/bin/env python3
"""
Robust file extractor for on-chain UTF-8 chunks.

Usage:
python3 extract.py # writes files into notdeafbeef_program/
python3 extract.py out_dir # writes into out_dir (created if absent)
"""

import sys, os, glob, re, hashlib, textwrap

FILE_START = b"||FILE:"
FILE_END = b"||ENDFILE||"

def natural_sort_key(path:str):
"""Order chunk_00, chunk_01, …, chunk_10 correctly."""
head, num, tail = re.match(r"(.*?)(\d+)(\D*)$", path).groups()
return (head, int(num), tail)

def read_chunks() -> bytes:
chunks = sorted(glob.glob("chunk_*.txt"), key=natural_sort_key)
if not chunks:
sys.exit("❌ No chunk_*.txt files found.")
print(f"🔍 Found {len(chunks)} chunk files")
buf_parts = []
for fp in chunks:
with open(fp, "rb") as f:
buf_parts.append(f.read())
return b"".join(buf_parts)

def safe_path(path:str, out_root:str) -> str:
"""Prevent path traversal and create parent dirs if needed."""
norm = os.path.normpath(path.lstrip("/\\"))
if norm.startswith(".."):
raise ValueError(f"Unsafe path outside tree: {path}")
abs_path = os.path.join(out_root, norm)
os.makedirs(os.path.dirname(abs_path), exist_ok=True)
return abs_path

def write_files(full_blob:bytes, out_root:str):
pos = 0
seen = {} # path -> sha256 digest
total = 0
while True:
start = full_blob.find(FILE_START, pos)
if start == -1: break
end_path = full_blob.find(b"||", start + len(FILE_START))
if end_path == -1:
raise ValueError("Malformed chunk: missing path terminator '||'")
raw_path = full_blob[start + len(FILE_START):end_path]
try:
path_str = raw_path.decode("utf-8")
except UnicodeDecodeError:
raise ValueError(f"Non-UTF8 chars in file path: {raw_path!r}")
content_start = end_path + 2
end_marker = full_blob.find(FILE_END, content_start)
if end_marker == -1:
raise ValueError(f"Missing ENDFILE for {path_str}")
content = full_blob[content_start:end_marker]
file_hash = hashlib.sha256(content).hexdigest()

# Skip extract.py from bundle (we're running our own version)
if path_str == 'extract.py':
print(f"⚠️ Skipped bundled {path_str}")
pos = end_marker + len(FILE_END)
continue

if path_str in seen:
if seen[path_str] != file_hash:
raise RuntimeError(
f"Duplicate path with different contents: {path_str}"
)
# identical duplicate – ignore
else:
out_fp = safe_path(path_str, out_root)
with open(out_fp, "wb") as out_f:
out_f.write(content)

# Set executable for shell scripts
if path_str.endswith('.sh'):
os.chmod(out_fp, 0o755)

seen[path_str] = file_hash
total += 1
print(f"✅ Wrote {path_str} ({len(content)} bytes)")

pos = end_marker + len(FILE_END)
print(f"\n🎉 Extraction complete: {total} unique files written to {out_root}/")
print("Next steps:")
print("1. Edit seed.s with your token's 32-byte seed")
print("2. Run: ./build.sh")
print("3. Output: nft_audio.wav + nft_final.mp4")

def main():
out_root = sys.argv[1] if len(sys.argv) > 1 else "notdeafbeef_program"
os.makedirs(out_root, exist_ok=True)
blob = read_chunks()
write_files(blob, out_root)

if __name__ == "__main__":
main()
||ENDFILE||
||NOTDEAFBEEF_MASTER_END||
at txn 0x341e52be42fbba0aeaf5b0259b3aac96b6dfc0c35f4875f45d6597eb429aca1b Aug-20-2025 12:47:59 AM UTC (26 days ago)

||FILE:src/timeline_reader.c||
#include "timeline.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

/* Minimal, robust-enough JSON scanner for our known format. Avoids dependencies. */

static char *read_file_all(const char *path, size_t *len_out){
FILE *f = fopen(path, "rb");
if(!f) return NULL;
fseek(f, 0, SEEK_END);
long len = ftell(f);
fseek(f, 0, SEEK_SET);
char *buf = (char*)malloc(len + 1);
if(!buf){ fclose(f); return NULL; }
if(fread(buf, 1, len, f) != (size_t)len){ free(buf); fclose(f); return NULL; }
buf[len] = '\0';
fclose(f);
if(len_out) *len_out = (size_t)len;
return buf;
}

static int parse_uint_array(const char *s, const char *key, uint32_t **out, uint32_t *count){
*out = NULL; *count = 0;
char needle[64];
snprintf(needle, sizeof(needle), "\"%s\": [", key);
const char *p = strstr(s, needle);
if(!p) return 0;
p += strlen(needle);
// count commas
const char *q = p;
uint32_t n = 0;
while(*q && *q != ']'){ if(*q == ',') n++; q++; }
if(*q != ']') return 0;
n = n + 1; // elements = commas + 1
uint32_t *arr = (uint32_t*)malloc(n * sizeof(uint32_t));
if(!arr) return 0;
uint32_t idx = 0;
const char *cur = p;
while(cur < q && idx < n){
while(cur < q && (*cur == ' ' || *cur == '\n')) cur++;
char *endp;
unsigned long v = strtoul(cur, &endp, 10);
arr[idx++] = (uint32_t)v;
cur = endp;
const char *comma = strchr(cur, ',');
if(comma && comma < q) cur = comma + 1; else break;
}
*out = arr;
*count = idx;
return 1;
}

static int parse_header_u32(const char *s, const char *key, uint32_t *out){
char needle[64];
snprintf(needle, sizeof(needle), "\"%s\": ", key);
const char *p = strstr(s, needle);
if(!p) return 0;
p += strlen(needle);
*out = (uint32_t)strtoul(p, NULL, 10);
return 1;
}

static int parse_header_f(const char *s, const char *key, float *out){
char needle[64];
snprintf(needle, sizeof(needle), "\"%s\": ", key);
const char *p = strstr(s, needle);
if(!p) return 0;
p += strlen(needle);
*out = strtof(p, NULL);
return 1;
}

static int parse_header_seed(const char *s, uint64_t *out){
const char *p = strstr(s, "\"seed\": \"");
if(!p) return 0;
p += strlen("\"seed\": \"");
char *endq = strchr(p, '\"');
if(!endq) return 0;
// Expect 0x... hex
char buf[32];
size_t len = (size_t)(endq - p);
if(len >= sizeof(buf)) len = sizeof(buf) - 1;
memcpy(buf, p, len); buf[len] = '\0';
*out = strtoull(buf, NULL, 16);
return 1;
}

bool timeline_load(const char *path, timeline_t *out){
memset(out, 0, sizeof(*out));
size_t len = 0; char *txt = read_file_all(path, &len);
if(!txt) return false;
if(!parse_header_seed(txt, &out->seed)) { free(txt); return false; }
if(!parse_header_u32(txt, "sample_rate", &out->sample_rate)) { free(txt); return false; }
if(!parse_header_f(txt, "bpm", &out->bpm)) { free(txt); return false; }
if(!parse_header_u32(txt, "step_samples", &out->step_samples)) { free(txt); return false; }
if(!parse_header_u32(txt, "total_samples", &out->total_samples)) { free(txt); return false; }
if(!parse_uint_array(txt, "steps", &out->steps, &out->steps_count)) { free(txt); return false; }
if(!parse_uint_array(txt, "beats", &out->beats, &out->beats_count)) { free(txt); return false; }

// Parse events array minimally: scan lines with {"time": X, "type": "name", "aux": Y}
const char *evs = strstr(txt, "\"events\": [");
if(!evs){ free(txt); return false; }
evs += strlen("\"events\": [");
const char *end = strstr(evs, "]");
if(!end){ free(txt); return false; }

// Rough count '{'
uint32_t count = 0; for(const char *p = evs; p < end; ++p){ if(*p == '{') count++; }
tl_event_t *events = (tl_event_t*)calloc(count, sizeof(tl_event_t));
if(!events){ free(txt); return false; }

const char *p = evs; uint32_t idx = 0;
while(p < end && idx < count){
const char *obj = strchr(p, '{');
if(!obj || obj >= end) break;
const char *obj_end = strchr(obj, '}'); if(!obj_end || obj_end > end) break;
// time
const char *tkey = strstr(obj, "\"time\": ");
const char *typekey = strstr(obj, "\"type\": \"");
const char *auxkey = strstr(obj, "\"aux\": ");
if(tkey && typekey && auxkey && tkey < obj_end && typekey < obj_end && auxkey < obj_end){
uint32_t time = (uint32_t)strtoul(tkey + 8, NULL, 10);
const char *ts = typekey + 9; const char *te = strchr(ts, '\"');
char tbuf[32]; size_t tlen = (size_t)(te - ts); if(tlen >= sizeof(tbuf)) tlen = sizeof(tbuf)-1; memcpy(tbuf, ts, tlen); tbuf[tlen] = '\0';
uint8_t type = 255;
if(strcmp(tbuf, "kick")==0) type = 0; else if(strcmp(tbuf, "snare")==0) type = 1; else if(strcmp(tbuf, "hat")==0) type = 2; else if(strcmp(tbuf, "melody")==0) type = 3; else if(strcmp(tbuf, "mid")==0) type = 4; else if(strcmp(tbuf, "fm_bass")==0) type = 5; else type = 254;
uint8_t aux = (uint8_t)strtoul(auxkey + 7, NULL, 10);
events[idx++] = (tl_event_t){ time, type, aux };
}
p = obj_end + 1;
}
out->events = events; out->events_count = idx;
free(txt);
return true;
}

void timeline_free(timeline_t *t){
if(!t) return;
free(t->steps); t->steps = NULL; t->steps_count = 0;
free(t->beats); t->beats = NULL; t->beats_count = 0;
free(t->events); t->events = NULL; t->events_count = 0;
}

/* Simple derived signals, mapped to 60 FPS. */
static float exp_env(float dt, float tau){ return expf(-dt / fmaxf(1e-6f, tau)); }

float timeline_compute_level(const timeline_t *t, int frame_idx, int fps){
if(!t) return 0.0f;
float sec = (float)frame_idx / (float)fps;
// Accumulate simple decays from recent kick + snare events
float level = 0.0f;
for(uint32_t i=0;i<t->events_count;i++){
uint8_t type = t->events[i].type;
if(type > 5) continue;
if(type==0 || type==1){ // kick/snare
float esec = (float)t->events[i].time / (float)t->sample_rate;
float dt = sec - esec; if(dt < 0) continue;
float amp = (type==0)? 1.0f : 0.6f;
level += amp * exp_env(dt, 0.2f);
}
}
if(level > 1.0f) level = 1.0f;
return level;
}

float timeline_compute_glitch(const timeline_t *t, int frame_idx, int fps){
if(!t) return 0.3f;
float sec = (float)frame_idx / (float)fps;
float g = 0.2f + 0.3f * sinf(sec * 3.0f);
// add treble-ish spikes from hat/melody
for(uint32_t i=0;i<t->events_count;i++){
uint8_t type = t->events[i].type;
if(type==2 || type==3){
float esec = (float)t->events[i].time / (float)t->sample_rate;
float dt = sec - esec; if(dt < 0) continue;
g += 0.1f * exp_env(dt, 0.08f);
}
}
if(g < 0.0f) g = 0.0f; if(g > 1.5f) g = 1.5f;
return g;
}

float timeline_compute_hue(const timeline_t *t, int frame_idx, int fps){
if(!t) return 0.5f;
float base = fmodf((float)frame_idx / (float)fps * 0.1f, 1.0f);
// small hue jumps on bass
for(uint32_t i=0;i<t->events_count;i++){
if(t->events[i].type==5){
float esec = (float)t->events[i].time / (float)t->sample_rate;
float dt = ((float)frame_idx / (float)fps) - esec; if(dt < 0) continue;
base += 0.05f * exp_env(dt, 0.4f);
}
}
base = fmodf(base, 1.0f);
if(base < 0) base += 1.0f;
return base;
}



||ENDFILE||
||FILE:src/vis_main.c||
#include <SDL.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <math.h>
#include "include/visual_types.h"

// Forward declarations for ASM visual functions
extern void clear_frame_asm(uint32_t *pixels, uint32_t color);
extern void init_terrain_asm(uint32_t seed, float base_hue);
extern void draw_terrain_asm(uint32_t *pixels, int frame);
extern void init_particles_asm(void);
extern void update_particles_asm(float elapsed_ms, float step_sec, float base_hue);
extern void draw_particles_asm(uint32_t *pixels);
extern void init_glitch_system_asm(uint32_t seed, float intensity);
extern void update_glitch_intensity_asm(float new_intensity);
extern void init_bass_hits_asm(void);
extern void spawn_bass_hit_asm(float cx, float cy, int shape_type, float base_hue);
extern void draw_bass_hits_asm(uint32_t *pixels, int frame);
extern uint32_t circle_color_asm(float hue, float saturation, float value);
extern void draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color);
extern void draw_ascii_string_asm(uint32_t *pixels, int x, int y, const char *text, uint32_t color, int bg_alpha);

// C functions that remain (system interface)
void draw_centerpiece(uint32_t *pixels, centerpiece_t *centerpiece, float time, float level, int frame);
void init_centerpiece(centerpiece_t *centerpiece, uint32_t seed, int bpm);
void init_degradation_effects(degradation_t *effects, uint32_t seed);
bool load_wav_file(const char *filename);
float get_audio_rms_for_frame(int frame);
float get_audio_bpm(void);
float get_max_rms(void);
bool is_audio_finished(int frame);
void print_audio_info(void);
void cleanup_audio_data(void);
void start_audio_playback(void);
void stop_audio_playback(void);

// Audio-visual mapping functions
void init_audio_visual_mapping(void);
float get_smoothed_audio_level(int frame);
bool detect_beat_onset(int frame);
float get_bass_energy(int frame);
float get_treble_energy(int frame);
void update_audio_visual_effects(int frame, float base_hue);
float get_audio_driven_glitch_intensity(int frame);
float get_audio_driven_hue_shift(int frame);

#define FRAME_TIME_MS (1000 / VIS_FPS)

typedef struct {
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
visual_context_t visual;
bool running;
} VisualContext;

static VisualContext ctx = {0};

static bool init_sdl(void) {
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
return false;
}

ctx.window = SDL_CreateWindow(
"NotDeafBeef Visual",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
VIS_WIDTH, VIS_HEIGHT,
SDL_WINDOW_SHOWN
);

if (!ctx.window) {
fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
return false;
}

ctx.renderer = SDL_CreateRenderer(ctx.window, -1, SDL_RENDERER_ACCELERATED);
if (!ctx.renderer) {
fprintf(stderr, "SDL_CreateRenderer failed: %s\n", SDL_GetError());
return false;
}

ctx.texture = SDL_CreateTexture(
ctx.renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
VIS_WIDTH, VIS_HEIGHT
);

if (!ctx.texture) {
fprintf(stderr, "SDL_CreateTexture failed: %s\n", SDL_GetError());
return false;
}

ctx.visual.pixels = calloc(VIS_WIDTH * VIS_HEIGHT, sizeof(uint32_t));
if (!ctx.visual.pixels) {
fprintf(stderr, "Failed to allocate pixel buffer\n");
return false;
}

// Load and analyze audio file
const char *wav_file = "src/c/seed_0xcafebabe.wav";
if (!load_wav_file(wav_file)) {
printf("Failed to load audio file: %s\n", wav_file);
printf("Falling back to test mode\n");
// Fallback to test parameters
ctx.visual.bpm = 120;
} else {
printf("Successfully loaded audio file!\n");
print_audio_info();
ctx.visual.bpm = (int)get_audio_bpm();
}

// Initialize visual system with real audio parameters
ctx.visual.seed = 0xcafebabe; // Match the WAV file seed
ctx.visual.frame = 0;
ctx.visual.time = 0.0f;
ctx.visual.step_sec = 60.0f / ctx.visual.bpm / 4.0f; // 16th note duration

init_centerpiece(&ctx.visual.centerpiece, ctx.visual.seed, ctx.visual.bpm);
init_degradation_effects(&ctx.visual.effects, ctx.visual.seed);

// Initialize ASM terrain system
init_terrain_asm(ctx.visual.seed, ctx.visual.centerpiece.base_hue);

// Initialize ASM particle system
init_particles_asm();

// Initialize ASM glitch system with medium intensity
init_glitch_system_asm(ctx.visual.seed, 0.6f);

// Initialize ASM bass hit system
init_bass_hits_asm();

// Initialize audio-visual mapping
init_audio_visual_mapping();

// Start audio playback
start_audio_playback();

ctx.running = true;
return true;
}

static void cleanup_sdl(void) {
stop_audio_playback();
cleanup_audio_data();
if (ctx.visual.pixels) free(ctx.visual.pixels);
if (ctx.texture) SDL_DestroyTexture(ctx.texture);
if (ctx.renderer) SDL_DestroyRenderer(ctx.renderer);
if (ctx.window) SDL_DestroyWindow(ctx.window);
SDL_Quit();
}

static void handle_events(void) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
ctx.running = false;
break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_ESCAPE) {
ctx.running = false;
}
break;
}
}
}

static void render_frame(void) {
// Clear to black using ASM
clear_frame_asm(ctx.visual.pixels, 0xFF000000);

// Update time and frame
ctx.visual.time = ctx.visual.frame / (float)VIS_FPS;

// Get enhanced audio analysis
float audio_level = get_smoothed_audio_level(ctx.visual.frame);
float bass_energy = get_bass_energy(ctx.visual.frame);
float treble_energy = get_treble_energy(ctx.visual.frame);

// Update dynamic base hue based on audio
ctx.visual.centerpiece.base_hue = get_audio_driven_hue_shift(ctx.visual.frame);

// Calculate elapsed time in segment (for particle timing) with looping
float segment_duration_ms = 9220.0f; // ~9.22 seconds from our audio
float elapsed_ms = fmod(ctx.visual.time * 1000.0f, segment_duration_ms);

// Update particles using ASM (handles explosions and physics)
update_particles_asm(elapsed_ms, ctx.visual.step_sec, ctx.visual.centerpiece.base_hue);

// Audio-reactive effects (particle explosions, bass hits)
update_audio_visual_effects(ctx.visual.frame, ctx.visual.centerpiece.base_hue);

// Update glitch intensity based on audio characteristics
float glitch_intensity = get_audio_driven_glitch_intensity(ctx.visual.frame);
update_glitch_intensity_asm(glitch_intensity);

// Draw orbiting centerpiece (C function with some ASM calls)
draw_centerpiece(ctx.visual.pixels, &ctx.visual.centerpiece, ctx.visual.time, audio_level, ctx.visual.frame);

// 🚀 CHAOS MODE RENDERING - Multiple layers with audio-reactive speed!
float chaos_level = get_smoothed_audio_level(ctx.visual.frame);

// 🔯 MULTI-LAYER BASS HITS - Draw multiple times for intensity!
for (int layer = 0; layer < (int)(chaos_level * 3) + 1; layer++) {
draw_bass_hits_asm(ctx.visual.pixels, ctx.visual.frame + layer * 5);
}

// 🏔️ HYPER-SPEED TERRAIN - Speed varies with audio!
int terrain_speed = (int)(1 + chaos_level * 8); // 1x to 9x speed
draw_terrain_asm(ctx.visual.pixels, ctx.visual.frame * terrain_speed);

// 💥 PARTICLE STORM - Draw multiple times for particle density!
for (int burst = 0; burst < (int)(chaos_level * 4) + 1; burst++) {
draw_particles_asm(ctx.visual.pixels);
}

// TODO: Add other visual elements
// - Audio-reactive elements
// - Post-processing effects

// Update texture with pixel buffer
SDL_UpdateTexture(ctx.texture, NULL, ctx.visual.pixels, VIS_WIDTH * sizeof(uint32_t));

// Render to screen
SDL_RenderClear(ctx.renderer);
SDL_RenderCopy(ctx.renderer, ctx.texture, NULL, NULL);
SDL_RenderPresent(ctx.renderer);

ctx.visual.frame++;
}

static void main_loop(void) {
uint32_t frame_start;
uint32_t frame_time;

while (ctx.running) {
frame_start = SDL_GetTicks();

handle_events();

// TODO: Get audio timing and sync visuals
// unsigned int audio_time = get_audio_time_ms();
// float rms = get_rms_level(frame_idx);

render_frame();

// Frame rate limiting
frame_time = SDL_GetTicks() - frame_start;
if (frame_time < FRAME_TIME_MS) {
SDL_Delay(FRAME_TIME_MS - frame_time);
}
}
}

int main(int argc, char *argv[]) {
printf("🌋 NUCLEAR CHAOS MODE VISUAL SYSTEM 💥\n");
printf("Resolution: %dx%d @ %d FPS\n", VIS_WIDTH, VIS_HEIGHT, VIS_FPS);

// Check for audio file argument
if (argc < 2) {
printf("Usage: %s <audio_file.wav>\n", argv[0]);
return 1;
}

// Load audio file for visual analysis
if (!load_wav_file(argv[1])) {
printf("Error: Could not load audio file: %s\n", argv[1]);
return 1;
}

printf("Successfully loaded audio file!\n");
print_audio_info();

if (!init_sdl()) {
cleanup_sdl();
return 1;
}

printf("SDL2 initialized successfully\n");
printf("🔥 CHAOS MODE ACTIVE - PREPARE FOR MADNESS! 🔥\n");
printf("Press ESC to exit\n");

// Initialize audio-visual mapping
init_audio_visual_mapping();

main_loop();

cleanup_sdl();
cleanup_audio_data();
printf("Visual system shutdown complete\n");
return 0;
}
||ENDFILE||
||FILE:src/visual_c_stubs.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "include/visual_types.h"

// External ASM visual functions we can use
extern uint32_t circle_color_asm(float hue, float saturation, float value);
extern void draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color);
extern void draw_ascii_string_asm(uint32_t *pixels, int x, int y, const char *text, uint32_t color, int bg_alpha);

// Centerpiece implementation using ASM functions
void draw_centerpiece(uint32_t *pixels, centerpiece_t *centerpiece, float time, float level, int frame) {
// Central orbiting elements driven by audio
int num_orbs = 6;
float base_radius = 100.0f + level * 50.0f;

for (int i = 0; i < num_orbs; i++) {
float angle = time * 0.5f + i * 2.0f * M_PI / num_orbs;
float radius = base_radius + 30.0f * sin(time * 0.7f + i);

int cx = 800 / 2 + (int)(radius * cos(angle)); // VIS_WIDTH
int cy = 600 / 2 + (int)(radius * sin(angle)); // VIS_HEIGHT
int orb_radius = 8 + (int)(level * 15);

float hue = fmod(centerpiece->base_hue + i * 0.15f + level * 0.1f, 1.0f);
uint32_t color = circle_color_asm(hue, 0.9f, 0.8f + level * 0.2f);

draw_circle_filled_asm(pixels, cx, cy, orb_radius, color);
}

// Add some text overlay
char info[64];
snprintf(info, sizeof(info), "BPM: %d | Mode: %d | Level: %.1f%%",
centerpiece->bpm, centerpiece->mode, level * 100.0f);

draw_ascii_string_asm(pixels, 10, 560, info, 0xFFCCCCCC, 128);
}

void init_centerpiece(centerpiece_t *centerpiece, uint32_t seed, int bpm) {
centerpiece->mode = VIS_MODE_RINGS; // Default mode
centerpiece->bpm = bpm;
centerpiece->orbit_radius = 100.0f;
centerpiece->base_hue = 0.0f;
centerpiece->orbit_speed = 0.5f;

// Vary based on seed
srand(seed);
centerpiece->base_hue = (rand() % 100) / 100.0f;
centerpiece->orbit_speed = 0.3f + (rand() % 50) / 100.0f;
}

void init_degradation_effects(degradation_t *effects, uint32_t seed) {
// Simple degradation effects based on seed
srand(seed);
effects->persistence = 0.8f + (rand() % 20) / 100.0f;
effects->scanline_alpha = 50 + (rand() % 100);
effects->chroma_shift = rand() % 5;
effects->noise_pixels = rand() % 1000;
effects->jitter_amount = (rand() % 10) / 100.0f;
effects->frame_drop_chance = 0.01f;
effects->color_bleed = 0.1f + (rand() % 20) / 100.0f;
}

// 🔥 CHAOS MODE STUB - Temporary fallback
void draw_bass_hits_asm(uint32_t *pixels, int frame) {
printf("CHAOS: Bass hits rendering at frame %d\n", frame);
}
||ENDFILE||
at txn 0xf706f2911130d88083f6566620f271938ceea2fcfd84c5fd668c3e48cd93d401 Aug-20-2025 12:47:47 AM UTC (26 days ago)

||FILE:src/c/src/test_kick_isolation.c||
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "generator.h"

// Simple test to isolate kick function corruption - Match gen_kick.c pattern
int main(void) {
printf("Starting kick isolation test...\n");

// Create a simple generator struct
generator_t g;
memset(&g, 0, sizeof(g));

// Initialize delay with known values
float delay_buf[1000];
delay_init(&g.delay, delay_buf, 100);

printf("Before kick_process: delay.buf=%p size=%u idx=%u\n",
g.delay.buf, g.delay.size, g.delay.idx);
printf("Delay struct address: %p\n", &g.delay);

// Initialize kick exactly like gen_kick.c
kick_init(&g.kick, 44100.0f);
kick_trigger(&g.kick);

// Create small buffers - use smaller blocks like gen_kick.c (256 samples)
float L[256] = {0};
float R[256] = {0};

printf("About to call kick_process with 256 samples...\n");

// Call kick_process with smaller block
kick_process(&g.kick, L, R, 256);

printf("After kick_process: delay.buf=%p size=%u idx=%u\n",
g.delay.buf, g.delay.size, g.delay.idx);

printf("Test completed successfully!\n");
return 0;
} ||ENDFILE||
||FILE:src/c/src/test_mixing.c||
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// External ASM function
extern void generator_mix_buffers_asm(float *L, float *R,
const float *Ld, const float *Rd,
const float *Ls, const float *Rs,
uint32_t num_frames);

int main() {
const uint32_t frames = 1024;

// Allocate aligned buffers
float *L = malloc(frames * sizeof(float));
float *R = malloc(frames * sizeof(float));
float *Ld = malloc(frames * sizeof(float));
float *Rd = malloc(frames * sizeof(float));
float *Ls = malloc(frames * sizeof(float));
float *Rs = malloc(frames * sizeof(float));

if (!L || !R || !Ld || !Rd || !Ls || !Rs) {
printf("MALLOC_FAILED\n");
return 1;
}

// Initialize test data
for (uint32_t i = 0; i < frames; i++) {
Ld[i] = 0.1f; // drums left
Rd[i] = 0.1f; // drums right
Ls[i] = 0.2f; // synth left
Rs[i] = 0.2f; // synth right
L[i] = 0.0f; // output left (should become 0.3)
R[i] = 0.0f; // output right (should become 0.3)
}

printf("BEFORE_MIX: L[0]=%f R[0]=%f\n", L[0], R[0]);
printf("INPUTS: Ld=%f Rd=%f Ls=%f Rs=%f\n", Ld[0], Rd[0], Ls[0], Rs[0]);

// Call the mixing function
generator_mix_buffers_asm(L, R, Ld, Rd, Ls, Rs, frames);

printf("AFTER_MIX: L[0]=%f R[0]=%f\n", L[0], R[0]);

// Check if mixing worked correctly
float expected = 0.1f + 0.2f; // Ld + Ls = 0.3
if (L[0] > expected - 0.01f && L[0] < expected + 0.01f) {
printf("MIX_SUCCESS\n");
} else {
printf("MIX_FAILED: expected=%f actual=%f\n", expected, L[0]);
}

free(L); free(R); free(Ld); free(Rd); free(Ls); free(Rs);
return 0;
}
||ENDFILE||
||FILE:src/c/src/ultra_minimal_kick_test.c||
#include <stdio.h>
#include <stdint.h>

// Minimal kick struct definition (matches kick.h layout)
typedef struct {
float sr; // offset 0
uint32_t pos; // offset 4
uint32_t len; // offset 8
} kick_t;

// External assembly function declaration
extern void kick_process(kick_t *k, float *L, float *R, uint32_t n);

int main(void) {
printf("🔍 ULTRA-MINIMAL KICK TEST\n");
printf("Goal: Isolate exact kick_process crash with minimal dependencies\n\n");

// Minimal setup
kick_t kick = {
.sr = 44100.0f,
.pos = 0,
.len = 1000 // Small len to limit loop iterations
};

// Small buffers
float L[16] = {0.0f}; // Very small to limit crash scope
float R[16] = {0.0f};
uint32_t frames = 4; // Process only 4 samples

printf("Setup:\n");
printf(" kick.sr: %f\n", kick.sr);
printf(" kick.pos: %u\n", kick.pos);
printf(" kick.len: %u\n", kick.len);
printf(" frames: %u\n", frames);
printf(" L buffer: %p\n", L);
printf(" R buffer: %p\n", R);

printf("\n🚨 CALLING kick_process with minimal parameters...\n");

// Direct call to assembly function
kick_process(&kick, L, R, frames);

printf("✅ SUCCESS: kick_process completed!\n");
printf(" L[0] = %f\n", L[0]);
printf(" R[0] = %f\n", R[0]);
printf(" kick.pos = %u\n", kick.pos);

return 0;
} ||ENDFILE||
||FILE:src/c/src/video.c||
#include "video.h"
#ifdef float32_t
#undef float32_t
#endif
#include <SDL.h>
#include <stdlib.h>

typedef struct {
SDL_Window *win;
SDL_Renderer *ren;
SDL_Texture *tex;
uint32_t fps_interval_ms;
uint32_t last_ticks;
int width;
int height;
uint32_t *fb;
} video_state_t;

static video_state_t g;

int video_init(int width, int height, int fps, bool vsync)
{
if(SDL_Init(SDL_INIT_VIDEO) != 0){
SDL_Log("SDL_Init failed: %s", SDL_GetError());
return 1;
}

uint32_t flags = SDL_RENDERER_ACCELERATED | (vsync?SDL_RENDERER_PRESENTVSYNC:0);
g.win = SDL_CreateWindow("Euclid Visualiser", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width, height, SDL_WINDOW_SHOWN);
if(!g.win){ SDL_Log("CreateWindow failed: %s", SDL_GetError()); return 1; }

g.ren = SDL_CreateRenderer(g.win, -1, flags);
if(!g.ren){ SDL_Log("CreateRenderer failed: %s", SDL_GetError()); return 1; }

g.width = width; g.height = height;
g.fb = (uint32_t*)malloc(width * height * sizeof(uint32_t));
if(!g.fb){ SDL_Log("malloc framebuffer failed"); return 1; }

g.tex = SDL_CreateTexture(g.ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING,
width, height);
if(!g.tex){ SDL_Log("CreateTexture failed: %s", SDL_GetError()); return 1; }

g.fps_interval_ms = (fps>0)? (1000u / (uint32_t)fps) : 0u;
g.last_ticks = SDL_GetTicks();
return 0;
}

bool video_frame_begin(void)
{
/* Frame pacing */
if(g.fps_interval_ms){
uint32_t now = SDL_GetTicks();
uint32_t elapsed = now - g.last_ticks;
if(elapsed < g.fps_interval_ms){
SDL_Delay(g.fps_interval_ms - elapsed);
}
g.last_ticks = SDL_GetTicks();
}

/* Event polling */
SDL_Event ev;
while(SDL_PollEvent(&ev)){
if(ev.type == SDL_QUIT){
return false; /* request close */
}
}

/* nothing else here, draw into framebuffer in caller */
return true;
}

void video_frame_end(void)
{
/* upload framebuffer to texture & present */
SDL_UpdateTexture(g.tex, NULL, g.fb, g.width * sizeof(uint32_t));
SDL_RenderClear(g.ren);
SDL_RenderCopy(g.ren, g.tex, NULL, NULL);
SDL_RenderPresent(g.ren);
}

void video_shutdown(void)
{
if(g.ren) SDL_DestroyRenderer(g.ren);
if(g.tex) SDL_DestroyTexture(g.tex);
if(g.win) SDL_DestroyWindow(g.win);
free(g.fb);
SDL_Quit();
}

uint32_t* video_get_framebuffer(void){ return g.fb; }
int video_get_width(void){ return g.width; }
int video_get_height(void){ return g.height; } ||ENDFILE||
||FILE:src/c/src/wav_writer.c||
#include "wav_writer.h"
#include <stdio.h>
#include <string.h>

static void write_le32(FILE *f, uint32_t v) { fwrite(&v, 4, 1, f); }
static void write_le16(FILE *f, uint16_t v) { fwrite(&v, 2, 1, f); }

void write_wav(const char *path,
const int16_t *samples,
uint32_t frames,
uint16_t num_channels,
uint32_t sample_rate)
{
FILE *f = fopen(path, "wb");
if (!f) {
perror("write_wav: fopen");
return;
}

uint16_t bits_per_sample = 16;
uint32_t byte_rate = sample_rate * num_channels * bits_per_sample / 8;
uint16_t block_align = num_channels * bits_per_sample / 8;
uint32_t data_chunk_size = frames * block_align;
uint32_t riff_size = 4 + 8 + 16 + 8 + data_chunk_size; // WAVE + fmt + data

/* RIFF header */
fwrite("RIFF", 1, 4, f);
write_le32(f, riff_size);
fwrite("WAVE", 1, 4, f);

/* fmt sub-chunk */
fwrite("fmt ", 1, 4, f);
write_le32(f, 16); // PCM header size
write_le16(f, 1); // AudioFormat = PCM
write_le16(f, num_channels);
write_le32(f, sample_rate);
write_le32(f, byte_rate);
write_le16(f, block_align);
write_le16(f, bits_per_sample);

/* data sub-chunk */
fwrite("data", 1, 4, f);
write_le32(f, data_chunk_size);
fwrite(samples, block_align, frames, f);

fclose(f);
} ||ENDFILE||
||FILE:src/deterministic_prng.c||
#include "include/deterministic_prng.h"

// Global PRNG streams for different visual systems
prng_t g_visual_prng;
prng_t g_particle_prng;
prng_t g_ship_prng;
prng_t g_boss_prng;
prng_t g_projectile_prng;
prng_t g_effects_prng;

void init_visual_prng_streams(uint32_t base_seed) {
// Initialize each stream with different seeds derived from base_seed
// Using prime number offsets to ensure good distribution
prng_seed(&g_visual_prng, base_seed);
prng_seed(&g_particle_prng, base_seed ^ 0x7F4A7C15);
prng_seed(&g_ship_prng, base_seed ^ 0x9E3779B9);
prng_seed(&g_boss_prng, base_seed ^ 0x6A09E667);
prng_seed(&g_projectile_prng, base_seed ^ 0xBB67AE85);
prng_seed(&g_effects_prng, base_seed ^ 0x3C6EF372);
}
||ENDFILE||
||FILE:src/drawing_wrappers copy.c||
// Wrapper functions to bridge C test suite with ASM implementations

#include "include/visual_types.h"

// ASM function declarations (with single underscore as they appear in object files)
extern void _set_pixel_asm(uint32_t *pixels, int x, int y, uint32_t color);
extern void _clear_frame_asm(uint32_t *pixels, uint32_t color);
extern void _draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color);
extern uint32_t _circle_color_asm(float base_hue, float saturation, float value);
extern color_t* _hsv_to_rgb(hsv_t *hsv, color_t *output);
extern uint32_t _color_to_pixel(color_t *color);

// C wrapper functions (remove underscore for C linking)
void set_pixel_asm(uint32_t *pixels, int x, int y, uint32_t color) {
_set_pixel_asm(pixels, x, y, color);
}

void clear_frame_asm(uint32_t *pixels, uint32_t color) {
_clear_frame_asm(pixels, color);
}

void draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color) {
_draw_circle_filled_asm(pixels, cx, cy, radius, color);
}

uint32_t circle_color_asm(float base_hue, float saturation, float value) {
return _circle_color_asm(base_hue, saturation, value);
}

color_t* hsv_to_rgb(hsv_t *hsv, color_t *output) {
return _hsv_to_rgb(hsv, output);
}

uint32_t color_to_pixel(color_t *color) {
return _color_to_pixel(color);
}
||ENDFILE||
||FILE:src/drawing_wrappers.c||
// Wrapper functions to bridge C test suite with ASM implementations

#include "include/visual_types.h"

// ASM function declarations (with single underscore as they appear in object files)
extern void _set_pixel_asm(uint32_t *pixels, int x, int y, uint32_t color);
extern void _clear_frame_asm(uint32_t *pixels, uint32_t color);
extern void _draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color);
extern uint32_t _circle_color_asm(float base_hue, float saturation, float value);
extern color_t* _hsv_to_rgb(hsv_t *hsv, color_t *output);
extern uint32_t _color_to_pixel(color_t *color);

// C wrapper functions (remove underscore for C linking)
void set_pixel_asm(uint32_t *pixels, int x, int y, uint32_t color) {
_set_pixel_asm(pixels, x, y, color);
}

void clear_frame_asm(uint32_t *pixels, uint32_t color) {
_clear_frame_asm(pixels, color);
}

void draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color) {
_draw_circle_filled_asm(pixels, cx, cy, radius, color);
}

uint32_t circle_color_asm(float base_hue, float saturation, float value) {
return _circle_color_asm(base_hue, saturation, value);
}

color_t* hsv_to_rgb(hsv_t *hsv, color_t *output) {
return _hsv_to_rgb(hsv, output);
}

uint32_t color_to_pixel(color_t *color) {
return _color_to_pixel(color);
}
||ENDFILE||
||FILE:src/include/deterministic_prng.h||
#ifndef DETERMINISTIC_PRNG_H
#define DETERMINISTIC_PRNG_H

#include <stdint.h>

// Simple, fast xorshift32 PRNG for deterministic generation
// Based on deafbeef-style reproducible randomness
typedef struct {
uint32_t state;
} prng_t;

// Initialize PRNG with seed
static inline void prng_seed(prng_t* rng, uint32_t seed) {
rng->state = seed ? seed : 1; // Ensure non-zero state
}

// Generate next random uint32
static inline uint32_t prng_next(prng_t* rng) {
rng->state ^= rng->state << 13;
rng->state ^= rng->state >> 17;
rng->state ^= rng->state << 5;
return rng->state;
}

// Generate float in [0.0, 1.0)
static inline float prng_float(prng_t* rng) {
return (float)prng_next(rng) / (float)UINT32_MAX;
}

// Generate int in [0, max)
static inline int prng_range(prng_t* rng, int max) {
if (max <= 0) return 0;
return (int)(prng_next(rng) % (uint32_t)max);
}

// Global PRNG streams for different visual systems
extern prng_t g_visual_prng; // Main visual composition
extern prng_t g_particle_prng; // Particle system
extern prng_t g_ship_prng; // Ship generation
extern prng_t g_boss_prng; // Boss generation
extern prng_t g_projectile_prng; // Projectile system
extern prng_t g_effects_prng; // Visual effects

// Initialize all PRNG streams from base seed
void init_visual_prng_streams(uint32_t base_seed);

#endif // DETERMINISTIC_PRNG_H
||ENDFILE||
||FILE:src/include/timeline.h||
#ifndef TIMELINE_H
#define TIMELINE_H

#include <stdint.h>
#include <stdbool.h>

typedef struct {
uint32_t time; /* samples */
uint8_t type; /* 0..N mapped to strings */
uint8_t aux;
} tl_event_t;

typedef struct {
/* header */
uint64_t seed;
uint32_t sample_rate;
float bpm;
uint32_t step_samples;
uint32_t total_samples;

/* arrays (owned) */
uint32_t *steps; /* length steps_count */
uint32_t steps_count;
uint32_t *beats; /* length beats_count */
uint32_t beats_count;
tl_event_t *events; /* length events_count */
uint32_t events_count;
} timeline_t;

/* Load a minimal JSON written by export_timeline.c.
Returns true on success; on success, out will own allocated arrays and must be freed with timeline_free(). */
bool timeline_load(const char *path, timeline_t *out);
void timeline_free(timeline_t *t);

/* Helpers to derive frame-time signals from events (simple exponential decays). */
float timeline_compute_level(const timeline_t *t, int frame_idx, int fps);
float timeline_compute_glitch(const timeline_t *t, int frame_idx, int fps);
float timeline_compute_hue(const timeline_t *t, int frame_idx, int fps);

#endif /* TIMELINE_H */


||ENDFILE||
||FILE:src/include/visual_types.h||
#ifndef VISUAL_TYPES_H
#define VISUAL_TYPES_H

#include <stdint.h>

#define VIS_FPS 60
#define WIDTH 800
#define HEIGHT 600
#define VIS_WIDTH 800
#define VIS_HEIGHT 600

// HSV color structure
typedef struct {
float h; // Hue [0, 1]
float s; // Saturation [0, 1]
float v; // Value [0, 1]
} hsv_t;

// RGB color structure
typedef struct {
uint8_t r; // Red [0, 255]
uint8_t g; // Green [0, 255]
uint8_t b; // Blue [0, 255]
uint8_t a; // Alpha [0, 255]
} color_t;

// Point with float coordinates
typedef struct {
float x;
float y;
} pointf_t;

// Visual modes based on BPM
typedef enum {
VIS_MODE_THICK = 0,
VIS_MODE_RINGS = 1,
VIS_MODE_POLY = 2,
VIS_MODE_LISSA = 3
} visual_mode_t;

// Degradation effects structure
typedef struct {
float persistence;
int scanline_alpha;
int chroma_shift;
int noise_pixels;
float jitter_amount;
float frame_drop_chance;
float color_bleed;
} degradation_t;

// Centerpiece structure
typedef struct {
visual_mode_t mode;
int bpm;
float orbit_radius;
float base_hue;
float orbit_speed;
} centerpiece_t;

// Visual context structure
typedef struct {
centerpiece_t centerpiece;
degradation_t effects;
uint32_t seed;
int frame_count;
float elapsed_time;

// Additional fields for integration
uint32_t *pixels; // Frame buffer
int frame; // Current frame number
float time; // Current time in seconds
float step_sec; // Duration of 16th note
int bpm; // Beats per minute
} visual_context_t;

#endif // VISUAL_TYPES_H
||ENDFILE||
||FILE:src/particles_wrapper.c||
// Particles System C Wrapper
// Provides memory allocation for particles ASM code

#include <stdint.h>
#include <string.h>
#include "include/visual_types.h"

// Global particle array - allocated in C, used by ASM
// 256 particles, 32 bytes each (matches ASM struct layout)
static uint8_t particle_data[256 * 32];

// Export this symbol for ASM code to reference
uint8_t *particles_array = particle_data;

// ASM function prototypes
extern void init_particles_asm(void);
extern int is_saw_step_asm(int step);
extern void spawn_explosion_asm(int count, float x, float y, float base_hue, uint32_t seed);
extern void update_particles_asm(float elapsed_ms, float step_sec, float base_hue);
extern void draw_particles_asm(uint32_t *pixels);
extern void reset_particle_step_tracking_asm(void);

// C wrapper functions that call ASM implementations
void init_particles(void) {
// Clear the particle array first
memset(particle_data, 0, sizeof(particle_data));

// Call ASM initialization
init_particles_asm();
}

bool is_saw_step(int step) {
return is_saw_step_asm(step) != 0;
}

void spawn_explosion(int count, float x, float y, float base_hue, uint32_t seed) {
spawn_explosion_asm(count, x, y, base_hue, seed);
}

void update_particles(float elapsed_ms, float step_sec, float base_hue) {
update_particles_asm(elapsed_ms, step_sec, base_hue);
}

void draw_particles(uint32_t *pixels) {
draw_particles_asm(pixels);
}

void reset_particle_step_tracking(void) {
reset_particle_step_tracking_asm();
}
||ENDFILE||
at txn 0xe023c280f3b5f2dd5609e8ec713154c0c070e1e5dbe80367b9ba399baa704fb5 Aug-20-2025 12:47:35 AM UTC (26 days ago)

||FILE:src/c/src/raster.c||
#include "raster.h"
#include <math.h>
#include <stdlib.h>
#include <string.h>

void raster_clear(uint32_t *fb, int w, int h, uint32_t color)
{
for(int i=0;i<w*h;i++) fb[i]=color;
}

static inline void plot(uint32_t *fb,int w,int h,int x,int y,uint32_t col){
if((unsigned)x<(unsigned)w && (unsigned)y<(unsigned)h) fb[y*w+x]=col;
}

void raster_circle(uint32_t *fb,int w,int h,int cx,int cy,int r,uint32_t col,int thickness)
{
if(thickness<=0) thickness=1;
int r_out=r;
int r_in=r-thickness;
int r_out2=r_out*r_out;
int r_in2=r_in*r_in;
for(int y=-r_out;y<=r_out;y++){
int yy=y+cy;
int y2=y*y;
for(int x=-r_out;x<=r_out;x++){
int xx=x+cx;
int dist2 = x*x + y2;
if(dist2<=r_out2 && dist2>=r_in2){ plot(fb,w,h,xx,yy,col);} }
}
}

/* Filled circle using simple scanline fill */
void raster_fill_circle(uint32_t *fb,int w,int h,int cx,int cy,int r,uint32_t col)
{
int r2 = r*r;
for(int y=-r; y<=r; ++y){
int yy = cy + y;
if((unsigned)yy >= (unsigned)h) continue;
int x_extent = (int)sqrtf((float)(r2 - y*y));
int x_min = cx - x_extent;
int x_max = cx + x_extent;
if(x_min < 0) x_min = 0;
if(x_max >= w) x_max = w-1;
for(int x = x_min; x <= x_max; ++x){
fb[yy*w + x] = col;
}
}
}

/* Bresenham line (thickness = 1) */
void raster_line(uint32_t *fb,int w,int h,int x0,int y0,int x1,int y1,uint32_t col)
{
int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1;
int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1;
int err = dx + dy, e2; /* error value e_xy */

while(true){
plot(fb, w, h, x0, y0, col);
if(x0 == x1 && y0 == y1) break;
e2 = 2*err;
if(e2 >= dy){ err += dy; x0 += sx; }
if(e2 <= dx){ err += dx; y0 += sy; }
}
}

/* Simple polygon: if fill==true, use scanline fill; otherwise draw outline with raster_line */
void raster_poly(uint32_t *fb,int w,int h,const int *vx,const int *vy,int n,uint32_t col,bool fill,int thickness)
{
if(n < 2) return;
if(!fill){
for(int i=0;i<n;i++){
int j = (i+1)%n;
raster_line(fb,w,h,vx[i],vy[i],vx[j],vy[j],col);
if(thickness>1){ /* naive thickness by drawing parallel lines */
for(int t=1;t<thickness;t++){
raster_line(fb,w,h,vx[i]+t,vy[i],vx[j]+t,vy[j],col);
raster_line(fb,w,h,vx[i]-t,vy[i],vx[j]-t,vy[j],col);
}
}
}
return;
}

/* --- fill --- */
/* Determine bounding box */
int y_min = vy[0], y_max = vy[0];
for(int i=1;i<n;i++){
if(vy[i] < y_min) y_min = vy[i];
if(vy[i] > y_max) y_max = vy[i];
}
if(y_min < 0) y_min = 0;
if(y_max >= h) y_max = h-1;

for(int y=y_min; y<=y_max; ++y){
/* Build list of x intersections with edges */
int inter[32]; /* assume n<=32 */
int count = 0;
for(int i=0;i<n;i++){
int j = (i+1)%n;
int y0 = vy[i], y1 = vy[j];
if((y0<y && y1>=y) || (y1<y && y0>=y)){
int x0 = vx[i], x1 = vx[j];
/* linear interpolation */
int x = x0 + (int)((float)(y - y0) * (float)(x1 - x0) / (float)(y1 - y0 + (y1==y0))); /* avoid div0 */
if(count < 32){ inter[count++] = x; }
}
}
if(count < 2) continue;
/* sort small array (insertion) */
for(int i=1;i<count;i++){
int key=inter[i]; int j=i-1; while(j>=0 && inter[j]>key){ inter[j+1]=inter[j]; j--; } inter[j+1]=key; }
for(int i=0;i<count; i+=2){
int x_start = inter[i];
int x_end = inter[i+1];
if(x_start < 0) x_start = 0;
if(x_end >= w) x_end = w-1;
for(int x=x_start; x<=x_end; ++x){
fb[y*w + x] = col;
}
}
}
}

/* Blit helper: copy src_w*src_h pixels at (dx,dy) into dst, no alpha */
void raster_blit_rgba(const uint32_t *src,int src_w,int src_h,uint32_t *dst,int dst_w,int dst_h,int dx,int dy)
{
for(int y=0;y<src_h;y++){
int dst_y = dy + y;
if((unsigned)dst_y >= (unsigned)dst_h) continue;
const uint32_t *srow = src + y*src_w;
uint32_t *drow = dst + dst_y*dst_w;
int copy_w = src_w;
int dst_x = dx;
if(dst_x < 0){ srow += -dst_x; copy_w += dst_x; dst_x = 0; }
if(dst_x + copy_w > dst_w) copy_w = dst_w - dst_x;
if(copy_w <= 0) continue;
memcpy(drow + dst_x, srow, copy_w * sizeof(uint32_t));
}
}

void raster_blit_rgba_alpha(const uint32_t *src,int src_w,int src_h,uint32_t *dst,int dst_w,int dst_h,int dx,int dy)
{
for(int y=0;y<src_h;y++){
int dst_y = dy + y;
if((unsigned)dst_y >= (unsigned)dst_h) continue;
const uint32_t *srow = src + y*src_w;
uint32_t *drow = dst + dst_y*dst_w;
for(int x=0; x<src_w; ++x){
int dst_x = dx + x;
if((unsigned)dst_x >= (unsigned)dst_w) continue;
uint32_t px = srow[x];
if((px & 0xFF) == 0) continue; /* alpha==0 skip */
drow[dst_x] = px;
}
}
} ||ENDFILE||
||FILE:src/c/src/segment.c||
#include "wav_writer.h"
#include "generator.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* extern counter defined in generator_step.c */
extern int g_mid_trigger_count;

// Deterministically hash a transaction hash to a 32-bit seed
// Preserves deafbeef-style reproducibility while handling long hashes
uint32_t hash_transaction_to_seed(const char* tx_hash) {
uint32_t seed = 0;
const char* hex_start = tx_hash;

// Skip "0x" prefix if present
if (tx_hash[0] == '0' && (tx_hash[1] == 'x' || tx_hash[1] == 'X')) {
hex_start += 2;
}

size_t len = strlen(hex_start);

// XOR all 8-character chunks together for good distribution
for (int i = 0; i < len; i += 8) {
char chunk[9] = {0};
int chunk_len = (len - i >= 8) ? 8 : (len - i);
strncpy(chunk, hex_start + i, chunk_len);

// Convert hex chunk to uint32_t and XOR into seed
uint32_t chunk_val = (uint32_t)strtoul(chunk, NULL, 16);
seed ^= chunk_val;
}

// If seed is 0, use a fallback to avoid degenerate case
if (seed == 0) {
seed = 0xDEADBEEF;
}

return seed;
}

#define MAX_SEG_FRAMES 424000
static float L[MAX_SEG_FRAMES], R[MAX_SEG_FRAMES];
static int16_t pcm[MAX_SEG_FRAMES * 2];

/* Fallback scalar RMS when assembly version not linked */
#ifndef GENERATOR_RMS_ASM_PRESENT
float generator_compute_rms_asm(const float *L, const float *R, uint32_t num_frames)
{
double sum = 0.0;
for(uint32_t i=0;i<num_frames;i++){
double sL = L[i];
double sR = R[i];
sum += sL*sL + sR*sR;
}
return (float)sqrt(sum / (double)(2*num_frames));
}
#endif

int main(int argc, char **argv)
{
uint32_t seed = 0xCAFEBABE; // Changed to 32-bit
if(argc > 1) {
seed = hash_transaction_to_seed(argv[1]); // Use hash-the-hash function
}

generator_t g;
generator_init(&g, seed);

uint32_t total_frames = g.mt.seg_frames;
if(total_frames > MAX_SEG_FRAMES) total_frames = MAX_SEG_FRAMES;

printf("C-DBG before gen_process: step_samples=%u addr=%p\n", g.mt.step_samples, &g.mt.step_samples);
generator_process(&g, L, R, total_frames);

/* RMS diagnostic to verify audio energy */
float rms = generator_compute_rms_asm(L, R, total_frames);
printf("C-POST rms=%f\n", rms);
printf("DEBUG: MID triggers fired = %d\n", g_mid_trigger_count);

for(uint32_t i=0;i<total_frames;i++){
pcm[2*i] = (int16_t)(L[i]*32767);
pcm[2*i+1] = (int16_t)(R[i]*32767);
}

char wavname[128]; // Increased buffer for long transaction hashes
sprintf(wavname, "seed_0x%x.wav", seed); // Use 32-bit format
write_wav(wavname, pcm, total_frames, 2, SR);
printf("Wrote %s (%u frames, %.2f bpm, root %.2f Hz)\n", wavname, total_frames, g.mt.bpm, g.music.root_freq);

return 0;
} ||ENDFILE||
||FILE:src/c/src/segment_test.c||
#include "generator.h"
#include "wav_writer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <category1> [category2] ... [seed]\n", argv[0]);
printf("Categories: drums, melody, fm, delay, limiter\n");
printf("Examples:\n");
printf(" %s drums\n", argv[0]);
printf(" %s drums delay\n", argv[0]);
printf(" %s drums 0x12345\n", argv[0]);
printf(" %s drums melody delay fm limiter 0xdeadbeef\n", argv[0]);
return 1;
}

// Parse which categories to enable and optional seed
bool enable_drums = false, enable_melody = false, enable_fm = false;
bool enable_delay = false, enable_limiter = false;
uint64_t seed = 0xCAFEBABEULL;

for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "drums") == 0) enable_drums = true;
else if (strcmp(argv[i], "melody") == 0) enable_melody = true;
else if (strcmp(argv[i], "fm") == 0) enable_fm = true;
else if (strcmp(argv[i], "delay") == 0) enable_delay = true;
else if (strcmp(argv[i], "limiter") == 0) enable_limiter = true;
else if (argv[i][0] == '0' && (argv[i][1] == 'x' || argv[i][1] == 'X')) {
// Parse hex seed
seed = strtoull(argv[i], NULL, 0);
}
else {
printf("Unknown category or invalid seed: %s\n", argv[i]);
return 1;
}
}

printf("Generating segment with: ");
if (enable_drums) printf("drums ");
if (enable_melody) printf("melody ");
if (enable_fm) printf("fm ");
if (enable_delay) printf("delay ");
if (enable_limiter) printf("limiter ");
printf("\n");

const uint32_t sr = 44100;
generator_t g;
generator_init(&g, seed);

// Calculate total frames (same as segment.c)
uint32_t total_frames = g.mt.seg_frames;
printf("Total duration: %.2f sec (%u frames)\n", g.mt.seg_sec, total_frames);

float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

// Generate the audio using the same process as segment.c
// but with selective voice processing
for (uint32_t frame = 0; frame < total_frames; ) {
uint32_t remaining = total_frames - frame;
uint32_t block_size = (remaining > 1024) ? 1024 : remaining;

// Trigger events (always run this to advance timing)
generator_trigger_step(&g);

// Process voices selectively
float *block_L = &L[frame];
float *block_R = &R[frame];

// Clear the block
memset(block_L, 0, block_size * sizeof(float));
memset(block_R, 0, block_size * sizeof(float));

if (enable_drums) {
kick_process(&g.kick, block_L, block_R, block_size);
snare_process(&g.snare, block_L, block_R, block_size);
hat_process(&g.hat, block_L, block_R, block_size);
}

if (enable_melody) {
melody_process(&g.mel, block_L, block_R, block_size);
}

if (enable_fm) {
fm_voice_process(&g.mid_fm, block_L, block_R, block_size);
fm_voice_process(&g.bass_fm, block_L, block_R, block_size);
}

if (enable_delay) {
delay_process_block(&g.delay, block_L, block_R, block_size, 0.45f);
}

if (enable_limiter) {
limiter_process(&g.limiter, block_L, block_R, block_size);
}

// Advance timing manually (since we're not using generator_process)
g.pos_in_step += block_size;
if (g.pos_in_step >= g.mt.step_samples) {
g.pos_in_step = 0;
g.step++;
}

frame += block_size;
}

// Convert to int16 WAV
int16_t *pcm = malloc(sizeof(int16_t) * total_frames * 2);
for (uint32_t i = 0; i < total_frames; i++) {
float vL = L[i]; if(vL > 1) vL = 1; if(vL < -1) vL = -1;
float vR = R[i]; if(vR > 1) vR = 1; if(vR < -1) vR = -1;
pcm[2*i] = (int16_t)(vL * 32767);
pcm[2*i+1] = (int16_t)(vR * 32767);
}

char filename[64];
snprintf(filename, sizeof(filename), "segment_test_0x%llx.wav", (unsigned long long)seed);
write_wav(filename, pcm, total_frames, 2, sr);
printf("Generated %s\n", filename);

free(L); free(R); free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/shapes.c||
#include "shapes.h"
#include "raster.h"
#include <math.h>
#include <stdlib.h>

static bass_shape_t g_shapes[MAX_SHAPES];
static int g_count = 0;

void shapes_init(void) { g_count = 0; }

void shapes_spawn(shape_type_t type, uint32_t color)
{
if(g_count >= MAX_SHAPES) return;
bass_shape_t *s = &g_shapes[g_count++];
s->type = type;
s->scale = 0.1f;
s->rotation = 0.0f;
s->rot_speed = -0.05f + (rand()%100)/1000.0f; /* -0.05 to +0.05 */
s->alpha = 255;
s->color = color;
}

static void rotate_point(float *x, float *y, float cx, float cy, float angle)
{
float dx = *x - cx;
float dy = *y - cy;
float rx = dx * cosf(angle) - dy * sinf(angle);
float ry = dx * sinf(angle) + dy * cosf(angle);
*x = cx + rx;
*y = cy + ry;
}

void shapes_update_and_draw(uint32_t *fb, int w, int h)
{
int cx = w/2;
int cy = h/2;
float max_size = fminf(w,h) * 0.6f;

for(int i=0; i<g_count;){
bass_shape_t *s = &g_shapes[i];

/* update */
if(s->scale < 1.0f) s->scale += 0.15f; /* fast growth */
s->alpha -= 8;
if(s->alpha < 0) s->alpha = 0;
s->rotation += s->rot_speed;

if(s->alpha <= 0){
/* remove by swap */
g_shapes[i] = g_shapes[--g_count];
continue;
}

/* draw with alpha blend simulation */
float size = max_size * fminf(s->scale, 1.0f);
float alpha_f = s->alpha / 255.0f;
uint32_t r = (s->color >> 24) & 0xFF;
uint32_t g = (s->color >> 16) & 0xFF;
uint32_t b = (s->color >> 8) & 0xFF;
r = (uint32_t)(r * alpha_f);
g = (uint32_t)(g * alpha_f);
b = (uint32_t)(b * alpha_f);
uint32_t col = (r<<24)|(g<<16)|(b<<8)|0xFF;

int vx[10], vy[10];
int n = 0;

switch(s->type){
case SHAPE_TRIANGLE:
n = 3;
for(int j=0; j<3; j++){
float angle = s->rotation + j * 2.0f * M_PI / 3.0f;
float x = cx + size * 0.8f * cosf(angle);
float y = cy + size * 0.8f * sinf(angle);
vx[j] = (int)x;
vy[j] = (int)y;
}
break;

case SHAPE_DIAMOND:
n = 4;
vx[0] = cx; vy[0] = cy - (int)(size*0.8f);
vx[1] = cx + (int)(size*0.6f); vy[1] = cy;
vx[2] = cx; vy[2] = cy + (int)(size*0.8f);
vx[3] = cx - (int)(size*0.6f); vy[3] = cy;
for(int j=0; j<4; j++){
float x = vx[j], y = vy[j];
rotate_point(&x, &y, cx, cy, s->rotation);
vx[j] = (int)x; vy[j] = (int)y;
}
break;

case SHAPE_HEXAGON:
n = 6;
for(int j=0; j<6; j++){
float angle = s->rotation + j * M_PI / 3.0f;
vx[j] = cx + (int)(size * 0.7f * cosf(angle));
vy[j] = cy + (int)(size * 0.7f * sinf(angle));
}
break;

case SHAPE_STAR:
n = 10;
for(int j=0; j<10; j++){
float angle = s->rotation + j * M_PI / 5.0f;
float r = (j%2==0) ? size*0.8f : size*0.4f;
vx[j] = cx + (int)(r * cosf(angle));
vy[j] = cy + (int)(r * sinf(angle));
}
break;

case SHAPE_SQUARE:
n = 4;
float half = size * 0.6f;
vx[0] = cx - (int)half; vy[0] = cy - (int)half;
vx[1] = cx + (int)half; vy[1] = cy - (int)half;
vx[2] = cx + (int)half; vy[2] = cy + (int)half;
vx[3] = cx - (int)half; vy[3] = cy + (int)half;
for(int j=0; j<4; j++){
float x = vx[j], y = vy[j];
rotate_point(&x, &y, cx, cy, s->rotation);
vx[j] = (int)x; vy[j] = (int)y;
}
break;
}

/* draw outline only (thickness 3) */
raster_poly(fb, w, h, vx, vy, n, col, false, 3);

++i;
}
} ||ENDFILE||
||FILE:src/c/src/simple_voice.c||
#include "simple_voice.h"
#include <math.h>
#include "env.h"

#define TAU 6.2831853071795864769f

void simple_voice_init(simple_voice_t *v, float32_t sr)
{
osc_reset(&v->osc);
v->sr = sr;
v->len = 0;
v->pos = 0;
v->decay = 6.0f;
v->amp = 0.2f;
v->wave = SIMPLE_SINE;
v->freq = 440.0f;
}

void simple_voice_trigger(simple_voice_t *v, float32_t freq, float32_t dur_sec, simple_wave_t wave, float32_t amp, float32_t decay)
{
v->freq = freq;
v->wave = wave;
v->amp = amp;
v->decay = decay;
v->len = (uint32_t)(dur_sec * v->sr);
v->pos = 0;
}

static inline float32_t render_sample(simple_voice_t *v)
{
float32_t phase = v->osc.phase;
float32_t frac = phase / TAU; /* 0..1 */
float32_t s=0.0f;
switch(v->wave){
case SIMPLE_TRI:
s = 2.0f * fabsf(2.0f * frac - 1.0f) - 1.0f;
break;
case SIMPLE_SQUARE:
s = (frac < 0.5f) ? 1.0f : -1.0f;
break;
default: /* sine */
s = sinf(phase);
break;
}
return s;
}

void simple_voice_process(simple_voice_t *v, float32_t *L, float32_t *R, uint32_t n)
{
if(v->pos >= v->len) return;
float32_t phase = v->osc.phase;
float32_t inc = TAU * v->freq / v->sr;
for(uint32_t i=0;i<n;++i){
if(v->pos >= v->len) break;
float32_t t = (float32_t)v->pos / v->sr;
float32_t env = env_exp_decay(t, v->decay);
float32_t sample;
float32_t frac = phase / TAU;
switch(v->wave){
case SIMPLE_TRI:
sample = (2.0f * fabsf(2.0f * frac - 1.0f) - 1.0f);
break;
case SIMPLE_SQUARE:
sample = (frac < 0.5f)?1.0f:-1.0f;
break;
default:
sample = sinf(phase);
break;
}
sample *= env * v->amp;
L[i]+=sample;
R[i]+=sample;
phase += inc;
if(phase>=TAU) phase -= TAU;
v->pos++;
}
v->osc.phase = phase;
} ||ENDFILE||
||FILE:src/c/src/snare.c||
#include "snare.h"
#include <math.h>

#define SNARE_DECAY_RATE 35.0f
#define SNARE_DUR_SEC 0.1f

void snare_init(snare_t *s, float32_t sr, uint64_t seed)
{
s->len = 0;
s->pos = 0;
s->sr = sr;
s->env = 0.0f;
s->env_coef = 0.0f;
s->rng = rng_seed(seed);
}

void snare_trigger(snare_t *s)
{
s->pos = 0;
s->len = (uint32_t)(SNARE_DUR_SEC * s->sr);
s->env = 1.0f;
s->env_coef = expf(-SNARE_DECAY_RATE / s->sr);
}

/* NO snare_process - ASM implementation required */
||ENDFILE||
||FILE:src/c/src/terrain.c||
#include "terrain.h"
#include <string.h>
#include <math.h>

/* --- internal static assets --- */
static uint32_t g_tile_flat[TILE_SIZE*TILE_SIZE];
static uint32_t g_tile_slope_up[TILE_SIZE*TILE_SIZE];
static uint32_t g_tile_slope_down[TILE_SIZE*TILE_SIZE];

static terrain_tile_t g_pattern[TERRAIN_LEN];

/* pack rgb8 + alpha 255 into uint32 */
static inline uint32_t rgba(uint8_t r,uint8_t g,uint8_t b){ return ((uint32_t)r<<24)|((uint32_t)g<<16)|((uint32_t)b<<8)|0xFF; }

static void build_rock_tile(uint32_t *dst, uint8_t base)
{
uint8_t dark = base;
uint8_t mid = (uint8_t)fminf(base*1.3f, 255.0f);
uint8_t hi = (uint8_t)fminf(base*1.8f, 255.0f);
for(int y=0;y<TILE_SIZE;y++){
for(int x=0;x<TILE_SIZE;x++){
uint8_t h = (uint8_t)(((x*13 + y*7) ^ (x>>3)) & 0xFF);
uint32_t col;
if(h < 40) col = rgba(hi,hi,hi);
else if(h < 120) col = rgba(mid,mid,mid);
else col = rgba(dark,dark,dark);
dst[y*TILE_SIZE + x] = col;
}
}
}

static void build_slope_tile(uint32_t *dst,const uint32_t *rock,uint8_t direction) /* 0=up,1=down */
{
for(int y=0;y<TILE_SIZE;y++){
for(int x=0;x<TILE_SIZE;x++){
int threshold = (direction==0)? x : (TILE_SIZE-1 - x);
if(y > threshold){
dst[y*TILE_SIZE + x] = rock[y*TILE_SIZE + x];
} else {
dst[y*TILE_SIZE + x] = 0x00000000; /* transparent */
}
}
}
}

void terrain_init(uint64_t seed)
{
/* choose base grey based on seed for determinism */
rng_t rng = rng_seed(seed ^ 0xA17E44ULL);
uint8_t base = (uint8_t)(64 + (rng_next_u32(&rng) % 96));
build_rock_tile(g_tile_flat, base);
build_slope_tile(g_tile_slope_up, g_tile_flat, 0);
build_slope_tile(g_tile_slope_down, g_tile_flat, 1);

/* --- pattern generation --- */
size_t i=0;
while(i < TERRAIN_LEN){
uint32_t feature = rng_next_u32(&rng) % 5; /* 0..4 */
if(feature == 0){ /* flat */
int length = 2 + (rng_next_u32(&rng)%5); /* 2-6 */
for(int k=0;k<length && i<TERRAIN_LEN;k++){
g_pattern[i++] = (terrain_tile_t){TILE_FLAT, 2};
}
} else if(feature == 1){ /* wall */
int wall_h = (rng_next_u32(&rng)%2)?4:6;
int wall_w = 2 + (rng_next_u32(&rng)%3); /*2-4*/
for(int k=0;k<wall_w && i<TERRAIN_LEN;k++){
g_pattern[i++] = (terrain_tile_t){TILE_WALL, (uint8_t)wall_h};
}
} else if(feature == 2){ /* slope up then platform */
if(i<TERRAIN_LEN){ g_pattern[i++] = (terrain_tile_t){TILE_SLOPE_UP,2}; }
int length = 2 + (rng_next_u32(&rng)%3); /*2-4*/
for(int k=0;k<length && i<TERRAIN_LEN;k++){
g_pattern[i++] = (terrain_tile_t){TILE_FLAT,3};
}
} else if(feature == 3){ /* slope down */
if(i<TERRAIN_LEN){ g_pattern[i++] = (terrain_tile_t){TILE_SLOPE_DOWN,3}; }
} else { /* gap */
int length = 1 + (rng_next_u32(&rng)%2); /*1-2*/
for(int k=0;k<length && i<TERRAIN_LEN;k++){
g_pattern[i++] = (terrain_tile_t){TILE_GAP,0};
}
}
}
}

void terrain_draw(uint32_t *fb,int w,int h,int frame)
{
const int SCROLL_SPEED = 2; /* pixels/frame */
int offset_px = (frame * SCROLL_SPEED) % TILE_SIZE;
int scroll_tiles = (frame * SCROLL_SPEED) / TILE_SIZE;
int tiles_per_screen = w / TILE_SIZE + 2;

for(int i=0;i<tiles_per_screen;i++){
int terrain_idx = (scroll_tiles + i) % TERRAIN_LEN;
terrain_tile_t tile = g_pattern[terrain_idx];
int x0 = i*TILE_SIZE - offset_px;
if(tile.type == TILE_GAP) continue;

for(int row=0; row<tile.height; ++row){
int y0 = h - (row+1)*TILE_SIZE;
const uint32_t *src_px;
if(tile.type == TILE_SLOPE_UP && row==tile.height-1){
src_px = g_tile_slope_up;
} else if(tile.type == TILE_SLOPE_DOWN && row==tile.height-1){
src_px = g_tile_slope_down;
} else {
src_px = g_tile_flat;
}
/* choose blit with alpha for slope tiles (transparent parts) */
bool use_alpha = (src_px == g_tile_slope_up || src_px == g_tile_slope_down);
if(use_alpha){
raster_blit_rgba_alpha(src_px, TILE_SIZE, TILE_SIZE, fb, w, h, x0, y0);
} else {
raster_blit_rgba(src_px, TILE_SIZE, TILE_SIZE, fb, w, h, x0, y0);
}
}
}
} ||ENDFILE||
at txn 0x223ffb4a5d5d45d5a3e67b589c592c2e2170fe2c2f327e87681729a55218fcdc Aug-20-2025 12:47:23 AM UTC (26 days ago)

||FILE:src/c/src/limiter.c||
#include "limiter.h"

void limiter_process(limiter_t *l, float32_t *L, float32_t *R, uint32_t n)
{
float32_t env = l->envelope;
float32_t att = l->attack_coeff;
float32_t rel = l->release_coeff;
float32_t thresh = l->threshold;

for(uint32_t i = 0; i < n; ++i){
// detect instantaneous stereo peak
float32_t peak = fmaxf(fabsf(L[i]), fabsf(R[i]));

// simple envelope follower
env = (peak > env) ? peak + att * (env - peak)
: peak + rel * (env - peak);

// HARD LIMITER: if env exceeds threshold, scale sample so env == thresh
float32_t gain = 1.0f;
if(env > thresh){
gain = thresh / env;
L[i] *= gain;
R[i] *= gain;
env = thresh; // clamp envelope so release starts here
}
}
l->envelope = env;
} ||ENDFILE||
||FILE:src/c/src/main.c||
#include <stdio.h>

int main(void)
{
puts("build ok");
return 0;
} ||ENDFILE||
||FILE:src/c/src/main_realtime.c||
#include "coreaudio.h"
#include "generator.h"
#include "video.h"
#include "raster.h"
#include "terrain.h"
#include "particles.h"
#include "shapes.h"
#include "crt_fx.h"
#include <stdio.h>
#include <unistd.h> // for sleep
#include <stdlib.h> // for strtoull
#include <stdbool.h>
#include <math.h>

static generator_t g_generator;
static volatile int callback_count = 0;

// Static buffers to avoid VLA stack overflow in real-time callback
static float L_buffer[1024], R_buffer[1024];

void audio_render_callback(float* buffer, uint32_t num_frames, void* user_data)
{
callback_count++; // Atomic increment to track calls

// Safety check - prevent buffer overflow
if(num_frames > 1024) num_frames = 1024;

generator_process(&g_generator, L_buffer, R_buffer, num_frames);
for(uint32_t i=0; i<num_frames; ++i){
buffer[i*2] = L_buffer[i];
buffer[i*2+1] = R_buffer[i];
}
}

int main(int argc, char **argv)
{
uint64_t seed = 0xCAFEBABEULL;
if(argc > 1) {
seed = strtoull(argv[1], NULL, 0);
}

generator_init(&g_generator, seed);
terrain_init(seed);
particles_init();
shapes_init();

/* init CRT effects */
crt_fx_t crt_fx;
crt_fx_init(&crt_fx, seed, 800, 600);

if(audio_init(SR, 512, audio_render_callback, NULL) != 0){
fprintf(stderr, "Audio init failed\n");
return 1;
}

printf("Playing with seed 0x%llx. Close the window to quit.\n", (unsigned long long)seed);

/* show CRT effect levels */
printf("CRT FX: persist=%.2f, scan=%d, chroma=%d, noise=%d\n",
crt_fx.persistence, crt_fx.scanline_alpha, crt_fx.chroma_shift, crt_fx.noise_pixels);
printf(" jitter=%.1f, drops=%.2f, bleed=%.2f\n",
crt_fx.jitter_amount, crt_fx.frame_drop_chance, crt_fx.color_bleed);

/* --- Start audio & video --- */
audio_start();
if(video_init(800, 600, 30, true) != 0){
fprintf(stderr, "Video init failed\n");
return 1;
}

bool running = true;
uint32_t *fb = video_get_framebuffer();
int vw = video_get_width();
int vh = video_get_height();
float base_hue = 0.0f;
float angle=0.0f;
int frame=0;
while(running){
running = video_frame_begin();
/* clear */
raster_clear(fb, vw, vh, 0x000000FF); /* black, alpha 255 */

/* orbiting circle driven by RMS */
float level = g_block_rms; /* 0..1 */

/* Debug: Show callback count and generator state every 60 frames */
if(frame % 60 == 0) {
printf("Callbacks: %d, Step: %u, Pos: %u\n", callback_count, g_generator.step, g_generator.pos_in_step);
}
int radius = 30 + (int)(80.0f * level);
int cx = vw/2 + (int)(cosf(angle)* (vw/4));
int cy = vh/2 + (int)(sinf(angle)* (vh/4));
/* filled circle background */
raster_fill_circle(fb, vw, vh, cx, cy, radius, 0x005500FF);
/* outlined ring */
raster_circle(fb, vw, vh, cx, cy, radius+10, 0x00FF00FF, 4);

/* draw scrolling floor */
terrain_draw(fb, vw, vh, frame);

/* bass hit shapes (behind floor) */
shapes_update_and_draw(fb, vw, vh);

/* spawn particles on saw hits */
if(g_generator.saw_hit){
float cx = vw * 0.3f + (rand() % (int)(vw * 0.4f));
float cy = vh * 0.2f + (rand() % (int)(vh * 0.3f));
/* color with slight hue variation from base */
float hue = (float)(rand() % 360) / 360.0f;
uint8_t r = (uint8_t)(127 + 127 * cosf(hue * 2 * M_PI));
uint8_t g = (uint8_t)(127 + 127 * cosf((hue + 0.33f) * 2 * M_PI));
uint8_t b = (uint8_t)(127 + 127 * cosf((hue + 0.66f) * 2 * M_PI));
uint32_t color = (r << 24) | (g << 16) | (b << 8) | 0xFF;
particles_spawn_burst(cx, cy, 20, color);
}

/* spawn bass shapes on bass hits */
if(g_generator.bass_hit){
shape_type_t types[] = {SHAPE_TRIANGLE, SHAPE_DIAMOND, SHAPE_HEXAGON, SHAPE_STAR, SHAPE_SQUARE};
shape_type_t type = types[rand() % 5];
/* color variation */
float hue = (float)(rand() % 360) / 360.0f;
uint8_t r = (uint8_t)(200 + 55 * cosf(hue * 2 * M_PI));
uint8_t g = (uint8_t)(200 + 55 * cosf((hue + 0.33f) * 2 * M_PI));
uint8_t b = (uint8_t)(200 + 55 * cosf((hue + 0.66f) * 2 * M_PI));
uint32_t color = (r << 24) | (g << 16) | (b << 8) | 0xFF;
shapes_spawn(type, color);
}

particles_update_and_draw(fb, vw, vh);

/* apply CRT post-processing effects */
crt_fx_apply(&crt_fx, fb, vw, vh, frame);

/* jitter effect (screen shake) */
if(crt_fx.jitter_amount > 0.01f && (rand() % 100) < 30){
int jx = (int)(-crt_fx.jitter_amount + (rand() % (int)(crt_fx.jitter_amount * 2)));
int jy = (int)(-crt_fx.jitter_amount + (rand() % (int)(crt_fx.jitter_amount * 2)));
/* shift framebuffer content */
uint32_t *temp = (uint32_t*)malloc(vw * vh * sizeof(uint32_t));
memcpy(temp, fb, vw * vh * sizeof(uint32_t));
raster_clear(fb, vw, vh, 0x000000FF);
for(int y = 0; y < vh; y++){
for(int x = 0; x < vw; x++){
int src_x = x - jx;
int src_y = y - jy;
if(src_x >= 0 && src_x < vw && src_y >= 0 && src_y < vh){
fb[y * vw + x] = temp[src_y * vw + src_x];
}
}
}
free(temp);
}

angle += 0.02f;

/* frame drop effect (skip presenting occasionally) */
if(crt_fx.frame_drop_chance < 0.01f || (rand() % 1000) > (int)(crt_fx.frame_drop_chance * 1000)){
video_frame_end();
}

frame++;
}

video_shutdown();
crt_fx_cleanup(&crt_fx);
audio_stop();
return 0;
} ||ENDFILE||
||FILE:src/c/src/melody.c||
#include "melody.h"
#include <math.h>
#include <stdio.h>

#define MELODY_MAX_SEC 2.0f

void melody_init(melody_t *m, float32_t sr)
{
osc_reset(&m->osc);
m->sr = sr;
m->len = 0;
m->pos = 0;
m->freq = 440.0f;
}

void melody_trigger(melody_t *m, float32_t freq, float32_t dur_sec)
{
m->freq = freq;
m->len = (uint32_t)(dur_sec * m->sr);
if(m->len > (uint32_t)(MELODY_MAX_SEC * m->sr))
m->len = (uint32_t)(MELODY_MAX_SEC * m->sr);
m->pos = 0;
#ifndef REALTIME_MODE
printf("*** MELODY_TRIGGER: freq=%.2f dur=%.2f len=%u ***\n", freq, dur_sec, m->len);
#endif
}

/* NO melody_process - ASM implementation required */ ||ENDFILE||
||FILE:src/c/src/melody_debug_test.c||
#include "melody.h"
#include "wav_writer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t test_frames = 1000; // Short test

melody_t melody;
melody_init(&melody, sr);

// Trigger a melody note
melody_trigger(&melody, 440.0f, 0.5f);
printf("MELODY DEBUG: triggered freq=440.0 dur=0.5 len=%u pos=%u\n", melody.len, melody.pos);

float *L = calloc(test_frames, sizeof(float));
float *R = calloc(test_frames, sizeof(float));

// Process just the first few frames with debug
printf("MELODY DEBUG: Before melody_process - pos=%u len=%u\n", melody.pos, melody.len);

melody_process(&melody, L, R, test_frames);

printf("MELODY DEBUG: After melody_process - pos=%u len=%u\n", melody.pos, melody.len);

// Check first few samples for non-zero values
printf("MELODY DEBUG: First 10 samples:\n");
for (int i = 0; i < 10; i++) {
printf(" L[%d] = %f, R[%d] = %f\n", i, L[i], i, R[i]);
}

// Check for any non-zero values in the buffer
int non_zero_count = 0;
float max_val = 0;
for (uint32_t i = 0; i < test_frames; i++) {
if (L[i] != 0.0f || R[i] != 0.0f) {
non_zero_count++;
if (fabsf(L[i]) > max_val) max_val = fabsf(L[i]);
if (fabsf(R[i]) > max_val) max_val = fabsf(R[i]);
}
}
printf("MELODY DEBUG: Non-zero samples: %d/%u, max_val=%f\n", non_zero_count, test_frames, max_val);

// Convert and save
int16_t *pcm = malloc(sizeof(int16_t) * test_frames * 2);
for (uint32_t i = 0; i < test_frames; i++) {
float vL = L[i]; if(vL > 1) vL = 1; if(vL < -1) vL = -1;
float vR = R[i]; if(vR > 1) vR = 1; if(vR < -1) vR = -1;
pcm[2*i] = (int16_t)(vL * 32767);
pcm[2*i+1] = (int16_t)(vR * 32767);
}

write_wav("melody_debug.wav", pcm, test_frames, 2, sr);
printf("Generated melody_debug.wav\n");

free(L); free(R); free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/melody_delay_test.c||
#include "wav_writer.h"
#include "melody.h"
#include "delay.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 8; // 8 seconds
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

// Initialize melody
melody_t melody;
melody_init(&melody, (float)sr);

// Initialize delay
delay_t delay;
const uint32_t max_delay_samples = 106000;
float *delay_buf = calloc(max_delay_samples * 2, sizeof(float));
delay_init(&delay, delay_buf, max_delay_samples);

// Trigger melody notes with gaps for delay to be heard
printf("Triggering melody notes with delay processing...\n");

// Note 1: 440Hz at start (0.5s duration)
melody_trigger(&melody, 440.0f, 0.5f);
for(uint32_t i = 0; i < sr/2 && i < total_frames; i++) {
if(melody.pos < melody.len) {
melody_process(&melody, &L[i], &R[i], 1);
}
}

// Note 2: 554Hz at 2 seconds (0.5s duration)
melody_trigger(&melody, 554.37f, 0.5f);
for(uint32_t i = sr*2; i < sr*2 + sr/2 && i < total_frames; i++) {
if(melody.pos < melody.len) {
melody_process(&melody, &L[i], &R[i], 1);
}
}

// Note 3: 659Hz at 4 seconds (0.5s duration)
melody_trigger(&melody, 659.25f, 0.5f);
for(uint32_t i = sr*4; i < sr*4 + sr/2 && i < total_frames; i++) {
if(melody.pos < melody.len) {
melody_process(&melody, &L[i], &R[i], 1);
}
}

// Note 4: 880Hz at 6 seconds (0.5s duration)
melody_trigger(&melody, 880.0f, 0.5f);
for(uint32_t i = sr*6; i < sr*6 + sr/2 && i < total_frames; i++) {
if(melody.pos < melody.len) {
melody_process(&melody, &L[i], &R[i], 1);
}
}

printf("Applying delay to melody (feedback=0.45)...\n");

// Apply delay to the entire melody buffer
delay_process_block(&delay, L, R, total_frames, 0.45f);

/* convert to int16 wav */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0; i<total_frames; i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
float vR=R[i]; if(vR>1) vR=1; if(vR<-1) vR=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = (int16_t)(vR*32767);
}
write_wav("melody_delay_test.wav", pcm, total_frames, 2, sr);

printf("Generated melody_delay_test.wav (8 seconds, spaced melody with delay)\n");

free(L); free(R); free(pcm); free(delay_buf);
return 0;
}
||ENDFILE||
||FILE:src/c/src/minimal_kick_test.c||
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "kick.h"

// Minimal test to reproduce kick_process() parameter corruption
int main(void) {
printf("🔍 MINIMAL KICK CORRUPTION TEST\n");
printf("Goal: Isolate if kick_process() corrupts caller's stack/registers\n\n");

// Test data on stack (simulates orchestration context)
kick_t kick;
float L[512] = {0};
float R[512] = {0};
uint32_t frames = 256;

// Canary values to detect corruption
void *canary1 = (void*)0xDEADBEEF;
void *canary2 = (void*)0xCAFEBABE;
uint32_t canary3 = 0x12345678;
uint32_t canary4 = 0x87654321;

printf("BEFORE kick_init:\n");
printf(" kick ptr: %p\n", &kick);
printf(" L ptr: %p\n", L);
printf(" R ptr: %p\n", R);
printf(" frames: %u\n", frames);
printf(" canary1: %p\n", canary1);
printf(" canary2: %p\n", canary2);
printf(" canary3: 0x%x\n", canary3);
printf(" canary4: 0x%x\n", canary4);

// Initialize kick
kick_init(&kick, 44100.0f);
kick_trigger(&kick);

printf("\nAFTER kick_init:\n");
printf(" canary1: %p\n", canary1);
printf(" canary2: %p\n", canary2);
printf(" canary3: 0x%x\n", canary3);
printf(" canary4: 0x%x\n", canary4);
printf(" kick.pos: %u\n", kick.pos);
printf(" kick.len: %u\n", kick.len);

// Call kick_process (this is where corruption might happen)
printf("\n🚨 CALLING kick_process() - WATCH FOR CORRUPTION:\n");
kick_process(&kick, L, R, frames);

printf("\nAFTER kick_process:\n");
printf(" kick ptr: %p\n", &kick);
printf(" L ptr: %p\n", L);
printf(" R ptr: %p\n", R);
printf(" frames: %u\n", frames);
printf(" canary1: %p %s\n", canary1, (canary1 == (void*)0xDEADBEEF) ? "✅" : "❌ CORRUPTED!");
printf(" canary2: %p %s\n", canary2, (canary2 == (void*)0xCAFEBABE) ? "✅" : "❌ CORRUPTED!");
printf(" canary3: 0x%x %s\n", canary3, (canary3 == 0x12345678) ? "✅" : "❌ CORRUPTED!");
printf(" canary4: 0x%x %s\n", canary4, (canary4 == 0x87654321) ? "✅" : "❌ CORRUPTED!");
printf(" kick.pos: %u\n", kick.pos);
printf(" L[0]: %f\n", L[0]);
printf(" R[0]: %f\n", R[0]);

// Check if we can make a second call (simulates orchestration sequence)
printf("\n🔄 SECOND CALL TEST (simulates snare_process call pattern):\n");

void *test_ptr = &kick;
void *test_L = L;
void *test_R = R;
uint32_t test_frames = 128;

printf(" Parameters before second call:\n");
printf(" kick ptr: %p\n", test_ptr);
printf(" L ptr: %p\n", test_L);
printf(" R ptr: %p\n", test_R);
printf(" frames: %u\n", test_frames);

// Second call
kick_process(&kick, L, R, test_frames);

printf(" ✅ Second call completed successfully!\n");
printf(" Final canary check:\n");
printf(" canary1: %p %s\n", canary1, (canary1 == (void*)0xDEADBEEF) ? "✅" : "❌ CORRUPTED!");
printf(" canary2: %p %s\n", canary2, (canary2 == (void*)0xCAFEBABE) ? "✅" : "❌ CORRUPTED!");
printf(" canary3: 0x%x %s\n", canary3, (canary3 == 0x12345678) ? "✅" : "❌ CORRUPTED!");
printf(" canary4: 0x%x %s\n", canary4, (canary4 == 0x87654321) ? "✅" : "❌ CORRUPTED!");

printf("\n🎯 CONCLUSION: kick_process() in isolation ");
if (canary1 == (void*)0xDEADBEEF && canary2 == (void*)0xCAFEBABE &&
canary3 == 0x12345678 && canary4 == 0x87654321) {
printf("WORKS CORRECTLY ✅\n");
printf(" Stack corruption happens only in multi-voice orchestration context\n");
} else {
printf("CORRUPTS STACK ❌\n");
printf(" kick_process() has intrinsic stack corruption bug\n");
}

return 0;
} ||ENDFILE||
||FILE:src/c/src/noise.c||
#include "noise.h"

void noise_block(rng_t *rng, float *out, uint32_t n)
{
for (uint32_t i = 0; i < n; ++i) {
// rng_next_float returns [0,1). Map to [-1,1)
float v = rng_next_float(rng) * 2.0f - 1.0f;
out[i] = v;
}
} ||ENDFILE||
||FILE:src/c/src/osc.c||
#include "osc.h"
#include <math.h>

#define TAU 6.28318530717958647692f

#ifndef OSC_SINE_ASM
void osc_sine_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr)
{
const float32_t phase_inc = TAU * freq / sr;
float32_t ph = o->phase;
for (uint32_t i = 0; i < n; ++i) {
out[i] = sinf(ph);
ph += phase_inc;
if (ph >= TAU) ph -= TAU;
}
o->phase = ph;
}
#endif

#ifndef OSC_SHAPES_ASM
void osc_saw_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr)
{
const float32_t phase_inc = TAU * freq / sr;
float32_t ph = o->phase;
for (uint32_t i = 0; i < n; ++i) {
float32_t frac = ph / TAU; // 0..1
out[i] = 2.0f * frac - 1.0f; // -1..1
ph += phase_inc;
if (ph >= TAU) ph -= TAU;
}
o->phase = ph;
}

void osc_square_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr)
{
const float32_t phase_inc = TAU * freq / sr;
float32_t ph = o->phase;
for (uint32_t i = 0; i < n; ++i) {
out[i] = (ph < TAU * 0.5f) ? 1.0f : -1.0f;
ph += phase_inc;
if (ph >= TAU) ph -= TAU;
}
o->phase = ph;
}

void osc_triangle_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr)
{
const float32_t phase_inc = TAU * freq / sr;
float32_t ph = o->phase;
for (uint32_t i = 0; i < n; ++i) {
float32_t frac = ph / TAU; // 0..1
float32_t val = 2.0f * fabsf(2.0f * frac - 1.0f) - 1.0f; // triangle -1..1
out[i] = val;
ph += phase_inc;
if (ph >= TAU) ph -= TAU;
}
o->phase = ph;
}
#endif ||ENDFILE||
||FILE:src/c/src/particles.c||
#include "particles.h"
#include "raster.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* Simple 5x7 bitmap font for ASCII glyphs */
static const uint8_t FONT_5X7[][7] = {
/* A */ {0x0E,0x11,0x11,0x1F,0x11,0x11,0x11},
/* B */ {0x1E,0x11,0x11,0x1E,0x11,0x11,0x1E},
/* C */ {0x0E,0x11,0x10,0x10,0x10,0x11,0x0E},
/* D */ {0x1E,0x11,0x11,0x11,0x11,0x11,0x1E},
/* E */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x1F},
/* F */ {0x1F,0x10,0x10,0x1E,0x10,0x10,0x10},
/* G */ {0x0E,0x11,0x10,0x17,0x11,0x11,0x0E},
/* H */ {0x11,0x11,0x11,0x1F,0x11,0x11,0x11},
/* I */ {0x0E,0x04,0x04,0x04,0x04,0x04,0x0E},
/* J */ {0x07,0x02,0x02,0x02,0x02,0x12,0x0C},
/* K */ {0x11,0x12,0x14,0x18,0x14,0x12,0x11},
/* L */ {0x10,0x10,0x10,0x10,0x10,0x10,0x1F},
/* M */ {0x11,0x1B,0x15,0x15,0x11,0x11,0x11},
/* N */ {0x11,0x19,0x15,0x13,0x11,0x11,0x11},
/* O */ {0x0E,0x11,0x11,0x11,0x11,0x11,0x0E},
/* P */ {0x1E,0x11,0x11,0x1E,0x10,0x10,0x10},
/* Q */ {0x0E,0x11,0x11,0x11,0x15,0x12,0x0D},
/* R */ {0x1E,0x11,0x11,0x1E,0x14,0x12,0x11},
/* S */ {0x0E,0x11,0x10,0x0E,0x01,0x11,0x0E},
/* T */ {0x1F,0x04,0x04,0x04,0x04,0x04,0x04},
/* U */ {0x11,0x11,0x11,0x11,0x11,0x11,0x0E},
/* V */ {0x11,0x11,0x11,0x11,0x11,0x0A,0x04},
/* W */ {0x11,0x11,0x11,0x15,0x15,0x1B,0x11},
/* X */ {0x11,0x11,0x0A,0x04,0x0A,0x11,0x11},
/* Y */ {0x11,0x11,0x0A,0x04,0x04,0x04,0x04},
/* Z */ {0x1F,0x01,0x02,0x04,0x08,0x10,0x1F},
/* 0 */ {0x0E,0x11,0x13,0x15,0x19,0x11,0x0E},
/* 1 */ {0x04,0x0C,0x04,0x04,0x04,0x04,0x0E},
/* 2 */ {0x0E,0x11,0x01,0x02,0x04,0x08,0x1F},
/* 3 */ {0x0E,0x11,0x01,0x06,0x01,0x11,0x0E},
/* 4 */ {0x02,0x06,0x0A,0x12,0x1F,0x02,0x02},
/* 5 */ {0x1F,0x10,0x1E,0x01,0x01,0x11,0x0E},
/* 6 */ {0x06,0x08,0x10,0x1E,0x11,0x11,0x0E},
/* 7 */ {0x1F,0x01,0x02,0x04,0x08,0x08,0x08},
/* 8 */ {0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E},
/* 9 */ {0x0E,0x11,0x11,0x0F,0x01,0x02,0x0C},
/* ! */ {0x04,0x04,0x04,0x04,0x04,0x00,0x04},
/* @ */ {0x0E,0x11,0x17,0x15,0x17,0x10,0x0E},
/* # */ {0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A},
/* $ */ {0x04,0x0F,0x14,0x0E,0x05,0x1E,0x04},
/* % */ {0x18,0x19,0x02,0x04,0x08,0x13,0x03},
/* ^ */ {0x04,0x0A,0x11,0x00,0x00,0x00,0x00},
/* & */ {0x0C,0x12,0x14,0x08,0x15,0x12,0x0D},
/* * */ {0x00,0x04,0x15,0x0E,0x15,0x04,0x00},
/* + */ {0x00,0x04,0x04,0x1F,0x04,0x04,0x00},
/* - */ {0x00,0x00,0x00,0x1F,0x00,0x00,0x00},
/* = */ {0x00,0x00,0x1F,0x00,0x1F,0x00,0x00},
/* ? */ {0x0E,0x11,0x01,0x02,0x04,0x00,0x04}
};

static const char GLYPH_SET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*+-=?";

static void draw_glyph(uint32_t *fb,int w,int h,int x,int y,uint8_t glyph_idx,uint32_t color)
{
if(glyph_idx >= sizeof(FONT_5X7)/sizeof(FONT_5X7[0])) return;
const uint8_t *bitmap = FONT_5X7[glyph_idx];
for(int row=0;row<7;row++){
uint8_t bits = bitmap[row];
for(int col=0;col<5;col++){
if(bits & (1<<(4-col))){
int px = x + col;
int py = y + row;
if((unsigned)px < (unsigned)w && (unsigned)py < (unsigned)h){
fb[py*w + px] = color;
}
}
}
}
}

static particle_t g_particles[MAX_PARTICLES];
static int g_count=0;

void particles_init(void){ g_count=0; }

void particles_spawn_burst(float x,float y,int count,uint32_t color)
{
if(count<1) return;
if(count>MAX_PARTICLES) count = MAX_PARTICLES;
float angle_step = 2.0f * (float)M_PI / (float)count;
for(int i=0;i<count;i++){
if(g_count>=MAX_PARTICLES) break;
float ang = i * angle_step;
particle_t *p = &g_particles[g_count++];
p->x = x; p->y=y;
float speed = 2.0f + (rand()%100)/50.0f; /* 2–4 */
p->vx = cosf(ang)*speed;
p->vy = sinf(ang)*speed;
p->life = 30 + (rand()%2)*30 + (rand()%2)*30; /* 30,60,90 */
p->max_life = p->life;
p->color = color;
p->glyph = (uint8_t)(rand() % strlen(GLYPH_SET));
}
}

void particles_update_and_draw(uint32_t *fb,int w,int h)
{
for(int i=0;i<g_count;){
particle_t *p = &g_particles[i];
/* update */
p->x += p->vx;
p->y += p->vy;
p->vy += 0.1f; /* gravity */
p->life--;
if(p->life<=0 || p->x<0 || p->x>=w || p->y>=h){
/* remove by swap with last */
g_particles[i] = g_particles[--g_count];
continue;
}
/* fade alpha based on life */
float alpha = (float)p->life / (float)p->max_life;
uint32_t r = (p->color >> 24) & 0xFF;
uint32_t g = (p->color >> 16) & 0xFF;
uint32_t b = (p->color >> 8) & 0xFF;
r = (uint32_t)(r * alpha);
g = (uint32_t)(g * alpha);
b = (uint32_t)(b * alpha);
uint32_t faded_color = (r<<24)|(g<<16)|(b<<8)|0xFF;

/* draw glyph */
draw_glyph(fb,w,h,(int)p->x-2,(int)p->y-3,p->glyph,faded_color);
++i;
}
} ||ENDFILE||
at txn 0x3cae9f60b18c99bf774beee4ee67113005b8ac7bcad855c082c90351062e2b9a Aug-20-2025 12:47:11 AM UTC (26 days ago)
) / 100.0f;
float val = 0.7f + ((grid_x * 5 + grid_y * 13) % 30) / 100.0f;
float rotation = base_rotation + (grid_x + grid_y) * 0.25f;

int x = boss_x + (grid_x - grid_size/2) * 30;
int y = boss_y + (grid_y - grid_size/2) * 30;
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;

case 5: // Random Chaos Formation - completely random placement
for (int i = 0; i < num_components; i++) {
int shape = prng_range(&g_boss_prng, 5);
int size = 10 + prng_range(&g_boss_prng, 30); // Wide size range
float random_x = boss_x + prng_range(&g_boss_prng, 120) - 60; // ±60 pixel spread
float random_y = boss_y + prng_range(&g_boss_prng, 120) - 60;
float shape_hue = prng_range(&g_boss_prng, 100) / 100.0f; // Completely random hue
float sat = 0.5f + prng_range(&g_boss_prng, 50) / 100.0f;
float val = 0.6f + prng_range(&g_boss_prng, 40) / 100.0f;
float rotation = prng_range(&g_boss_prng, 360) * M_PI / 180.0f;

draw_boss_shape(random_x, random_y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;

case 6: // Layered Formation - concentric circles of different shapes
int layers = 1 + (num_components / 4);
for (int layer = 0; layer < layers; layer++) {
int shapes_in_layer = 3 + layer * 2;
float layer_radius = 20 + layer * 25;
for (int i = 0; i < shapes_in_layer && layer * shapes_in_layer + i < num_components; i++) {
float angle = (2.0f * M_PI * i) / shapes_in_layer;
int shape = (layer + i) % 5;
int size = base_size - layer * 3; // Smaller shapes in outer layers
float shape_hue = boss_base_hue + layer * 0.2f + i * 0.1f;
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.8f - layer * 0.1f;
float val = 0.9f - layer * 0.1f;
float rotation = base_rotation + layer * 0.5f + i * 0.3f;

int x = boss_x + (int)(cos(angle) * layer_radius);
int y = boss_y + (int)(sin(angle) * layer_radius);
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
}
break;

case 7: // Pulsing Formation - sizes vary with audio and frame
for (int i = 0; i < num_components; i++) {
float pulse_phase = (i * 0.5f) + (frame * 0.08f);
float pulse_factor = 0.7f + 0.3f * sin(pulse_phase) + audio_level * 0.4f;
int shape = i % 5;
int size = (int)(base_size * pulse_factor);
float angle = (2.0f * M_PI * i) / num_components;
float radius = 35 + sin(frame * 0.05f + i) * 15; // Varying radius
float shape_hue = boss_base_hue + sin(pulse_phase) * 0.2f;
if (shape_hue > 1.0f) shape_hue -= 1.0f;
if (shape_hue < 0.0f) shape_hue += 1.0f;
float sat = 0.7f + audio_level * 0.3f;
float val = 0.8f + sin(pulse_phase) * 0.2f;
float rotation = base_rotation + pulse_phase;

int x = boss_x + (int)(cos(angle) * radius);
int y = boss_y + (int)(sin(angle) * radius);
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;
}
}

int main(int argc, char *argv[]) {
// CLI: <audio.wav> [seed_hex] [max_frames] [--pipe-ppm] [--range start end]
bool pipe_ppm = false;
int range_start = -1, range_end = -1;

if (argc < 2 || argc > 8) {
printf("🎬 NotDeafBeef Frame Generator\n");
printf("Usage: %s <audio_file.wav> [seed_hex] [max_frames] [--pipe-ppm] [--range start end]\n", argv[0]);
printf("Example: %s audio.wav 0xDEADBEEF\n", argv[0]);
printf("Example: %s audio.wav 0xDEADBEEF 24 --pipe-ppm # Stream frames to stdout\n", argv[0]);
printf("Example: %s audio.wav 0xDEADBEEF 0 --range 100 200 # Render frames 100-199\n", argv[0]);
return 1;
}

// Parse flags and options
int arg_idx = argc - 1;
while (arg_idx >= 2) {
if (strcmp(argv[arg_idx], "--pipe-ppm") == 0) {
pipe_ppm = true;
argc--;
arg_idx--;
} else if (strcmp(argv[arg_idx], "--range") == 0 && arg_idx >= 3) {
// --range start end
range_end = atoi(argv[arg_idx + 1]);
range_start = atoi(argv[arg_idx]);
argc -= 3; // Remove --range start end
arg_idx -= 3;
} else {
break;
}
}

printf("🎨 Generating visual frames from audio: %s\n", argv[1]);

// Load audio file
if (!load_wav_file(argv[1])) {
fprintf(stderr, "❌ Failed to load audio file: %s\n", argv[1]);
return 1;
}

print_audio_info();

// Initialize audio-visual mapping
init_audio_visual_mapping();

// Initialize visual systems with seed from audio
uint32_t seed = 0xCAFEBABE; // Could be derived from audio file hash

// For testing: allow command line seed override
if (argc >= 3) {
// OPTIMIZATION: Hash long transaction hashes to 32-bit seeds
seed = hash_transaction_to_seed(argv[2]);
printf("🎲 Using hashed seed: 0x%08X (from %s)\n", seed, argv[2]);
}

// Initialize PRNG streams
init_visual_prng_streams(seed);

// Allocate pixel buffer
uint32_t *pixels = calloc(VIS_WIDTH * VIS_HEIGHT, sizeof(uint32_t));
if (!pixels) {
fprintf(stderr, "❌ Failed to allocate pixel buffer\n");
return 1;
}

printf("🚀 Initializing visual systems...\n");

float base_hue = 0.5f;

// Prefer timeline sidecar if present (<audio>.json) to drive visuals deterministically
timeline_t tl = {0};
char sidecar_path[512];
snprintf(sidecar_path, sizeof(sidecar_path), "%s.json", argv[1]);
bool have_timeline = timeline_load(sidecar_path, &tl);
if (have_timeline) {
printf("🧭 Using timeline sidecar: %s\n", sidecar_path);
} else {
printf("ℹ️ No timeline sidecar found (%s). Falling back to WAV analysis.\n", sidecar_path);
}

init_terrain_asm(seed, base_hue);
// init_particles_asm(); // Removed for now
init_glitch_system_asm(seed, 0.5f);
init_bass_hits_asm();

// Initialize second terrain system for top with different color
uint32_t top_seed = seed ^ 0x12345678; // Different seed for variation
float top_hue = base_hue + 0.3f; // Shift hue for different color
if (top_hue > 1.0f) top_hue -= 1.0f; // Wrap around
// We'll call init_terrain_asm again but we need a way to have two terrains

printf("🎬 Generating frames at 60 FPS...\n");

int frame = 0;
int total_frames = 0;

// Calculate total frames needed (audio duration * FPS)
// Get actual audio duration from loaded WAV file instead of hardcoded 5.0s
float audio_duration = get_audio_duration(); // Use actual audio duration
total_frames = (int)(audio_duration * VIS_FPS);

// Allow frame limit override for quick testing
if (argc == 4) {
int max_frames = atoi(argv[3]);
if (max_frames > 0 && max_frames < total_frames) {
total_frames = max_frames;
fprintf(pipe_ppm ? stderr : stdout, "🎯 Limiting to %d frames for quick test\n", total_frames);
}
}

// Apply range filtering if specified
int start_frame = 0;
int end_frame = total_frames;
if (range_start >= 0 && range_end >= 0) {
if (range_start >= total_frames || range_end <= range_start) {
fprintf(stderr, "❌ Invalid range: %d-%d (total frames: %d)\n", range_start, range_end, total_frames);
return 1;
}
start_frame = range_start;
end_frame = (range_end > total_frames) ? total_frames : range_end;
fprintf(pipe_ppm ? stderr : stdout, "🎯 Rendering slice: frames %d-%d\n", start_frame, end_frame-1);
}

fprintf(pipe_ppm ? stderr : stdout,
"📽️ Total frames to generate: %d (%.1f seconds at %d FPS)\n",
end_frame - start_frame, audio_duration, VIS_FPS);

frame = start_frame; // Start from specified frame
while (frame < end_frame && !is_audio_finished(frame)) {
// Clear frame
clear_frame_asm(pixels, 0x000000); // Black background

// Set current pixels for shape drawing functions
set_current_pixels(pixels);

// Get audio-driven parameters (from sidecar if available)
float audio_hue = have_timeline ? timeline_compute_hue(&tl, frame, VIS_FPS)
: get_audio_driven_hue_shift(frame);
float audio_level = have_timeline ? timeline_compute_level(&tl, frame, VIS_FPS)
: get_smoothed_audio_level(frame);
float glitch_intensity = have_timeline ? timeline_compute_glitch(&tl, frame, VIS_FPS)
: get_audio_driven_glitch_intensity(frame);

// Update workload budget based on current audio intensity
update_workload_budget(audio_level);

// Update audio-visual effects
update_audio_visual_effects(frame, audio_hue);

// Update glitch intensity
update_glitch_intensity_asm(glitch_intensity);

// Focus on terrain systems

// Calculate different audio responses for each terrain
float bottom_speed_multiplier = 1.0f + audio_level * 3.0f; // 1x to 4x speed
float top_hue = audio_hue + 0.3f; // Different hue for top terrain
if (top_hue > 1.0f) top_hue -= 1.0f;

// Draw bottom terrain (enhanced system) - moderate speed with dynamic colors
int bottom_frame = (int)(frame * bottom_speed_multiplier);
draw_terrain_enhanced_asm(pixels, bottom_frame, audio_level);

// Draw top terrain (new system) - different pattern and color
draw_top_terrain(pixels, frame, top_hue, audio_level);

// Update bass hits animation (needed for proper rendering)
float elapsed_ms = frame * FRAME_TIME_MS;
update_bass_hits_asm(elapsed_ms);

// Budget-aware visual rendering - skip expensive elements on heavy frames
if (g_budget.complexity_factor < 0.8f) { // Only render complex elements when audio is not too intense
// Draw ship flying through the corridor (pass seed for unique design)
draw_ship(pixels, frame, audio_hue, audio_level, seed);

// Draw enemy boss on the right side
draw_enemy_boss(pixels, frame, audio_hue, audio_level, seed);

// Update and draw projectiles (ship firing at boss)
update_projectiles();
draw_projectiles();
} else {
// High intensity - only update projectiles, don't render ship/boss
update_projectiles();
draw_projectiles();
}

// Draw the bass hits (this renders the ship and any other shapes)
draw_bass_hits_asm(pixels, frame);

// Output frame (with slice-aware naming)
if (pipe_ppm) {
write_frame_ppm(stdout, pixels);
} else {
// Include range info in filename for parallel slice rendering
if (range_start >= 0 && range_end >= 0) {
char filename[256];
snprintf(filename, sizeof(filename), "frame_%04d_slice_%d_%d.ppm", frame, range_start, range_end-1);
FILE *f = fopen(filename, "wb");
if (!f) { fprintf(stderr, "Could not create %s\n", filename); return 1; }
write_frame_ppm(f, pixels);
fclose(f);
fprintf(stderr, "✅ Generated %s\n", filename);
} else {
save_frame_as_ppm(pixels, frame);
}
}

// Progress indicator
if (!pipe_ppm && frame % 30 == 0) {
printf("🎬 Frame %d/%d (%.1f%% complete)\n",
frame, end_frame, ((frame - start_frame) * 100.0f) / (end_frame - start_frame));
} else if (pipe_ppm && frame % 120 == 0) {
fprintf(stderr, "🎬 Frame %d/%d (%.1f%%)\n",
frame, end_frame, ((frame - start_frame) * 100.0f) / (end_frame - start_frame));
}

frame++;
}

if (!pipe_ppm) {
printf("🎉 Frame generation complete! Generated %d frames\n", frame - start_frame);
if (range_start >= 0 && range_end >= 0) {
printf("📽️ Slice complete: frames %d-%d\n", range_start, range_end-1);
printf("📽️ To merge slices: use parallel_render_coordinator.sh\n");
} else {
printf("📽️ To create video: ffmpeg -r 60 -i frame_%%04d.ppm -c:v libx264 -pix_fmt yuv420p output.mp4\n");
}
} else {
fprintf(stderr, "🎉 Frame piping complete! Sent %d frames to stdout.\n", frame - start_frame);
fprintf(stderr, "💡 Example: ./generate_frames audio.wav 0xSEED --pipe-ppm | ffmpeg -r 60 -f image2pipe -vcodec ppm -i - -i audio.wav -c:v libx264 -pix_fmt yuv420p -shortest output.mp4\n");
}

// Cleanup
free(pixels);
cleanup_audio_data();
if (have_timeline) timeline_free(&tl);

return 0;
}



||ENDFILE||
||FILE:src/c/src/generator.c||
#include "generator.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include "fm_presets.h"
#include "euclid.h"

/* Helper for RNG float */
#define RNG_FLOAT(rng) ( (rng_next_u32(rng) >> 8) * (1.0f/16777216.0f) )

/* Global RMS for real-time visual feedback */
volatile float g_block_rms = 0.0f;

void generator_init(generator_t *g, uint64_t seed)
{
memset(g, 0, sizeof(generator_t));
g->rng = rng_seed(seed);

/* ---- Derive per-run musical variation from seed ---- */
uint8_t kick_hits = 2 + (rng_next_u32(&g->rng) % 3);
uint8_t snare_hits = 1 + (rng_next_u32(&g->rng) % 3);
uint8_t hat_hits = 4 + (rng_next_u32(&g->rng) % 5);

float bpm = 50.0f + (RNG_FLOAT(&g->rng) * 70.0f);
music_time_init(&g->mt, bpm);
music_globals_init(&g->music, &g->rng);

/* ---- Init voices ---- */
kick_init(&g->kick, SR);
snare_init(&g->snare, SR, seed ^ 0xABCDEF);
hat_init(&g->hat, SR, seed ^ 0x123456);
melody_init(&g->mel, SR);
fm_voice_init(&g->mid_fm, SR);
fm_voice_init(&g->bass_fm, SR);

/* ---- Init delay ---- */
delay_init(&g->delay, g->delay_buf, MAX_DELAY_SAMPLES);

/* ---- Create simple event sequence ---- */
eq_init(&g->q);

/* Simple patterns based on variations */
uint8_t kick_pattern = (kick_hits >= 3) ? 0x91 : 0x11; // kick on 1, and maybe 5
uint8_t snare_pattern = (snare_hits >= 2) ? 0x44 : 0x04; // snare on 3, maybe 7
uint8_t hat_pattern = 0xAA; // hat on off-beats
uint8_t melody_pattern = 0xAA; // melody on even beats
uint8_t mid_fm_pattern = 0x88; // mid FM on beats 4 and 8
uint8_t bass_fm_pattern = 0x11; // bass FM on beats 1 and 5

for(uint32_t step = 0; step < TOTAL_STEPS; step++) {
uint32_t t = step * g->mt.step_samples;

if(kick_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_KICK, 127);
if(snare_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_SNARE, 100);
if(hat_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_HAT, 80);
if(melody_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_MELODY, 100);
if(mid_fm_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_MID, 100);
if(bass_fm_pattern & (1 << (step % 8)))
eq_push(&g->q, t, EVT_FM_BASS, 80);
}
}

/* generator_process is implemented in ASM - src/asm/active/generator.s */
||ENDFILE||
||FILE:src/c/src/generator_offsets.c||
/* generator_offsets.c - Generate ASM constants for struct offsets */
#include <stddef.h>
#include "generator.h"

#define OFF(sym, type, member) \
asm(".equ " #sym ", %0" :: "i"(offsetof(type, member)));

void generator_offsets(void) {
OFF(G_OFF_KICK , generator_t, kick)
OFF(G_OFF_SNARE , generator_t, snare)
OFF(G_OFF_HAT , generator_t, hat)
OFF(G_OFF_MELODY , generator_t, mel)
OFF(G_OFF_MID_FM , generator_t, mid_fm)
OFF(G_OFF_BASS_FM , generator_t, bass_fm)
OFF(G_OFF_EVQ , generator_t, q)
OFF(G_OFF_EV_COUNT , generator_t, q.count)
OFF(G_OFF_EVENT_IDX , generator_t, event_idx)
OFF(G_OFF_STEP , generator_t, step)
OFF(G_OFF_POS_IN_STEP, generator_t, pos_in_step)
OFF(G_OFF_DELAY , generator_t, delay)
OFF(G_OFF_LIMITER , generator_t, limiter)
}
||ENDFILE||
||FILE:src/c/src/generator_step.c||
#include "generator.h"
#include "fm_presets.h"
#include "fm_voice.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define DEBUG_MID_LOG 1

/* Helper for RNG float (copied from generator.c) */
#define RNG_FLOAT(rng) ( (rng_next_u32(rng) >> 8) * (1.0f/16777216.0f) )

/* Global debug counter for mid-FM triggers */
int g_mid_trigger_count = 0;

void generator_trigger_step(generator_t *g)
{
/* Only act at the very start of a step */
if(g->pos_in_step != 0) return;

uint32_t t_step_start = g->step * g->mt.step_samples;

while(g->event_idx < g->q.count && g->q.events[g->event_idx].time == t_step_start){
event_t *e = &g->q.events[g->event_idx];
#ifndef REALTIME_MODE
printf("TRIGGER type=%u aux=%u step=%u pos=%u\n", e->type, e->aux, g->step, g->pos_in_step);
#endif
switch(e->type){
case EVT_KICK:
kick_trigger(&g->kick);
break;
case EVT_SNARE:
snare_trigger(&g->snare);
break;
case EVT_HAT:
hat_trigger(&g->hat);
break;
case EVT_MELODY: {
float32_t freq = g->music.root_freq;
int deg;
switch(e->aux){
case 0:
freq *= 4.0f;
break;
case 1:
deg = g->music.scale_degrees[rng_next_u32(&g->rng) % (g->music.scale_len - 1) + 1];
freq *= powf(2.0f, deg / 12.0f + 1.0f);
break;
case 2:
freq *= 4.0f;
break;
case 3:
deg = g->music.scale_degrees[rng_next_u32(&g->rng) % (g->music.scale_len - 1) + 1];
freq *= powf(2.0f, deg / 12.0f);
break;
}
melody_trigger(&g->mel, freq, g->mt.beat_sec);
g->saw_hit = true;
break; }
case EVT_MID: {
/* TEMP DEBUG: Log each mid trigger */
#ifdef DEBUG_MID_LOG
#ifndef REALTIME_MODE
printf("MID TRIGGER step=%u aux=%u pos=%u\n", g->step, e->aux, g->pos_in_step);
#endif
#endif
g_mid_trigger_count++; /* count how many actually fire */
uint8_t idx = e->aux;
int deg = g->music.scale_degrees[rng_next_u32(&g->rng) % g->music.scale_len];
float32_t freq = g->music.root_freq * powf(2.0f, deg / 12.0f + 1.0f);
if(idx < 3){
simple_wave_t w = (idx == 0) ? SIMPLE_TRI : (idx == 1) ? SIMPLE_SINE : SIMPLE_SQUARE;
simple_voice_trigger(&g->mid_simple, freq, g->mt.step_sec, w, 0.2f, 6.0f);
} else {
fm_params_t mid_presets[4] = {FM_PRESET_BELLS, FM_PRESET_CALM, FM_PRESET_QUANTUM, FM_PRESET_PLUCK};
fm_params_t p = mid_presets[(idx - 3) % 4];
fm_voice_trigger(&g->mid_fm, freq, g->mt.step_sec + (1.0f/ (float32_t)SR), p.ratio, p.index, p.amp, p.decay);
}
break; }
case EVT_FM_BASS: {
int deg = g->music.scale_degrees[rng_next_u32(&g->rng) % g->music.scale_len];
float32_t freq = g->music.root_freq / 4.0f * powf(2.0f, deg / 12.0f);
uint8_t bass_choice = rng_next_u32(&g->rng) % 3;
fm_params_t p;
switch(bass_choice){
default:
case 0:
p = FM_BASS_DEFAULT;
break;
case 1:
p = FM_BASS_QUANTUM;
break;
case 2:
p = FM_BASS_PLUCKY;
break;
}
fm_voice_trigger(&g->bass_fm, freq, g->mt.beat_sec * 2, p.ratio, p.index, p.amp, p.decay);
g->bass_hit = true;
break; }
}
g->event_idx++;
}

#ifdef DEBUG_MID_LOG
#ifndef REALTIME_MODE
printf("TRIGGER_STEP END event_idx=%u step=%u pos=%u\n", g->event_idx, g->step, g->pos_in_step);
#endif
#endif
}

void generator_process_voices(generator_t *g, float32_t *Ld, float32_t *Rd,
float32_t *Ls, float32_t *Rs, uint32_t n)
{
// TEMP: Only kick for testing
kick_process(&g->kick, Ld, Rd, n);

// Check if kick actually wrote to the buffer
static int check_count = 0;
if(check_count < 3) { // Only check first few calls
float max_val = 0;
for(uint32_t i = 0; i < (n < 100 ? n : 100); i++) { // Check first 100 samples
if(Ld[i] > max_val || Ld[i] < -max_val) {
max_val = (Ld[i] > 0) ? Ld[i] : -Ld[i];
}
}
// Use a simple debug approach that won't corrupt the stack
if(max_val > 0.001) {
// Write to stderr to avoid printf issues
const char msg[] = "KICK_BUFFER_HAS_AUDIO\n";
write(2, msg, sizeof(msg)-1);
} else {
const char msg[] = "KICK_BUFFER_SILENT\n";
write(2, msg, sizeof(msg)-1);
}
check_count++;
}
} ||ENDFILE||
||FILE:src/c/src/hat.c||
#include "hat.h"
#include <math.h>
#include <stdio.h>

#define HAT_DECAY_RATE 120.0f
#define HAT_DUR_SEC 0.05f

void hat_init(hat_t *h, float32_t sr, uint64_t seed)
{
h->pos=0; h->len=0; h->sr=sr;
h->env = 0.0f;
h->env_coef = 0.0f;
h->rng = rng_seed(seed);
}

void hat_trigger(hat_t *h)
{
h->pos = 0;
h->len = (uint32_t)(HAT_DUR_SEC * h->sr);
h->env = 1.0f;
h->env_coef = expf(-HAT_DECAY_RATE / h->sr);

#ifndef REALTIME_MODE
printf("*** HAT_TRIGGER: len=%u env_coef=%f ***\n",
h->len, h->env_coef);
fflush(stdout);
#endif
}

/* NO hat_process - ASM implementation required */
||ENDFILE||
||FILE:src/c/src/kick.c||
#include "kick.h"
#include <math.h>
#include <assert.h>
#include <stdio.h>

#define KICK_BASE_FREQ 70.0f
#define TAU (2.0f * M_PI)

void kick_init(kick_t *k, float32_t sr)
{
k->sr = sr;
k->pos = k->len; // initially inactive

/* Compute recurrence coefficients for sine oscillator */
float32_t delta = TAU * KICK_BASE_FREQ / k->sr;
k->k1 = 2.0f * cosf(delta);

/* Reset sine recurrence state */
k->y_prev = 0.0f; /* sin(0) */
k->y_prev2 = -sinf(delta); /* y[-1] = -sin(Δ) */
}

void kick_trigger(kick_t *k)
{
k->pos = 0;
k->env = 1.0f;
k->len = (uint32_t)(k->sr * 0.5f); // 500ms duration
k->env_coef = powf(0.001f, 1.0f / k->len); // -60dB envelope

/* Reset sine recurrence state */
float32_t delta = TAU * KICK_BASE_FREQ / k->sr;
k->y_prev = 0.0f; /* sin(0) */
k->y_prev2 = -sinf(delta); /* y[-1] = -sin(Δ) */

#ifndef REALTIME_MODE
printf("*** KICK_TRIGGER: len=%u env_coef=%f y_prev2=%f k1=%f ***\n",
k->len, k->env_coef, k->y_prev2, k->k1);
fflush(stdout);
#endif
}

/* NO kick_process - ASM implementation required */
||ENDFILE||
at txn 0x59442ead57fe79485a7d5e09ffcf80b974db989b67565cfb5e23c0b240de64f2 Aug-20-2025 12:46:59 AM UTC (26 days ago)

||FILE:src/c/src/generate_frames.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include "src/include/visual_types.h"
#include "src/include/deterministic_prng.h"

// Deterministically hash a transaction hash to a 32-bit seed
// Preserves deafbeef-style reproducibility while handling long hashes
uint32_t hash_transaction_to_seed(const char* tx_hash) {
uint32_t seed = 0;
const char* hex_start = tx_hash;

// Skip "0x" prefix if present
if (tx_hash[0] == '0' && (tx_hash[1] == 'x' || tx_hash[1] == 'X')) {
hex_start += 2;
}

size_t len = strlen(hex_start);

// XOR all 8-character chunks together for good distribution
for (int i = 0; i < len; i += 8) {
char chunk[9] = {0};
int chunk_len = (len - i >= 8) ? 8 : (len - i);
strncpy(chunk, hex_start + i, chunk_len);

// Convert hex chunk to uint32_t and XOR into seed
uint32_t chunk_val = (uint32_t)strtoul(chunk, NULL, 16);
seed ^= chunk_val;
}

// If seed is 0, use a fallback to avoid degenerate case
if (seed == 0) {
seed = 0xDEADBEEF;
}

return seed;
}

// Forward declarations for ASM visual functions
extern void clear_frame_asm(uint32_t *pixels, uint32_t color);
extern void init_terrain_asm(uint32_t seed, float base_hue);
extern void draw_terrain_asm(uint32_t *pixels, int frame);
extern void draw_terrain_enhanced_asm(uint32_t *pixels, int frame, float audio_level);
// Particles removed for now
// extern void init_particles_asm(void);
// extern void update_particles_asm(float elapsed_ms, float step_sec, float base_hue);
// extern void draw_particles_asm(uint32_t *pixels);
extern void init_glitch_system_asm(uint32_t seed, float intensity);
extern void update_glitch_intensity_asm(float new_intensity);
extern void init_bass_hits_asm(void);
extern void draw_bass_hits_asm(uint32_t *pixels, int frame);
extern void update_bass_hits_asm(float elapsed_ms);
extern uint32_t circle_color_asm(float hue, float saturation, float value);
extern void draw_circle_filled_asm(uint32_t *pixels, int cx, int cy, int radius, uint32_t color);
extern void draw_ascii_char_asm(uint32_t *pixels, int x, int y, char c, uint32_t color, int bg_alpha);

// Global pixels buffer for shape drawing
static uint32_t *g_current_pixels = NULL;
void set_current_pixels(uint32_t *pixels) { g_current_pixels = pixels; }

// Workload budget system for 60 FPS stability
typedef struct {
int max_projectiles; // Dynamic cap on active projectiles
int max_boss_shapes; // Dynamic cap on boss formation complexity
int min_firing_cooldown; // Dynamic minimum between shots
float complexity_factor; // 0.0-1.0 based on audio intensity
} workload_budget_t;

static workload_budget_t g_budget = {0};

// Workload budget management
void update_workload_budget(float audio_level) {
// AGGRESSIVE budget to maintain 60 FPS - performance over visual complexity

// Drastically reduced base budgets for 60 FPS stability
int base_projectiles = 2; // Reduced from 8
int base_boss_shapes = 2; // Reduced from 5
int base_cooldown = 10; // Reduced from 15

// Audio intensity factor (0.0 = quiet, 1.0 = loud)
g_budget.complexity_factor = audio_level;

// Scale projectiles: 2-6 based on audio, capped at 6 for performance
g_budget.max_projectiles = base_projectiles + (int)(audio_level * 4);
if (g_budget.max_projectiles > 6) g_budget.max_projectiles = 6;

// Scale boss complexity: 2-4 shapes max, very conservative
g_budget.max_boss_shapes = base_boss_shapes + (int)(audio_level * 2);
if (g_budget.max_boss_shapes > 4) g_budget.max_boss_shapes = 4;

// Faster firing on loud sections, but not too fast
g_budget.min_firing_cooldown = base_cooldown - (int)(audio_level * 6);
if (g_budget.min_firing_cooldown < 5) g_budget.min_firing_cooldown = 5;
}

// Projectile system for ship firing
typedef struct {
float x, y; // Position
float vx, vy; // Velocity
char character; // ASCII character ('o', 'x', '-', '0', etc.)
uint32_t color; // Projectile color
int life; // Remaining life frames
bool active; // Is this projectile active?
} projectile_t;

#define MAX_PROJECTILES 32
#define VIS_WIDTH 800
#define VIS_HEIGHT 600
static projectile_t projectiles[MAX_PROJECTILES] = {0};
static int last_shot_frame = -100; // Frame when last shot was fired

// Enhanced boss shape system using all 5 ASM shapes with diversity
extern void draw_ascii_triangle_asm(uint32_t *pixels, int cx, int cy, int size, float rotation, uint32_t color, int alpha, int frame);
extern void draw_ascii_diamond_asm(uint32_t *pixels, int cx, int cy, int size, float rotation, uint32_t color, int alpha, int frame);
extern void draw_ascii_hexagon_asm(uint32_t *pixels, int cx, int cy, int size, float rotation, uint32_t color, int alpha, int frame);
extern void draw_ascii_star_asm(uint32_t *pixels, int cx, int cy, int size, float rotation, uint32_t color, int alpha, int frame);
extern void draw_ascii_square_asm(uint32_t *pixels, int cx, int cy, int size, float rotation, uint32_t color, int alpha, int frame);

void draw_boss_shape(float cx, float cy, int shape_type, int size, float rotation, float hue, float saturation, float value, int frame) {
if (!g_current_pixels) return; // Safety check

uint32_t color = circle_color_asm(hue, saturation, value);
int alpha = 255; // Full opacity for boss shapes

// Use all 5 ASM shapes with proper parameters
switch(shape_type) {
case 0: // Triangle
draw_ascii_triangle_asm(g_current_pixels, (int)cx, (int)cy, size, rotation, color, alpha, frame);
break;
case 1: // Diamond
draw_ascii_diamond_asm(g_current_pixels, (int)cx, (int)cy, size, rotation, color, alpha, frame);
break;
case 2: // Hexagon
draw_ascii_hexagon_asm(g_current_pixels, (int)cx, (int)cy, size, rotation, color, alpha, frame);
break;
case 3: // Star
draw_ascii_star_asm(g_current_pixels, (int)cx, (int)cy, size, rotation, color, alpha, frame);
break;
case 4: // Square
draw_ascii_square_asm(g_current_pixels, (int)cx, (int)cy, size, rotation, color, alpha, frame);
break;
}
}

// Projectile system functions
void spawn_projectile(float ship_x, float ship_y, float boss_x, float boss_y, uint32_t seed) {
// Count active projectiles first
int active_count = 0;
for (int i = 0; i < MAX_PROJECTILES; i++) {
if (projectiles[i].active) active_count++;
}

// Respect workload budget - don't spawn if at cap
if (active_count >= g_budget.max_projectiles) {
return; // Budget exceeded, skip this projectile
}

// Find an inactive projectile slot
for (int i = 0; i < MAX_PROJECTILES; i++) {
if (!projectiles[i].active) {
// Seed-based projectile type selection
prng_seed(&g_projectile_prng, seed + i);
char projectile_chars[] = {'o', 'x', '-', '0', '*', '+', '>', '=', '~'};
int char_count = sizeof(projectile_chars) / sizeof(projectile_chars[0]);

projectiles[i].x = ship_x + 20; // Start slightly ahead of ship
projectiles[i].y = ship_y;

// Calculate velocity towards boss
float dx = boss_x - ship_x;
float dy = boss_y - ship_y;
float distance = sqrt(dx*dx + dy*dy);
float speed = 8.0f; // Pixels per frame

projectiles[i].vx = (dx / distance) * speed;
projectiles[i].vy = (dy / distance) * speed;
projectiles[i].character = projectile_chars[prng_range(&g_projectile_prng, char_count)];
projectiles[i].color = circle_color_asm(0.1f + prng_range(&g_projectile_prng, 100) / 1000.0f, 1.0f, 1.0f); // Yellowish
projectiles[i].life = 120; // 2 seconds at 60fps
projectiles[i].active = true;
break;
}
}
}

void update_projectiles(void) {
for (int i = 0; i < MAX_PROJECTILES; i++) {
if (projectiles[i].active) {
// Move projectile
projectiles[i].x += projectiles[i].vx;
projectiles[i].y += projectiles[i].vy;
projectiles[i].life--;

// Deactivate if off screen or life expired
if (projectiles[i].x < 0 || projectiles[i].x >= VIS_WIDTH ||
projectiles[i].y < 0 || projectiles[i].y >= VIS_HEIGHT ||
projectiles[i].life <= 0) {
projectiles[i].active = false;
}
}
}
}

void draw_projectiles(void) {
if (!g_current_pixels) return;

for (int i = 0; i < MAX_PROJECTILES; i++) {
if (projectiles[i].active) {
draw_ascii_char_asm(g_current_pixels,
(int)projectiles[i].x, (int)projectiles[i].y,
projectiles[i].character, projectiles[i].color, 255);
}
}
}

// Sidecar timeline reader (preferred) and audio-analysis fallback
#include "src/include/timeline.h"
void init_audio_visual_mapping(void);
float get_smoothed_audio_level(int frame);
void update_audio_visual_effects(int frame, float base_hue);
float get_audio_driven_glitch_intensity(int frame);
float get_audio_driven_hue_shift(int frame);

// Audio functions
bool load_wav_file(const char *filename);
float get_audio_rms_for_frame(int frame);
float get_audio_bpm(void);
float get_max_rms(void);
float get_audio_duration(void); // Get actual audio duration in seconds
bool is_audio_finished(int frame);
void print_audio_info(void);
void cleanup_audio_data(void);

#define FRAME_TIME_MS (1000 / VIS_FPS)

// PPM image output helpers
static inline void write_frame_ppm(FILE *out, uint32_t *pixels) {
// Each frame carries its own header (PPM P6) for ffmpeg image2pipe
fprintf(out, "P6\n%d %d\n255\n", VIS_WIDTH, VIS_HEIGHT);
for (int y = 0; y < VIS_HEIGHT; y++) {
for (int x = 0; x < VIS_WIDTH; x++) {
uint32_t pixel = pixels[y * VIS_WIDTH + x];
uint8_t r = (pixel >> 16) & 0xFF;
uint8_t g = (pixel >> 8) & 0xFF;
uint8_t b = pixel & 0xFF;
fwrite(&r, 1, 1, out);
fwrite(&g, 1, 1, out);
fwrite(&b, 1, 1, out);
}
}
fflush(out);
}

void save_frame_as_ppm(uint32_t *pixels, int frame_num) {
char filename[256];
snprintf(filename, sizeof(filename), "frame_%04d.ppm", frame_num);
FILE *f = fopen(filename, "wb");
if (!f) { fprintf(stderr, "Could not create %s\n", filename); return; }
write_frame_ppm(f, pixels);
fclose(f);
fprintf(stderr, "✅ Generated frame_%04d.ppm\n", frame_num);
}

// Custom top terrain drawing function
void draw_top_terrain(uint32_t *pixels, int frame, float hue, float audio_level) {
// Simple procedural top terrain using different algorithm
const int char_width = 8; // Use proper 8x12 glyph spacing
const int char_height = 12;
const char terrain_chars[] = "^^^^====~~~~----____";
const int num_chars = 20;
const int char_alpha = 255; // Fully opaque - this was the bug!

// Create brighter color based on hue
uint32_t color = circle_color_asm(hue, 1.0f, 1.0f); // Full brightness and saturation

// Generate terrain from top down - make it much more visible
for (int x = 0; x < VIS_WIDTH; x += char_width) {
// Use different pattern than bottom terrain
int pattern = (x / char_width + frame / 2) % num_chars;
char c = terrain_chars[pattern];

// Audio-reactive height - different response than bottom
int height_variation = (int)(audio_level * 8) + 3; // Audio variation
int y_offset = (int)(sin((x + frame * 3) * 0.03f) * height_variation);

// Draw multiple rows for thickness, from top down
for (int row = 0; row < 6 + height_variation; row++) {
int y = row * char_height + y_offset + 10; // Start 10 pixels from top
if (y >= 0 && y < VIS_HEIGHT / 2) { // Use top half
draw_ascii_char_asm(pixels, x, y, c, color, char_alpha);
}
}
}
}

// Ship component system - seed determines design
typedef struct {
const char* nose_patterns[4]; // 4 different nose designs
const char* body_patterns[4]; // 4 different body designs
const char* wing_patterns[4]; // 4 different wing designs
const char* trail_patterns[4]; // 4 different trail designs
int sizes[3]; // 3 different sizes
} ship_components_t;

ship_components_t ship_parts = {
.nose_patterns = {
" ^ ", // Classic
" /^\\ ", // Wide
" <*> ", // Star
" >+< " // Cross
},
.body_patterns = {
"[###]", // Block
"<ooo>", // Circles
"{***}", // Stars
"(===)" // Lines
},
.wing_patterns = {
"< >", // Simple
"<<+>>", // Double
"[---]", // Brackets
"\\___/" // Curves
},
.trail_patterns = {
" ~~~ ", // Waves
" --- ", // Lines
" *** ", // Stars
" ... " // Dots
},
.sizes = {1, 2, 3} // Size multipliers
};

// Ship flying through the terrain corridor
void draw_ship(uint32_t *pixels, int frame, float hue, float audio_level, uint32_t seed) {
// Ship position on LEFT side of screen (leaving room for enemies)
float base_x = VIS_WIDTH * 0.15f; // 15% from left (moved further left)
float center_y = VIS_HEIGHT / 2.0f;

// Audio-reactive movement - enhanced for bigger ship
float sway = sin(frame * 0.05f) * 40.0f; // Side-to-side movement
float bob = sin(frame * 0.08f) * 30.0f; // Up-down movement
float audio_dodge = audio_level * 35.0f; // React to audio

// Calculate final position
int ship_x = (int)(base_x + sway + audio_dodge);
int ship_y = (int)(center_y + bob);

// Calculate boss position for targeting (using same logic as draw_enemy_boss)
float boss_base_x = VIS_WIDTH * 0.75f;
float boss_center_y = VIS_HEIGHT / 2.0f;
float boss_hover = sin(frame * 0.03f) * 20.0f;
float boss_pulse = sin(frame * 0.12f) * 15.0f;
float boss_audio_react = audio_level * 25.0f;
int boss_x = (int)(boss_base_x + boss_hover - boss_audio_react);
int boss_y = (int)(boss_center_y + boss_pulse);

// Ship firing logic - budget-aware firing rate
if (frame - last_shot_frame >= g_budget.min_firing_cooldown) {
spawn_projectile(ship_x, ship_y, boss_x, boss_y, seed + frame);
last_shot_frame = frame;
}

// Seed-based ship design selection
prng_seed(&g_ship_prng, seed);
int nose_type = prng_range(&g_ship_prng, 4);
int body_type = prng_range(&g_ship_prng, 4);
int wing_type = prng_range(&g_ship_prng, 4);
int trail_type = prng_range(&g_ship_prng, 4);
int size = ship_parts.sizes[prng_range(&g_ship_prng, 3)];

// Seed-based colors - create unique palette
float primary_hue = prng_float(&g_ship_prng);
float secondary_hue = primary_hue + 0.3f;
if (secondary_hue > 1.0f) secondary_hue -= 1.0f;

uint32_t primary_color = circle_color_asm(primary_hue, 1.0f, 1.0f);
uint32_t secondary_color = circle_color_asm(secondary_hue, 0.8f, 0.9f);

// Selected ship components
const char* nose = ship_parts.nose_patterns[nose_type];
const char* body = ship_parts.body_patterns[body_type];
const char* wings = ship_parts.wing_patterns[wing_type];
const char* trail = ship_parts.trail_patterns[trail_type];

int char_spacing = 8 * size;
int line_spacing = 12 * size;

// Draw ship layers (bigger and more detailed)
for (int layer = 0; layer < size; layer++) {
int offset_y = layer * 2; // Slight layer offset

// Nose (top)
for (int i = 0; i < 5; i++) {
if (nose[i] != ' ') {
for (int s = 0; s < size; s++) {
draw_ascii_char_asm(pixels,
ship_x + (i-2)*char_spacing + s*4,
ship_y - line_spacing*2 + offset_y,
nose[i], primary_color, 255);
}
}
}

// Wings (upper middle)
for (int i = 0; i < 5; i++) {
if (wings[i] != ' ') {
for (int s = 0; s < size; s++) {
draw_ascii_char_asm(pixels,
ship_x + (i-2)*char_spacing + s*4,
ship_y - line_spacing + offset_y,
wings[i], secondary_color, 255);
}
}
}

// Body (center)
for (int i = 0; i < 5; i++) {
if (body[i] != ' ') {
for (int s = 0; s < size; s++) {
draw_ascii_char_asm(pixels,
ship_x + (i-2)*char_spacing + s*4,
ship_y + offset_y,
body[i], primary_color, 255);
}
}
}

// Trail (bottom)
for (int i = 0; i < 5; i++) {
if (trail[i] != ' ') {
for (int s = 0; s < size; s++) {
draw_ascii_char_asm(pixels,
ship_x + (i-2)*char_spacing + s*4,
ship_y + line_spacing + offset_y,
trail[i], secondary_color, 255);
}
}
}
}
}

// Enhanced boss system with massive diversity - mix and match shapes, sizes, colors
void draw_enemy_boss(uint32_t *pixels, int frame, float hue, float audio_level, uint32_t seed) {
// Boss position on RIGHT side of screen (75% from left)
float base_x = VIS_WIDTH * 0.75f; // 75% from left
float center_y = VIS_HEIGHT / 2.0f;

// Audio-reactive movement - different pattern from ship
float hover = sin(frame * 0.03f) * 20.0f; // Slower hovering movement
float pulse = sin(frame * 0.12f) * 15.0f; // Pulsing motion
float audio_react = audio_level * 25.0f; // React to audio differently

// Calculate final position
int boss_x = (int)(base_x + hover - audio_react); // Move left on audio hits
int boss_y = (int)(center_y + pulse);

// Seed-based boss design with MASSIVE DIVERSITY
prng_seed(&g_boss_prng, seed + 0x1000); // Different seed offset for boss variety

// 1. Random formation type (8 different formation patterns)
int formation_type = prng_range(&g_boss_prng, 8);

// 2. Budget-aware number of components (respects workload cap)
int max_shapes = (g_budget.max_boss_shapes > 3) ? g_budget.max_boss_shapes : 3;
int num_components = 3 + prng_range(&g_boss_prng, max_shapes - 2);

// 3. Base boss hue with variety
float boss_base_hue = hue + prng_float(&g_boss_prng); // More hue variety
if (boss_base_hue > 1.0f) boss_base_hue -= 1.0f;

// 4. Size variety (small to massive)
int base_size = 15 + prng_range(&g_boss_prng, 25); // Size range: 15-40

// 5. Rotation variety
float base_rotation = prng_range(&g_boss_prng, 360) * M_PI / 180.0f;

// Draw diverse boss formations
switch(formation_type) {
case 0: // Star Burst Formation - mixed shapes radiating outward
for (int i = 0; i < num_components; i++) {
float angle = (2.0f * M_PI * i) / num_components;
float radius = 30 + (i * 15); // Expanding radius
int shape = prng_range(&g_boss_prng, 5); // All 5 shapes
int size = base_size + prng_range(&g_boss_prng, 15) - 7; // Size variety ±7
float shape_hue = boss_base_hue + (i * 0.1f);
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.7f + prng_range(&g_boss_prng, 30) / 100.0f; // Saturation variety
float val = 0.8f + prng_range(&g_boss_prng, 20) / 100.0f; // Brightness variety
float rotation = base_rotation + (i * 0.3f);

int x = boss_x + (int)(cos(angle) * radius);
int y = boss_y + (int)(sin(angle) * radius);
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;

case 1: // Cluster Formation - tight group with mixed shapes
for (int i = 0; i < num_components; i++) {
int shape = prng_range(&g_boss_prng, 5);
int size = base_size + prng_range(&g_boss_prng, 10) - 5;
float cluster_radius = 20 + prng_range(&g_boss_prng, 30);
float angle = prng_range(&g_boss_prng, 360) * M_PI / 180.0f;
float shape_hue = boss_base_hue + prng_range(&g_boss_prng, 30) / 100.0f;
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.6f + prng_range(&g_boss_prng, 40) / 100.0f;
float val = 0.7f + prng_range(&g_boss_prng, 30) / 100.0f;
float rotation = base_rotation + prng_range(&g_boss_prng, 360) * M_PI / 180.0f;

int x = boss_x + (int)(cos(angle) * cluster_radius);
int y = boss_y + (int)(sin(angle) * cluster_radius);
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;

case 2: // Wing Formation - symmetrical left/right
int wing_shapes = num_components / 2;
for (int i = 0; i < wing_shapes; i++) {
int shape = prng_range(&g_boss_prng, 5);
int size = base_size + prng_range(&g_boss_prng, 12) - 6;
float wing_distance = 40 + (i * 20);
float y_offset = (i - wing_shapes/2) * 25;
float shape_hue = boss_base_hue + (i * 0.15f);
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.8f + prng_range(&g_boss_prng, 20) / 100.0f;
float val = 0.9f + prng_range(&g_boss_prng, 10) / 100.0f;
float rotation = base_rotation + (i * 0.2f);

// Left wing
draw_boss_shape(boss_x - wing_distance, boss_y + y_offset, shape, size, rotation, shape_hue, sat, val, frame);
// Right wing (different shape)
int right_shape = (shape + 1 + prng_range(&g_boss_prng, 4)) % 5;
draw_boss_shape(boss_x + wing_distance, boss_y + y_offset, right_shape, size, -rotation, shape_hue + 0.1f, sat, val, frame);
}
break;

case 3: // Spiral Formation - shapes in rotating spiral
for (int i = 0; i < num_components; i++) {
float spiral_angle = (i * 0.6f) + (frame * 0.02f); // Rotating spiral
float spiral_radius = 10 + (i * 8);
int shape = (i + seed) % 5; // Sequential shapes
int size = base_size + (i % 8) - 4;
float shape_hue = boss_base_hue + (i * 0.08f);
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.7f + ((i * 13) % 30) / 100.0f;
float val = 0.8f + ((i * 17) % 20) / 100.0[CHUNK 2 OF 3]
BUNDLE_6_C_BRIDGE - PART 2
Concatenate all chunks in order to reconstruct.

f;
float rotation = spiral_angle + base_rotation;

int x = boss_x + (int)(cos(spiral_angle) * spiral_radius);
int y = boss_y + (int)(sin(spiral_angle) * spiral_radius);
draw_boss_shape(x, y, shape, size, rotation, shape_hue, sat, val, frame);
}
break;

case 4: // Grid Formation - organized rectangular pattern
int grid_size = (int)sqrt(num_components);
for (int i = 0; i < num_components; i++) {
int grid_x = i % grid_size;
int grid_y = i / grid_size;
int shape = (grid_x + grid_y + seed) % 5; // Pattern-based shapes
int size = base_size + ((grid_x + grid_y) % 6) - 3;
float shape_hue = boss_base_hue + ((grid_x + grid_y) * 0.12f);
if (shape_hue > 1.0f) shape_hue -= 1.0f;
float sat = 0.6f + ((grid_x * 7 + grid_y * 11) % 40
at txn 0x9adfda38754694a7eb561a482b57c547235acc40a0ba0c6cec738617c70bc34a Aug-20-2025 12:46:35 AM UTC (26 days ago)

||FILE:src/c/src/gen_custom.c||
#include "wav_writer.h"
#include "kick.h"
#include "snare.h"
#include "hat.h"
#include "melody.h"
#include "fm_voice.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdbool.h>

int main(int argc, char **argv)
{
if (argc < 2) {
printf("Usage: %s <voice1> [voice2] ...\n", argv[0]);
printf("Available voices: kick, snare, hat, melody, fm\n");
printf("Examples:\n");
printf(" %s kick\n", argv[0]);
printf(" %s kick snare hat\n", argv[0]);
printf(" %s drums (= kick + snare + hat)\n", argv[0]);
return 1;
}

const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2; // 2 seconds
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

// Initialize voices
kick_t kick; kick_init(&kick, (float)sr);
snare_t snare; snare_init(&snare, (float)sr, 0x12345678);
hat_t hat; hat_init(&hat, (float)sr, 0x87654321);
melody_t melody; melody_init(&melody, (float)sr);
fm_voice_t fm; fm_voice_init(&fm, (float)sr);

// Parse arguments to determine which voices to enable
bool enable_kick = false, enable_snare = false, enable_hat = false;
bool enable_melody = false, enable_fm = false;

for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "kick") == 0) enable_kick = true;
else if (strcmp(argv[i], "snare") == 0) enable_snare = true;
else if (strcmp(argv[i], "hat") == 0) enable_hat = true;
else if (strcmp(argv[i], "melody") == 0) enable_melody = true;
else if (strcmp(argv[i], "fm") == 0) enable_fm = true;
else if (strcmp(argv[i], "drums") == 0) {
enable_kick = enable_snare = enable_hat = true;
}
else {
printf("Unknown voice: %s\n", argv[i]);
return 1;
}
}

printf("Testing voices: ");
if (enable_kick) printf("kick ");
if (enable_snare) printf("snare ");
if (enable_hat) printf("hat ");
if (enable_melody) printf("melody ");
if (enable_fm) printf("fm ");
printf("\n");

// Trigger voices at different times
uint32_t triggers[] = {0, sr/2, sr, sr*3/2}; // 0, 0.5, 1.0, 1.5 seconds

for (uint32_t frame = 0; frame < total_frames; frame += 256) {
// Check for triggers
for (int t = 0; t < 4; t++) {
if (frame == triggers[t]) {
if (enable_kick) { kick_trigger(&kick); printf("Kick trigger at %.1fs\n", (float)frame/sr); }
if (enable_snare) { snare_trigger(&snare); printf("Snare trigger at %.1fs\n", (float)frame/sr); }
if (enable_hat) { hat_trigger(&hat); printf("Hat trigger at %.1fs\n", (float)frame/sr); }
if (enable_melody) {
melody_trigger(&melody, 440.0f, 0.5f);
printf("Melody trigger at %.1fs\n", (float)frame/sr);
}
if (enable_fm) {
fm_voice_trigger(&fm, 220.0f, 0.8f, 2.0f, 3.0f, 0.5f, 5.0f);
printf("FM trigger at %.1fs\n", (float)frame/sr);
}
}
}

uint32_t block = (frame + 256 <= total_frames) ? 256 : (total_frames - frame);

// Process enabled voices
if (enable_kick) kick_process(&kick, &L[frame], &R[frame], block);
if (enable_snare) snare_process(&snare, &L[frame], &R[frame], block);
if (enable_hat) hat_process(&hat, &L[frame], &R[frame], block);
if (enable_melody) melody_process(&melody, &L[frame], &R[frame], block);
if (enable_fm) fm_voice_process(&fm, &L[frame], &R[frame], block);
}

// Convert to WAV
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = pcm[2*i];
}
write_wav("custom_test.wav", pcm, total_frames, 2, sr);

printf("Generated custom_test.wav (2 seconds)\n");

free(L);free(R);free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/gen_fm.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>
#include <math.h>

int main(void)
{
const uint32_t sr=44100;
const uint32_t total_frames=sr*2;
float *L=calloc(total_frames,sizeof(float));
float *R=calloc(total_frames,sizeof(float));

fm_voice_t mid; fm_voice_init(&mid,(float)sr);
fm_voice_t bass; fm_voice_init(&bass,(float)sr);

fm_params_t presets[4] = {FM_PRESET_BELLS, FM_PRESET_CALM, FM_PRESET_QUANTUM, FM_PRESET_PLUCK};

for(uint32_t frame=0; frame<total_frames; frame+=256){
float t=(float)frame/sr;
if(fmodf(t,0.5f)<1e-4f){
fm_params_t p = presets[(uint32_t)(t/0.5f)%4];
fm_voice_trigger(&mid, 880.0f, 0.45f, p.ratio, p.index, p.amp, p.decay);
}
if(fmodf(t,1.0f)<1e-4f){
/* bass fm */
fm_voice_trigger(&bass, 55.0f, 0.8f, 2.0f, 5.0f, 0.4f, 10.0f);
}
uint32_t block = (frame+256<=total_frames)?256:(total_frames-frame);
fm_voice_process(&mid,&L[frame],&R[frame],block);
fm_voice_process(&bass,&L[frame],&R[frame],block);
}

int16_t *pcm=malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float v=L[i]; if(v>1)v=1;if(v<-1)v=-1;
int16_t s=(int16_t)(v*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("fm.wav",pcm,total_frames,2,sr);
free(L);free(R);free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_hat.c||
#include "wav_writer.h"
#include "hat.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2;
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

hat_t h; hat_init(&h, (float)sr, 0x12345678);

/* trigger every 0.25s */
for(uint32_t frame=0; frame< total_frames; frame += 128){
float t = (float)frame / sr;
if (fabsf(fmodf(t,0.25f)) < 1e-4f) hat_trigger(&h);
uint32_t block = (frame+128<=total_frames)?128:(total_frames-frame);
hat_process(&h, &L[frame], &R[frame], block);
}

int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float v=L[i]; if(v>1)v=1;if(v<-1)v=-1;
pcm[2*i]= (int16_t)(v*32767);
pcm[2*i+1]=pcm[2*i];
}
write_wav("hat.wav", pcm, total_frames,2,sr);
free(L);free(R);free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_hat_single.c||
#include "wav_writer.h"
#include "hat.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 1; // 1 second
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

hat_t hat;
hat_init(&hat, (float)sr, 0x12345678); // seed for noise generator

// Trigger once at the beginning
hat_trigger(&hat);
printf("Single hat triggered, processing %u frames\n", total_frames);

// Process the entire duration in one call
hat_process(&hat, L, R, total_frames);

/* convert to int16 wav */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = pcm[2*i];
}
write_wav("hat_single.wav", pcm, total_frames, 2, sr);

printf("Generated hat_single.wav (1 second, single hat)\n");

free(L);free(R);free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/gen_kick.c||
#include "wav_writer.h"
#include "kick.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2; // 2 seconds
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

kick_t kick; kick_init(&kick, (float)sr);

printf("L base: %p\n", (void*)L);

/* Trigger kick at 0.0, 0.5, 1.0, 1.5 sec */
for(uint32_t frame = 0; frame < total_frames; frame += 256){
float t = (float)frame / sr;
if (fabsf(fmodf(t, 0.5f)) < 1e-4f) {
kick_trigger(&kick);
}
printf("call @ frame %u, ptr=%p\n", frame, (void*)&L[frame]);
uint32_t block = (frame + 256 <= total_frames) ? 256 : (total_frames - frame);
kick_process(&kick, &L[frame], &R[frame], block);
}

/* convert to int16 wav */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = pcm[2*i];
}
write_wav("kick.wav", pcm, total_frames, 2, sr);

free(L);free(R);free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_kick_single.c||
#include "wav_writer.h"
#include "kick.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 1; // 1 second
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

kick_t kick;
kick_init(&kick, (float)sr);

// Trigger once at the beginning
kick_trigger(&kick);
printf("Single kick triggered, processing %u frames\n", total_frames);

// Process the entire duration in one call
kick_process(&kick, L, R, total_frames);

/* convert to int16 wav */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = pcm[2*i];
}
write_wav("kick_single.wav", pcm, total_frames, 2, sr);

printf("Generated kick_single.wav (1 second, single kick)\n");

free(L);free(R);free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/gen_melody.c||
#include "wav_writer.h"
#include "melody.h"
#include <stdlib.h>
#include <stdint.h>
#include <math.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2; // 2 seconds
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

melody_t mel; melody_init(&mel, (float)sr);

/* frequencies for simple arpeggio */
const float freqs[4] = {440.0f, 554.37f, 659.25f, 880.0f};
uint32_t note_idx = 0;

for(uint32_t frame=0; frame<total_frames; frame += 256){
float t = (float)frame / sr;
/* start new note every 0.5 seconds */
if (fmodf(t, 0.5f) < 1e-4f){
melody_trigger(&mel, freqs[note_idx % 4], 0.45f);
note_idx++;
}
uint32_t block = (frame + 256 <= total_frames) ? 256 : (total_frames - frame);
melody_process(&mel, &L[frame], &R[frame], block);
}

int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float v = L[i]; if(v>1) v=1; if(v<-1) v=-1;
int16_t s = (int16_t)(v*32767);
pcm[2*i] = s; pcm[2*i+1] = s;
}

write_wav("melody.wav", pcm, total_frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_noise_delay.c||
#include "wav_writer.h"
#include "osc.h"
#include "noise.h"
#include "delay.h"
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2; // 2 seconds
float *L = malloc(sizeof(float)*total_frames);
float *R = malloc(sizeof(float)*total_frames);
if(!L||!R) return 1;

/* First second: 440 Hz sine with 5 ms fade-in/out; then silence */
const float fade_time = 0.005f; // 5 ms
const uint32_t fade_samps = (uint32_t)(sr * fade_time);

osc_t osc; osc_reset(&osc);
for(uint32_t i=0;i<total_frames;i++){
if(i<sr){
float s; osc_sine_block(&osc,&s,1,440.0f,(float)sr);
float amp = 0.4f;
/* linear fade */
if(i < fade_samps) amp *= (float)i / fade_samps;
if(sr - i <= fade_samps) amp *= (float)(sr - i) / fade_samps;
L[i]=R[i]=s*amp;
}else{ L[i]=R[i]=0.0f; }
}

/* Prepare delay line of 0.25s */
uint32_t delay_samples = sr/4;
float *delay_buf = malloc(sizeof(float)*delay_samples*2);
delay_t delay; delay_init(&delay,&delay_buf[0],delay_samples);

printf("Before delay: total_frames=%u delay.size=%u delay.idx=%u\n", total_frames, delay.size, delay.idx);
delay_process_block(&delay,L,R,total_frames,0.5f);

/* convert to int16 */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
/* clamp to [-1,1] to avoid wrap distortion */
float vL = L[i]; if(vL>1.0f) vL=1.0f; if(vL<-1.0f) vL=-1.0f;
float vR = R[i]; if(vR>1.0f) vR=1.0f; if(vR<-1.0f) vR=-1.0f;
int16_t s = (int16_t)(vL*32767);
pcm[2*i]=s; pcm[2*i+1]=(int16_t)(vR*32767);
}

write_wav("delay.wav",pcm,total_frames,2,sr);

free(L);free(R);free(delay_buf);free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_pluck.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr/2;
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t v; fm_voice_init(&v, (float)sr);
fm_params_t p = FM_PRESET_PLUCK;
fm_voice_trigger(&v, 880.0f, 0.9f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&v, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float val = L[i]; if(val>1)val=1;if(val<-1)val=-1;
int16_t s = (int16_t)(val*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("pluck-c.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_quantum.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr/2;
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t v; fm_voice_init(&v, (float)sr);
fm_params_t p = FM_PRESET_QUANTUM;
fm_voice_trigger(&v, 880.0f, 0.9f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&v, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float val = L[i]; if(val>1)val=1;if(val<-1)val=-1;
int16_t s = (int16_t)(val*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("quantum-c.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_sine.c||
#include "wav_writer.h"
#include "osc.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr; // 1 second
float *mono = malloc(frames * sizeof(float));
if (!mono) return 1;

osc_t osc; osc_reset(&osc);
osc_sine_block(&osc, mono, frames, 440.0f, (float)sr);

int16_t *stereo = malloc(frames * 2 * sizeof(int16_t));
for (uint32_t i = 0; i < frames; ++i) {
int16_t s = (int16_t)(mono[i] * 32767 * 0.5f); // -6 dBFS
stereo[2*i] = stereo[2*i+1] = s;
}

write_wav("sine.wav", stereo, frames, 2, sr);

free(mono);
free(stereo);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_snare.c||
#include "wav_writer.h"
#include "snare.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 2;
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

snare_t sn; snare_init(&sn, (float)sr, 0xdeadbeef);

/* trigger every 0.5s */
for(uint32_t frame=0; frame< total_frames; frame += 256){
float t = (float)frame / sr;
if (fabsf(fmodf(t,0.5f)) < 1e-4f) snare_trigger(&sn);
uint32_t block = (frame+256<=total_frames)?256:(total_frames-frame);
snare_process(&sn, &L[frame], &R[frame], block);
}

int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float v=L[i]; if(v>1)v=1;if(v<-1)v=-1;
pcm[2*i]= (int16_t)(v*32767);
pcm[2*i+1]=pcm[2*i];
}
write_wav("snare.wav", pcm, total_frames,2,sr);
free(L);free(R);free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_snare_single.c||
#include "wav_writer.h"
#include "snare.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <stdio.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t total_frames = sr * 1; // 1 second
float *L = calloc(total_frames, sizeof(float));
float *R = calloc(total_frames, sizeof(float));

snare_t snare;
snare_init(&snare, (float)sr, 0x87654321); // seed for noise generator

// Trigger once at the beginning
snare_trigger(&snare);
printf("Single snare triggered, processing %u frames\n", total_frames);

// Process the entire duration in one call
snare_process(&snare, L, R, total_frames);

/* convert to int16 wav */
int16_t *pcm = malloc(sizeof(int16_t)*total_frames*2);
for(uint32_t i=0;i<total_frames;i++){
float vL=L[i]; if(vL>1) vL=1; if(vL<-1) vL=-1;
pcm[2*i] = (int16_t)(vL*32767);
pcm[2*i+1] = pcm[2*i];
}
write_wav("snare_single.wav", pcm, total_frames, 2, sr);

printf("Generated snare_single.wav (1 second, single snare)\n");

free(L);free(R);free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/gen_tones.c||
#include "wav_writer.h"
#include "osc.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

static void write_wave(const char *name, void (*render)(osc_t*,float*,uint32_t,float,float))
{
const uint32_t sr = 44100;
const uint32_t frames = sr; // 1 s
float *mono = malloc(frames * sizeof(float));
int16_t *st = malloc(frames * 2 * sizeof(int16_t));
if (!mono || !st) { exit(1);}

osc_t o; osc_reset(&o);
render(&o, mono, frames, 440.0f, (float)sr);
for (uint32_t i=0;i<frames;++i){
int16_t s = (int16_t)(mono[i]*32767*0.5f);
st[2*i]=st[2*i+1]=s;
}
write_wav(name, st, frames, 2, sr);

free(mono); free(st);
}

int main(void)
{
write_wave("saw.wav", osc_saw_block);
write_wave("square.wav", osc_square_block);
write_wave("triangle.wav", osc_triangle_block);
return 0;
} ||ENDFILE||
at txn 0x35ba9df511b83c1c5b3fe8ab820fc6c71846b2e54109e4bc0bd7d42ba26ea20a Aug-20-2025 12:46:23 AM UTC (26 days ago)

||FILE:src/c/src/coreaudio.c||
#include "coreaudio.h"
#include <AudioToolbox/AudioToolbox.h>
#include <stdio.h>

#define NUM_BUFFERS 3

typedef struct {
AudioQueueRef queue;
AudioQueueBufferRef buffers[NUM_BUFFERS];
AudioStreamBasicDescription format;
audio_callback_t user_callback;
void* user_data;
uint32_t buffer_size_frames;
} audio_state_t;

static audio_state_t g_audio_state;

static void audio_queue_callback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer)
{
audio_state_t* state = (audio_state_t*)inUserData;
if (state->user_callback) {
state->user_callback((float*)inBuffer->mAudioData, state->buffer_size_frames, state->user_data);
}
inBuffer->mAudioDataByteSize = state->buffer_size_frames * state->format.mBytesPerFrame;
AudioQueueEnqueueBuffer(state->queue, inBuffer, 0, NULL);
}

int audio_init(uint32_t sr, uint32_t buffer_size, audio_callback_t callback, void* user_data)
{
g_audio_state.user_callback = callback;
g_audio_state.user_data = user_data;
g_audio_state.buffer_size_frames = buffer_size;

g_audio_state.format.mSampleRate = sr;
g_audio_state.format.mFormatID = kAudioFormatLinearPCM;
g_audio_state.format.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked;
g_audio_state.format.mFramesPerPacket = 1;
g_audio_state.format.mChannelsPerFrame = 2;
g_audio_state.format.mBitsPerChannel = 32;
g_audio_state.format.mBytesPerPacket = sizeof(float) * 2;
g_audio_state.format.mBytesPerFrame = sizeof(float) * 2;

OSStatus status = AudioQueueNewOutput(&g_audio_state.format, audio_queue_callback, &g_audio_state, NULL, NULL, 0, &g_audio_state.queue);
if(status != noErr) { fprintf(stderr, "AudioQueueNewOutput failed\n"); return 1; }

uint32_t buffer_size_bytes = buffer_size * g_audio_state.format.mBytesPerFrame;
for (int i = 0; i < NUM_BUFFERS; ++i) {
status = AudioQueueAllocateBuffer(g_audio_state.queue, buffer_size_bytes, &g_audio_state.buffers[i]);
if(status != noErr) { fprintf(stderr, "AudioQueueAllocateBuffer failed\n"); return 1; }
// Prime the buffer
audio_queue_callback(&g_audio_state, g_audio_state.queue, g_audio_state.buffers[i]);
}
return 0;
}

void audio_start(void)
{
AudioQueueStart(g_audio_state.queue, NULL);
}

void audio_stop(void)
{
AudioQueueStop(g_audio_state.queue, true);
AudioQueueDispose(g_audio_state.queue, true);
} ||ENDFILE||
||FILE:src/c/src/crt_fx.c||
#include "crt_fx.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>

void crt_fx_init(crt_fx_t *fx, uint64_t seed, int w, int h)
{
/* allocate persistence buffer */
fx->prev_frame = (uint32_t*)calloc(w * h, sizeof(uint32_t));

/* seed-based randomization of effect levels */
fx->rng = rng_seed(seed ^ 0xDE5A7ULL);

fx->persistence = 0.3f + rng_next_float(&fx->rng) * 0.6f;
fx->scanline_alpha = (int)(rng_next_float(&fx->rng) * 200.0f);
fx->chroma_shift = (int)(rng_next_float(&fx->rng) * 5.0f);
fx->noise_pixels = (int)(rng_next_float(&fx->rng) * 300.0f);
fx->jitter_amount = rng_next_float(&fx->rng) * 3.0f;
fx->frame_drop_chance = rng_next_float(&fx->rng) * 0.1f;
fx->color_bleed = rng_next_float(&fx->rng) * 0.3f;
}

void crt_fx_cleanup(crt_fx_t *fx)
{
free(fx->prev_frame);
}

/* blend two pixels with alpha */
static inline uint32_t blend_alpha(uint32_t dst, uint32_t src, float alpha)
{
uint8_t dr = (dst >> 24) & 0xFF;
uint8_t dg = (dst >> 16) & 0xFF;
uint8_t db = (dst >> 8) & 0xFF;

uint8_t sr = (src >> 24) & 0xFF;
uint8_t sg = (src >> 16) & 0xFF;
uint8_t sb = (src >> 8) & 0xFF;

uint8_t r = (uint8_t)(dr * (1.0f - alpha) + sr * alpha);
uint8_t g = (uint8_t)(dg * (1.0f - alpha) + sg * alpha);
uint8_t b = (uint8_t)(db * (1.0f - alpha) + sb * alpha);

return (r << 24) | (g << 16) | (b << 8) | 0xFF;
}

void crt_fx_apply(crt_fx_t *fx, uint32_t *fb, int w, int h, int frame)
{
/* 1. Persistence (ghost trails) - blend with previous frame */
if(fx->persistence > 0.01f){
for(int i = 0; i < w*h; i++){
fb[i] = blend_alpha(fx->prev_frame[i], fb[i], 1.0f - fx->persistence);
}
}

/* Save current frame for next time */
memcpy(fx->prev_frame, fb, w * h * sizeof(uint32_t));

/* 2. Scanlines - darken every other row */
if(fx->scanline_alpha > 0){
float alpha = fx->scanline_alpha / 255.0f;
for(int y = 0; y < h; y += 2){
for(int x = 0; x < w; x++){
int idx = y * w + x;
uint32_t p = fb[idx];
uint8_t r = ((p >> 24) & 0xFF) * (1.0f - alpha);
uint8_t g = ((p >> 16) & 0xFF) * (1.0f - alpha);
uint8_t b = ((p >> 8) & 0xFF) * (1.0f - alpha);
fb[idx] = (r << 24) | (g << 16) | (b << 8) | 0xFF;
}
}
}

/* 3. Chromatic aberration - shift red/blue channels */
if(fx->chroma_shift > 0){
/* temporary buffer for shifted channels */
uint32_t *temp = (uint32_t*)malloc(w * h * sizeof(uint32_t));
memcpy(temp, fb, w * h * sizeof(uint32_t));

int shift = (frame % 30 < 15) ? fx->chroma_shift : -fx->chroma_shift;

/* shift red channel right */
for(int y = 0; y < h; y++){
for(int x = 0; x < w; x++){
int src_x = x - shift;
if(src_x >= 0 && src_x < w){
uint8_t r = (temp[y * w + src_x] >> 24) & 0xFF;
fb[y * w + x] = (fb[y * w + x] & 0x00FFFFFF) | (r << 24);
}
}
}

/* shift blue channel left */
for(int y = 0; y < h; y++){
for(int x = 0; x < w; x++){
int src_x = x + shift;
if(src_x >= 0 && src_x < w){
uint8_t b = (temp[y * w + src_x] >> 8) & 0xFF;
fb[y * w + x] = (fb[y * w + x] & 0xFFFF00FF) | (b << 8);
}
}
}

free(temp);
}

/* 4. Color bleed (horizontal blur) */
if(fx->color_bleed > 0.01f){
for(int y = 0; y < h; y++){
for(int x = 1; x < w-1; x++){
int idx = y * w + x;
uint32_t left = fb[idx - 1];
uint32_t right = fb[idx + 1];
fb[idx] = blend_alpha(fb[idx], blend_alpha(left, right, 0.5f), fx->color_bleed);
}
}
}

/* 5. Random pixel noise */
for(int i = 0; i < fx->noise_pixels; i++){
int x = rng_next_u32(&fx->rng) % w;
int y = rng_next_u32(&fx->rng) % h;
uint8_t val = rng_next_u32(&fx->rng) & 0xFF;
fb[y * w + x] = (val << 24) | (val << 16) | (val << 8) | 0xFF;
}

/* 6. Jitter (whole screen offset) - handled in main loop */
/* 7. Frame drops - handled in main loop */
} ||ENDFILE||
||FILE:src/c/src/delay.c||
#include "delay.h"

#ifndef DELAY_ASM
void delay_process_block(delay_t *d, float32_t *L, float32_t *R, uint32_t n, float32_t feedback)
{
float32_t *buf = d->buf;
uint32_t idx = d->idx;
const uint32_t size = d->size;

for(uint32_t i=0;i<n;++i){
// Fetch delayed samples
float32_t yl = buf[idx*2];
float32_t yr = buf[idx*2+1];

// Cache dry samples before we modify the output buffers
float32_t dryL = L[i];
float32_t dryR = R[i];

// Write new values into the delay line (cross-feed with feedback)
buf[idx*2] = dryL + yr * feedback;
buf[idx*2+1] = dryR + yl * feedback;

// Add delayed signal to the dry signal instead of overwriting it
L[i] = dryL + yl;
R[i] = dryR + yr;

// Advance circular buffer index
idx++;
if(idx>=size) idx=0;
}
d->idx = idx;
}
#endif // DELAY_ASM ||ENDFILE||
||FILE:src/c/src/euclid.c||
#include "euclid.h"

void euclid_pattern(int pulses, int steps, uint8_t *out)
{
int bucket = 0;
for (int i = 0; i < steps; ++i) {
bucket += pulses;
if (bucket >= steps) {
bucket -= steps;
out[i] = 1;
} else {
out[i] = 0;
}
}
} ||ENDFILE||
||FILE:src/c/src/event_queue.c||
#include "event_queue.h"
/* All functions are inline in the header. This translation unit exists
to satisfy the build system linking rules. */ ||ENDFILE||
||FILE:src/c/src/export_timeline.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>

#include "generator.h"
#include "music_time.h"
#include "event_queue.h"

static const char *event_type_to_string(uint8_t t) {
switch ((event_type_t)t) {
case EVT_KICK: return "kick";
case EVT_SNARE: return "snare";
case EVT_HAT: return "hat";
case EVT_MELODY: return "melody";
case EVT_MID: return "mid";
case EVT_FM_BASS: return "fm_bass";
default: return "unknown";
}
}

int main(int argc, char **argv) {
uint64_t seed = 0xCAFEBABEULL;
const char *out_path = "timeline.json";

if (argc >= 2) {
// Accept hex like 0xDEADBEEF or decimal
seed = strtoull(argv[1], NULL, 0);
}
if (argc >= 3) {
out_path = argv[2];
}

generator_t g;
generator_init(&g, seed);

FILE *f = fopen(out_path, "wb");
if (!f) {
fprintf(stderr, "Failed to open %s for writing\n", out_path);
return 1;
}

// Header
fprintf(f, "{\n");
fprintf(f, " \"seed\": \"0x%016" PRIx64 "\",\n", seed);
fprintf(f, " \"sample_rate\": %u,\n", SR);
fprintf(f, " \"bpm\": %.6f,\n", g.mt.bpm);
fprintf(f, " \"step_samples\": %u,\n", g.mt.step_samples);
fprintf(f, " \"total_samples\": %u,\n", g.mt.seg_frames);

// Steps array (every 16th note)
fprintf(f, " \"steps\": [");
for (uint32_t s = 0; s < TOTAL_STEPS; ++s) {
uint32_t t = s * g.mt.step_samples;
fprintf(f, "%s%u", (s == 0 ? "" : ","), t);
}
fprintf(f, "],\n");

// Beats array (every 4 steps)
uint32_t total_beats = TOTAL_STEPS / STEPS_PER_BEAT;
fprintf(f, " \"beats\": [");
for (uint32_t b = 0; b < total_beats; ++b) {
uint32_t t = (b * STEPS_PER_BEAT) * g.mt.step_samples;
fprintf(f, "%s%u", (b == 0 ? "" : ","), t);
}
fprintf(f, "],\n");

// Events
fprintf(f, " \"events\": [\n");
for (uint32_t i = 0; i < g.q.count; ++i) {
const event_t *ev = &g.q.events[i];
fprintf(f,
" {\"time\": %u, \"type\": \"%s\", \"aux\": %u}%s\n",
ev->time,
event_type_to_string(ev->type),
(unsigned)ev->aux,
(i + 1 < g.q.count ? "," : ""));
}
fprintf(f, " ]\n");

fprintf(f, "}\n");
fclose(f);

printf("Exported timeline to %s (bpm=%.3f, steps=%u, events=%u)\n",
out_path, g.mt.bpm, TOTAL_STEPS, g.q.count);
return 0;
}



||ENDFILE||
||FILE:src/c/src/fm_debug_test.c||
#include "fm_voice.h"
#include "wav_writer.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t test_frames = 5000; // Short test

fm_voice_t fm;
fm_voice_init(&fm, sr);

// Trigger an FM note with higher amplitude for better audibility
fm_voice_trigger(&fm, 440.0f, 1.0f, 2.0f, 3.0f, 1.0f, 0.5f); // freq, dur, ratio, idx, amp, decay
printf("FM DEBUG: triggered freq=440.0 dur=1.0 ratio=2.0 idx=3.0 amp=0.5 decay=1.0\n");
printf("FM DEBUG: len=%u pos=%u\n", fm.len, fm.pos);

float *L = calloc(test_frames, sizeof(float));
float *R = calloc(test_frames, sizeof(float));

// Process just the first few frames with debug
printf("FM DEBUG: Before fm_voice_process - pos=%u len=%u\n", fm.pos, fm.len);

fm_voice_process(&fm, L, R, test_frames);

printf("FM DEBUG: After fm_voice_process - pos=%u len=%u\n", fm.pos, fm.len);

// Check first few samples for non-zero values
printf("FM DEBUG: First 10 samples:\n");
for (int i = 0; i < 10; i++) {
printf(" L[%d] = %f, R[%d] = %f\n", i, L[i], i, R[i]);
}

// Check for any non-zero values in the buffer
int non_zero_count = 0;
float max_val = 0;
for (uint32_t i = 0; i < test_frames; i++) {
if (L[i] != 0.0f || R[i] != 0.0f) {
non_zero_count++;
if (fabsf(L[i]) > max_val) max_val = fabsf(L[i]);
if (fabsf(R[i]) > max_val) max_val = fabsf(R[i]);
}
}
printf("FM DEBUG: Non-zero samples: %d/%u, max_val=%f\n", non_zero_count, test_frames, max_val);

// Convert and save
int16_t *pcm = malloc(sizeof(int16_t) * test_frames * 2);
for (uint32_t i = 0; i < test_frames; i++) {
float vL = L[i]; if(vL > 1) vL = 1; if(vL < -1) vL = -1;
float vR = R[i]; if(vR > 1) vR = 1; if(vR < -1) vR = -1;
pcm[2*i] = (int16_t)(vL * 32767);
pcm[2*i+1] = (int16_t)(vR * 32767);
}

write_wav("fm_debug.wav", pcm, test_frames, 2, sr);
printf("Generated fm_debug.wav\n");

free(L); free(R); free(pcm);
return 0;
}
||ENDFILE||
||FILE:src/c/src/fm_presets.c||
#include "fm_presets.h"

const fm_params_t FM_PRESET_BELLS = {3.5f, 4.0f, 0.0f, 0.15f}; // was 1.0f
const fm_params_t FM_PRESET_CALM = {2.0f, 2.5f, 6.0f, 0.25f};
const fm_params_t FM_PRESET_QUANTUM = {1.5f, 3.0f, 6.0f, 0.25f};
/* fm_pluck uses high index that decays quickly; index stored as peak */
const fm_params_t FM_PRESET_PLUCK = {1.0f, 6.0f, 8.0f, 0.25f};

const fm_params_t FM_BASS_DEFAULT = {2.0f, 5.0f, 0.0f, 0.25f}; // was 1.0f
const fm_params_t FM_BASS_QUANTUM = {1.5f, 8.0f, 8.0f, 0.45f};
const fm_params_t FM_BASS_PLUCKY = {3.0f, 2.5f, 14.0f, 0.35f}; ||ENDFILE||
||FILE:src/c/src/fm_voice.c||
#include "fm_voice.h"
#include <stdio.h>

void fm_voice_init(fm_voice_t *v, float32_t sr)
{
v->sr = sr;
v->len = 0;
v->pos = 0;
v->carrier_phase = 0.0f;
v->mod_phase = 0.0f;
}

void fm_voice_trigger(fm_voice_t *v, float32_t carrier_freq, float32_t duration_sec, float32_t ratio, float32_t index, float32_t amp, float32_t decay)
{
v->carrier_freq = carrier_freq;
v->ratio = ratio;
v->index0 = index;
v->amp = amp;
v->decay = decay;
v->len = (uint32_t)(duration_sec * v->sr);
v->pos = 0;
#ifndef REALTIME_MODE
printf("FM_TRIGGER cf=%.2f dur=%.2f ratio=%.2f idx=%.2f amp=%.2f len=%u\n", carrier_freq, duration_sec, ratio, index, amp, v->len);
#endif
}

/* When NO_C_VOICES=1: Only init/trigger stubs - no C processing fallback
* ASM implementation required for fm_voice_process */
||ENDFILE||
||FILE:src/c/src/fm_voice_neon.c||
#ifdef float32_t
#undef float32_t
#endif
#ifdef __ARM_NEON
#include <arm_neon.h>
#endif
#include <math.h>
#include <stdint.h>
#include "fm_voice.h"
#include "fast_math_neon.h"
#include "fast_math_asm.h"

#ifndef TAU
#define TAU 6.2831853071795864769f
#endif

#ifdef __ARM_NEON
#define EXP4 exp4_ps_asm
#define SIN4 sin4_ps_asm
#else
#define EXP4 exp4_ps
#define SIN4 sin4_ps
#endif

// Road-map Phase 4.2b — 4-sample NEON implementation that still relies on
// scalar sinf/expf for transcendental ops. It delivers functional parity
// while laying the groundwork for 4.2c where we replace those calls with
// polynomial/vector approximations.

void fm_voice_process(fm_voice_t *v, float32_t *L, float32_t *R, uint32_t n)
{
if (!v || n==0) return;
const float32_t sr=v->sr;
const float32_t carrier_freq=v->carrier_freq;
const float32_t ratio=v->ratio;
const float32_t index0=v->index0;
const float32_t amp=v->amp;
const float32_t decay=v->decay;
float32_t cp=v->carrier_phase;
float32_t mp=v->mod_phase;
const float32_t c_inc = TAU * carrier_freq / sr;
const float32_t m_inc = TAU * carrier_freq * ratio / sr;
uint32_t i=0;
#ifdef __ARM_NEON
if (v->pos < v->len) {
for (; i + 3 < n && v->pos + 3 < v->len; i += 4) {
const float32x4_t lane = {0.f,1.f,2.f,3.f};

/* phase vectors */
float32x4_t cp_v = vaddq_f32(vdupq_n_f32(cp), vmulq_n_f32(lane, c_inc));
float32x4_t mp_v = vaddq_f32(vdupq_n_f32(mp), vmulq_n_f32(lane, m_inc));

/* time vector for envelope */
float32x4_t pos_v = { (float)(v->pos+0), (float)(v->pos+1),
(float)(v->pos+2), (float)(v->pos+3) };
pos_v = vmulq_n_f32(pos_v, 1.0f / sr);

/* env = exp(-decay * t) */
float32x4_t env_v = EXP4(vmulq_n_f32(pos_v, -decay));

/* index & mod */
float32x4_t idx_v = vmulq_n_f32(env_v, index0);
float32x4_t inner_v = SIN4(mp_v);

float32x4_t arg_v = vmlaq_f32(cp_v, idx_v, inner_v);
float32x4_t sample_v= SIN4(arg_v);

sample_v = vmulq_f32(sample_v, env_v);
sample_v = vmulq_n_f32(sample_v, amp);

/* accumulate */
vst1q_f32(L+i, vaddq_f32(vld1q_f32(L+i), sample_v));
vst1q_f32(R+i, vaddq_f32(vld1q_f32(R+i), sample_v));

/* advance phases / pos */
cp += 4*c_inc; if(cp>=TAU) cp=fmodf(cp,TAU);
mp += 4*m_inc; if(mp>=TAU) mp=fmodf(mp,TAU);
v->pos += 4;
}
}
#endif // __ARM_NEON
// scalar loop (may run all or tail)
for(; i<n && v->pos<v->len; ++i){
float32_t t=(float32_t)v->pos/sr;
float32_t env=expf(-decay*t);
float32_t idx=index0*env;
float32_t sample=sinf(cp + idx * sinf(mp))*env*amp;
L[i]+=sample;
R[i]+=sample;
cp+=c_inc; if(cp>=TAU) cp-=TAU;
mp+=m_inc; if(mp>=TAU) mp-=TAU;
v->pos++;
}
v->carrier_phase=cp;
v->mod_phase=mp;
} ||ENDFILE||
||FILE:src/c/src/gen_bass.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr * 2; // 2 seconds
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t bass; fm_voice_init(&bass, (float)sr);
fm_params_t p = FM_BASS_DEFAULT; p.amp *= 2.0f; // louder for debug
fm_voice_trigger(&bass, 110.0f, 1.5f, p.ratio, p.index, p.amp, p.decay);

fm_voice_process(&bass, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float v=L[i]; if(v>1)v=1; if(v<-1)v=-1;
int16_t s = (int16_t)(v*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("bass_only.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_bass_plucky.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr * 2; // 2 seconds
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t bass; fm_voice_init(&bass, (float)sr);
fm_params_t p = FM_BASS_PLUCKY;
fm_voice_trigger(&bass, 110.0f, 1.5f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&bass, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float v=L[i]; if(v>1)v=1; if(v<-1)v=-1;
int16_t s = (int16_t)(v*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("bass_plucky.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_bass_quantum.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr * 2; // 2 seconds
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t bass; fm_voice_init(&bass, (float)sr);
fm_params_t p = FM_BASS_QUANTUM;
fm_voice_trigger(&bass, 110.0f, 1.5f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&bass, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float v=L[i]; if(v>1)v=1; if(v<-1)v=-1;
int16_t s = (int16_t)(v*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("bass_quantum.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_bells.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr/2; // 0.5 second
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t mid; fm_voice_init(&mid, (float)sr);
fm_params_t p = FM_PRESET_BELLS;
fm_voice_trigger(&mid, 880.0f, 0.9f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&mid, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float v=L[i]; if(v>1)v=1;if(v<-1)v=-1;
int16_t s=(int16_t)(v*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("bells-c.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
||FILE:src/c/src/gen_calm.c||
#include "wav_writer.h"
#include "fm_voice.h"
#include "fm_presets.h"
#include <stdlib.h>
#include <stdint.h>

int main(void)
{
const uint32_t sr = 44100;
const uint32_t frames = sr/2;
float *L = calloc(frames, sizeof(float));
float *R = calloc(frames, sizeof(float));

fm_voice_t v; fm_voice_init(&v, (float)sr);
fm_params_t p = FM_PRESET_CALM;
fm_voice_trigger(&v, 880.0f, 0.9f, p.ratio, p.index, p.amp, p.decay);
fm_voice_process(&v, L, R, frames);

int16_t *pcm = malloc(sizeof(int16_t)*frames*2);
for(uint32_t i=0;i<frames;i++){
float val = L[i]; if(val>1)val=1;if(val<-1)val=-1;
int16_t s = (int16_t)(val*32767);
pcm[2*i]=s; pcm[2*i+1]=s;
}
write_wav("calm-c.wav", pcm, frames, 2, sr);
free(L); free(R); free(pcm);
return 0;
} ||ENDFILE||
at txn 0x2e1ce49b487db0445f313c0a71c66ff695eab3cbfb8e542ecb34c3c478f4c976 Aug-20-2025 12:46:11 AM UTC (26 days ago)

||FILE:src/c/include/crt_fx.h||
#ifndef CRT_FX_H
#define CRT_FX_H

#include <stdint.h>
#include "rand.h"

typedef struct {
/* persistence (ghost trails) */
uint32_t *prev_frame;
float persistence; /* 0.3 (heavy) to 0.9 (minimal) */

/* scanlines */
int scanline_alpha; /* 0-200 */

/* chromatic aberration */
int chroma_shift; /* 0-5 pixels */

/* noise */
int noise_pixels; /* 0-300 per frame */

/* jitter */
float jitter_amount; /* 0-3 pixels */

/* frame drops */
float frame_drop_chance; /* 0-0.1 */

/* color bleed */
float color_bleed; /* 0-0.3 */

/* RNG for effects */
rng_t rng;
} crt_fx_t;

void crt_fx_init(crt_fx_t *fx, uint64_t seed, int w, int h);
void crt_fx_apply(crt_fx_t *fx, uint32_t *fb, int w, int h, int frame);
void crt_fx_cleanup(crt_fx_t *fx);

#endif /* CRT_FX_H */ ||ENDFILE||
||FILE:src/c/include/delay.h||
#ifndef DELAY_H
#define DELAY_H

#include <stdint.h>
#include <string.h>

typedef struct {
float32_t *buf; /* interleaved stereo buffer, length = size*2 */
uint32_t size; /* delay in samples */
uint32_t idx; /* write/read index */
} delay_t;

static inline void delay_init(delay_t *d, float32_t *storage, uint32_t size)
{
d->buf = storage; d->size = size; d->idx = 0;
memset(d->buf, 0, sizeof(float32_t)*size*2);
}

/* Process block in-place (L and R arrays). */
void delay_process_block(delay_t *d, float32_t *L, float32_t *R, uint32_t n, float32_t feedback);

#endif /* DELAY_H */ ||ENDFILE||
||FILE:src/c/include/env.h||
#ifndef ENV_H
#define ENV_H

#include <stdint.h>

/* Generate exponential decay envelope into `out[n]`.
* Formula: exp(-rate * t) where t in seconds.
* Provide sample rate `sr` and decay constant `rate` (per second).
*/
void exp_env_block(float *out, uint32_t n, float rate, float sr);

/* simple exponential decay envelope */
static inline float32_t env_exp_decay(float32_t t, float32_t decay_rate)
{
return expf(-decay_rate * t);
}

#endif /* ENV_H */ ||ENDFILE||
||FILE:src/c/include/euclid.h||
#ifndef EUCLID_H
#define EUCLID_H

#include <stddef.h>
#include <stdint.h>

/* Fill `out[steps]` with 0/1 values representing a Bjorklund Euclidean rhythm.
* `pulses` may be 0..steps.
*/
void euclid_pattern(int pulses, int steps, uint8_t *out);

#endif /* EUCLID_H */ ||ENDFILE||
||FILE:src/c/include/event_queue.h||
#ifndef EVENT_QUEUE_H
#define EVENT_QUEUE_H

#include <stdint.h>

/* Event types for the segment composer */
typedef enum {
EVT_KICK = 0,
EVT_SNARE,
EVT_HAT,
EVT_MELODY,
EVT_MID, /* generic mid-range note with 7 possible waveforms */
EVT_FM_BASS,
EVT_COUNT
} event_type_t;

typedef struct {
uint32_t time; /* sample index at which to trigger */
uint8_t type; /* event_type_t */
uint8_t aux; /* optional small parameter (e.g. preset/freq index) */
} event_t;

#define MAX_EVENTS 512 /* adjust if needed */

typedef struct {
event_t events[MAX_EVENTS];
uint32_t count;
} event_queue_t;

static inline void eq_init(event_queue_t *q){ q->count = 0; }
static inline void eq_push(event_queue_t *q, uint32_t time, uint8_t type, uint8_t aux){
if(q->count < MAX_EVENTS){
q->events[q->count++] = (event_t){time, type, aux};
}
}

#endif /* EVENT_QUEUE_H */ ||ENDFILE||
||FILE:src/c/include/fast_math_asm.h||
||ENDFILE||
||FILE:src/c/include/fast_math_neon.h||
// fast_math_neon.h – 4-lane NEON approximations for expf() and sinf()
// Source: adapted from Julien Pommier's "neon_mathfun" (zlib licence)
// Provides ~1 ulp accuracy, vastly faster than libm scalar calls.
#pragma once

#ifdef __ARM_NEON
#include <arm_neon.h>

// ------- exp4_ps -----------------------------------------------------------
static inline float32x4_t exp4_ps(float32x4_t x)
{
const float32x4_t max_x = vdupq_n_f32( 88.3762626647949f);
const float32x4_t min_x = vdupq_n_f32(-88.3762626647949f);
x = vmaxq_f32(vminq_f32(x, max_x), min_x);

const float32x4_t log2e = vdupq_n_f32(1.44269504088896341f);
const float32x4_t half = vdupq_n_f32(0.5f);
float32x4_t fx = vmlaq_f32(half, x, log2e);
int32x4_t emm0 = vcvtq_s32_f32(fx);
fx = vcvtq_f32_s32(emm0);

const float32x4_t ln2_hi = vdupq_n_f32(0.693359375f);
const float32x4_t ln2_lo = vdupq_n_f32(-2.12194440e-4f);
float32x4_t tmp = vmulq_f32(fx, ln2_hi);
float32x4_t z = vmulq_f32(fx, ln2_lo);
x = vsubq_f32(x, tmp);
x = vsubq_f32(x, z);

const float32x4_t c1 = vdupq_n_f32(1.9875691500E-4f);
const float32x4_t c2 = vdupq_n_f32(1.3981999507E-3f);
const float32x4_t c3 = vdupq_n_f32(8.3334519073E-3f);
const float32x4_t c4 = vdupq_n_f32(4.1665795894E-2f);
const float32x4_t c5 = vdupq_n_f32(1.6666665459E-1f);

float32x4_t x2 = vmulq_f32(x, x);

float32x4_t y = vmlaq_f32(c1, x, c2);
y = vmlaq_f32(y, x2, c3);
y = vmlaq_f32(y, vmulq_f32(x2, x), c4);
y = vmlaq_f32(y, vmulq_f32(x2, x2), c5);

y = vaddq_f32(vaddq_f32(y, x), vdupq_n_f32(1.0f));

emm0 = vaddq_s32(emm0, vdupq_n_s32(127));
emm0 = vshlq_n_s32(emm0, 23);
float32x4_t pow2n = vreinterpretq_f32_s32(emm0);

return vmulq_f32(y, pow2n);
}

// ------- sin4_ps -----------------------------------------------------------
static inline float32x4_t sin4_ps(float32x4_t x)
{
// Range reduce to [-π, π]
const float32x4_t inv_pi = vdupq_n_f32(0.31830988618379067154f); // 1/π
const float32x4_t pi = vdupq_n_f32(3.14159265358979323846f);

float32x4_t y = vmulq_f32(x, inv_pi);
int32x4_t n = vcvtq_s32_f32(vrndnq_f32(y));
y = vcvtq_f32_s32(n);
x = vsubq_f32(x, vmulq_f32(y, pi));

// flip sign if n is odd
uint32x4_t swap_sign = vandq_u32(vreinterpretq_u32_s32(n), vdupq_n_u32(1));
x = vbslq_f32(vshlq_n_u32(swap_sign,31), vnegq_f32(x), x);

const float32x4_t s1 = vdupq_n_f32(-1.6666664611e-1f);
const float32x4_t s2 = vdupq_n_f32( 8.3333337670e-3f);
const float32x4_t s3 = vdupq_n_f32(-1.9841270114e-4f);
const float32x4_t s4 = vdupq_n_f32( 2.7557314297e-6f);

float32x4_t z = vmulq_f32(x, x);

float32x4_t y1 = vmlaq_f32(s2, z, s3);
y1 = vmlaq_f32(y1, vmulq_f32(z,z), s4);
y1 = vmlaq_f32(y1, z, s1);

return vmlaq_f32(x, vmulq_f32(x, vmulq_f32(z, y1)), vdupq_n_f32(0.0f));
}

#endif // __ARM_NEON ||ENDFILE||
||FILE:src/c/include/fm_presets.h||
#ifndef FM_PRESETS_H
#define FM_PRESETS_H

#include <stddef.h>

typedef struct {
float32_t ratio;
float32_t index;
float32_t decay;
float32_t amp;
} fm_params_t;

/* Mid-range FM timbres (used by python: fm_bells, fm_calm, fm_quantum, fm_pluck) */
extern const fm_params_t FM_PRESET_BELLS;
extern const fm_params_t FM_PRESET_CALM;
extern const fm_params_t FM_PRESET_QUANTUM;
extern const fm_params_t FM_PRESET_PLUCK;

/* Bass FM profiles (python bass_profiles) */
extern const fm_params_t FM_BASS_DEFAULT;
extern const fm_params_t FM_BASS_QUANTUM;
extern const fm_params_t FM_BASS_PLUCKY;

#endif /* FM_PRESETS_H */ ||ENDFILE||
||FILE:src/c/include/fm_voice.h||
#ifndef FM_VOICE_H
#define FM_VOICE_H

#include <stdint.h>
#include "osc.h"

typedef struct {
/* runtime params */
float32_t sr;
float32_t carrier_freq;
float32_t ratio; /* modulator/carrier */
float32_t index0; /* starting index */
float32_t amp;
float32_t decay;

/* state */
uint32_t len; /* total samples */
uint32_t pos; /* current position */
float32_t carrier_phase;
float32_t mod_phase;
} fm_voice_t;

void fm_voice_init(fm_voice_t *v, float32_t sr);
void fm_voice_trigger(fm_voice_t *v, float32_t carrier_freq, float32_t duration_sec, float32_t ratio, float32_t index, float32_t amp, float32_t decay);
void fm_voice_process(fm_voice_t *v, float32_t *L, float32_t *R, uint32_t n);

#endif /* FM_VOICE_H */ ||ENDFILE||
||FILE:src/c/include/generator.h||
#ifndef GENERATOR_H
#define GENERATOR_H

/* Nuclear refactor flag - when enabled, removes all C voice fallbacks */
#define NO_C_VOICES 1

#include <stdint.h>
#include <stdbool.h>
#include "music_time.h"
#include "music_defs.h"
#include "rand.h"
#include "kick.h"
#include "snare.h"
#include "hat.h"
#include "melody.h"
#include "fm_voice.h"
#include "simple_voice.h"
#include "delay.h"
#include "limiter.h"
#include "event_queue.h"

#define MAX_DELAY_SAMPLES 106000

typedef struct {
music_time_t mt;
music_globals_t music;
rng_t rng;

kick_t kick;
snare_t snare;
hat_t hat;
melody_t mel;
fm_voice_t mid_fm;
fm_voice_t bass_fm;
simple_voice_t mid_simple;

event_queue_t q;
uint32_t event_idx;
uint32_t step;
uint32_t pos_in_step; /* samples into current step */

delay_t delay;
limiter_t limiter;

float32_t delay_buf[MAX_DELAY_SAMPLES * 2];

/* visual event flags */
bool saw_hit; /* set when saw melody triggers */
bool bass_hit; /* set when bass triggers */

} generator_t;

void generator_init(generator_t *g, uint64_t seed);
void generator_process(generator_t *g, float32_t *L, float32_t *R, uint32_t num_frames);
void generator_process_voices(generator_t *g, float32_t *Ld, float32_t *Rd,
float32_t *Ls, float32_t *Rs, uint32_t num_frames);

/* Phase 5 - Pure Assembly Orchestration Functions */
void generator_mix_buffers_asm(float32_t *L, float32_t *R,
const float32_t *Ld, const float32_t *Rd,
const float32_t *Ls, const float32_t *Rs,
uint32_t num_frames);

float generator_compute_rms_asm(const float32_t *L, const float32_t *R,
uint32_t num_frames);

void generator_clear_buffers_asm(float32_t *Ld, float32_t *Rd,
float32_t *Ls, float32_t *Rs,
uint32_t num_frames);

void generator_rotate_pattern_asm(uint8_t *pattern, uint8_t *tmp,
uint32_t size, uint32_t rot);

void generator_build_events_asm(event_queue_t *q, rng_t *rng,
const uint8_t *kick_pat, const uint8_t *snare_pat, const uint8_t *hat_pat,
uint32_t step_samples);

void generator_trigger_step(generator_t *g);

extern volatile float g_block_rms;

#endif /* GENERATOR_H */ ||ENDFILE||
||FILE:src/c/include/hat.h||
#ifndef HAT_H
#define HAT_H

#include <stdint.h>
#include "rand.h"

typedef struct {
uint32_t pos;
uint32_t len;
float32_t sr;
float32_t env;
float32_t env_coef;
rng_t rng;
} hat_t;

void hat_init(hat_t *h, float32_t sr, uint64_t seed);
void hat_trigger(hat_t *h);
void hat_process(hat_t *h, float32_t *L, float32_t *R, uint32_t n);

#endif /* HAT_H */ ||ENDFILE||
||FILE:src/c/include/kick.h||
#ifndef KICK_H
#define KICK_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
float32_t sr;
uint32_t pos; /* current sample in envelope; =len when inactive */
uint32_t len; /* total samples of sound */
float32_t env; /* current envelope value (1→0) */
float32_t env_coef;/* per-sample decay coefficient */
float32_t phase; /* current phase accumulator (radians or table index) */
float32_t phase_inc; /* per-sample phase increment for table lookup */
float32_t y_prev;
float32_t y_prev2;
float32_t k1;
} kick_t;

/* Initialise kick voice */
void kick_init(kick_t *k, float32_t sr);

/* Start a new kick hit */
void kick_trigger(kick_t *k);

/* Render `n` samples, adding into stereo buffers L/R. */
void kick_process(kick_t *k, float32_t *L, float32_t *R, uint32_t n);

#ifdef __cplusplus
}
#endif

#endif /* KICK_H */ ||ENDFILE||
||FILE:src/c/include/limiter.h||
#ifndef LIMITER_H
#define LIMITER_H

#include <stdint.h>
#include <math.h>

/* A simple soft-knee stereo limiter. */

typedef struct {
float32_t attack_coeff;
float32_t release_coeff;
float32_t envelope;
float32_t threshold;
float32_t knee_width;
} limiter_t;

static inline void limiter_init(limiter_t *l, float32_t sr, float32_t attack_ms, float32_t release_ms, float32_t threshold_db)
{
l->attack_coeff = expf(-1.0f / (attack_ms * sr / 1000.0f));
l->release_coeff = expf(-1.0f / (release_ms * sr / 1000.0f));
l->envelope = 0.0f;
l->threshold = powf(10.0f, threshold_db / 20.0f);
l->knee_width = 5.0f; // 5dB soft knee
}

void limiter_process(limiter_t *l, float32_t *L, float32_t *R, uint32_t n);

#endif /* LIMITER_H */ ||ENDFILE||
||FILE:src/c/include/melody.h||
#ifndef MELODY_H
#define MELODY_H

#include <stdint.h>
#include "osc.h"

typedef struct {
osc_t osc;
uint32_t pos;
uint32_t len;
float32_t sr;
float32_t freq;
} melody_t;

void melody_init(melody_t *m, float32_t sr);
void melody_trigger(melody_t *m, float32_t freq, float32_t dur_sec);
void melody_process(melody_t *m, float32_t *L, float32_t *R, uint32_t n);

#endif /* MELODY_H */ ||ENDFILE||
||FILE:src/c/include/music_defs.h||
#ifndef MUSIC_DEFS_H
#define MUSIC_DEFS_H

#include <stdint.h>
#include "rand.h"

/* Defines musical scales, keys, and other seed-driven parameters */

typedef enum {
SCALE_MAJOR_PENT,
SCALE_MINOR_PENT
} scale_type_t;

typedef struct {
float root_freq;
scale_type_t scale_type;
const int *scale_degrees;
uint8_t scale_len;
} music_globals_t;

static const int PENT_MAJOR_DEGREES[] = {0,2,4,7,9};
static const int PENT_MINOR_DEGREES[] = {0,3,5,7,10};

static inline void music_globals_init(music_globals_t *g, rng_t *rng)
{
float root_choices[] = {220.0f, 233.08f, 246.94f, 261.63f, 293.66f};
g->root_freq = root_choices[rng_next_u32(rng) % 5];

if(rng_next_u32(rng) % 2){
g->scale_type = SCALE_MAJOR_PENT;
g->scale_degrees = PENT_MAJOR_DEGREES;
g->scale_len = sizeof(PENT_MAJOR_DEGREES)/sizeof(int);
} else {
g->scale_type = SCALE_MINOR_PENT;
g->scale_degrees = PENT_MINOR_DEGREES;
g->scale_len = sizeof(PENT_MINOR_DEGREES)/sizeof(int);
}
}

#endif /* MUSIC_DEFS_H */ ||ENDFILE||
||FILE:src/c/include/music_time.h||
#ifndef MUSIC_TIME_H
#define MUSIC_TIME_H

#include <stdint.h>

/* Global musical timing constants for the segment renderer. */

#define SR 44100u
#define STEPS_PER_BEAT 4u /* 16th notes */
#define BARS_PER_SEG 2u
#define STEPS_PER_BAR (4u * STEPS_PER_BEAT)
#define TOTAL_STEPS (BARS_PER_SEG * STEPS_PER_BAR)

typedef struct {
float bpm;
float beat_sec;
float step_sec;
uint32_t step_samples;
float seg_sec;
uint32_t seg_frames;
} music_time_t;

static inline void music_time_init(music_time_t *t, float bpm)
{
t->bpm = bpm;
t->beat_sec = 60.0f / t->bpm;
t->step_sec = t->beat_sec / (float)STEPS_PER_BEAT;
t->step_samples = (uint32_t)(t->step_sec * SR + 0.5f);
t->seg_sec = t->step_sec * (float)TOTAL_STEPS;
t->seg_frames = (uint32_t)(t->seg_sec * SR + 0.5f);
}

#endif /* MUSIC_TIME_H */ ||ENDFILE||
||FILE:src/c/include/noise.h||
#ifndef NOISE_H
#define NOISE_H

#include <stdint.h>
#include "rand.h"

/* Fill `out[n]` with white noise in range [-1,1). Uses provided RNG. */
void noise_block(rng_t *rng, float *out, uint32_t n);

#endif /* NOISE_H */ ||ENDFILE||
||FILE:src/c/include/osc.h||
#ifndef OSC_H
#define OSC_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/* Basic phase-accumulator oscillator helpers. */

typedef struct {
float32_t phase; /* in radians */
} osc_t;

static inline void osc_reset(osc_t *o) { o->phase = 0.0f; }

/* Render `n` mono samples of a sine wave at `freq` Hz into `out`.
* The oscillator keeps its phase between calls.
*/
void osc_sine_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr);

/* Render `n` mono samples of a saw wave at `freq` Hz into `out`.
* The oscillator keeps its phase between calls.
*/
void osc_saw_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr);

/* Render `n` mono samples of a square wave at `freq` Hz into `out`.
* The oscillator keeps its phase between calls.
*/
void osc_square_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr);

/* Render `n` mono samples of a triangle wave at `freq` Hz into `out`.
* The oscillator keeps its phase between calls.
*/
void osc_triangle_block(osc_t *o, float32_t *out, uint32_t n, float32_t freq, float32_t sr);

#ifdef __cplusplus
}
#endif

#endif /* OSC_H */ ||ENDFILE||
||FILE:src/c/include/particles.h||
#ifndef PARTICLES_H
#define PARTICLES_H

#include <stdint.h>
#include <stdbool.h>

#define MAX_PARTICLES 256

typedef struct {
float x,y;
float vx,vy;
int life;
int max_life;
uint32_t color;
uint8_t glyph; /* index into glyph set */
} particle_t;

void particles_init(void);
void particles_spawn_burst(float x,float y,int count,uint32_t color);
void particles_update_and_draw(uint32_t *fb,int w,int h);

#endif /* PARTICLES_H */ ||ENDFILE||
||FILE:src/c/include/rand.h||
#ifndef RAND_H
#define RAND_H

#include <stdint.h>

/* Simple 64-bit SplitMix64 PRNG seeded with any 64-bit value. */
typedef struct {
uint64_t state;
} rng_t;

static inline rng_t rng_seed(uint64_t seed)
{
rng_t r; r.state = seed + 0x9E3779B97F4A7C15ULL; return r;
}

/* Produce next 64-bit pseudo-random value. */
static inline uint64_t rng_next_u64(rng_t *r)
{
uint64_t z = (r->state += 0x9E3779B97F4A7C15ULL);
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ULL;
z = (z ^ (z >> 27)) * 0x94D049BB133111EBULL;
return z ^ (z >> 31);
}

static inline uint32_t rng_next_u32(rng_t *r)
{
return (uint32_t)rng_next_u64(r);
}

/* Return float in [0,1). */
static inline float rng_next_float(rng_t *r)
{
return (rng_next_u32(r) >> 8) * (1.0f / 16777216.0f); // 24-bit mantissa
}

static inline float rng_float_mono(rng_t *r)
{
return rng_next_float(r) * 2.0f - 1.0f; /* -1..1 */
}

#endif /* RAND_H */ ||ENDFILE||
||FILE:src/c/include/raster.h||
#ifndef RASTER_H
#define RASTER_H
#include <stdint.h>
#include <stdbool.h>

void raster_clear(uint32_t *fb, int w, int h, uint32_t color_rgba);
void raster_circle(uint32_t *fb, int w, int h, int cx, int cy, int r, uint32_t color_rgba, int thickness);
void raster_fill_circle(uint32_t *fb, int w, int h, int cx, int cy, int r, uint32_t color_rgba);
void raster_line(uint32_t *fb, int w, int h, int x0, int y0, int x1, int y1, uint32_t color_rgba);
void raster_poly(uint32_t *fb, int w, int h, const int *vx, const int *vy, int n, uint32_t color_rgba, bool fill, int thickness);
void raster_blit_rgba(const uint32_t *src, int src_w, int src_h, uint32_t *dst_fb, int dst_w, int dst_h, int dx, int dy);
void raster_blit_rgba_alpha(const uint32_t *src, int src_w, int src_h, uint32_t *dst_fb, int dst_w, int dst_h, int dx, int dy);

#endif ||ENDFILE||
||FILE:src/c/include/shapes.h||
#ifndef SHAPES_H
#define SHAPES_H

#include <stdint.h>
#include <stdbool.h>

#define MAX_SHAPES 8

typedef enum {
SHAPE_TRIANGLE,
SHAPE_DIAMOND,
SHAPE_HEXAGON,
SHAPE_STAR,
SHAPE_SQUARE
} shape_type_t;

typedef struct {
shape_type_t type;
float scale; /* 0.1 to 1.0 */
float rotation; /* radians */
float rot_speed; /* radians per frame */
int alpha; /* 0-255 */
uint32_t color;
} bass_shape_t;

void shapes_init(void);
void shapes_spawn(shape_type_t type, uint32_t color);
void shapes_update_and_draw(uint32_t *fb, int w, int h);

#endif /* SHAPES_H */ ||ENDFILE||
||FILE:src/c/include/simple_voice.h||
#ifndef SIMPLE_VOICE_H
#define SIMPLE_VOICE_H

#include <stdint.h>
#include "osc.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Simple oscillator voice with exponential decay envelope.
Supports sine, triangle, square waveforms. */

typedef enum {
SIMPLE_SINE = 0,
SIMPLE_TRI = 1,
SIMPLE_SQUARE = 2
} simple_wave_t;

typedef struct {
osc_t osc;
uint32_t len;
uint32_t pos;
float32_t sr;
float32_t decay;
float32_t amp;
simple_wave_t wave;
float32_t freq;
} simple_voice_t;

void simple_voice_init(simple_voice_t *v, float32_t sr);
void simple_voice_trigger(simple_voice_t *v, float32_t freq, float32_t dur_sec, simple_wave_t wave, float32_t amp, float32_t decay);
void simple_voice_process(simple_voice_t *v, float32_t *L, float32_t *R, uint32_t n);

#ifdef __cplusplus
}
#endif

#endif /* SIMPLE_VOICE_H */ ||ENDFILE||
||FILE:src/c/include/snare.h||
#ifndef SNARE_H
#define SNARE_H

#include <stdint.h>
#include "rand.h"

typedef struct {
uint32_t pos;
uint32_t len;
float32_t sr;
float32_t env; /* current envelope value */
float32_t env_coef; /* per-sample decay coefficient */
rng_t rng;
} snare_t;

void snare_init(snare_t *s, float32_t sr, uint64_t seed);
void snare_trigger(snare_t *s);
void snare_process(snare_t *s, float32_t *L, float32_t *R, uint32_t n);

#endif /* SNARE_H */ ||ENDFILE||
||FILE:src/c/include/terrain.h||
#ifndef TERRAIN_H
#define TERRAIN_H

#include <stdint.h>
#include <stdbool.h>
#include "raster.h"
#include "rand.h"

#define TILE_SIZE 32
#define TERRAIN_LEN 64

/* Tile types */
enum { TILE_FLAT=0, TILE_WALL=1, TILE_SLOPE_UP=2, TILE_SLOPE_DOWN=3, TILE_GAP=4 };

typedef struct {
uint8_t type;
uint8_t height; /* rows of tiles */
} terrain_tile_t;

void terrain_init(uint64_t seed);
void terrain_draw(uint32_t *fb, int w, int h, int frame);

#endif /* TERRAIN_H */ ||ENDFILE||
||FILE:src/c/include/video.h||
#ifndef VIDEO_H
#define VIDEO_H

#include <stdint.h>
#include <stdbool.h>

/* Simple SDL2 + OpenGL video facade used by the visualiser.
* This is intentionally minimal for Stage-1 scaffolding.
*/

/* Initialise window & renderer.
* width/height → window size (pixels)
* fps → target frame-rate (logical). 0 = uncapped.
* vsync → true = let SDL use VSYNC; false = immediate.
* Returns 0 on success, non-zero on failure.
*/
int video_init(int width, int height, int fps, bool vsync);

/* Begin a new frame. Handles frame pacing, event polling, clears the screen.
* Returns false when the user has requested to quit (e.g. window close).
*/
bool video_frame_begin(void);

/* End the frame: present back-buffer. */
void video_frame_end(void);

/* Accessors for software framebuffer */
uint32_t* video_get_framebuffer(void);
int video_get_width(void);
int video_get_height(void);

/* Shutdown & free resources. */
void video_shutdown(void);

#endif /* VIDEO_H */ ||ENDFILE||
||FILE:src/c/include/wav_writer.h||
#ifndef WAV_WRITER_H
#define WAV_WRITER_H

#include <stdint.h>

/*
* Write a little-endian 16-bit PCM WAV file.
* path — output filename
* samples — interleaved PCM samples (len = frames * channels)
* frames — number of audio frames
* num_channels — 1 = mono, 2 = stereo
* sample_rate — e.g., 44100
*/
void write_wav(const char *path,
const int16_t *samples,
uint32_t frames,
uint16_t num_channels,
uint32_t sample_rate);

#endif /* WAV_WRITER_H */ ||ENDFILE||
at txn 0xa0841d87cd7ded4a92253bb06555f4fbc5a95e119ab75018a8113e2ab383924d Aug-20-2025 12:45:59 AM UTC (26 days ago)
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6ImE1NWVkMGIyLTg2ODAtNDRjOS04MTZlLWU3YTI5Njc0ZmU0ZiIsIm9yZGVySWRlbnRpZmllciI6IjlmZDZjNDYxLWY5MzQtNDRiMi04NjZjLTViNDgyMGExOTRiZiIsImlhdCI6MTc1NTY1MDY4NH0.Gf8m-fjg0RDCUeny4DU-NPNd123nKH0uu5DYv4vmNCg------END MEMO------
at txn 0xa321834c1ecd59aa75892962aa89976d73910bcccca18b9c9cc69fb1da5f75c9 Aug-20-2025 12:45:47 AM UTC (26 days ago)

||FILE:src/c/Makefile||
# Simple build script – Phase 0 scaffolding

CC := clang
SDL_CFLAGS := $(shell sdl2-config --cflags)
SDL_LIBS := $(shell sdl2-config --libs)

# Determine host arch first
ARCH := $(shell uname -m)

# Detect request for cross-compilation (set CROSS=1 from CLI)
ifndef CROSS
CROSS := 0
endif

# If we are on an x86_64 host *and* not explicitly cross-compiling, disable ASM
ifeq ($(ARCH),x86_64)
ifeq ($(CROSS),0)
USE_ASM := 0
endif
endif

# If CROSS=1, enforce arm64 code-gen flags
ifeq ($(CROSS),1)
USE_ASM := 1
CFLAGS += -target arm64-apple-macos13
endif

# Default USE_ASM detection if not already set
ifndef USE_ASM
# Simple architecture detection - on ARM64 machines, enable ASM by default
ifeq ($(ARCH),arm64)
USE_ASM := 1
else
USE_ASM := 0
endif
endif

ifeq ($(findstring GENERATOR_ASM,$(VOICE_ASM)),)
GENERATOR_IS_C := 1
else
GENERATOR_IS_C := 0
endif

# base flags
CFLAGS := -std=c11 -Wall -Wextra -O2 -Iinclude $(SDL_CFLAGS)

# Enhanced debug flags for LLDB debugging with mixed C+assembly (mentioned in roadmap)
ifeq ($(DEBUG),1)
CFLAGS += -g -O0 -fstandalone-debug -fno-omit-frame-pointer
endif

# float32_t helper macro (typedef-like). The NEON compile unit undefines it to avoid clash.
CFLAGS += -Dfloat32_t=float

# Append profiling flags when PROFILE=1
ifeq ($(PROFILE),1)
CFLAGS += -pg -fno-omit-frame-pointer
endif

# Optional Address Sanitizer support (enable via ASAN=1)
ifeq ($(ASAN),1)
CFLAGS += -fsanitize=address -fno-omit-frame-pointer
LDFLAGS += -fsanitize=address
endif

LDFLAGS := -framework AudioToolbox -framework CoreFoundation -framework OpenGL $(SDL_LIBS)

# BEGIN ASM SUPPORT
ifeq ($(USE_ASM),1)
ASM_DIR := ../../asm/active
ASM_SRC := $(ASM_DIR)/euclid.s $(ASM_DIR)/limiter.s $(ASM_DIR)/noise.s $(ASM_DIR)/osc_shapes.s $(ASM_DIR)/osc_sine.s $(ASM_DIR)/generator.s
# If the VOICE_ASM variable is provided, include only the requested voice assembly files to
# avoid duplicate symbol errors with the C fallback implementations.
ifneq ($(origin VOICE_ASM), undefined)
# 1) Remove all per-voice assembly files from the list
ASM_SRC := $(filter-out $(ASM_DIR)/kick.s $(ASM_DIR)/snare.s $(ASM_DIR)/hat.s $(ASM_DIR)/melody.s $(ASM_DIR)/delay.s $(ASM_DIR)/fm_voice.s $(ASM_DIR)/exp4_ps_asm.s $(ASM_DIR)/sin4_ps_asm.s,$(ASM_SRC))

# 2) Re-add only those explicitly requested via VOICE_ASM.
ifneq ($(findstring KICK_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/kick.s
endif
ifneq ($(findstring SNARE_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/snare.s
endif
ifneq ($(findstring HAT_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/hat.s
endif
ifneq ($(findstring MELODY_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/melody.s
endif
ifneq ($(findstring DELAY_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/delay.s
endif
ifneq ($(findstring FM_VOICE_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/fm_voice.s $(ASM_DIR)/exp4_ps_asm.s $(ASM_DIR)/sin4_ps_asm.s
endif
endif

# --- Assembly generator (generator_process) opt-in -----------------------
# By default we now EXCLUDE generator.s so that the stable C implementation
# is used. If you really want the work-in-progress assembly version, pass
# VOICE_ASM="GENERATOR_ASM"
# or include GENERATOR_ASM in the existing list.

# 1) Always remove generator.s first
ASM_SRC := $(filter-out $(ASM_DIR)/generator.s,$(ASM_SRC))

# 2) Re-add only if user explicitly asks for it
ifneq ($(findstring GENERATOR_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/generator.s
endif

ASM_OBJ := $(ASM_SRC:.s=.o)
# Add math objects only if FM voice assembly is enabled
ifeq ($(findstring -DFM_VOICE_ASM,$(CFLAGS)),-DFM_VOICE_ASM)
ASM_OBJ += $(ASM_DIR)/exp4_ps_asm.o $(ASM_DIR)/sin4_ps_asm.o
endif
# per-module ASM optimisation flags
CFLAGS += -DOSC_SINE_ASM -DOSC_SHAPES_ASM
# Voice assembly macros. By default enable all voices that have an ASM version implemented.
# For debugging you can override this via:
# make segment VOICE_ASM="KICK_ASM" # only kick in ASM, others in C
# make segment VOICE_ASM="KICK_ASM SNARE_ASM" # kick + snare in ASM
# If VOICE_ASM is undefined we fall back to enabling every voice (legacy behaviour).
ifeq ($(origin VOICE_ASM), undefined)
CFLAGS += -DKICK_ASM -DSNARE_ASM -DHAT_ASM -DMELODY_ASM -DDELAY_ASM
ASM_SRC += $(ASM_DIR)/kick.s $(ASM_DIR)/snare.s $(ASM_DIR)/hat.s $(ASM_DIR)/melody.s $(ASM_DIR)/delay.s
else
CFLAGS += $(addprefix -D,$(VOICE_ASM))
# Also add corresponding assembly sources for specified voices
ifneq ($(findstring KICK_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/kick.s
endif
ifneq ($(findstring SNARE_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/snare.s
endif
ifneq ($(findstring HAT_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/hat.s
endif
ifneq ($(findstring MELODY_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/melody.s
endif
ifneq ($(findstring DELAY_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/delay.s
endif
ifneq ($(findstring FM_VOICE_ASM,$(VOICE_ASM)),)
ASM_SRC += $(ASM_DIR)/fm_voice.s $(ASM_DIR)/exp4_ps_asm.s $(ASM_DIR)/sin4_ps_asm.s
endif
endif
# CFLAGS += -DFM_VOICE_ASM
else
ASM_DIR :=
ASM_SRC :=
ASM_OBJ :=
endif
# END ASM SUPPORT

# Detect whether the assembly delay implementation is included
DELAY_ASM_PRESENT := $(filter $(ASM_DIR)/delay.s,$(ASM_SRC))
# Detect whether the assembly limiter implementation is included
LIMITER_ASM_PRESENT := $(filter $(ASM_DIR)/limiter.s,$(ASM_SRC))
# Detect generator assembly presence
GENERATOR_ASM_PRESENT := $(filter $(ASM_DIR)/generator.s,$(ASM_SRC))

# If the assembly generator provides its own RMS helper, tell C sources not to compile the fallback
ifeq ($(GENERATOR_ASM_PRESENT),$(ASM_DIR)/generator.s)
CFLAGS += -DGENERATOR_RMS_ASM_PRESENT
endif

ifeq ($(USE_ASM),1)
ifneq ($(ARCH),arm64)
# x86 hosts need explicit cross-target so clang understands AArch64 mnemonics
CFLAGS += -target arm64-apple-macos13
endif
# fm_voice_neon.c superseded by hand-written assembly; skip this object
NEON_OBJ :=
else
NEON_OBJ :=
endif

OBJ := src/main.o src/wav_writer.o src/euclid.o src/osc.o src/kick.o src/snare.o src/hat.o src/melody.o src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/event_queue.o src/simple_voice.o
BIN := bin/euclid
TEST_BIN := bin/gen_sine
TONE_BIN := bin/gen_tones
NOISE_BIN := bin/gen_noise_delay
KICK_BIN := bin/gen_kick
SNARE_BIN := bin/gen_snare
HAT_BIN := bin/gen_hat
MELODY_BIN := bin/gen_melody
FM_BIN := bin/gen_fm
SEG_BIN := bin/segment
SEG_TEST_BIN := bin/segment_test
DRUMS_BIN := bin/segment_drums
DRUMS_MEL_BIN := bin/segment_drums_mel
DRUMS_BASS_BIN := bin/segment_drums_bass
BELLS_BIN := bin/gen_bells
CALM_BIN := bin/gen_calm
QUANTUM_BIN := bin/gen_quantum
PLUCK_BIN := bin/gen_pluck
BASS_BIN := bin/gen_bass
BASSQ_BIN := bin/gen_bass_quantum
BASSP_BIN := bin/gen_bass_plucky
MELODY_DEBUG_BIN := bin/melody_debug_test
FM_DEBUG_BIN := bin/fm_debug_test

SEG_OBJ := src/segment.o src/wav_writer.o
SEG_TEST_OBJ := src/segment_test.o src/wav_writer.o

# Include C euclid.o only when not using assembly (to avoid duplicate symbols)
ifneq ($(USE_ASM),1)
SEG_OBJ += src/euclid.o
SEG_TEST_OBJ += src/euclid.o
endif

# -----------------------------------------------------------------
# Conditional C object inclusion depending on whether ASM version
# of each voice/effect is present (prevents duplicate symbols).
# -----------------------------------------------------------------
# Detect per-voice ASM presence
KICK_ASM_PRESENT := $(filter $(ASM_DIR)/kick.s,$(ASM_SRC))
SNARE_ASM_PRESENT := $(filter $(ASM_DIR)/snare.s,$(ASM_SRC))
HAT_ASM_PRESENT := $(filter $(ASM_DIR)/hat.s,$(ASM_SRC))
MELODY_ASM_PRESENT := $(filter $(ASM_DIR)/melody.s,$(ASM_SRC))

# Rebuild GEN_OBJ list: start with ASM objects and common C helpers
# Exclude src/osc.o when ASM oscillators are present to avoid duplicate symbols
ifeq ($(USE_ASM),1)
GEN_OBJ := $(ASM_OBJ) $(NEON_OBJ) src/fm_presets.o \
src/event_queue.o src/simple_voice.o
else
GEN_OBJ := $(ASM_OBJ) src/osc.o $(NEON_OBJ) src/fm_presets.o \
src/event_queue.o src/simple_voice.o
endif

# Add FM voice object (hybrid ASM+C for helpers, or pure C fallback)
ifeq ($(findstring -DFM_VOICE_ASM,$(CFLAGS)),-DFM_VOICE_ASM)
GEN_OBJ += $(ASM_DIR)/fm_voice.o src/fm_voice.o
else
GEN_OBJ += src/fm_voice.o
endif

# Nuclear refactor flag - set to 1 to remove all C voice fallbacks
NO_C_VOICES := 0
ifeq ($(NO_C_VOICES),1)
CFLAGS += -DNO_C_VOICES=1
endif

# Selective melody delay is now the permanent behavior
# (no longer requires conditional compilation)

# Always include per-voice C modules for init/trigger helpers.
# When NO_C_VOICES=0: Their process() functions work as fallbacks via #ifndef guards
# When NO_C_VOICES=1: Only init/trigger helpers are used, process() functions disabled
ifeq ($(NO_C_VOICES),1)
# With NO_C_VOICES=1, all voices must have ASM implementations
VOICE_LIST := kick snare hat melody
$(foreach voice,$(VOICE_LIST),\
$(if $(findstring $(shell echo $(voice) | tr '[:lower:]' '[:upper:]')_ASM,$(VOICE_ASM)),,\
$(error NO_C_VOICES=1 but $(voice) ASM implementation missing)\
)\
)
endif
GEN_OBJ += src/kick.o src/snare.o src/hat.o src/melody.o

# Delay C fallback only when ASM version *not* present (it contains only the
# process implementation guarded by #ifndef DELAY_ASM; omitting it when the
# ASM version is linked avoids a redundant empty object).
ifndef DELAY_ASM_PRESENT
GEN_OBJ += src/delay.o
endif

# Generator: always include C for generator_init (compiled with -DGENERATOR_ASM)
GEN_OBJ += src/generator.o

# Limiter C fallback
ifndef LIMITER_ASM_PRESENT
GEN_OBJ += src/limiter.o
endif

# Include minimal generator_step stub for trigger functionality
GEN_OBJ += src/generator_step.o

REALTIME_OBJ := src/main_realtime.o src/coreaudio.o src/video.o src/raster.o src/terrain.o src/particles.o src/shapes.o src/crt_fx.o

REALTIME_BIN := bin/realtime

# Timeline export tool (link only minimal C objects; avoid ASM-only process fns)
TIMELINE_OBJ := src/export_timeline.o \
src/generator.o src/event_queue.o src/fm_presets.o \
src/kick.o src/snare.o src/hat.o src/melody.o src/fm_voice.o \
src/delay.o src/limiter.o
TIMELINE_BIN := bin/export_timeline

all: $(SEG_BIN) $(REALTIME_BIN) $(TIMELINE_BIN)

$(SEG_BIN): $(SEG_OBJ) $(GEN_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(SEG_TEST_BIN): $(SEG_TEST_OBJ) $(GEN_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

bin/long_loop_test: long_loop_test.c $(GEN_OBJ) src/wav_writer.o $(ASM_OBJ) ../asm/active/generator.o ../asm/active/kick.o ../asm/active/snare.o ../asm/active/hat.o ../asm/active/melody.o ../asm/active/fm_voice.o ../asm/active/delay.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(REALTIME_BIN): $(REALTIME_OBJ) $(GEN_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)

$(TIMELINE_BIN): $(TIMELINE_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

# Individual generator builds - conditional to avoid duplicate symbols
ifeq ($(USE_ASM),1)
$(TEST_BIN): src/gen_sine.c src/osc.o $(ASM_OBJ) src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(TONE_BIN): src/gen_tones.c src/osc.o $(ASM_OBJ) src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(NOISE_BIN): src/gen_noise_delay.c src/osc.o src/delay.o $(ASM_OBJ) src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(KICK_BIN): src/gen_kick.c src/kick.o $(ASM_OBJ) src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(SNARE_BIN): src/gen_snare.c src/snare.o $(ASM_OBJ) src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(HAT_BIN): src/gen_hat.c src/hat.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(MELODY_BIN): src/gen_melody.c src/melody.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(FM_BIN): src/gen_fm.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^
else
$(TEST_BIN): src/gen_sine.c src/osc.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(TONE_BIN): src/gen_tones.c src/osc.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(NOISE_BIN): src/gen_noise_delay.c src/osc.o src/delay.o src/noise.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(KICK_BIN): src/gen_kick.c src/kick.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(SNARE_BIN): src/gen_snare.c src/snare.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(HAT_BIN): src/gen_hat.c src/hat.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(MELODY_BIN): src/gen_melody.c src/melody.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(FM_BIN): src/gen_fm.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^
endif

$(DRUMS_BIN): src/segment.c $(SEG_OBJ) | bin
$(CC) $(CFLAGS) -DDRUMS_ONLY -o $@ src/segment.c $(SEG_OBJ)

$(DRUMS_MEL_BIN): src/segment.c $(SEG_OBJ) | bin
$(CC) $(CFLAGS) -DNO_FM -o $@ src/segment.c $(SEG_OBJ)

$(DRUMS_BASS_BIN): src/segment.c $(SEG_OBJ) | bin
$(CC) $(CFLAGS) -DNO_MID_FM -o $@ src/segment.c $(SEG_OBJ)

# FM-related generator builds - conditional to avoid duplicate symbols
ifeq ($(USE_ASM),1)
$(BELLS_BIN): src/gen_bells.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(CALM_BIN): src/gen_calm.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(QUANTUM_BIN): src/gen_quantum.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(PLUCK_BIN): src/gen_pluck.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASS_BIN): src/gen_bass.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASSQ_BIN): src/gen_bass_quantum.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASSP_BIN): src/gen_bass_plucky.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o $(ASM_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(MELODY_DEBUG_BIN): src/melody_debug_test.c src/wav_writer.o $(GEN_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^

$(FM_DEBUG_BIN): src/fm_debug_test.c src/wav_writer.o $(GEN_OBJ) | bin
$(CC) $(CFLAGS) -o $@ $^
else
$(BELLS_BIN): src/gen_bells.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(CALM_BIN): src/gen_calm.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(QUANTUM_BIN): src/gen_quantum.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(PLUCK_BIN): src/gen_pluck.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASS_BIN): src/gen_bass.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASSQ_BIN): src/gen_bass_quantum.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^

$(BASSP_BIN): src/gen_bass_plucky.c src/fm_voice.o $(NEON_OBJ) src/fm_presets.o src/wav_writer.o | bin
$(CC) $(CFLAGS) -o $@ $^
endif

bin:
@mkdir -p bin

# pattern rule for objects
src/%.o: src/%.c | src include
$(CC) $(CFLAGS) -c $< -o $@

src include:
@mkdir -p src include

$(ASM_DIR)/%.o: $(ASM_DIR)/%.s | $(ASM_DIR)
$(CC) $(CFLAGS) -c $< -o $@

$(ASM_DIR):
@mkdir -p $(ASM_DIR)

.PHONY: clean
clean:
rm -rf src/*.o bin src/euclid.o 2>/dev/null || true

.PHONY: sine
sine: $(TEST_BIN)
$(TEST_BIN)
@echo "Generated sine.wav"

.PHONY: tones
tones: $(TONE_BIN)
$(TONE_BIN)
@echo "Generated saw.wav square.wav triangle.wav"

.PHONY: delay
delay: $(NOISE_BIN)
$(NOISE_BIN)
@echo "Generated delay.wav"

.PHONY: kick
kick: $(KICK_BIN)
$(KICK_BIN)
@echo "Generated kick.wav"

.PHONY: snare
snare: $(SNARE_BIN)
$(SNARE_BIN)
@echo "Generated snare.wav"

.PHONY: hat
hat: $(HAT_BIN)
$(HAT_BIN)
@echo "Generated hat.wav"

.PHONY: melody
melody: $(MELODY_BIN)
$(MELODY_BIN)
@echo "Generated melody.wav"

.PHONY: fm
fm: clean $(FM_BIN)
$(FM_BIN)
@echo "Generated fm.wav"

.PHONY: fm_c
fm_c: clean
$(MAKE) $(FM_BIN)
$(FM_BIN)
mv fm.wav fm_c.wav
@echo "Generated fm_c.wav (C version)"

.PHONY: fm_asm
fm_asm: clean
$(MAKE) $(FM_BIN) USE_ASM=1 VOICE_ASM="FM_VOICE_ASM"
$(FM_BIN)
mv fm.wav fm_asm.wav
@echo "Generated fm_asm.wav (Assembly version)"

.PHONY: segment
segment: $(SEG_BIN)
ifndef NO_RUN
ifdef SEED
$(SEG_BIN) $(SEED)
else
$(SEG_BIN)
endif
@echo "Generated segment.wav"
endif

.PHONY: segment_test
segment_test: $(SEG_TEST_BIN)
@echo "Built segment_test. Usage: $(SEG_TEST_BIN) <category1> [category2] ..."

.PHONY: long_loop_test
long_loop_test: bin/long_loop_test
@echo "Built long_loop_test. Usage: bin/long_loop_test [seed] [output.wav]"

.PHONY: melody_debug
melody_debug: $(MELODY_DEBUG_BIN)
$(MELODY_DEBUG_BIN)

.PHONY: fm_debug
fm_debug: $(FM_DEBUG_BIN)
$(FM_DEBUG_BIN)

.PHONY: drums
drums: $(DRUMS_BIN)
$(DRUMS_BIN)
@echo "Generated segment_drums.wav"

.PHONY: drums_mel
drums_mel: $(DRUMS_MEL_BIN)
$(DRUMS_MEL_BIN)
@echo "Generated segment_drums_mel.wav"

.PHONY: drums_bass
drums_bass: $(DRUMS_BASS_BIN)
$(DRUMS_BASS_BIN)
@echo "Generated segment_drums_bass.wav"

# =============================================================================
# VOICE DEBUGGING TARGETS - Individual and combination testing
# =============================================================================

# Individual ASM voice tests (using current ASM configuration)
.PHONY: test_kick_asm test_snare_asm test_hat_asm test_melody_asm test_fm_asm
test_kick_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav kick_asm_test.wav
@echo "Generated kick_asm_test.wav (ASM kick only)"

test_snare_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM SNARE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav snare_asm_test.wav
@echo "Generated snare_asm_test.wav (ASM snare only)"

test_hat_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM HAT_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav hat_asm_test.wav
@echo "Generated hat_asm_test.wav (ASM hat only)"

test_melody_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM MELODY_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav melody_asm_test.wav
@echo "Generated melody_asm_test.wav (ASM melody only)"

test_fm_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM FM_VOICE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav fm_asm_test.wav
@echo "Generated fm_asm_test.wav (ASM FM only)"

# Drum combinations
.PHONY: test_drums_asm test_drums_c
test_drums_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav drums_asm_test.wav
@echo "Generated drums_asm_test.wav (ASM drums only)"

test_drums_c: clean
$(MAKE) segment USE_ASM=0 NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav drums_c_test.wav
@echo "Generated drums_c_test.wav (C version reference)"

# Voice combinations (incremental building)
.PHONY: test_drums_melody test_drums_fm test_melody_fm
test_drums_melody: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM MELODY_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav drums_melody_test.wav
@echo "Generated drums_melody_test.wav (ASM drums + melody)"

test_drums_fm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM FM_VOICE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav drums_fm_test.wav
@echo "Generated drums_fm_test.wav (ASM drums + FM)"

test_melody_fm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM MELODY_ASM FM_VOICE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav melody_fm_test.wav
@echo "Generated melody_fm_test.wav (ASM melody + FM)"

# Effects testing
.PHONY: test_with_delay test_with_limiter test_no_effects
test_with_delay: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM MELODY_ASM FM_VOICE_ASM DELAY_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav with_delay_test.wav
@echo "Generated with_delay_test.wav (voices + delay)"

test_with_limiter: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM MELODY_ASM FM_VOICE_ASM LIMITER_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav with_limiter_test.wav
@echo "Generated with_limiter_test.wav (voices + limiter)"

test_no_effects: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM MELODY_ASM FM_VOICE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav no_effects_test.wav
@echo "Generated no_effects_test.wav (voices only, no delay/limiter)"

# Complete configuration (what we just fixed)
.PHONY: test_full_asm
test_full_asm: clean
$(MAKE) segment USE_ASM=1 VOICE_ASM="GENERATOR_ASM KICK_ASM SNARE_ASM HAT_ASM MELODY_ASM LIMITER_ASM DELAY_ASM FM_VOICE_ASM" NO_RUN=1
$(SEG_BIN)
cp seed_0xcafebabe.wav full_asm_test.wav
@echo "Generated full_asm_test.wav (complete ASM pipeline)"

# Quick test suite - generates all individual voices for comparison
.PHONY: test_all_voices
test_all_voices: test_kick_asm test_snare_asm test_hat_asm test_melody_asm test_fm_asm test_drums_c
@echo "Generated all individual voice tests:"
@echo " kick_asm_test.wav snare_asm_test.wav hat_asm_test.wav"
@echo " melody_asm_test.wav fm_asm_test.wav drums_c_test.wav"

# Help target for debugging
.PHONY: help_debug
help_debug:
@echo "Voice Debugging Targets:"
@echo ""
@echo "Individual Voices (ASM):"
@echo " make test_kick_asm → kick_asm_test.wav"
@echo " make test_snare_asm → snare_asm_test.wav"
@echo " make test_hat_asm → hat_asm_test.wav"
@echo " make test_melody_asm → melody_asm_test.wav"
@echo " make test_fm_asm → fm_asm_test.wav"
@echo ""
@echo "Drum Combinations:"
@echo " make test_drums_asm → drums_asm_test.wav (ASM kick+snare+hat)"
@echo " make test_drums_c → drums_c_test.wav (C version reference)"
@echo ""
@echo "Voice Combinations:"
@echo " make test_drums_melody → drums_melody_test.wav"
@echo " make test_drums_fm → drums_fm_test.wav"
@echo " make test_melody_fm → melody_fm_test.wav"
@echo ""
@echo "Effects Testing:"
@echo " make test_no_effects → no_effects_test.wav (voices only)"
@echo " make test_with_delay → with_delay_test.wav"
@echo " make test_with_limiter → with_limiter_test.wav"
@echo ""
@echo "Complete Pipeline:"
@echo " make test_full_asm → full_asm_test.wav (everything)"
@echo ""
@echo "Quick Suites:"
@echo " make test_all_voices → generates all individual voice tests"

.PHONY: bells
bells: $(BELLS_BIN)
$(BELLS_BIN)
@echo "Generated bells-c.wav"

.PHONY: calm
calm: $(CALM_BIN)
$(CALM_BIN)
@echo "Generated calm-c.wav"

.PHONY: quantum
quantum: $(QUANTUM_BIN)
$(QUANTUM_BIN)
@echo "Generated quantum-c.wav"

.PHONY: pluck
pluck: $(PLUCK_BIN)
$(PLUCK_BIN)
@echo "Generated pluck-c.wav"

.PHONY: bass
bass: $(BASS_BIN)
$(BASS_BIN)
@echo "Generated bass_only.wav"

.PHONY: realtime
realtime: $(REALTIME_BIN)

.PHONY: clang_check
clang_check:
@clang -v >/dev/null 2>&1 && echo "clang OK" || echo "clang missing"

.PHONY: clean-asm
clean-asm:
rm -f $(ASM_OBJ)

.PHONY: bass_quantum
bass_quantum: $(BASSQ_BIN)
$(BASSQ_BIN)
@echo "Generated bass_quantum.wav"

.PHONY: bass_plucky
bass_plucky: $(BASSP_BIN)
$(BASSP_BIN)
@echo "Generated bass_plucky.wav"

# Convenience target: build everything for arm64 on x86 hosts
.PHONY: cross
cross:
$(MAKE) clean
$(MAKE) all CROSS=1 -j$(shell sysctl -n hw.logicalcpu)||ENDFILE||
||FILE:src/c/include/coreaudio.h||
#ifndef COREAUDIO_H
#define COREAUDIO_H

#include <stdint.h>

/*
* A callback function that the user of this module provides.
* It will be called when the audio system needs more samples.
*
* buffer: An interleaved stereo float32_t buffer to be filled.
* num_frames: The number of stereo frames requested.
* user_data: A pointer to whatever state the callback needs.
*/
typedef void (*audio_callback_t)(float* buffer, uint32_t num_frames, void* user_data);

/*
* Initializes the audio playback system.
*
* sr: The desired sample rate (e.g., 44100).
* buffer_size: The number of frames per buffer chunk.
* callback: The function to call to generate audio.
* user_data: A pointer that will be passed to the callback.
*
* returns: 0 on success, non-zero on failure.
*/
int audio_init(uint32_t sr, uint32_t buffer_size, audio_callback_t callback, void* user_data);

/* Starts the audio playback. The program should enter a run loop after this. */
void audio_start(void);

/* Stops playback and cleans up resources. */
void audio_stop(void);

#endif /* COREAUDIO_H */ ||ENDFILE||
at txn 0x9245f9187beec2ced06a7bade1e5594f481ce4b91c309f584929bbdbe33d548d Aug-20-2025 12:45:47 AM UTC (26 days ago)
------BEGIN MEMO------eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6ImE1NWVkMGIyLTg2ODAtNDRjOS04MTZlLWU3YTI5Njc0ZmU0ZiIsIm9yZGVySWRlbnRpZmllciI6IjlmZDZjNDYxLWY5MzQtNDRiMi04NjZjLTViNDgyMGExOTRiZiIsImlhdCI6MTc1NTY1MDY4NH0.Gf8m-fjg0RDCUeny4DU-NPNd123nKH0uu5DYv4vmNCg------END MEMO------
at txn 0xc6000b4d28700d3ce9ec3424d06114162b27647b5a9418d11dc751c79c95b4e1 Aug-20-2025 12:45:35 AM UTC (26 days ago)

||FILE:simple_wav_reader.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>

// WAV file header structure
typedef struct {
char riff[4]; // "RIFF"
uint32_t chunk_size; // File size - 8
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
uint32_t fmt_size; // Format chunk size
uint16_t audio_format; // Audio format (1 = PCM)
uint16_t num_channels; // Number of channels
uint32_t sample_rate; // Sample rate
uint32_t byte_rate; // Byte rate
uint16_t block_align; // Block align
uint16_t bits_per_sample; // Bits per sample
char data[4]; // "data"
uint32_t data_size; // Data size
} wav_header_t;

// Audio analysis data
typedef struct {
int16_t *samples; // Raw audio samples (stereo interleaved)
uint32_t sample_count; // Total samples (left + right)
uint32_t frame_count; // Number of stereo frames
uint32_t sample_rate; // Sample rate (Hz)
float duration; // Duration in seconds
} audio_data_t;

static audio_data_t audio_data = {0};

// Simple audio level calculation (RMS)
float calculate_audio_level_at_frame(int frame_number, float fps) {
if (!audio_data.samples || audio_data.frame_count == 0) {
return 0.2f; // Default level
}

float time_seconds = frame_number / fps;
uint32_t sample_index = (uint32_t)(time_seconds * audio_data.sample_rate);

if (sample_index >= audio_data.frame_count) {
sample_index = audio_data.frame_count - 1;
}

// Calculate RMS over a small window
uint32_t window_size = audio_data.sample_rate / 30; // ~33ms window
uint32_t start_sample = (sample_index > window_size/2) ? sample_index - window_size/2 : 0;
uint32_t end_sample = start_sample + window_size;
if (end_sample > audio_data.frame_count) {
end_sample = audio_data.frame_count;
start_sample = (end_sample > window_size) ? end_sample - window_size : 0;
}

float sum_squares = 0.0f;
uint32_t count = 0;

for (uint32_t i = start_sample; i < end_sample; i++) {
float left = audio_data.samples[i * 2] / 32768.0f;
float right = audio_data.samples[i * 2 + 1] / 32768.0f;
float mono = (left + right) * 0.5f;
sum_squares += mono * mono;
count++;
}

if (count == 0) return 0.2f;

float rms = sqrtf(sum_squares / count);
return fminf(1.0f, fmaxf(0.0f, rms * 3.0f)); // Scale and clamp
}

// Load WAV file
bool load_wav_file(const char* filename) {
FILE* file = fopen(filename, "rb");
if (!file) {
printf("Failed to open WAV file: %s\n", filename);
return false;
}

wav_header_t header;
if (fread(&header, sizeof(header), 1, file) != 1) {
printf("Failed to read WAV header\n");
fclose(file);
return false;
}

// Basic validation
if (strncmp(header.riff, "RIFF", 4) != 0 ||
strncmp(header.wave, "WAVE", 4) != 0 ||
strncmp(header.data, "data", 4) != 0) {
printf("Invalid WAV file format\n");
fclose(file);
return false;
}

if (header.audio_format != 1 || header.bits_per_sample != 16) {
printf("Unsupported WAV format (need 16-bit PCM)\n");
fclose(file);
return false;
}

// Allocate and read sample data
uint32_t sample_count = header.data_size / 2; // 16-bit samples
audio_data.samples = malloc(header.data_size);
if (!audio_data.samples) {
printf("Failed to allocate memory for samples\n");
fclose(file);
return false;
}

if (fread(audio_data.samples, header.data_size, 1, file) != 1) {
printf("Failed to read sample data\n");
free(audio_data.samples);
audio_data.samples = NULL;
fclose(file);
return false;
}

audio_data.sample_count = sample_count;
audio_data.frame_count = sample_count / header.num_channels;
audio_data.sample_rate = header.sample_rate;
audio_data.duration = (float)audio_data.frame_count / header.sample_rate;

fclose(file);

printf("Loaded WAV: %d samples, %.2f seconds, %d Hz\n",
audio_data.frame_count, audio_data.duration, audio_data.sample_rate);

return true;
}

// Additional functions needed by audio_visual_bridge.c
float get_audio_duration() {
return audio_data.duration;
}

bool is_audio_finished() {
return false; // For frame generation, never consider audio "finished"
}

void print_audio_info() {
printf("Audio info: %.2f seconds, %d Hz, %d frames\n",
audio_data.duration, audio_data.sample_rate, audio_data.frame_count);
}

float get_audio_rms_for_frame(int frame_number, float fps) {
return calculate_audio_level_at_frame(frame_number, fps);
}

float get_max_rms() {
return 1.0f; // Assume normalized
}

float get_audio_bpm() {
return 120.0f; // Default BPM
}

// Cleanup
void cleanup_audio_data() {
if (audio_data.samples) {
free(audio_data.samples);
audio_data.samples = NULL;
}
audio_data.sample_count = 0;
audio_data.frame_count = 0;
audio_data.sample_rate = 0;
audio_data.duration = 0.0f;
}
||ENDFILE||
||FILE:src/audio_visual_bridge.c||
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <stdbool.h>
#include <time.h>

// External audio analysis functions (from wav_reader.c)
extern float get_audio_rms_for_frame(int frame);
extern float get_max_rms(void);
extern float get_audio_bpm(void);

// External ASM visual functions we can trigger
extern void spawn_explosion_asm(float cx, float cy, float base_hue);
extern void spawn_bass_hit_asm(float cx, float cy, int shape_type, float base_hue);

// Audio-Visual mapping state
typedef struct {
float last_rms;
float rms_smoothed;
float beat_phase;
float bass_energy;
float treble_energy;
int last_beat_frame;
int explosion_cooldown;
int bass_hit_cooldown;
} audio_visual_state_t;

static audio_visual_state_t av_state = {0};

// Initialize audio-visual mapping
void init_audio_visual_mapping(void) {
av_state.last_rms = 0.0f;
av_state.rms_smoothed = 0.0f;
av_state.beat_phase = 0.0f;
av_state.bass_energy = 0.0f;
av_state.treble_energy = 0.0f;
av_state.last_beat_frame = 0;
av_state.explosion_cooldown = 0;
av_state.bass_hit_cooldown = 0;
}

// Smooth RMS values to avoid visual jitter
float get_smoothed_audio_level(int frame) {
float raw_rms = get_audio_rms_for_frame(frame);
float max_rms = get_max_rms();
float normalized = (max_rms > 0.0f) ? (raw_rms / max_rms) : 0.0f;

// Exponential smoothing
float alpha = 0.1f; // Smoothing factor
av_state.rms_smoothed = alpha * normalized + (1.0f - alpha) * av_state.rms_smoothed;

return fmaxf(0.0f, fminf(1.0f, av_state.rms_smoothed));
}

// 🔥 HAIR-TRIGGER BEAT DETECTION - Maximum reactivity! 🔥
bool detect_beat_onset(int frame) {
float current_rms = get_audio_rms_for_frame(frame);
float max_rms = get_max_rms();
float normalized = (max_rms > 0.0f) ? (current_rms / max_rms) : 0.0f;

// CHAOS MODE: Much more sensitive beat detection!
float threshold = 0.05f; // Way lower threshold = more beats detected!
float ratio = (av_state.last_rms > 0.0f) ? (normalized / av_state.last_rms) : 1.0f;

bool is_onset = (ratio > (1.0f + threshold)) &&
(normalized > 0.1f) && // Much lower level needed
(frame - av_state.last_beat_frame > 3); // Shorter gap = more frequent beats

if (is_onset) {
av_state.last_beat_frame = frame;
}

av_state.last_rms = normalized;
return is_onset;
}

// Calculate beat phase for cycling effects
float get_beat_phase(int frame, float bpm) {
float time_sec = frame / 60.0f; // Assuming 60 FPS
float beat_duration = 60.0f / bpm;
return fmod(time_sec, beat_duration) / beat_duration;
}

// Get bass frequency energy (low frequencies)
float get_bass_energy(int frame) {
// Simplified: use RMS as proxy for bass energy
// In a real system, this would use FFT analysis
float rms = get_audio_rms_for_frame(frame);
float max_rms = get_max_rms();
float normalized = (max_rms > 0.0f) ? (rms / max_rms) : 0.0f;

// Simulate bass emphasis
av_state.bass_energy = 0.9f * av_state.bass_energy + 0.1f * normalized;
return av_state.bass_energy;
}

// Get treble frequency energy (high frequencies)
float get_treble_energy(int frame) {
// Simplified: use inverted bass energy as proxy
float bass = get_bass_energy(frame);
float rms = get_audio_rms_for_frame(frame);
float max_rms = get_max_rms();
float normalized = (max_rms > 0.0f) ? (rms / max_rms) : 0.0f;

// Simulate treble as complement to bass
av_state.treble_energy = normalized - bass * 0.5f;
return fmaxf(0.0f, av_state.treble_energy);
}

// 💥 NUCLEAR PARTICLE MAYHEM 💥
void update_audio_reactive_particles(int frame, float base_hue) {
float audio_level = get_smoothed_audio_level(frame);

// 🔥 BEAT EXPLOSION FRENZY - Multiple explosions per beat!
if (detect_beat_onset(frame)) {
int explosion_count = (int)(audio_level * 15) + 5; // 5-20 explosions per beat!
for (int i = 0; i < explosion_count; i++) {
float cx = rand() % 800; // Entire screen width
float cy = rand() % 600; // Entire screen height
float chaos_hue = fmod(base_hue + (i * 0.08f) + (rand() % 100 / 100.0f), 1.0f);
spawn_explosion_asm(cx, cy, chaos_hue);
}
}

// 🌊 CONSTANT AUDIO-REACTIVE EXPLOSIONS - No cooldowns!
if (frame % (int)fmax(1, 6 - audio_level * 5) == 0) {
for (int i = 0; i < 6; i++) {
float x = (i * 133) % 800; // Distributed across screen
float y = 100 + (rand() % 400);
float hue = fmod(frame * 0.03f + i * 0.16f, 1.0f);
spawn_explosion_asm(x, y, hue);
}
}

// 🌈 RAINBOW SPIRAL MADNESS
if (frame % 3 == 0) {
for (int i = 0; i < 8; i++) {
float angle = (frame * 0.1f) + (i * 0.785f); // 8 spokes
float radius = 150 + (audio_level * 100);
float cx = 400 + cos(angle) * radius;
float cy = 300 + sin(angle) * radius;
if (cx >= 0 && cx < 800 && cy >= 0 && cy < 600) {
spawn_explosion_asm(cx, cy, i / 8.0f); // Perfect rainbow
}
}
}
}

// 🔯 GEOMETRIC SHAPE STORM 🔯
void update_audio_reactive_bass_hits(int frame, float base_hue) {
float bass_energy = get_bass_energy(frame);
float audio_level = get_smoothed_audio_level(frame);

// 🌪️ SHAPE SPAM FRENZY - Any audio activity triggers shapes!
if (audio_level > 0.02f) { // Super low threshold = constant shapes
int shape_count = (int)(bass_energy * 12) + 2; // 2-14 shapes
for (int i = 0; i < shape_count; i++) {
float cx = (i * 80 + frame * 2) % 800; // Moving across screen
float cy = 100 + (rand() % 400);
int shape_type = (frame + i) % 3; // Cycling through all shapes
float shape_hue = fmod(base_hue + (i * 0.12f), 1.0f);
spawn_bass_hit_asm(cx, cy, shape_type, shape_hue);
}
}

// 💫 GEOMETRIC GRID EXPLOSION
if (bass_energy > 0.3f) {
for (int x = 0; x < 6; x++) {
for (int y = 0; y < 4; y++) {
float grid_x = 50 + x * 120;
float grid_y = 75 + y * 125;
int shape = (x + y + frame/10) % 3;
float hue = fmod((x + y) * 0.1f + base_hue, 1.0f);
spawn_bass_hit_asm(grid_x, grid_y, shape, hue);
}
}
}

// 🎯 PULSING CONCENTRIC SHAPES
if (frame % 5 == 0) {
for (int ring = 0; ring < 4; ring++) {
float radius = 80 + ring * 60 + bass_energy * 50;
for (int i = 0; i < 6; i++) {
float angle = i * 1.047f + frame * 0.05f; // 6 shapes per ring
float cx = 400 + cos(angle) * radius;
float cy = 300 + sin(angle) * radius;
if (cx >= 0 && cx < 800 && cy >= 0 && cy < 600) {
spawn_bass_hit_asm(cx, cy, ring % 3, ring * 0.25f);
}
}
}
}
}

// ⚡ MAXIMUM DIGITAL CHAOS ⚡
float get_audio_driven_glitch_intensity(int frame) {
float treble = get_treble_energy(frame);
float bass = get_bass_energy(frame);
float audio_level = get_smoothed_audio_level(frame);

// 🔥 EXTREME GLITCH MODE - Way more intense!
float base_chaos = 0.5f; // Much higher base intensity
float audio_chaos = powf(audio_level + treble + bass, 0.4f) * 2.0f; // Amplified chaos

// 💥 Beat-synchronized glitch explosions
float bpm = get_audio_bpm();
float beat_phase = get_beat_phase(frame, bpm);
float beat_explosion = (beat_phase < 0.15f) ? 1.0f : 0.0f; // Massive beat spikes

// 🌊 Oscillating chaos waves
float chaos_wave = sin(frame * 0.1f) * 0.3f + 0.3f;

float total_chaos = base_chaos + audio_chaos + beat_explosion + chaos_wave;
return fmaxf(0.0f, fminf(3.0f, total_chaos)); // Allow up to 3x normal intensity!
}

// 🌈 PSYCHEDELIC COLOR MADNESS 🌈
float get_audio_driven_hue_shift(int frame) {
float bpm = get_audio_bpm();
float time_sec = frame / 60.0f;
float audio_level = get_smoothed_audio_level(frame);
float bass = get_bass_energy(frame);

// 🔥 RAPID COLOR CYCLING - Much faster than before!
float speed_multiplier = 5.0f + audio_level * 10.0f; // 5x-15x faster!
float base_rotation = fmod(time_sec * speed_multiplier * 0.02f, 1.0f);

// 💫 AUDIO-REACTIVE COLOR JUMPS
float bass_jump = bass * 0.3f * sin(time_sec * 8.0f);
float treble_flicker = get_treble_energy(frame) * 0.2f * sin(time_sec * 20.0f);

// 🌊 CHAOS WAVE MODULATION
float chaos_wave1 = sin(time_sec * 3.0f) * 0.15f;
float chaos_wave2 = cos(time_sec * 7.0f) * 0.1f;

float total_hue = base_rotation + bass_jump + treble_flicker + chaos_wave1 + chaos_wave2;
return fmod(total_hue, 1.0f);
}

// 🌋 NUCLEAR CHAOS MODE - EVERYTHING AT MAXIMUM! 🌋
void update_audio_visual_effects(int frame, float base_hue) {
// Seed random for consistent chaos across frames
srand(frame / 10);

// Update chaos particle effects
update_audio_reactive_particles(frame, base_hue);

// Update chaos bass hits
update_audio_reactive_bass_hits(frame, base_hue);

// 🎆 BONUS CHAOS EFFECTS!
float audio_level = get_smoothed_audio_level(frame);

// 💥 SCREEN EDGE EXPLOSIONS
if (frame % 8 == 0) {
// Top edge
for (int i = 0; i < 5; i++) {
spawn_explosion_asm(i * 160, 20, fmod(i * 0.2f + frame * 0.01f, 1.0f));
}
// Bottom edge
for (int i = 0; i < 5; i++) {
spawn_explosion_asm(i * 160, 580, fmod(i * 0.2f + frame * 0.01f + 0.5f, 1.0f));
}
}

// 🌪️ AUDIO-REACTIVE VORTEX
if (audio_level > 0.3f) {
for (int i = 0; i < 12; i++) {
float angle = i * 0.524f + frame * 0.05f; // 12 spokes
float radius = 200 + audio_level * 150;
float x = 400 + cos(angle) * radius;
float y = 300 + sin(angle) * radius;
if (x >= 0 && x < 800 && y >= 0 && y < 600) {
spawn_bass_hit_asm(x, y, i % 3, i / 12.0f);
}
}
}
}

// Get current audio analysis values for debugging/display
void get_audio_analysis_values(float *rms, float *bass, float *treble, float *glitch) {
static int last_frame = -1;
static int current_frame = 0;

// Simple frame counter
if (last_frame != current_frame) {
current_frame++;
last_frame = current_frame;
}

*rms = get_smoothed_audio_level(current_frame);
*bass = get_bass_energy(current_frame);
*treble = get_treble_energy(current_frame);
*glitch = get_audio_driven_glitch_intensity(current_frame);
}
||ENDFILE||
at txn 0x3eb633a8efc55af642e66270bc15858e8e233ddc7df4c487c054a5260de228e1 Aug-20-2025 12:45:35 AM UTC (26 days ago)
Show messages: