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 <mgba/internal/gba/audio.h>
7
8#include <mgba/internal/arm/macros.h>
9#include <mgba/core/blip_buf.h>
10#include <mgba/core/sync.h>
11#include <mgba/internal/gba/dma.h>
12#include <mgba/internal/gba/gba.h>
13#include <mgba/internal/gba/io.h>
14#include <mgba/internal/gba/serialize.h>
15#include <mgba/internal/gba/video.h>
16
17#ifdef _3DS
18#define blip_add_delta blip_add_delta_fast
19#endif
20
21mLOG_DEFINE_CATEGORY(GBA_AUDIO, "GBA Audio", "gba.audio");
22
23const unsigned GBA_AUDIO_SAMPLES = 2048;
24const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
25const int GBA_AUDIO_VOLUME_MAX = 0x100;
26
27static const int CLOCKS_PER_FRAME = 0x400;
28
29static int _applyBias(struct GBAAudio* audio, int sample);
30static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate);
31
32void GBAAudioInit(struct GBAAudio* audio, size_t samples) {
33 audio->sampleEvent.context = audio;
34 audio->sampleEvent.name = "GBA Audio Sample";
35 audio->sampleEvent.callback = _sample;
36 audio->sampleEvent.priority = 0x18;
37 audio->psg.p = NULL;
38 uint8_t* nr52 = (uint8_t*) &audio->p->memory.io[REG_SOUNDCNT_X >> 1];
39#ifdef __BIG_ENDIAN__
40 ++nr52;
41#endif
42 GBAudioInit(&audio->psg, 0, nr52, GB_AUDIO_GBA);
43 audio->psg.timing = &audio->p->timing;
44 audio->psg.clockRate = GBA_ARM7TDMI_FREQUENCY;
45 audio->samples = samples;
46 // Guess too large; we hang producing extra samples if we guess too low
47 blip_set_rates(audio->psg.left, GBA_ARM7TDMI_FREQUENCY, 96000);
48 blip_set_rates(audio->psg.right, GBA_ARM7TDMI_FREQUENCY, 96000);
49 CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
50 CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
51
52 audio->forceDisableChA = false;
53 audio->forceDisableChB = false;
54 audio->masterVolume = GBA_AUDIO_VOLUME_MAX;
55}
56
57void GBAAudioReset(struct GBAAudio* audio) {
58 GBAudioReset(&audio->psg);
59 mTimingDeschedule(&audio->p->timing, &audio->sampleEvent);
60 mTimingSchedule(&audio->p->timing, &audio->sampleEvent, 0);
61 audio->chA.dmaSource = 1;
62 audio->chB.dmaSource = 2;
63 audio->chA.sample = 0;
64 audio->chB.sample = 0;
65 audio->sampleRate = 0x8000;
66 audio->soundbias = 0x200;
67 audio->volume = 0;
68 audio->volumeChA = false;
69 audio->volumeChB = false;
70 audio->chARight = false;
71 audio->chALeft = false;
72 audio->chATimer = false;
73 audio->chBRight = false;
74 audio->chBLeft = false;
75 audio->chBTimer = false;
76 audio->enable = false;
77 audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
78 audio->psg.sampleInterval = audio->sampleInterval;
79
80 blip_clear(audio->psg.left);
81 blip_clear(audio->psg.right);
82 audio->clock = 0;
83 CircleBufferClear(&audio->chA.fifo);
84 CircleBufferClear(&audio->chB.fifo);
85}
86
87void GBAAudioDeinit(struct GBAAudio* audio) {
88 GBAudioDeinit(&audio->psg);
89 CircleBufferDeinit(&audio->chA.fifo);
90 CircleBufferDeinit(&audio->chB.fifo);
91}
92
93void GBAAudioResizeBuffer(struct GBAAudio* audio, size_t samples) {
94 mCoreSyncLockAudio(audio->p->sync);
95 audio->samples = samples;
96 blip_clear(audio->psg.left);
97 blip_clear(audio->psg.right);
98 audio->clock = 0;
99 mCoreSyncConsumeAudio(audio->p->sync);
100}
101
102void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
103 switch (info->dest) {
104 case BASE_IO | REG_FIFO_A_LO:
105 audio->chA.dmaSource = number;
106 break;
107 case BASE_IO | REG_FIFO_B_LO:
108 audio->chB.dmaSource = number;
109 break;
110 default:
111 mLOG(GBA_AUDIO, GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
112 return;
113 }
114 info->reg = GBADMARegisterSetDestControl(info->reg, GBA_DMA_FIXED);
115 info->reg = GBADMARegisterSetWidth(info->reg, 1);
116}
117
118void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
119 GBAudioWriteNR10(&audio->psg, value);
120}
121
122void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
123 GBAudioWriteNR11(&audio->psg, value);
124 GBAudioWriteNR12(&audio->psg, value >> 8);
125}
126
127void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
128 GBAudioWriteNR13(&audio->psg, value);
129 GBAudioWriteNR14(&audio->psg, value >> 8);
130}
131
132void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
133 GBAudioWriteNR21(&audio->psg, value);
134 GBAudioWriteNR22(&audio->psg, value >> 8);
135}
136
137void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
138 GBAudioWriteNR23(&audio->psg, value);
139 GBAudioWriteNR24(&audio->psg, value >> 8);
140}
141
142void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
143 audio->psg.ch3.size = GBAudioRegisterBankGetSize(value);
144 audio->psg.ch3.bank = GBAudioRegisterBankGetBank(value);
145 GBAudioWriteNR30(&audio->psg, value);
146}
147
148void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
149 GBAudioWriteNR31(&audio->psg, value);
150 audio->psg.ch3.volume = GBAudioRegisterBankVolumeGetVolumeGBA(value >> 8);
151}
152
153void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
154 GBAudioWriteNR33(&audio->psg, value);
155 GBAudioWriteNR34(&audio->psg, value >> 8);
156}
157
158void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
159 GBAudioWriteNR41(&audio->psg, value);
160 GBAudioWriteNR42(&audio->psg, value >> 8);
161}
162
163void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
164 GBAudioWriteNR43(&audio->psg, value);
165 GBAudioWriteNR44(&audio->psg, value >> 8);
166}
167
168void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
169 GBAudioWriteNR50(&audio->psg, value);
170 GBAudioWriteNR51(&audio->psg, value >> 8);
171}
172
173void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {
174 audio->volume = GBARegisterSOUNDCNT_HIGetVolume(value);
175 audio->volumeChA = GBARegisterSOUNDCNT_HIGetVolumeChA(value);
176 audio->volumeChB = GBARegisterSOUNDCNT_HIGetVolumeChB(value);
177 audio->chARight = GBARegisterSOUNDCNT_HIGetChARight(value);
178 audio->chALeft = GBARegisterSOUNDCNT_HIGetChALeft(value);
179 audio->chATimer = GBARegisterSOUNDCNT_HIGetChATimer(value);
180 audio->chBRight = GBARegisterSOUNDCNT_HIGetChBRight(value);
181 audio->chBLeft = GBARegisterSOUNDCNT_HIGetChBLeft(value);
182 audio->chBTimer = GBARegisterSOUNDCNT_HIGetChBTimer(value);
183 if (GBARegisterSOUNDCNT_HIIsChAReset(value)) {
184 CircleBufferClear(&audio->chA.fifo);
185 }
186 if (GBARegisterSOUNDCNT_HIIsChBReset(value)) {
187 CircleBufferClear(&audio->chB.fifo);
188 }
189}
190
191void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) {
192 audio->enable = GBAudioEnableGetEnable(value);
193 GBAudioWriteNR52(&audio->psg, value);
194}
195
196void GBAAudioWriteSOUNDBIAS(struct GBAAudio* audio, uint16_t value) {
197 audio->soundbias = value;
198}
199
200void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
201 audio->psg.ch3.wavedata32[address | (!audio->psg.ch3.bank * 4)] = value;
202}
203
204void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
205 struct CircleBuffer* fifo;
206 switch (address) {
207 case REG_FIFO_A_LO:
208 fifo = &audio->chA.fifo;
209 break;
210 case REG_FIFO_B_LO:
211 fifo = &audio->chB.fifo;
212 break;
213 default:
214 mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", address);
215 return;
216 }
217 int i;
218 for (i = 0; i < 4; ++i) {
219 while (!CircleBufferWrite8(fifo, value >> (8 * i))) {
220 int8_t dummy;
221 CircleBufferRead8(fifo, &dummy);
222 }
223 }
224}
225
226void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId, int32_t cycles) {
227 struct GBAAudioFIFO* channel;
228 if (fifoId == 0) {
229 channel = &audio->chA;
230 } else if (fifoId == 1) {
231 channel = &audio->chB;
232 } else {
233 mLOG(GBA_AUDIO, ERROR, "Bad FIFO write to address 0x%03x", fifoId);
234 return;
235 }
236 if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t) && channel->dmaSource > 0) {
237 struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
238 if (GBADMARegisterGetTiming(dma->reg) == GBA_DMA_TIMING_CUSTOM) {
239 dma->when = mTimingCurrentTime(&audio->p->timing) - cycles;
240 dma->nextCount = 4;
241 GBADMASchedule(audio->p, channel->dmaSource, dma);
242 } else {
243 channel->dmaSource = 0;
244 }
245 }
246 CircleBufferRead8(&channel->fifo, (int8_t*) &channel->sample);
247}
248
249static int _applyBias(struct GBAAudio* audio, int sample) {
250 sample += GBARegisterSOUNDBIASGetBias(audio->soundbias);
251 if (sample >= 0x400) {
252 sample = 0x3FF;
253 } else if (sample < 0) {
254 sample = 0;
255 }
256 return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume) >> 3;
257}
258
259static void _sample(struct mTiming* timing, void* user, uint32_t cyclesLate) {
260 struct GBAAudio* audio = user;
261 int16_t sampleLeft = 0;
262 int16_t sampleRight = 0;
263 int psgShift = 4 - audio->volume;
264 GBAudioSamplePSG(&audio->psg, &sampleLeft, &sampleRight);
265 sampleLeft >>= psgShift;
266 sampleRight >>= psgShift;
267
268 if (!audio->forceDisableChA) {
269 if (audio->chALeft) {
270 sampleLeft += (audio->chA.sample << 2) >> !audio->volumeChA;
271 }
272
273 if (audio->chARight) {
274 sampleRight += (audio->chA.sample << 2) >> !audio->volumeChA;
275 }
276 }
277
278 if (!audio->forceDisableChB) {
279 if (audio->chBLeft) {
280 sampleLeft += (audio->chB.sample << 2) >> !audio->volumeChB;
281 }
282
283 if (audio->chBRight) {
284 sampleRight += (audio->chB.sample << 2) >> !audio->volumeChB;
285 }
286 }
287
288 sampleLeft = _applyBias(audio, sampleLeft);
289 sampleRight = _applyBias(audio, sampleRight);
290
291 mCoreSyncLockAudio(audio->p->sync);
292 unsigned produced;
293 if ((size_t) blip_samples_avail(audio->psg.left) < audio->samples) {
294 blip_add_delta(audio->psg.left, audio->clock, sampleLeft - audio->lastLeft);
295 blip_add_delta(audio->psg.right, audio->clock, sampleRight - audio->lastRight);
296 audio->lastLeft = sampleLeft;
297 audio->lastRight = sampleRight;
298 audio->clock += audio->sampleInterval;
299 if (audio->clock >= CLOCKS_PER_FRAME) {
300 blip_end_frame(audio->psg.left, CLOCKS_PER_FRAME);
301 blip_end_frame(audio->psg.right, CLOCKS_PER_FRAME);
302 audio->clock -= CLOCKS_PER_FRAME;
303 }
304 }
305 produced = blip_samples_avail(audio->psg.left);
306 if (audio->p->stream && audio->p->stream->postAudioFrame) {
307 audio->p->stream->postAudioFrame(audio->p->stream, sampleLeft, sampleRight);
308 }
309 bool wait = produced >= audio->samples;
310 mCoreSyncProduceAudio(audio->p->sync, wait);
311
312 if (wait && audio->p->stream && audio->p->stream->postAudioBuffer) {
313 audio->p->stream->postAudioBuffer(audio->p->stream, audio->psg.left, audio->psg.right);
314 }
315
316 mTimingSchedule(timing, &audio->sampleEvent, audio->sampleInterval - cyclesLate);
317}
318
319void GBAAudioSerialize(const struct GBAAudio* audio, struct GBASerializedState* state) {
320 GBAudioPSGSerialize(&audio->psg, &state->audio.psg, &state->audio.flags);
321
322 CircleBufferDump(&audio->chA.fifo, state->audio.fifoA, sizeof(state->audio.fifoA));
323 CircleBufferDump(&audio->chB.fifo, state->audio.fifoB, sizeof(state->audio.fifoB));
324 uint32_t fifoSize = CircleBufferSize(&audio->chA.fifo);
325 STORE_32(fifoSize, 0, &state->audio.fifoSize);
326 STORE_32(audio->sampleEvent.when - mTimingCurrentTime(&audio->p->timing), 0, &state->audio.nextSample);
327}
328
329void GBAAudioDeserialize(struct GBAAudio* audio, const struct GBASerializedState* state) {
330 GBAudioPSGDeserialize(&audio->psg, &state->audio.psg, &state->audio.flags);
331
332 CircleBufferClear(&audio->chA.fifo);
333 CircleBufferClear(&audio->chB.fifo);
334 uint32_t fifoSize;
335 LOAD_32(fifoSize, 0, &state->audio.fifoSize);
336 if (state->audio.fifoSize > CircleBufferCapacity(&audio->chA.fifo)) {
337 fifoSize = CircleBufferCapacity(&audio->chA.fifo);
338 }
339 size_t i;
340 for (i = 0; i < fifoSize; ++i) {
341 CircleBufferWrite8(&audio->chA.fifo, state->audio.fifoA[i]);
342 CircleBufferWrite8(&audio->chB.fifo, state->audio.fifoB[i]);
343 }
344
345 uint32_t when;
346 LOAD_32(when, 0, &state->audio.nextSample);
347 mTimingSchedule(&audio->p->timing, &audio->sampleEvent, when);
348}
349
350float GBAAudioCalculateRatio(float inputSampleRate, float desiredFPS, float desiredSampleRate) {
351 return desiredSampleRate * GBA_ARM7TDMI_FREQUENCY / (VIDEO_TOTAL_LENGTH * desiredFPS * inputSampleRate);
352}