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.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/src/uxn/devices/apu.c b/src/uxn/devices/apu.c
new file mode 100644
index 0000000..fbe7c3d
--- /dev/null
+++ b/src/uxn/devices/apu.c
@@ -0,0 +1,241 @@
1#include "samples.c"
2
3#define SAMPLE_FREQUENCY 44100
4#define NOTE_PERIOD (SAMPLE_FREQUENCY * 0x4000 / 11025)
5#define ADSR_STEP (SAMPLE_FREQUENCY / 0xf)
6
7typedef struct AudioChannel {
8 u8 *samples;
9 u16 n_samples;
10 u16 position;
11 u16 sampling_freq;
12 u8 pitch;
13 bool loop;
14 // TODO: u16 adsr; // attack, decay, sustain, release
15 // TODO: u8 pitch; // Bit 8 is the "loop" bit
16 // TODO: u8 volume; // VOL_LEFT | (VOL_RIGHT << 4)
17 // u8 *addr;
18 // u32 count, advance, period, age, a, d, s, r;
19 // s8 volume[2];
20 // u8 pitch, repeat;
21} AudioChannel;
22
23typedef struct APU {
24 AudioChannel chan_0;
25 // u32 *samples_1;
26 // u32 *samples_2;
27 // u32 *samples_3;
28} APU;
29
30static APU apu;
31
32
33static u16 pitch_table[] = {
34 12173,
35 11490,
36 10845,
37 10237,
38 9662,
39 9120,
40 8608,
41 8125,
42 7669,
43 7238,
44 6832,
45 6448,
46 6086,
47 5745,
48 5422,
49 5118,
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};
156
157void
158reset_sound(AudioChannel *chan) {
159 TIMER_CTRL_0 = 0;
160 TIMER_CTRL_1 = 0;
161 DMA_CTRL(1) = 0;
162 if (chan->pitch >= 108 || chan->n_samples == 0) {
163 return;
164 }
165
166 // Set max volume, left-right sound, fifo reset and use timer 0 for
167 // DirectSound A.
168 SOUND_DSOUND_MASTER = SOUND_DSOUND_RATIO_A
169 | SOUND_DSOUND_LEFT_A
170 | SOUND_DSOUND_RIGHT_A
171 | SOUND_DSOUND_RESET_A;
172
173 // Prepare DMA copy.
174 dma_transfer_copy(SOUND_FIFO_A, chan->samples, 1, 1,
175 DMA_CHUNK_32 | DMA_REFRESH | DMA_REPEAT | DMA_ENABLE);
176
177 // Timer 1 used to stop playing samples.
178 u32 sample_duration = chan->n_samples;
179 TIMER_DATA_1 = 0xFFFF - sample_duration;
180 TIMER_CTRL_1 = TIMER_CTRL_IRQ
181 | TIMER_CTRL_ENABLE
182 | TIMER_CTRL_CASCADE;
183
184 // Timer 0 used to stop sample playing.
185 // TIMER_DATA_0 = 0xFFFF - sound_freq[chan->pitch];
186 // TIMER_DATA_0 = 0xFFFF - CPU_FREQUENCY / chan->sampling_freq / chan->pitch;
187 TIMER_DATA_0 = 0xFFFF - pitch_table[chan->pitch];
188 TIMER_CTRL_0 = TIMER_CTRL_ENABLE;
189}
190
191u8 square_wave[] = {
192 0x00 + 0x80, 0xFF + 0x80
193};
194#include "text.h"
195
196
197void
198init_sound(AudioChannel *chan) {
199 // Enable sound.
200 SOUND_STATUS = SOUND_ENABLE;
201
202 // chan->samples = &square_wave;
203 // chan->n_samples = 2;
204 // chan->samples = &samples;
205 // chan->n_samples = LEN(samples);
206 // chan->pitch++;
207 // chan->pitch = chan->pitch == LEN(pitch_table) - 1 ? 0 : chan->pitch + 1;
208 // chan->loop = true;
209 // chan->sampling_freq = pitch_table[chan->pitch];
210 // txt_printf("RATE: %lu", pitch_table[chan->pitch])
211}
212
213void
214irs_stop_sample(void) {
215 if (apu.chan_0.loop) {
216 reset_sound(&apu.chan_0);
217 } else {
218 TIMER_CTRL_0 = 0;
219 DMA_CTRL(1) = 0;
220 }
221}
222
223// void
224// apu_start(Apu *c, u16 adsr, u8 pitch) {
225// // if(pitch < 108 && c->len)
226// // c->advance = advances[pitch % 12] >> (8 - pitch / 12);
227// // else {
228// // c->advance = 0;
229// // return;
230// // }
231// // c->a = ADSR_STEP * (adsr >> 12);
232// // c->d = ADSR_STEP * (adsr >> 8 & 0xf) + c->a;
233// // c->s = ADSR_STEP * (adsr >> 4 & 0xf) + c->d;
234// // c->r = ADSR_STEP * (adsr >> 0 & 0xf) + c->s;
235// // c->age = 0;
236// // c->i = 0;
237// // if(c->len <= 0x100) /* single cycle mode */
238// // c->period = NOTE_PERIOD * 337 / 2 / c->len;
239// // else /* sample repeat mode */
240// // c->period = NOTE_PERIOD;
241// }