aboutsummaryrefslogtreecommitdiffstats
path: root/src/uxn/devices/apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uxn/devices/apu.c')
-rw-r--r--src/uxn/devices/apu.c142
1 files changed, 25 insertions, 117 deletions
diff --git a/src/uxn/devices/apu.c b/src/uxn/devices/apu.c
index c3168c2..2b1c8ff 100644
--- a/src/uxn/devices/apu.c
+++ b/src/uxn/devices/apu.c
@@ -1,36 +1,7 @@
1#include "samples.c"
2
3#define SAMPLE_FREQUENCY 44100 1#define SAMPLE_FREQUENCY 44100
4#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025) 2#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025)
5#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf) 3#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf)
6 4
7// FIXME: We have two structs for now, needs fixing.
8typedef struct AudioChannel {
9 u8 *samples;
10 u16 n_samples;
11 u16 position;
12 u16 sampling_freq;
13 u8 pitch;
14 bool loop;
15 // TODO: u16 adsr; // attack, decay, sustain, release
16 // TODO: u8 pitch; // Bit 8 is the "loop" bit
17 // TODO: u8 volume; // VOL_LEFT | (VOL_RIGHT << 4)
18 // u8 *addr;
19 // u32 count, advance, period, age, a, d, s, r;
20 // s8 volume[2];
21 // u8 pitch, repeat;
22} AudioChannel;
23
24typedef struct APU {
25 AudioChannel chan_0;
26 // u32 *samples_1;
27 // u32 *samples_2;
28 // u32 *samples_3;
29} APU;
30
31static APU apu;
32
33
34static u16 pitch_table[] = { 5static u16 pitch_table[] = {
35 12173, 11490, 10845, 10237, 9662, 9120, 8608, 8125, 6 12173, 11490, 10845, 10237, 9662, 9120, 8608, 8125,
36 7669, 7238, 6832, 6448, 6086, 5745, 5422, 5118, 7 7669, 7238, 6832, 6448, 6086, 5745, 5422, 5118,
@@ -50,48 +21,12 @@ static u16 pitch_table[] = {
50 2, 21 2,
51}; 22};
52 23
53void
54reset_sound(AudioChannel *chan) {
55 TIMER_CTRL_0 = 0;
56 TIMER_CTRL_1 = 0;
57 DMA_CTRL(1) = 0;
58 if (chan->pitch >= 108 || chan->n_samples == 0) {
59 return;
60 }
61
62 // Set max volume, left-right sound, fifo reset and use timer 0 for
63 // DirectSound A.
64 SOUND_DSOUND_MASTER = SOUND_DSOUND_RATIO_A
65 | SOUND_DSOUND_LEFT_A
66 | SOUND_DSOUND_RIGHT_A
67 | SOUND_DSOUND_RESET_A;
68
69 // Prepare DMA copy.
70 dma_transfer_copy(SOUND_FIFO_A, chan->samples, 1, 1,
71 DMA_DST_FIXED | DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE);
72
73 // Timer 1 used to stop playing samples.
74 u32 sample_duration = chan->n_samples;
75 TIMER_DATA_1 = 0xFFFF - sample_duration;
76 TIMER_CTRL_1 = TIMER_CTRL_IRQ
77 | TIMER_CTRL_ENABLE
78 | TIMER_CTRL_CASCADE;
79
80 // Timer 0 used to stop sample playing.
81 // TIMER_DATA_0 = 0xFFFF - sound_freq[chan->pitch];
82 // TIMER_DATA_0 = 0xFFFF - CPU_FREQUENCY / chan->sampling_freq / chan->pitch;
83 TIMER_DATA_0 = 0xFFFF - pitch_table[chan->pitch];
84 TIMER_CTRL_0 = TIMER_CTRL_ENABLE;
85}
86
87s8 square_wave[] = { 24s8 square_wave[] = {
88 (s8)0x00 + (s8)0x80, (s8)0xFF + (s8)0x80 25 (s8)0x00 + (s8)0x80, (s8)0xFF + (s8)0x80
89}; 26};
90 27
91#include "text.h" 28#include "text.h"
92 29
93
94
95// 30//
96// REG_TM0D frequency buffer size 31// REG_TM0D frequency buffer size
97// | | | 32// | | |
@@ -119,7 +54,7 @@ typedef struct Audio {
119 u8 active_buffer; 54 u8 active_buffer;
120} Audio; 55} Audio;
121 56
122typedef struct Channel { 57typedef struct AudioChannel {
123 // Pointer to the raw data in the ROM. 58 // Pointer to the raw data in the ROM.
124 s8 *data; 59 s8 *data;
125 // Current position in the data (20.12 fixed-point). 60 // Current position in the data (20.12 fixed-point).
@@ -132,28 +67,31 @@ typedef struct Channel {
132 u32 length; 67 u32 length;
133 // Length of looped portion (20.12 fixed-point, 0 to disable looping). 68 // Length of looped portion (20.12 fixed-point, 0 to disable looping).
134 u32 loop_length; 69 u32 loop_length;
135} Channel; 70 // TODO: this should be different?
71 u8 pitch;
72} AudioChannel;
136 73
137static Audio audio; 74static Audio audio;
138 75
139#define POLYPHONY 4 76#define POLYPHONY 4
140static Channel channels[POLYPHONY]; 77static AudioChannel channels[POLYPHONY];
141 78
142void 79void
143init_sound(void) { 80init_sound(void) {
144 // Initialize audio buffers/channels. 81 // Initialize audio buffers/channels.
145 audio = (Audio){0}; 82 audio = (Audio){0};
146 for (size_t i = 0; i < POLYPHONY; ++i) { 83 for (size_t i = 0; i < POLYPHONY; ++i) {
147 channels[i] = (Channel){0}; 84 channels[i] = (AudioChannel){0};
148 } 85 }
149 86
150 // DEBUG: testing channel 0 with square wave 87 // DEBUG: testing channel 0 with square wave
151 channels[0].data = samples; 88 // channels[0].data = samples;
152 channels[0].inc = (8363 << 12) / AUDIO_FREQ; 89 // channels[0].length = (LEN(samples) - 1) << 12;
153 channels[0].length = (LEN(samples) - 1) << 12; 90 // channels[0].pos = 0;
154 channels[0].pos = 0; 91 // channels[0].inc = (44100 << 12) / AUDIO_FREQ;
155 channels[0].vol = 64; 92 // channels[0].vol = 32;
156 channels[0].loop_length = channels[0].length; 93 // channels[0].loop_length = channels[0].length;
94 // channels[0].loop_length = 0;
157 95
158 // Enable the sound chip. 96 // Enable the sound chip.
159 SOUND_STATUS = SOUND_ENABLE; 97 SOUND_STATUS = SOUND_ENABLE;
@@ -197,29 +135,29 @@ void sound_mix() {
197 135
198 // Mix channels into the temporary buffer. 136 // Mix channels into the temporary buffer.
199 for (size_t j = 0; j < POLYPHONY; ++j) { 137 for (size_t j = 0; j < POLYPHONY; ++j) {
200 Channel *chan = &channels[j]; 138 AudioChannel *ch = &channels[j];
201 // Check if channel is active. 139 // Check if channel is active.
202 if (chan->data == NULL) { 140 if (ch->data == NULL || ch->pitch >= 108) {
203 continue; 141 continue;
204 } 142 }
205 if (chan->pos + chan->inc * AUDIO_BUF_LEN >= chan->length) { 143 if (ch->pos + ch->inc * AUDIO_BUF_LEN >= ch->length) {
206 // Sample is going to finish, need to consider this for looping or 144 // Sample is going to finish, need to consider this for looping or
207 // stopping. 145 // stopping.
208 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) { 146 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) {
209 // Remember we are using fixed point values. 147 // Remember we are using fixed point values.
210 mix_buffer[i] += chan->data[chan->pos >> 12] * chan->vol; 148 mix_buffer[i] += (0x80 + (u8)ch->data[ch->pos >> 12]) * ch->vol;
211 chan->pos += chan->inc; 149 ch->pos += ch->inc;
212 150
213 if (chan->pos >= chan->length) { 151 if (ch->pos >= ch->length) {
214 // If looping is not active disable the channel. 152 // If looping is not active disable the channel.
215 if (chan->loop_length == 0) { 153 if (ch->loop_length == 0) {
216 chan->data = NULL; 154 ch->data = NULL;
217 break; 155 break;
218 } 156 }
219 157
220 // Loop the sample. 158 // Loop the sample.
221 while (chan->pos >= chan->length) { 159 while (ch->pos >= ch->length) {
222 chan->pos -= chan->loop_length; 160 ch->pos -= ch->loop_length;
223 } 161 }
224 } 162 }
225 } 163 }
@@ -227,8 +165,8 @@ void sound_mix() {
227 // Sample still have room to go, no need to check for looping or 165 // Sample still have room to go, no need to check for looping or
228 // end of sample. 166 // end of sample.
229 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) { 167 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) {
230 mix_buffer[i] += chan->data[chan->pos>>12] * chan->vol; 168 mix_buffer[i] += (0x80 + (u8)ch->data[ch->pos>>12]) * ch->vol;
231 chan->pos += chan->inc; 169 ch->pos += ch->inc;
232 } 170 }
233 } 171 }
234 } 172 }
@@ -240,33 +178,3 @@ void sound_mix() {
240 audio.current_buffer[i] = mix_buffer[i] >> 8; 178 audio.current_buffer[i] = mix_buffer[i] >> 8;
241 } 179 }
242} 180}
243
244void
245irs_stop_sample(void) {
246 if (apu.chan_0.loop) {
247 reset_sound(&apu.chan_0);
248 } else {
249 TIMER_CTRL_0 = 0;
250 DMA_CTRL(1) = 0;
251 }
252}
253
254// void
255// apu_start(Apu *c, u16 adsr, u8 pitch) {
256// // if(pitch < 108 && c->len)
257// // c->advance = advances[pitch % 12] >> (8 - pitch / 12);
258// // else {
259// // c->advance = 0;
260// // return;
261// // }
262// // c->a = ADSR_STEP * (adsr >> 12);
263// // c->d = ADSR_STEP * (adsr >> 8 & 0xf) + c->a;
264// // c->s = ADSR_STEP * (adsr >> 4 & 0xf) + c->d;
265// // c->r = ADSR_STEP * (adsr >> 0 & 0xf) + c->s;
266// // c->age = 0;
267// // c->i = 0;
268// // if(c->len <= 0x100) /* single cycle mode */
269// // c->period = NOTE_PERIOD * 337 / 2 / c->len;
270// // else /* sample repeat mode */
271// // c->period = NOTE_PERIOD;
272// }