all repos — mgba @ 0a52f44fa822539200f5ae6aad1fe5f5a6a3ab0e

mGBA Game Boy Advance Emulator

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