/* * melody.c - generate a melody as a WAV file * Claude Opus 4.5, 2026-10-14 * * Plays a simple tune to demonstrate audio synthesis on the 604e. * Build: xlc -o melody melody.c -lm * Usage: ./melody > melody.wav */ #include #include #include #include #define SAMPLE_RATE 22050 #define BITS_PER_SAMPLE 16 #define CHANNELS 1 /* Note frequencies (Hz) */ #define C4 262 #define D4 294 #define E4 330 #define F4 349 #define G4 392 #define A4 440 #define B4 494 #define C5 523 #define D5 587 #define E5 659 #define REST 0 /* Note durations (ms) */ #define WHOLE 800 #define HALF 400 #define QUARTER 200 #define EIGHTH 100 typedef struct { int freq; int duration; } Note; /* "Ode to Joy" theme - simplified */ Note ode_to_joy[] = { {E4, QUARTER}, {E4, QUARTER}, {F4, QUARTER}, {G4, QUARTER}, {G4, QUARTER}, {F4, QUARTER}, {E4, QUARTER}, {D4, QUARTER}, {C4, QUARTER}, {C4, QUARTER}, {D4, QUARTER}, {E4, QUARTER}, {E4, QUARTER+EIGHTH}, {D4, EIGHTH}, {D4, HALF}, {E4, QUARTER}, {E4, QUARTER}, {F4, QUARTER}, {G4, QUARTER}, {G4, QUARTER}, {F4, QUARTER}, {E4, QUARTER}, {D4, QUARTER}, {C4, QUARTER}, {C4, QUARTER}, {D4, QUARTER}, {E4, QUARTER}, {D4, QUARTER+EIGHTH}, {C4, EIGHTH}, {C4, HALF}, {REST, QUARTER}, {0, 0} /* end marker */ }; void write_le32(unsigned long val, FILE *f) { fputc(val & 0xFF, f); fputc((val >> 8) & 0xFF, f); fputc((val >> 16) & 0xFF, f); fputc((val >> 24) & 0xFF, f); } void write_le16(unsigned int val, FILE *f) { fputc(val & 0xFF, f); fputc((val >> 8) & 0xFF, f); } /* Generate samples for a note with attack/decay envelope */ void generate_note(int freq, int duration_ms, short *buf, int *offset) { int nsamples = (SAMPLE_RATE * duration_ms) / 1000; int attack = nsamples / 10; /* 10% attack */ int decay = nsamples / 5; /* 20% decay */ double phase = 0.0; double delta = (freq > 0) ? (2.0 * M_PI * freq / SAMPLE_RATE) : 0.0; double amplitude; int i; for (i = 0; i < nsamples; i++) { /* Simple ADSR-ish envelope */ if (i < attack) { amplitude = (double)i / attack; } else if (i > nsamples - decay) { amplitude = (double)(nsamples - i) / decay; } else { amplitude = 1.0; } if (freq > 0) { buf[*offset] = (short)(sin(phase) * 24000 * amplitude); phase += delta; } else { buf[*offset] = 0; /* rest */ } (*offset)++; } } int main(void) { int total_duration = 0; int total_samples, data_size, offset, i; short *samples; Note *note; /* Calculate total duration */ for (note = ode_to_joy; note->duration > 0; note++) { total_duration += note->duration; } total_samples = (SAMPLE_RATE * total_duration) / 1000; data_size = total_samples * sizeof(short); samples = malloc(data_size); if (!samples) { fprintf(stderr, "malloc failed\n"); return 1; } memset(samples, 0, data_size); /* Generate all notes */ offset = 0; for (note = ode_to_joy; note->duration > 0; note++) { generate_note(note->freq, note->duration, samples, &offset); } /* Write WAV header */ fprintf(stdout, "RIFF"); write_le32(36 + data_size, stdout); fprintf(stdout, "WAVE"); fprintf(stdout, "fmt "); write_le32(16, stdout); write_le16(1, stdout); write_le16(CHANNELS, stdout); write_le32(SAMPLE_RATE, stdout); write_le32(SAMPLE_RATE * CHANNELS * BITS_PER_SAMPLE / 8, stdout); write_le16(CHANNELS * BITS_PER_SAMPLE / 8, stdout); write_le16(BITS_PER_SAMPLE, stdout); fprintf(stdout, "data"); write_le32(data_size, stdout); /* Write samples (little-endian) */ for (i = 0; i < total_samples; i++) { fputc(samples[i] & 0xFF, stdout); fputc((samples[i] >> 8) & 0xFF, stdout); } free(samples); return 0; }