src/gba/gba-audio.c (view raw)
1#include "gba-audio.h"
2
3#include "gba.h"
4#include "gba-io.h"
5#include "gba-thread.h"
6
7#include <limits.h>
8
9const unsigned GBA_AUDIO_SAMPLES = 512;
10const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
11
12static void _updateEnvelope(struct GBAAudioEnvelope* envelope);
13static int32_t _updateChannel1(struct GBAAudioChannel1* ch);
14static int32_t _updateChannel2(struct GBAAudioChannel2* ch);
15static int32_t _updateChannel3(struct GBAAudioChannel3* ch);
16static int32_t _updateChannel4(struct GBAAudioChannel4* ch);
17static void _sample(struct GBAAudio* audio);
18
19void GBAAudioInit(struct GBAAudio* audio) {
20 audio->nextEvent = 0;
21 audio->nextCh1 = 0;
22 audio->nextCh2 = 0;
23 audio->nextCh3 = 0;
24 audio->nextCh4 = 0;
25 audio->ch1.envelope.nextStep = INT_MAX;
26 audio->ch2.envelope.nextStep = INT_MAX;
27 audio->ch4.sample = 0;
28 audio->ch4.envelope.nextStep = INT_MAX;
29 audio->eventDiff = 0;
30 audio->nextSample = 0;
31 audio->sampleRate = 0x8000;
32 audio->soundcntLo = 0;
33 audio->soundcntHi = 0;
34 audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
35
36 CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t));
37 CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t));
38 CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
39 CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
40
41 pthread_mutex_init(&audio->bufferMutex, 0);
42}
43
44void GBAAudioDeinit(struct GBAAudio* audio) {
45 CircleBufferDeinit(&audio->left);
46 CircleBufferDeinit(&audio->right);
47 CircleBufferDeinit(&audio->chA.fifo);
48 CircleBufferDeinit(&audio->chB.fifo);
49
50 pthread_mutex_destroy(&audio->bufferMutex);
51}
52
53int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
54 audio->nextEvent -= cycles;
55 audio->eventDiff += cycles;
56 while (audio->nextEvent <= 0) {
57 audio->nextEvent = INT_MAX;
58
59 audio->nextCh1 -= audio->eventDiff;
60 audio->nextCh2 -= audio->eventDiff;
61 audio->nextCh3 -= audio->eventDiff;
62 audio->nextCh4 -= audio->eventDiff;
63
64 if (audio->ch1.envelope.nextStep != INT_MAX) {
65 audio->ch1.envelope.nextStep -= audio->eventDiff;
66 if (audio->ch1.envelope.nextStep <= 0) {
67 _updateEnvelope(&audio->ch1.envelope);
68 }
69 }
70
71 if (audio->ch2.envelope.nextStep != INT_MAX) {
72 audio->ch2.envelope.nextStep -= audio->eventDiff;
73 if (audio->ch2.envelope.nextStep <= 0) {
74 _updateEnvelope(&audio->ch2.envelope);
75 }
76 }
77
78 if (audio->ch4.envelope.nextStep != INT_MAX) {
79 audio->ch4.envelope.nextStep -= audio->eventDiff;
80 if (audio->ch4.envelope.nextStep <= 0) {
81 _updateEnvelope(&audio->ch4.envelope);
82 if (audio->ch4.envelope.nextStep < audio->nextEvent) {
83 audio->nextEvent = audio->nextCh4;
84 }
85 }
86 }
87
88 if ((audio->ch1Right || audio->ch1Left) && audio->nextCh1 <= 0) {
89 audio->nextCh1 += _updateChannel1(&audio->ch1);
90 }
91
92 if ((audio->ch2Right || audio->ch2Left) && audio->nextCh2 <= 0) {
93 audio->nextCh2 += _updateChannel2(&audio->ch2);
94 }
95
96 if ((audio->ch3Right || audio->ch3Left) && audio->nextCh3 <= 0) {
97 audio->nextCh3 += _updateChannel3(&audio->ch3);
98 }
99
100 if ((audio->ch4Right || audio->ch4Left) && audio->nextCh4 <= 0) {
101 audio->nextCh4 += _updateChannel4(&audio->ch4);
102 if (audio->nextCh4 < audio->nextEvent) {
103 audio->nextEvent = audio->nextCh4;
104 }
105 }
106
107 audio->nextSample -= audio->eventDiff;
108 if (audio->nextSample <= 0) {
109 _sample(audio);
110 audio->nextSample += audio->sampleInterval;
111 }
112
113 if (audio->nextSample < audio->nextEvent) {
114 audio->nextEvent = audio->nextSample;
115 }
116 audio->eventDiff = 0;
117 }
118 return audio->nextEvent;
119}
120
121void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
122 switch (info->dest) {
123 case BASE_IO | REG_FIFO_A_LO:
124 audio->chA.dmaSource = number;
125 break;
126 case BASE_IO | REG_FIFO_B_LO:
127 audio->chB.dmaSource = number;
128 break;
129 default:
130 GBALog(audio->p, GBA_LOG_GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
131 return;
132 }
133 info->dstControl = DMA_FIXED;
134}
135
136void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
137 audio->ch1.sweep.packed = value;
138}
139
140void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
141 audio->ch1.envelope.packed = value;
142 if (audio->ch1.envelope.stepTime) {
143 audio->ch1.envelope.nextStep = 0;
144 } else {
145 audio->ch1.envelope.nextStep = INT_MAX;
146 }
147}
148
149void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
150 audio->ch1.control.packed = value;
151}
152
153void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
154 audio->ch2.envelope.packed = value;
155 if (audio->ch2.envelope.stepTime) {
156 audio->ch2.envelope.nextStep = 0;
157 } else {
158 audio->ch2.envelope.nextStep = INT_MAX;
159 }
160}
161
162void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
163 audio->ch2.control.packed = value;
164}
165
166void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
167 audio->ch3.bank.packed = value;
168}
169
170void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
171 audio->ch3.wave.packed = value;
172}
173
174void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
175 audio->ch3.control.packed = value;
176}
177
178void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
179 audio->ch4.envelope.packed = value;
180 if (audio->ch4.envelope.stepTime) {
181 audio->ch4.envelope.nextStep = 0;
182 } else {
183 audio->ch4.envelope.nextStep = INT_MAX;
184 }
185}
186
187void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
188 audio->ch4.control.packed = value;
189 if (audio->ch4.control.restart) {
190 audio->ch4.envelope.currentVolume = audio->ch4.envelope.initialVolume;
191 if (audio->ch4.envelope.stepTime) {
192 audio->ch4.envelope.nextStep = 0;
193 } else {
194 audio->ch4.envelope.nextStep = INT_MAX;
195 }
196 if (audio->ch4.control.power) {
197 audio->ch4.lfsr = 0x40;
198 } else {
199 audio->ch4.lfsr = 0x4000;
200 }
201 audio->nextCh4 = 0;
202 }
203}
204
205void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
206 audio->soundcntLo = value;
207}
208
209void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {
210 audio->soundcntHi = value;
211}
212
213void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) {
214 audio->soundcntX = (value & 0xF0) | (audio->soundcntX & 0x0F);
215}
216
217void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
218 GBALog(audio->p, GBA_LOG_STUB, "Audio unimplemented");
219}
220
221void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
222 struct CircleBuffer* fifo;
223 switch (address) {
224 case REG_FIFO_A_LO:
225 fifo = &audio->chA.fifo;
226 break;
227 case REG_FIFO_B_LO:
228 fifo = &audio->chB.fifo;
229 break;
230 default:
231 GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", address);
232 return;
233 }
234 while (!CircleBufferWrite32(fifo, value)) {
235 int32_t dummy;
236 CircleBufferRead32(fifo, &dummy);
237 }
238}
239
240void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId) {
241 struct GBAAudioFIFO* channel;
242 if (fifoId == 0) {
243 channel = &audio->chA;
244 } else if (fifoId == 1) {
245 channel = &audio->chB;
246 } else {
247 GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", fifoId);
248 return;
249 }
250 if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t)) {
251 struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
252 dma->nextCount = 4;
253 GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma);
254 }
255 CircleBufferRead8(&channel->fifo, &channel->sample);
256}
257
258static void _updateEnvelope(struct GBAAudioEnvelope* envelope) {
259 if (envelope->direction) {
260 ++envelope->currentVolume;
261 } else {
262 --envelope->currentVolume;
263 }
264 if (envelope->currentVolume >= 15) {
265 envelope->currentVolume = 15;
266 envelope->nextStep = INT_MAX;
267 } else if (envelope->currentVolume <= 0) {
268 envelope->currentVolume = 0;
269 envelope->nextStep = INT_MAX;
270 } else {
271 envelope->nextStep += envelope->stepTime * (GBA_ARM7TDMI_FREQUENCY >> 6);
272 }
273}
274
275static int32_t _updateChannel1(struct GBAAudioChannel1* ch) {
276 return INT_MAX / 4;
277}
278
279static int32_t _updateChannel2(struct GBAAudioChannel2* ch) {
280 return INT_MAX / 4;
281}
282
283static int32_t _updateChannel3(struct GBAAudioChannel3* ch) {
284 return INT_MAX / 4;
285}
286
287static int32_t _updateChannel4(struct GBAAudioChannel4* ch) {
288 int lsb = ch->lfsr & 1;
289 ch->sample = lsb * 0x10 - 0x8;
290 ch->sample *= ch->envelope.currentVolume;
291 ch->lfsr >>= 1;
292 ch->lfsr ^= (lsb * 0x60) << (ch->control.power ? 0 : 8);
293 int timing = ch->control.ratio ? 2 * ch->control.ratio : 1;
294 timing <<= ch->control.frequency;
295 timing *= 32;
296 return timing;
297}
298
299static void _sample(struct GBAAudio* audio) {
300 int32_t sampleLeft = 0;
301 int32_t sampleRight = 0;
302 int psgShift = 2 - audio->volume;
303
304 if (audio->ch4Left) {
305 sampleLeft += audio->ch4.sample >> psgShift;
306 }
307
308 if (audio->ch4Right) {
309 sampleRight += audio->ch4.sample >> psgShift;
310 }
311
312 if (audio->chALeft) {
313 sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
314 }
315
316 if (audio->chARight) {
317 sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
318 }
319
320 if (audio->chBLeft) {
321 sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
322 }
323
324 if (audio->chBRight) {
325 sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
326 }
327
328 pthread_mutex_lock(&audio->bufferMutex);
329 while (CircleBufferSize(&audio->left) + (GBA_AUDIO_SAMPLES * 2 / 5) >= audio->left.capacity) {
330 if (!audio->p->sync->audioWait) {
331 break;
332 }
333 GBASyncProduceAudio(audio->p->sync, &audio->bufferMutex);
334 }
335 CircleBufferWrite32(&audio->left, sampleLeft);
336 CircleBufferWrite32(&audio->right, sampleRight);
337 pthread_mutex_unlock(&audio->bufferMutex);
338}