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