src/gba/gba-audio.c (view raw)
1#include "gba-audio.h"
2
3#include "gba.h"
4#include "gba-io.h"
5#include "gba-thread.h"
6
7#include <limits.h>
8
9const unsigned GBA_AUDIO_SAMPLES = 512;
10const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
11
12static int32_t _updateChannel1(struct GBAAudioChannel1* ch);
13static int32_t _updateChannel2(struct GBAAudioChannel2* ch);
14static int32_t _updateChannel3(struct GBAAudioChannel3* ch);
15static int32_t _updateChannel4(struct GBAAudioChannel4* ch);
16static void _sample(struct GBAAudio* audio);
17
18void GBAAudioInit(struct GBAAudio* audio) {
19 audio->nextEvent = 0;
20 audio->nextCh1 = 0;
21 audio->nextCh2 = 0;
22 audio->nextCh3 = 0;
23 audio->nextCh4 = 0;
24 audio->ch4.sample = 0;
25 audio->eventDiff = 0;
26 audio->nextSample = 0;
27 audio->sampleRate = 0x8000;
28 audio->soundcntLo = 0;
29 audio->soundcntHi = 0;
30 audio->sampleInterval = GBA_ARM7TDMI_FREQUENCY / audio->sampleRate;
31
32 CircleBufferInit(&audio->left, GBA_AUDIO_SAMPLES * sizeof(int32_t));
33 CircleBufferInit(&audio->right, GBA_AUDIO_SAMPLES * sizeof(int32_t));
34 CircleBufferInit(&audio->chA.fifo, GBA_AUDIO_FIFO_SIZE);
35 CircleBufferInit(&audio->chB.fifo, GBA_AUDIO_FIFO_SIZE);
36
37 pthread_mutex_init(&audio->bufferMutex, 0);
38}
39
40void GBAAudioDeinit(struct GBAAudio* audio) {
41 CircleBufferDeinit(&audio->left);
42 CircleBufferDeinit(&audio->right);
43 CircleBufferDeinit(&audio->chA.fifo);
44 CircleBufferDeinit(&audio->chB.fifo);
45
46 pthread_mutex_destroy(&audio->bufferMutex);
47}
48
49int32_t GBAAudioProcessEvents(struct GBAAudio* audio, int32_t cycles) {
50 audio->nextEvent -= cycles;
51 if (audio->nextEvent <= 0) {
52 audio->nextEvent = INT_MAX;
53
54 audio->nextCh1 -= audio->eventDiff;
55 audio->nextCh2 -= audio->eventDiff;
56 audio->nextCh3 -= audio->eventDiff;
57 audio->nextCh4 -= audio->eventDiff;
58
59 if ((audio->ch1Right || audio->ch1Left) && audio->nextCh1 <= 0) {
60 audio->nextCh1 += _updateChannel1(&audio->ch1);
61 }
62
63 if ((audio->ch2Right || audio->ch2Left) && audio->nextCh2 <= 0) {
64 audio->nextCh2 += _updateChannel2(&audio->ch2);
65 }
66
67 if ((audio->ch3Right || audio->ch3Left) && audio->nextCh3 <= 0) {
68 audio->nextCh3 += _updateChannel3(&audio->ch3);
69 }
70
71 if ((audio->ch4Right || audio->ch4Left) && audio->nextCh4 <= 0) {
72 audio->nextCh4 += _updateChannel4(&audio->ch4);
73 if (audio->nextCh4 < audio->nextEvent) {
74 audio->nextEvent = audio->nextCh4;
75 }
76 }
77
78 audio->nextSample -= audio->eventDiff;
79 if (audio->nextSample <= 0) {
80 _sample(audio);
81 audio->nextSample += audio->sampleInterval;
82 }
83
84 if (audio->nextSample < audio->nextEvent) {
85 audio->nextEvent = audio->nextSample;
86 }
87 audio->eventDiff = audio->nextEvent;
88 }
89 return audio->nextEvent;
90}
91
92void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA* info) {
93 switch (info->dest) {
94 case BASE_IO | REG_FIFO_A_LO:
95 audio->chA.dmaSource = number;
96 break;
97 case BASE_IO | REG_FIFO_B_LO:
98 audio->chB.dmaSource = number;
99 break;
100 default:
101 GBALog(audio->p, GBA_LOG_GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
102 return;
103 }
104 info->dstControl = DMA_FIXED;
105}
106
107void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
108 audio->ch1.sweep.packed = value;
109}
110
111void GBAAudioWriteSOUND1CNT_HI(struct GBAAudio* audio, uint16_t value) {
112 audio->ch1.envelope.packed = value;
113}
114
115void GBAAudioWriteSOUND1CNT_X(struct GBAAudio* audio, uint16_t value) {
116 audio->ch1.control.packed = value;
117}
118
119void GBAAudioWriteSOUND2CNT_LO(struct GBAAudio* audio, uint16_t value) {
120 audio->ch2.envelope.packed = value;
121}
122
123void GBAAudioWriteSOUND2CNT_HI(struct GBAAudio* audio, uint16_t value) {
124 audio->ch2.control.packed = value;
125}
126
127void GBAAudioWriteSOUND3CNT_LO(struct GBAAudio* audio, uint16_t value) {
128 audio->ch3.bank.packed = value;
129}
130
131void GBAAudioWriteSOUND3CNT_HI(struct GBAAudio* audio, uint16_t value) {
132 audio->ch3.wave.packed = value;
133}
134
135void GBAAudioWriteSOUND3CNT_X(struct GBAAudio* audio, uint16_t value) {
136 audio->ch3.control.packed = value;
137}
138
139void GBAAudioWriteSOUND4CNT_LO(struct GBAAudio* audio, uint16_t value) {
140 audio->ch4.envelope.packed = value;
141}
142
143void GBAAudioWriteSOUND4CNT_HI(struct GBAAudio* audio, uint16_t value) {
144 audio->ch4.control.packed = value;
145 if (audio->ch4.control.restart) {
146 if (audio->ch4.control.power) {
147 audio->ch4.lfsr = 0x40;
148 } else {
149 audio->ch4.lfsr = 0x4000;
150 }
151 audio->nextCh4 = 0;
152 }
153}
154
155void GBAAudioWriteSOUNDCNT_LO(struct GBAAudio* audio, uint16_t value) {
156 audio->soundcntLo = value;
157}
158
159void GBAAudioWriteSOUNDCNT_HI(struct GBAAudio* audio, uint16_t value) {
160 audio->soundcntHi = value;
161}
162
163void GBAAudioWriteSOUNDCNT_X(struct GBAAudio* audio, uint16_t value) {
164 audio->soundcntX = (value & 0xF0) | (audio->soundcntX & 0x0F);
165}
166
167void GBAAudioWriteWaveRAM(struct GBAAudio* audio, int address, uint32_t value) {
168 GBALog(audio->p, GBA_LOG_STUB, "Audio unimplemented");
169}
170
171void GBAAudioWriteFIFO(struct GBAAudio* audio, int address, uint32_t value) {
172 struct CircleBuffer* fifo;
173 switch (address) {
174 case REG_FIFO_A_LO:
175 fifo = &audio->chA.fifo;
176 break;
177 case REG_FIFO_B_LO:
178 fifo = &audio->chB.fifo;
179 break;
180 default:
181 GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", address);
182 return;
183 }
184 while (!CircleBufferWrite32(fifo, value)) {
185 int32_t dummy;
186 CircleBufferRead32(fifo, &dummy);
187 }
188}
189
190void GBAAudioSampleFIFO(struct GBAAudio* audio, int fifoId) {
191 struct GBAAudioFIFO* channel;
192 if (fifoId == 0) {
193 channel = &audio->chA;
194 } else if (fifoId == 1) {
195 channel = &audio->chB;
196 } else {
197 GBALog(audio->p, GBA_LOG_ERROR, "Bad FIFO write to address 0x%03x", fifoId);
198 return;
199 }
200 if (CircleBufferSize(&channel->fifo) <= 4 * sizeof(int32_t)) {
201 struct GBADMA* dma = &audio->p->memory.dma[channel->dmaSource];
202 dma->nextCount = 4;
203 GBAMemoryServiceDMA(&audio->p->memory, channel->dmaSource, dma);
204 }
205 CircleBufferRead8(&channel->fifo, &channel->sample);
206}
207
208static int32_t _updateChannel1(struct GBAAudioChannel1* ch) {
209 return INT_MAX / 4;
210}
211
212static int32_t _updateChannel2(struct GBAAudioChannel2* ch) {
213 return INT_MAX / 4;
214}
215
216static int32_t _updateChannel3(struct GBAAudioChannel3* ch) {
217 return INT_MAX / 4;
218}
219
220static int32_t _updateChannel4(struct GBAAudioChannel4* ch) {
221 int lsb = ch->lfsr & 1;
222 ch->sample = lsb * 0xFF - 0x80;
223 ch->lfsr >>= 1;
224 ch->lfsr ^= (lsb * 0x60) << (ch->control.power ? 0 : 8);
225 int timing = ch->control.ratio ? 2 * ch->control.ratio : 1;
226 timing <<= ch->control.frequency;
227 timing *= 32;
228 return timing;
229}
230
231static void _sample(struct GBAAudio* audio) {
232 int32_t sampleLeft = 0;
233 int32_t sampleRight = 0;
234 int psgShift = 2 - audio->volume;
235
236 if (audio->ch4Left) {
237 sampleLeft += audio->ch4.sample >> psgShift;
238 }
239
240 if (audio->ch4Right) {
241 sampleRight += audio->ch4.sample >> psgShift;
242 }
243
244 if (audio->chALeft) {
245 sampleLeft += audio->chA.sample >> audio->volumeChA;
246 }
247
248 if (audio->chARight) {
249 sampleRight += audio->chA.sample >> audio->volumeChA;
250 }
251
252 if (audio->chBLeft) {
253 sampleLeft += audio->chB.sample >> audio->volumeChB;
254 }
255
256 if (audio->chBRight) {
257 sampleRight += audio->chB.sample >> audio->volumeChB;
258 }
259
260 pthread_mutex_lock(&audio->bufferMutex);
261 while (CircleBufferSize(&audio->left) + (GBA_AUDIO_SAMPLES * 2 / 5) >= audio->left.capacity) {
262 if (!audio->p->sync->audioWait) {
263 break;
264 }
265 GBASyncProduceAudio(audio->p->sync, &audio->bufferMutex);
266 }
267 CircleBufferWrite32(&audio->left, sampleLeft);
268 CircleBufferWrite32(&audio->right, sampleRight);
269 pthread_mutex_unlock(&audio->bufferMutex);
270}