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}