src/gba/audio.c (view raw)
1/* Copyright (c) 2013-2016 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "audio.h"
7
8#include "core/sync.h"
9#include "gba/gba.h"
10#include "gba/io.h"
11#include "gba/serialize.h"
12#include "gba/video.h"
13
14mLOG_DEFINE_CATEGORY(GBA_AUDIO, "GBA Audio");
15
16const unsigned GBA_AUDIO_SAMPLES = 2048;
17const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
18const int GBA_AUDIO_VOLUME_MAX = 0x100;
19
20static const int CLOCKS_PER_FRAME = 0x400;
21
22static int _applyBias(struct GBAAudio* audio, int sample);
23static void _sample(struct GBAAudio* audio);
24
25void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
26 audio->psg.p = NULL;
27 uint8_t* nr52 = (uint8_t*) &audio->p->memory.io[REG_SOUNDCNT_X >> 1];
28#ifdef __BIG_ENDIAN__
29 ++n52;
30#endif
31 GBAudioInit(&audio->psg, 0, nr52);
32 audio->samples = samples;
33 audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY;
34 // Guess too large; we hang producing extra samples if we guess too low
35 blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000);
36 blip_set_rates(audio->psg.right, GBA_ARM7TDMI_FREQUENCY, 96000);
37 CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
38 CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
39
40 audio->forceDisableChA = false;
41 audio->forceDisableChB = false;
42 audio->masterVolume = GBA_AUDIO_VOLUME_MAX;
43}
44
45void GBAAudioReset(struct GBAAudio* audio) {
46 GBAudioReset(&audio->psg);
47 audio->nextEvent = 0;
48 audio->chA.sample = 0;
49 audio->chB.sample = 0;
50 audio->eventDiff = 0;
51 audio->nextSample = 0;
52 audio->sampleRate = 0x8000;
53 audio->soundbias = 0x200;
54 audio->volume = 0;
55 audio->volumeChA = false;
56 audio->volumeChB = false;
57 audio->chARight = false;
58 audio->chALeft = false;
59 audio->chATimer = false;
60 audio->chBRight = false;
61 audio->chBLeft = false;
62 audio->chBTimer = false;
63 audio->enable = false;
64 audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
65
66 blip_clear(audio->psg.left);
67 blip_clear(audio->psg.right);
68 audio->clock = 0;
69 CircleBufferClear(&audio->chA.fifo);
70 CircleBufferClear(&audio->chB.fifo);
71}
72
73void GBAAudioDeinit(struct GBAAudio* audio) {
74 GBAudioDeinit(&audio->psg);
75 CircleBufferDeinit(&audio->chA.fifo);
76 CircleBufferDeinit(&audio->chB.fifo);
77}
78
79void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
80 mCoreSyncLockAudio(audio->p->sync);
81 audio->samples = samples;
82 blip_clear(audio->psg.left);
83 blip_clear(audio->psg.right);
84 audio->clock = 0;
85 mCoreSyncConsumeAudio(audio->p->sync);
86}
87
88int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
89 audio->nextEvent -= cycles;
90 audio->eventDiff += cycles;
91 while (audio->nextEvent <= 0) {
92 audio->nextEvent = INT_MAX;
93 if (audio->enable) {
94 audio->nextEvent = GBAudioProcessEvents(&audio->psg, audio->eventDiff / 4);
95 if (audio->nextEvent != INT_MAX) {
96 audio->nextEvent *= 4;
97 }
98 }
99
100 audio->nextSample -= audio->eventDiff;
101 if (audio->nextSample <= 0) {
102 _sample(audio);
103 audio->nextSample += audio->sampleInterval;
104 }
105
106 if (audio->nextSample < audio->nextEvent) {
107 audio->nextEvent = audio->nextSample;
108 }
109 audio->eventDiff = 0;
110 }
111 return audio->nextEvent;
112}
113
114void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
115 switch (info->dest) {
116 case BASE_IO | REG_FIFO_A_LO:
117 audio->chA.dmaSource = number;
118 break;
119 case BASE_IO | REG_FIFO_B_LO:
120 audio->chB.dmaSource = number;
121 break;
122 default:
123 mLOG(GBA_AUDIO, GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
124 return;
125 }
126 info->reg = GBADMARegisterSetDestControl(info->reg, DMA_FIXED);
127}
128
129void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
130 GBAudioWriteNR10(&audio->psg, value);
131}
132
133void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
134 GBAudioWriteNR11(&audio->psg, value);
135 GBAudioWriteNR12(&audio->psg, value >> 8);
136}
137
138void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
139 GBAudioWriteNR13(&audio->psg, value);
140 GBAudioWriteNR14(&audio->psg, value >> 8);
141}
142
143void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
144 GBAudioWriteNR21(&audio->psg, value);
145 GBAudioWriteNR22(&audio->psg, value >> 8);
146}
147
148void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
149 GBAudioWriteNR23(&audio->psg, value);
150 GBAudioWriteNR24(&audio->psg, value >> 8);
151}
152
153void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
154 audio->psg.ch3.size = GBAudioRegisterBankGetSize(value);
155 audio->psg.ch3.bank = GBAudioRegisterBankGetBank(value);
156 GBAudioWriteNR30(&audio->psg, value);
157}
158
159void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
160 GBAudioWriteNR31(&audio->psg, value);
161 audio->psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value >> 8);
162}
163
164void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
165 GBAudioWriteNR33(&audio->psg, value);
166 GBAudioWriteNR34(&audio->psg, value >> 8);
167}
168
169void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
170 GBAudioWriteNR41(&audio->psg, value);
171 GBAudioWriteNR42(&audio->psg, value >> 8);
172}
173
174void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
175 GBAudioWriteNR43(&audio->psg, value);
176 GBAudioWriteNR44(&audio->psg, value >> 8);
177}
178
179void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
180 GBAudioWriteNR50(&audio->psg, value);
181 GBAudioWriteNR51(&audio->psg, value >> 8);
182}
183
184void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {
185 audio->volume = GBARegisterSOUNDCNT_HIGetVolume(value);
186 audio->volumeChA = GBARegisterSOUNDCNT_HIGetVolumeChA(value);
187 audio->volumeChB = GBARegisterSOUNDCNT_HIGetVolumeChB(value);
188 audio->chARight = GBARegisterSOUNDCNT_HIGetChARight(value);
189 audio->chALeft = GBARegisterSOUNDCNT_HIGetChALeft(value);
190 audio->chATimer = GBARegisterSOUNDCNT_HIGetChATimer(value);
191 audio->chBRight = GBARegisterSOUNDCNT_HIGetChBRight(value);
192 audio->chBLeft = GBARegisterSOUNDCNT_HIGetChBLeft(value);
193 audio->chBTimer = GBARegisterSOUNDCNT_HIGetChBTimer(value);
194 if (GBARegisterSOUNDCNT_HIIsChAReset(value)) {
195 CircleBufferClear(&audio->chA.fifo);
196 }
197 if (GBARegisterSOUNDCNT_HIIsChBReset(value)) {
198 CircleBufferClear(&audio->chB.fifo);
199 }
200}
201
202void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) {
203 audio->enable = GBAudioEnableGetEnable(value);
204 GBAudioWriteNR52(&audio->psg, value);
205}
206
207void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) {
208 audio->soundbias = value;
209}
210
211void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
212 audio->psg.ch3.wavedata[address | (!audio->psg.ch3.bank * 4)] = value;
213}
214
215void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
216 struct CircleBuffer* fifo;
217 switch (address) {
218 case REG_FIFO_A_LO:
219 fifo = &audio->chA.fifo;
220 break;
221 case REG_FIFO_B_LO:
222 fifo = &audio->chB.fifo;
223 break;
224 default:
225 mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", address);
226 return;
227 }
228 int i;
229 for (i = 0; i < 4; ++i) {
230 while (!CircleBufferWrite8(fifo, value >> (8 * i))) {
231 int8_t dummy;
232 CircleBufferRead8(fifo, &dummy);
233 }
234 }
235}
236
237void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) {
238 struct GBAAudioFIFO* channel;
239 if (fifoId == 0) {
240 channel = &audio->chA;
241 } else if (fifoId == 1) {
242 channel = &audio->chB;
243 } else {
244 mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", fifoId);
245 return;
246 }
247 if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t) && channel->dmaSource > 0) {
248 struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
249 if (GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_CUSTOM) {
250 dma->nextCount = 4;
251 dma->nextEvent = 0;
252 dma->reg = GBADMARegisterSetWidth(dma->reg, 1);
253 GBAMemoryUpdateDMAs(audio->p, -cycles);
254 } else {
255 channel->dmaSource = 0;
256 }
257 }
258 CircleBufferRead8(&channel->fifo, (int8_t*) &channel->sample);
259}
260
261static int _applyBias(struct GBAAudio* audio, int sample) {
262 sample += GBARegisterSOUNDBIASGetBias(audio->soundbias);
263 if (sample >= 0x400) {
264 sample = 0x3FF;
265 } else if (sample < 0) {
266 sample = 0;
267 }
268 return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume) >> 3;
269}
270
271static void _sample(struct GBAAudio* audio) {
272 int16_t sampleLeft = 0;
273 int16_t sampleRight = 0;
274 int psgShift = 5 - audio->volume;
275 GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight);
276 sampleLeft >>= psgShift;
277 sampleRight >>= psgShift;
278
279 if (!audio->forceDisableChA) {
280 if (audio->chALeft) {
281 sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
282 }
283
284 if (audio->chARight) {
285 sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
286 }
287 }
288
289 if (!audio->forceDisableChB) {
290 if (audio->chBLeft) {
291 sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
292 }
293
294 if (audio->chBRight) {
295 sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
296 }
297 }
298
299 sampleLeft = _applyBias(audio, sampleLeft);
300 sampleRight = _applyBias(audio, sampleRight);
301
302 mCoreSyncLockAudio(audio->p->sync);
303 unsigned produced;
304 if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) {
305 blip_add_delta(audio->psg.left, audio->clock, sampleLeft - audio->lastLeft);
306 blip_add_delta(audio->psg.right, audio->clock, sampleRight - audio->lastRight);
307 audio->lastLeft = sampleLeft;
308 audio->lastRight = sampleRight;
309 audio->clock += audio->sampleInterval;
310 if (audio->clock >= CLOCKS_PER_FRAME) {
311 blip_end_frame(audio->psg.left, audio->clock);
312 blip_end_frame(audio->psg.right, audio->clock);
313 audio->clock -= CLOCKS_PER_FRAME;
314 }
315 }
316 produced = blip_samples_avail(audio->psg.left);
317 if (audio->p->stream && audio->p->stream->postAudioFrame) {
318 audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight);
319 }
320 bool wait = produced >= audio->samples;
321 mCoreSyncProduceAudio(audio->p->sync, wait);
322
323 if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) {
324 audio->p->stream->postAudioBuffer(audio->p->stream, audio->psg.left, audio->psg.right);
325 }
326}
327
328void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) {
329 uint32_t flags = 0;
330
331 flags = GBASerializedAudioFlagsSetCh1Volume(flags, audio->psg.ch1.envelope.currentVolume);
332 flags = GBASerializedAudioFlagsSetCh1Dead(flags, audio->psg.ch1.envelope.dead);
333 flags = GBASerializedAudioFlagsSetCh1Hi(flags, audio->psg.ch1.control.hi);
334 /*STORE_32(audio->psg.ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep);
335 STORE_32(audio->psg.ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep);
336 STORE_32(audio->psg.ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep);
337 STORE_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime);*/
338 STORE_32(audio->psg.nextCh1, 0, &state->audio.ch1.nextEvent);
339
340 flags = GBASerializedAudioFlagsSetCh2Volume(flags, audio->psg.ch2.envelope.currentVolume);
341 flags = GBASerializedAudioFlagsSetCh2Dead(flags, audio->psg.ch2.envelope.dead);
342 flags = GBASerializedAudioFlagsSetCh2Hi(flags, audio->psg.ch2.control.hi);
343 /*STORE_32(audio->psg.ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep);
344 STORE_32(audio->psg.ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep);
345 STORE_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime);*/
346 STORE_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent);
347
348 memcpy(state->audio.ch3.wavebanks, audio->psg.ch3.wavedata, sizeof(state->audio.ch3.wavebanks));
349 //STORE_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime);
350 STORE_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent);
351
352 state->audio.flags = GBASerializedAudioFlagsSetCh4Volume(flags, audio->psg.ch4.envelope.currentVolume);
353 state->audio.flags = GBASerializedAudioFlagsSetCh4Dead(flags, audio->psg.ch4.envelope.dead);
354 STORE_32(audio->psg.ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep);
355 STORE_32(audio->psg.ch4.lfsr, 0, &state->audio.ch4.lfsr);
356 //STORE_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime);
357 STORE_32(audio->psg.nextCh4, 0, &state->audio.ch4.nextEvent);
358
359 STORE_32(flags, 0, &state->audio.flags);
360
361 CircleBufferDump(&audio->chA.fifo, state->audio.fifoA, sizeof(state->audio.fifoA));
362 CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB));
363 uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo);
364 STORE_32(fifoSize, 0, &state->audio.fifoSize);
365
366 STORE_32(audio->nextEvent, 0, &state->audio.nextEvent);
367 STORE_32(audio->eventDiff, 0, &state->audio.eventDiff);
368 STORE_32(audio->nextSample, 0, &state->audio.nextSample);
369}
370
371void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) {
372 uint32_t flags;
373 LOAD_32(flags, 0, &state->audio.flags);
374 audio->psg.ch1.envelope.currentVolume = GBASerializedAudioFlagsGetCh1Volume(flags);
375 audio->psg.ch1.envelope.dead = GBASerializedAudioFlagsGetCh1Dead(flags);
376 audio->psg.ch1.control.hi = GBASerializedAudioFlagsGetCh1Hi(flags);
377 LOAD_32(audio->psg.ch1.envelope.nextStep, 0, &state->audio.ch1.envelopeNextStep);
378 /*LOAD_32(audio->psg.ch1.control.nextStep, 0, &state->audio.ch1.waveNextStep);
379 LOAD_32(audio->psg.ch1.nextSweep, 0, &state->audio.ch1.sweepNextStep);
380 LOAD_32(audio->psg.ch1.control.endTime, 0, &state->audio.ch1.endTime);*/
381 LOAD_32(audio->psg.nextCh1, 0, &state->audio.ch1.nextEvent);
382
383 audio->psg.ch2.envelope.currentVolume = GBASerializedAudioFlagsGetCh2Volume(flags);
384 audio->psg.ch2.envelope.dead = GBASerializedAudioFlagsGetCh2Dead(flags);
385 audio->psg.ch2.control.hi = GBASerializedAudioFlagsGetCh2Hi(flags);
386 LOAD_32(audio->psg.ch2.envelope.nextStep, 0, &state->audio.ch2.envelopeNextStep);
387 /*LOAD_32(audio->psg.ch2.control.nextStep, 0, &state->audio.ch2.waveNextStep);
388 LOAD_32(audio->psg.ch2.control.endTime, 0, &state->audio.ch2.endTime);*/
389 LOAD_32(audio->psg.nextCh2, 0, &state->audio.ch2.nextEvent);
390
391 // TODO: Big endian?
392 memcpy(audio->psg.ch3.wavedata, state->audio.ch3.wavebanks, sizeof(audio->psg.ch3.wavedata));
393 //LOAD_32(audio->psg.ch3.endTime, 0, &state->audio.ch3.endTime);
394 LOAD_32(audio->psg.nextCh3, 0, &state->audio.ch3.nextEvent);
395
396 audio->psg.ch4.envelope.currentVolume = GBASerializedAudioFlagsGetCh4Volume(flags);
397 audio->psg.ch4.envelope.dead = GBASerializedAudioFlagsGetCh4Dead(flags);
398 LOAD_32(audio->psg.ch4.envelope.nextStep, 0, &state->audio.ch4.envelopeNextStep);
399 LOAD_32(audio->psg.ch4.lfsr, 0, &state->audio.ch4.lfsr);
400 //LOAD_32(audio->psg.ch4.endTime, 0, &state->audio.ch4.endTime);
401 LOAD_32(audio->psg.nextCh4, 0, &state->audio.ch4.nextEvent);
402
403 CircleBufferClear(&audio->chA.fifo);
404 CircleBufferClear(&audio->chB.fifo);
405 uint32_t fifoSize;
406 LOAD_32(fifoSize, 0, &state->audio.fifoSize);
407 if (state->audio.fifoSize > CircleBufferCapacity(&audio->chA.fifo)) {
408 fifoSize = CircleBufferCapacity(&audio->chA.fifo);
409 }
410 size_t i;
411 for (i = 0; i < fifoSize; ++i) {
412 CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]);
413 CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]);
414 }
415
416 LOAD_32(audio->nextEvent, 0, &state->audio.nextEvent);
417 LOAD_32(audio->eventDiff, 0, &state->audio.eventDiff);
418 LOAD_32(audio->nextSample, 0, &state->audio.nextSample);
419}
420
421float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) {
422 return desiredSampleRate * GBA_ARM7TDMI_FREQUENCY / (VIDEO_TOTAL_LENGTH * desiredFPS * inputSampleRate);
423}