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