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.c289
1 files changed, 156 insertions, 133 deletions
diff --git a/src/uxn/devices/apu.c b/src/uxn/devices/apu.c
index b2ccc18..ba9fe88 100644
--- a/src/uxn/devices/apu.c
+++ b/src/uxn/devices/apu.c
@@ -4,6 +4,7 @@
4#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025) 4#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025)
5#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf) 5#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf)
6 6
7// FIXME: We have two structs for now, needs fixing.
7typedef struct AudioChannel { 8typedef struct AudioChannel {
8 u8 *samples; 9 u8 *samples;
9 u16 n_samples; 10 u16 n_samples;
@@ -31,127 +32,22 @@ static APU apu;
31 32
32 33
33static u16 pitch_table[] = { 34static u16 pitch_table[] = {
34 12173, 35 12173, 11490, 10845, 10237, 9662, 9120, 8608, 8125,
35 11490, 36 7669, 7238, 6832, 6448, 6086, 5745, 5422, 5118,
36 10845, 37 4831, 4560, 4304, 4062, 3834, 3619, 3416, 3224,
37 10237, 38 3043, 2872, 2711, 2559, 2415, 2280, 2152, 2031,
38 9662, 39 1917, 1809, 1708, 1612, 1521, 1436, 1355, 1279,
39 9120, 40 1207, 1140, 1076, 1015, 958, 904, 854, 806,
40 8608, 41 760, 718, 677, 639, 603, 570, 538, 507,
41 8125, 42 479, 452, 427, 403, 380, 359, 338, 319,
42 7669, 43 301, 285, 269, 253, 239, 226, 213, 201,
43 7238, 44 190, 179, 169, 159, 150, 142, 134, 126,
44 6832, 45 119, 113, 106, 100, 95, 89, 84, 79,
45 6448, 46 75, 71, 67, 63, 59, 56, 53, 50,
46 6086, 47 47, 44, 42, 39, 37, 35, 33, 31,
47 5745, 48 29, 28, 26, 25, 23, 22, 21, 19,
48 5422, 49 18, 17, 16, 15, 14, 14, 13, 12,
49 5118, 50 2,
50 4831,
51 4560,
52 4304,
53 4062,
54 3834,
55 3619,
56 3416,
57 3224,
58 3043,
59 2872,
60 2711,
61 2559,
62 2415,
63 2280,
64 2152,
65 2031,
66 1917,
67 1809,
68 1708,
69 1612,
70 1521,
71 1436,
72 1355,
73 1279,
74 1207,
75 1140,
76 1076,
77 1015,
78 958,
79 904,
80 854,
81 806,
82 760,
83 718,
84 677,
85 639,
86 603,
87 570,
88 538,
89 507,
90 479,
91 452,
92 427,
93 403,
94 380,
95 359,
96 338,
97 319,
98 301,
99 285,
100 269,
101 253,
102 239,
103 226,
104 213,
105 201,
106 190,
107 179,
108 169,
109 159,
110 150,
111 142,
112 134,
113 126,
114 119,
115 113,
116 106,
117 100,
118 95,
119 89,
120 84,
121 79,
122 75,
123 71,
124 67,
125 63,
126 59,
127 56,
128 53,
129 50,
130 47,
131 44,
132 42,
133 39,
134 37,
135 35,
136 33,
137 31,
138 29,
139 28,
140 26,
141 25,
142 23,
143 22,
144 21,
145 19,
146 18,
147 17,
148 16,
149 15,
150 14,
151 14,
152 13,
153 12,
154 0,
155}; 51};
156 52
157void 53void
@@ -188,23 +84,150 @@ reset_sound(AudioChannel *chan) {
188 TIMER_CTRL_0 = TIMER_CTRL_ENABLE; 84 TIMER_CTRL_0 = TIMER_CTRL_ENABLE;
189} 85}
190 86
191u8 square_wave[] = { 87s8 square_wave[] = {
192 0x00 + 0x80, 0xFF + 0x80 88 (s8)0x00 + (s8)0x80, (s8)0xFF + (s8)0x80
193}; 89};
90
194#include "text.h" 91#include "text.h"
195 92
196 93
94
95//
96// REG_TM0D frequency buffer size
97// | | |
98// V V V
99//
100// Timer = 62610 = 65536 - (16777216 / 5734), buf = 96
101// Timer = 63940 = 65536 - (16777216 / 10512), buf = 176
102// Timer = 64282 = 65536 - (16777216 / 13379), buf = 224
103// Timer = 64612 = 65536 - (16777216 / 18157), buf = 304
104// Timer = 64738 = 65536 - (16777216 / 21024), buf = 352
105// Timer = 64909 = 65536 - (16777216 / 26758), buf = 448
106// Timer = 65004 = 65536 - (16777216 / 31536), buf = 528
107// Timer = 65073 = 65536 - (16777216 / 36314), buf = 608
108// Timer = 65118 = 65536 - (16777216 / 40137), buf = 672
109// Timer = 65137 = 65536 - (16777216 / 42048), buf = 704
110//
111// Source: https://deku.gbadev.org/program/sound1.html
112#define AUDIO_FREQ 18157
113#define AUDIO_BUF_LEN 304
114#define AUDIO_TIMER 64612
115
116typedef struct Audio {
117 s8 mix_buffer[AUDIO_BUF_LEN * 2];
118 s8 *current_buffer;
119 u8 active_buffer;
120} Audio;
121
122typedef struct Channel {
123 // Pointer to the raw data in the ROM.
124 s8 *data;
125 // Current position in the data (20.12 fixed-point).
126 u32 pos;
127 // Increment (20.12 fixed-point).
128 u32 inc;
129 // Volume (0-64, 1.6 fixed-point).
130 u32 vol;
131 // Sound length (20.12 fixed-point).
132 u32 length;
133 // Length of looped portion (20.12 fixed-point, 0 to disable looping).
134 u32 loop_length;
135} Channel;
136
137static Audio audio;
138
139#define POLYPHONY 4
140static Channel channels[POLYPHONY];
141
197void 142void
198init_sound(AudioChannel *chan) { 143init_sound(void) {
199 // chan->samples = &square_wave; 144 // Initialize audio buffers/channels.
200 // chan->n_samples = 2; 145 audio = (Audio){0};
201 // chan->samples = &samples; 146 for (size_t i = 0; i < POLYPHONY; ++i) {
202 // chan->n_samples = LEN(samples); 147 channels[i] = (Channel){0};
203 // chan->pitch++; 148 }
204 // chan->pitch = chan->pitch == LEN(pitch_table) - 1 ? 0 : chan->pitch + 1; 149
205 // chan->loop = true; 150 // DEBUG: testing channel 0 with square wave
206 // chan->sampling_freq = pitch_table[chan->pitch]; 151 channels[0].data = samples;
207 // txt_printf("RATE: %lu", pitch_table[chan->pitch]) 152 channels[0].inc = (8363 << 12) / AUDIO_FREQ;
153 channels[0].length = (LEN(samples) - 1) << 12;
154 channels[0].pos = 0;
155 channels[0].vol = 64;
156 channels[0].loop_length = channels[0].length;
157
158 // Enable the sound chip.
159 SOUND_STATUS = SOUND_ENABLE;
160
161 // Set max volume, left-right sound, fifo reset and use timer 0 for
162 // DirectSound A.
163 SOUND_DSOUND_MASTER = SOUND_DSOUND_RATIO_A
164 | SOUND_DSOUND_LEFT_A
165 | SOUND_DSOUND_RIGHT_A
166 | SOUND_DSOUND_RESET_A;
167
168 // TODO: No pitch selection yet.
169 TIMER_DATA_0 = AUDIO_TIMER;
170 TIMER_CTRL_0 = TIMER_CTRL_ENABLE;
171}
172
173void sound_vsync() {
174 // buffer 1 just got over
175 if(audio.active_buffer == 1) {
176 // Start playing buffer 0
177 dma_transfer_copy(SOUND_FIFO_A, audio.mix_buffer, 1, 1,
178 DMA_DST_FIXED | DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE);
179
180 // Set the current buffer pointer to the start of buffer 1
181 audio.current_buffer = audio.mix_buffer + AUDIO_BUF_LEN;
182 audio.active_buffer = 0;
183 } else {
184 // buffer 0 just got over
185 // DMA points to buffer 1 already, so don't bother stopping and resetting it
186 // Set the current buffer pointer to the start of buffer 0
187 audio.current_buffer = audio.mix_buffer;
188 audio.active_buffer = 1;
189 }
190}
191
192void sound_mix() {
193 // Initialize and clear mix_buffer.
194 s16 mix_buffer[AUDIO_BUF_LEN];
195 u32 fill = 0;
196 dma_fill(mix_buffer, fill, sizeof(mix_buffer), 3);
197
198 // Mix channels into the temporary buffer.
199 for (size_t j = 0; j < POLYPHONY; ++j) {
200 Channel *chan = &channels[j];
201 // Check if channel is active.
202 if (chan->data == NULL) {
203 continue;
204 }
205 for(size_t i = 0; i < AUDIO_BUF_LEN; i++) {
206 // Remember we are using fixed point values.
207 mix_buffer[i] += chan->data[chan->pos >> 12] * chan->vol;
208 chan->pos += chan->inc;
209
210 if (chan->pos >= chan->length) {
211 // If looping is not active disable the channel.
212 if (chan->loop_length == 0) {
213 chan->data = NULL;
214 break;
215 }
216
217 // Loop the sample.
218 while (chan->pos >= chan->length) {
219 chan->pos -= chan->loop_length;
220 }
221 }
222 }
223 }
224
225 // Downsample and copy to the playing buffer.
226 for (size_t i = 0; i < AUDIO_BUF_LEN; ++i) {
227 // >> 8 to divide off the volume, >> 2 to divide by 4 channels to
228 // prevent overflow.
229 audio.current_buffer[i] = mix_buffer[i] >> 8;
230 }
208} 231}
209 232
210void 233void