all repos — mgba @ 106685c1cd7624e1ce0aeb378e5fb9459659c658

mGBA Game Boy Advance Emulator

src/gba/extra/audio-mixer.c (view raw)

  1/* Copyright (c) 2013-2017 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/extra/audio-mixer.h>
  7
  8#include <mgba/core/blip_buf.h>
  9#include <mgba/internal/gba/gba.h>
 10#include <mgba/internal/gba/video.h>
 11
 12#define OVERSAMPLE 2
 13
 14static void _mp2kInit(void* cpu, struct mCPUComponent* component);
 15static void _mp2kDeinit(struct mCPUComponent* component);
 16
 17static bool _mp2kEngage(struct GBAAudioMixer* mixer, uint32_t address);
 18static void _mp2kVblank(struct GBAAudioMixer* mixer);
 19static void _mp2kStep(struct GBAAudioMixer* mixer);
 20
 21void GBAAudioMixerCreate(struct GBAAudioMixer* mixer) {
 22	mixer->d.init = _mp2kInit;
 23	mixer->d.deinit = _mp2kDeinit;
 24	mixer->engage = _mp2kEngage;
 25	mixer->vblank = _mp2kVblank;
 26	mixer->step = _mp2kStep;
 27}
 28
 29void _mp2kInit(void* cpu, struct mCPUComponent* component) {
 30	struct ARMCore* arm = cpu;
 31	struct GBA* gba = (struct GBA*) arm->master;
 32	struct GBAAudioMixer* mixer = (struct GBAAudioMixer*) component;
 33	gba->audio.mixer = mixer;
 34	mixer->p = &gba->audio;
 35	mixer->contextAddress = 0;
 36	mixer->tempo = 120.0 / 75.0;
 37	mixer->frame = 0;
 38	mixer->last.left = 0;
 39	mixer->last.right = 0;
 40	memset(&mixer->context, 0, sizeof(mixer->context));
 41	memset(&mixer->activeTracks, 0, sizeof(mixer->activeTracks));
 42
 43	size_t i;
 44	for (i = 0; i < MP2K_MAX_SOUND_CHANNELS; ++i) {
 45		mixer->activeTracks[i].channel = &mixer->context.chans[i];
 46		CircleBufferInit(&mixer->activeTracks[i].buffer, 0x10000);
 47	}
 48}
 49
 50void _mp2kDeinit(struct mCPUComponent* component) {
 51	struct GBAAudioMixer* mixer = (struct GBAAudioMixer*) component;
 52	size_t i;
 53	for (i = 0; i < MP2K_MAX_SOUND_CHANNELS; ++i) {
 54		CircleBufferDeinit(&mixer->activeTracks[i].buffer);
 55	}
 56}
 57
 58static void _loadInstrument(struct ARMCore* cpu, struct GBAMP2kInstrument* instrument, uint32_t base) {
 59	struct ARMMemory* memory = &cpu->memory;
 60	instrument->type = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, type), 0);
 61	instrument->key = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, key), 0);
 62	instrument->length = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, length), 0);
 63	instrument->ps.pan = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, ps.pan), 0);
 64	if (instrument->type == 0x40 || instrument->type == 0x80) {
 65		instrument->data.subTable = memory->load32(cpu, base + offsetof(struct GBAMP2kInstrument, data.subTable), 0);
 66		instrument->extInfo.map = memory->load32(cpu, base + offsetof(struct GBAMP2kInstrument, extInfo.map), 0);
 67	} else {
 68		instrument->data.waveData = memory->load32(cpu, base + offsetof(struct GBAMP2kInstrument, data.waveData), 0);
 69		instrument->extInfo.adsr.attack = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, extInfo.adsr.attack), 0);
 70		instrument->extInfo.adsr.decay = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, extInfo.adsr.decay), 0);
 71		instrument->extInfo.adsr.sustain = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, extInfo.adsr.sustain), 0);
 72		instrument->extInfo.adsr.release = memory->load8(cpu, base + offsetof(struct GBAMP2kInstrument, extInfo.adsr.release), 0);
 73	}
 74}
 75
 76static void _lookupInstrument(struct ARMCore* cpu, struct GBAMP2kInstrument* instrument, uint8_t key) {
 77	struct ARMMemory* memory = &cpu->memory;
 78	if (instrument->type == 0x40) {
 79		uint32_t subInstrumentBase = instrument->data.subTable;
 80		uint32_t keyTable = instrument->extInfo.map;
 81		uint8_t id = memory->load8(cpu, keyTable + key, 0);
 82		subInstrumentBase += 12 * id;
 83		_loadInstrument(cpu, instrument, subInstrumentBase);
 84	}
 85	if (instrument->type == 0x80) {
 86		uint32_t subInstrumentBase = instrument->data.subTable;
 87		subInstrumentBase += 12 * key;
 88		_loadInstrument(cpu, instrument, subInstrumentBase);
 89	}
 90}
 91
 92static void _stepSample(struct GBAAudioMixer* mixer, struct GBAMP2kTrack* track) {
 93	struct ARMCore* cpu = mixer->p->p->cpu;
 94	struct ARMMemory* memory = &cpu->memory;
 95	uint32_t headerAddress;
 96	struct GBAMP2kInstrument instrument = track->track.instrument;
 97
 98	uint8_t note = track->track.key;
 99	_lookupInstrument(cpu, &instrument, note);
100	double freq;
101
102	switch (instrument.type) {
103	case 0x00:
104	case 0x08:
105	case 0x40:
106	case 0x80:
107		freq = GBA_ARM7TDMI_FREQUENCY / (double) track->channel->freq;
108		break;
109	default:
110		// We don't care about PSG channels
111		return;
112	}
113	headerAddress = instrument.data.waveData;
114	if (headerAddress < 0x20) {
115		mLOG(GBA_AUDIO, ERROR, "Audio track has invalid instrument");
116		return;
117	}
118	uint32_t loopOffset = memory->load32(cpu, headerAddress + 0x8, 0);
119	uint32_t endOffset = memory->load32(cpu, headerAddress + 0xC, 0);
120	uint32_t sampleBase = headerAddress + 0x10;
121	uint32_t sampleI = track->samplePlaying;
122	double sampleOffset = track->currentOffset;
123	double updates = VIDEO_TOTAL_LENGTH / (mixer->tempo * mixer->p->sampleInterval / OVERSAMPLE);
124	int nSample;
125	for (nSample = 0; nSample < updates; ++nSample) {
126		int8_t sample = memory->load8(cpu, sampleBase + sampleI, 0);
127
128		struct GBAStereoSample stereo = {
129			(sample * track->channel->leftVolume * track->channel->envelopeV) >> 9,
130			(sample * track->channel->rightVolume * track->channel->envelopeV) >> 9
131		};
132
133		CircleBufferWrite16(&track->buffer, stereo.left);
134		CircleBufferWrite16(&track->buffer, stereo.right);
135
136		sampleOffset += mixer->p->sampleInterval / OVERSAMPLE;
137		while (sampleOffset > freq) {
138			sampleOffset -= freq;
139			++sampleI;
140			if (sampleI >= endOffset) {
141				sampleI = loopOffset;
142			}
143		}
144	}
145
146	track->samplePlaying = sampleI;
147	track->currentOffset = sampleOffset;
148}
149
150static void _mp2kReload(struct GBAAudioMixer* mixer) {
151	struct ARMCore* cpu = mixer->p->p->cpu;
152	struct ARMMemory* memory = &cpu->memory;
153	mixer->context.magic = memory->load32(cpu, mixer->contextAddress + offsetof(struct GBAMP2kContext, magic), 0);
154	int i;
155	for (i = 0; i < MP2K_MAX_SOUND_CHANNELS; ++i) {
156		struct GBAMP2kSoundChannel* ch = &mixer->context.chans[i];
157		struct GBAMP2kTrack* track = &mixer->activeTracks[i];
158		track->waiting = false;
159		uint32_t base = mixer->contextAddress + offsetof(struct GBAMP2kContext, chans[i]);
160
161		ch->status = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, status), 0);
162		ch->type = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, type), 0);
163		ch->rightVolume = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, rightVolume), 0);
164		ch->leftVolume = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, leftVolume), 0);
165		ch->adsr.attack = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, adsr.attack), 0);
166		ch->adsr.decay = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, adsr.decay), 0);
167		ch->adsr.sustain = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, adsr.sustain), 0);
168		ch->adsr.release = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, adsr.release), 0);
169		ch->ky = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, ky), 0);
170		ch->envelopeV = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, envelopeV), 0);
171		ch->envelopeRight = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, envelopeRight), 0);
172		ch->envelopeLeft = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, envelopeLeft), 0);
173		ch->echoVolume = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, echoVolume), 0);
174		ch->echoLength = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, echoLength), 0);
175		ch->d1 = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, d1), 0);
176		ch->d2 = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, d2), 0);
177		ch->gt = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, gt), 0);
178		ch->midiKey = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, midiKey), 0);
179		ch->ve = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, ve), 0);
180		ch->pr = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, pr), 0);
181		ch->rp = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, rp), 0);
182		ch->d3[0] = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, d3[0]), 0);
183		ch->d3[1] = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, d3[1]), 0);
184		ch->d3[2] = memory->load8(cpu, base + offsetof(struct GBAMP2kSoundChannel, d3[2]), 0);
185		ch->ct = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, ct), 0);
186		ch->fw = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, fw), 0);
187		ch->freq = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, freq), 0);
188		ch->waveData = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, waveData), 0);
189		ch->cp = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, cp), 0);
190		ch->track = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, track), 0);
191		ch->pp = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, pp), 0);
192		ch->np = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, np), 0);
193		ch->d4 = memory->load32(cpu, base + offsetof(struct GBAMP2kSoundChannel, d4), 0);
194		ch->xpi = memory->load16(cpu, base + offsetof(struct GBAMP2kSoundChannel, xpi), 0);
195		ch->xpc = memory->load16(cpu, base + offsetof(struct GBAMP2kSoundChannel, xpc), 0);
196
197		base = ch->track;
198		if (base) {
199			track->track.flags = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, flags), 0);
200			track->track.wait = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, wait), 0);
201			track->track.patternLevel = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, patternLevel), 0);
202			track->track.repN = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, repN), 0);
203			track->track.gateTime = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, gateTime), 0);
204			track->track.key = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, key), 0);
205			track->track.velocity = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, velocity), 0);
206			track->track.runningStatus = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, runningStatus), 0);
207			track->track.keyM = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, keyM), 0);
208			track->track.pitM = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, pitM), 0);
209			track->track.keyShift = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, keyShift), 0);
210			track->track.keyShiftX = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, keyShiftX), 0);
211			track->track.tune = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, tune), 0);
212			track->track.pitX = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, pitX), 0);
213			track->track.bend = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, bend), 0);
214			track->track.bendRange = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, bendRange), 0);
215			track->track.volMR = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, volMR), 0);
216			track->track.volML = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, volML), 0);
217			track->track.vol = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, vol), 0);
218			track->track.volX = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, volX), 0);
219			track->track.pan = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, pan), 0);
220			track->track.panX = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, panX), 0);
221			track->track.modM = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, modM), 0);
222			track->track.mod = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, mod), 0);
223			track->track.modT = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, modT), 0);
224			track->track.lfoSpeed = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, lfoSpeed), 0);
225			track->track.lfoSpeedC = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, lfoSpeedC), 0);
226			track->track.lfoDelay = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, lfoDelay), 0);
227			track->track.lfoDelayC = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, lfoDelayC), 0);
228			track->track.priority = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, priority), 0);
229			track->track.echoVolume = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, echoVolume), 0);
230			track->track.echoLength = memory->load8(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, echoLength), 0);
231			track->track.chan = memory->load32(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, chan), 0);
232			_loadInstrument(cpu, &track->track.instrument, base + offsetof(struct GBAMP2kMusicPlayerTrack, instrument));
233			track->track.cmdPtr = memory->load32(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, cmdPtr), 0);
234			track->track.patternStack[0] = memory->load32(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, patternStack[0]), 0);
235			track->track.patternStack[1] = memory->load32(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, patternStack[1]), 0);
236			track->track.patternStack[2] = memory->load32(cpu, base + offsetof(struct GBAMP2kMusicPlayerTrack, patternStack[2]), 0);
237		} else {
238			memset(&track->track, 0, sizeof(track->track));
239		}
240		if (track->track.runningStatus == 0xCD) {
241			// XCMD isn't supported
242			mixer->p->externalMixing = false;
243		}
244	}
245}
246
247bool _mp2kEngage(struct GBAAudioMixer* mixer, uint32_t address) {
248	if (address < BASE_WORKING_RAM) {
249		return false;
250	}
251	if (address != mixer->contextAddress) {
252		mixer->contextAddress = address;
253		mixer->p->externalMixing = true;
254		_mp2kReload(mixer);
255	}
256	return true;
257}
258
259void _mp2kStep(struct GBAAudioMixer* mixer) {
260	mixer->frame += mixer->p->sampleInterval;
261
262	while (mixer->frame >= VIDEO_TOTAL_LENGTH / mixer->tempo) {
263		int i;
264		for (i = 0; i < MP2K_MAX_SOUND_CHANNELS; ++i) {
265			struct GBAMP2kTrack* track = &mixer->activeTracks[i];
266			if (track->channel->status > 0) {
267				_stepSample(mixer, track);
268			} else {
269				track->currentOffset = 0;
270				track->samplePlaying = 0;
271				CircleBufferClear(&track->buffer);
272			}
273		}
274		mixer->frame -= VIDEO_TOTAL_LENGTH / mixer->tempo;
275	}
276
277	uint32_t interval = mixer->p->sampleInterval / OVERSAMPLE;
278	int i;
279	for (i = 0; i < OVERSAMPLE; ++i) {
280		struct GBAStereoSample sample = {0};
281		size_t track;
282		for (track = 0; track < MP2K_MAX_SOUND_CHANNELS; ++track) {
283			if (!mixer->activeTracks[track].channel->status) {
284				continue;
285			}
286			int16_t value;
287			CircleBufferRead16(&mixer->activeTracks[track].buffer, &value);
288			sample.left += value;
289			CircleBufferRead16(&mixer->activeTracks[track].buffer, &value);
290			sample.right += value;
291		}
292		if (mixer->p->externalMixing) {
293			blip_add_delta(mixer->p->psg.left, mixer->p->clock + i * interval, sample.left - mixer->last.left);
294			blip_add_delta(mixer->p->psg.right, mixer->p->clock + i * interval, sample.right - mixer->last.right);
295		}
296		mixer->last = sample;
297	}
298}
299
300void _mp2kVblank(struct GBAAudioMixer* mixer) {
301	if (!mixer->contextAddress) {
302		return;
303	}
304	mLOG(GBA_AUDIO, DEBUG, "Frame");
305	mixer->p->externalMixing = true;
306	_mp2kReload(mixer);
307}