#include "samples.c" #define SAMPLE_FREQUENCY 44100 #define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025) #define ADSR_STEP (SAMPLE_FREQUENCY / 0xf) typedef struct AudioChannel { u8 *samples; u16 n_samples; u16 position; u16 sampling_freq; u8 pitch; bool loop; // TODO: u16 adsr; // attack, decay, sustain, release // TODO: u8 pitch; // Bit 8 is the "loop" bit // TODO: u8 volume; // VOL_LEFT | (VOL_RIGHT << 4) // u8 *addr; // u32 count, advance, period, age, a, d, s, r; // s8 volume[2]; // u8 pitch, repeat; } AudioChannel; typedef struct APU { AudioChannel chan_0; // u32 *samples_1; // u32 *samples_2; // u32 *samples_3; } APU; static APU apu; static u16 pitch_table[] = { 12173, 11490, 10845, 10237, 9662, 9120, 8608, 8125, 7669, 7238, 6832, 6448, 6086, 5745, 5422, 5118, 4831, 4560, 4304, 4062, 3834, 3619, 3416, 3224, 3043, 2872, 2711, 2559, 2415, 2280, 2152, 2031, 1917, 1809, 1708, 1612, 1521, 1436, 1355, 1279, 1207, 1140, 1076, 1015, 958, 904, 854, 806, 760, 718, 677, 639, 603, 570, 538, 507, 479, 452, 427, 403, 380, 359, 338, 319, 301, 285, 269, 253, 239, 226, 213, 201, 190, 179, 169, 159, 150, 142, 134, 126, 119, 113, 106, 100, 95, 89, 84, 79, 75, 71, 67, 63, 59, 56, 53, 50, 47, 44, 42, 39, 37, 35, 33, 31, 29, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 14, 13, 12, 0, }; void reset_sound(AudioChannel *chan) { TIMER_CTRL_0 = 0; TIMER_CTRL_1 = 0; DMA_CTRL(1) = 0; if (chan->pitch >= 108 || chan->n_samples == 0) { return; } // Set max volume, left-right sound, fifo reset and use timer 0 for // DirectSound A. SOUND_DSOUND_MASTER = SOUND_DSOUND_RATIO_A | SOUND_DSOUND_LEFT_A | SOUND_DSOUND_RIGHT_A | SOUND_DSOUND_RESET_A; // Prepare DMA copy. dma_transfer_copy(SOUND_FIFO_A, chan->samples, 1, 1, DMA_DST_FIXED | DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE); // Timer 1 used to stop playing samples. u32 sample_duration = chan->n_samples; TIMER_DATA_1 = 0xFFFF - sample_duration; TIMER_CTRL_1 = TIMER_CTRL_IRQ | TIMER_CTRL_ENABLE | TIMER_CTRL_CASCADE; // Timer 0 used to stop sample playing. // TIMER_DATA_0 = 0xFFFF - sound_freq[chan->pitch]; // TIMER_DATA_0 = 0xFFFF - CPU_FREQUENCY / chan->sampling_freq / chan->pitch; TIMER_DATA_0 = 0xFFFF - pitch_table[chan->pitch]; TIMER_CTRL_0 = TIMER_CTRL_ENABLE; } u8 square_wave[] = { 0x00 + 0x80, 0xFF + 0x80 }; #include "text.h" void init_sound(AudioChannel *chan) { // chan->samples = &square_wave; // chan->n_samples = 2; // chan->samples = &samples; // chan->n_samples = LEN(samples); // chan->pitch++; // chan->pitch = chan->pitch == LEN(pitch_table) - 1 ? 0 : chan->pitch + 1; // chan->loop = true; // chan->sampling_freq = pitch_table[chan->pitch]; // txt_printf("RATE: %lu", pitch_table[chan->pitch]) } void irs_stop_sample(void) { if (apu.chan_0.loop) { reset_sound(&apu.chan_0); } else { TIMER_CTRL_0 = 0; DMA_CTRL(1) = 0; } } // void // apu_start(Apu *c, u16 adsr, u8 pitch) { // // if(pitch < 108 && c->len) // // c->advance = advances[pitch % 12] >> (8 - pitch / 12); // // else { // // c->advance = 0; // // return; // // } // // c->a = ADSR_STEP * (adsr >> 12); // // c->d = ADSR_STEP * (adsr >> 8 & 0xf) + c->a; // // c->s = ADSR_STEP * (adsr >> 4 & 0xf) + c->d; // // c->r = ADSR_STEP * (adsr >> 0 & 0xf) + c->s; // // c->age = 0; // // c->i = 0; // // if(c->len <= 0x100) /* single cycle mode */ // // c->period = NOTE_PERIOD * 337 / 2 / c->len; // // else /* sample repeat mode */ // // c->period = NOTE_PERIOD; // }