all repos — mgba @ 4a09d41aabd45f5790567284bfe80a9ab0d5b336

mGBA Game Boy Advance Emulator

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

  1#include "gba-audio.h"
  2
  3#include "gba.h"
  4#include "gba-io.h"
  5
  6const unsigned GBA_AUDIO_SAMPLES = 1024;
  7const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
  8
  9static void _sample(struct GBAAudio* audio);
 10
 11void GBAAudioInit(struct GBAAudio* audio) {
 12	audio->nextEvent = 0;
 13	audio->eventDiff = 0;
 14	audio->nextSample = 0;
 15	audio->sampleRate = 0x8000;
 16	audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
 17
 18	CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t));
 19	CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t));
 20	CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
 21	CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
 22}
 23
 24void GBAAudioDeinit(struct GBAAudio* audio) {
 25	CircleBufferDeinit(&audio->left);
 26	CircleBufferDeinit(&audio->right);
 27	CircleBufferDeinit(&audio->chA.fifo);
 28	CircleBufferDeinit(&audio->chB.fifo);
 29}
 30
 31int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
 32	audio->nextEvent -= cycles;
 33	if (audio->nextEvent <= 0) {
 34		audio->nextSample -= audio->eventDiff;
 35		if (audio->nextSample <= 0) {
 36			_sample(audio);
 37			audio->nextSample += audio->sampleInterval;
 38		}
 39
 40		audio->nextEvent = audio->nextSample;
 41		audio->eventDiff = audio->nextEvent;
 42	}
 43	return audio->nextEvent;
 44}
 45
 46void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
 47	switch (info->dest) {
 48	case BASE_IO | REG_FIFO_A_LO:
 49		audio->chA.dmaSource = number;
 50		break;
 51	case BASE_IO | REG_FIFO_B_LO:
 52		audio->chB.dmaSource = number;
 53		break;
 54	default:
 55		GBALog(audio->p, GBA_LOG_GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
 56		return;
 57	}
 58	info->dstControl = DMA_FIXED;
 59}
 60
 61void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
 62	audio->ch1.sweep.packed = value;
 63}
 64
 65void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
 66	audio->ch1.wave.packed = value;
 67}
 68
 69void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
 70	audio->ch1.control.packed = value;
 71}
 72
 73void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
 74	audio->ch2.wave.packed = value;
 75}
 76
 77void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
 78	audio->ch2.control.packed = value;
 79}
 80
 81void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
 82	audio->ch3.bank.packed = value;
 83}
 84
 85void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
 86	audio->ch3.wave.packed = value;
 87}
 88
 89void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
 90	audio->ch3.control.packed = value;
 91}
 92
 93void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
 94	audio->ch4.wave.packed = value;
 95}
 96
 97void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
 98	audio->ch4.control.packed = value;
 99}
100
101void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
102	audio->soundcntLo = value;
103}
104
105void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {
106	audio->soundcntHi = value;
107}
108
109void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) {
110	audio->soundcntX = (value & 0xF0) | (audio->soundcntX & 0x0F);
111}
112
113void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
114	GBALog(audio->p, GBA_LOG_STUB, "Audio unimplemented");
115}
116
117void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
118	struct CircleBuffer* fifo;
119	switch (address) {
120	case REG_FIFO_A_LO:
121		fifo = &audio->chA.fifo;
122		break;
123	case REG_FIFO_B_LO:
124		fifo = &audio->chB.fifo;
125		break;
126	default:
127		GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", address);
128		return;
129	}
130	while (!CircleBufferWrite32(fifo, value)) {
131		int32_t dummy;
132		CircleBufferRead32(fifo, &dummy);
133	}
134}
135
136void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId) {
137	struct GBAAudioFIFO* channel;
138	if (fifoId == 0) {
139		channel = &audio->chA;
140	} else if (fifoId == 1) {
141		channel = &audio->chB;
142	} else {
143		GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", fifoId);
144		return;
145	}
146	if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t)) {
147		struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
148		dma->nextCount = 4;
149		GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma);
150	}
151	CircleBufferRead8(&channel->fifo, &channel->sample);
152}
153
154static void _sample(struct GBAAudio* audio) {
155	int32_t sampleLeft = 0;
156	int32_t sampleRight = 0;
157
158	if (audio->chALeft) {
159		sampleLeft += audio->chA.sample;
160	}
161
162	if (audio->chARight) {
163		sampleRight += audio->chA.sample;
164	}
165
166	if (audio->chBLeft) {
167		sampleLeft += audio->chB.sample;
168	}
169
170	if (audio->chBRight) {
171		sampleRight += audio->chB.sample;
172	}
173
174	CircleBufferWrite32(&audio->left, sampleLeft);
175	CircleBufferWrite32(&audio->right, sampleRight);
176}