Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/audio/synthesis_sh.c
7857 views
1
#ifdef VERSION_SH
2
#include <ultra64.h>
3
4
#include "synthesis.h"
5
#include "heap.h"
6
#include "data.h"
7
#include "load.h"
8
#include "seqplayer.h"
9
#include "internal.h"
10
#include "external.h"
11
12
#ifndef TARGET_N64
13
#include "../pc/mixer.h"
14
#endif
15
16
17
#define DMEM_ADDR_TEMP 0x450
18
#define DMEM_ADDR_RESAMPLED 0x470
19
#define DMEM_ADDR_RESAMPLED2 0x5f0
20
#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x5f0
21
#define DMEM_ADDR_NOTE_PAN_TEMP 0x650
22
#define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x990
23
#define DMEM_ADDR_LEFT_CH 0x990
24
#define DMEM_ADDR_RIGHT_CH 0xb10
25
#define DMEM_ADDR_WET_LEFT_CH 0xc90
26
#define DMEM_ADDR_WET_RIGHT_CH 0xe10
27
28
#define aSetLoadBufferPair(pkt, c, off) \
29
aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c); \
30
aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \
31
aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_RIGHT_CH, 0, DEFAULT_LEN_1CH - c); \
32
aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)))
33
34
#define aSetSaveBufferPair(pkt, c, d, off) \
35
aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_LEFT_CH, d); \
36
aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \
37
aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d); \
38
aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)));
39
40
#define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
41
42
struct VolumeChange {
43
u16 sourceLeft;
44
u16 sourceRight;
45
u16 targetLeft;
46
u16 targetRight;
47
};
48
49
u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
50
u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
51
u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad);
52
u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags);
53
u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags);
54
u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight);
55
56
struct SynthesisReverb gSynthesisReverbs[4];
57
u8 sAudioSynthesisPad[0x10];
58
59
s16 gVolume;
60
s8 gUseReverb;
61
s8 gNumSynthesisReverbs;
62
s16 D_SH_803479B4; // contains 4096
63
struct NoteSubEu *gNoteSubsEu;
64
65
// Equivalent functionality as the US/JP version,
66
// just that the reverb structure is chosen from an array with index
67
// Identical in EU.
68
void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) {
69
struct ReverbRingBufferItem *item;
70
struct SynthesisReverb *reverb = &gSynthesisReverbs[reverbIndex];
71
s32 srcPos;
72
s32 dstPos;
73
s32 nSamples;
74
s32 excessiveSamples;
75
s32 UNUSED pad[3];
76
if (reverb->downsampleRate != 1) {
77
if (reverb->framesLeftToIgnore == 0) {
78
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
79
// samples.
80
item = &reverb->items[reverb->curFrame][updateIndex];
81
82
// Touches both left and right since they are adjacent in memory
83
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
84
85
for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
86
srcPos += reverb->downsampleRate, dstPos++) {
87
reverb->ringBuffer.left[item->startPos + dstPos] =
88
item->toDownsampleLeft[srcPos];
89
reverb->ringBuffer.right[item->startPos + dstPos] =
90
item->toDownsampleRight[srcPos];
91
}
92
for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) {
93
reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
94
reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
95
}
96
}
97
}
98
99
item = &reverb->items[reverb->curFrame][updateIndex];
100
nSamples = chunkLen / reverb->downsampleRate;
101
excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel;
102
if (excessiveSamples < 0) {
103
// There is space in the ring buffer before it wraps around
104
item->lengthA = nSamples * 2;
105
item->lengthB = 0;
106
item->startPos = (s32) reverb->nextRingBufferPos;
107
reverb->nextRingBufferPos += nSamples;
108
} else {
109
// Ring buffer wrapped around
110
item->lengthA = (nSamples - excessiveSamples) * 2;
111
item->lengthB = excessiveSamples * 2;
112
item->startPos = reverb->nextRingBufferPos;
113
reverb->nextRingBufferPos = excessiveSamples;
114
}
115
// These fields are never read later
116
item->numSamplesAfterDownsampling = nSamples;
117
item->chunkLen = chunkLen;
118
}
119
120
u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) {
121
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]),
122
addr, len);
123
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]),
124
addr + DEFAULT_LEN_1CH, len);
125
return cmd;
126
}
127
128
u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) {
129
aSaveBuffer(cmd++, addr,
130
VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]), len);
131
aSaveBuffer(cmd++, addr + DEFAULT_LEN_1CH,
132
VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]), len);
133
return cmd;
134
}
135
136
void func_sh_802ed644(s32 updateIndexStart, s32 noteIndex) {
137
s32 i;
138
139
for (i = updateIndexStart + 1; i < gAudioBufferParameters.updatesPerFrame; i++) {
140
if (!gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].needsInit) {
141
gNoteSubsEu[gMaxSimultaneousNotes * i + noteIndex].enabled = FALSE;
142
} else {
143
break;
144
}
145
}
146
}
147
148
void synthesis_load_note_subs_eu(s32 updateIndex) {
149
struct NoteSubEu *src;
150
struct NoteSubEu *dest;
151
s32 i;
152
153
for (i = 0; i < gMaxSimultaneousNotes; i++) {
154
src = &gNotes[i].noteSubEu;
155
dest = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
156
if (src->enabled) {
157
*dest = *src;
158
src->needsInit = FALSE;
159
} else {
160
dest->enabled = FALSE;
161
}
162
}
163
}
164
165
// TODO: (Scrub C) pointless mask and whitespace
166
u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
167
s32 i, j;
168
u32 *aiBufPtr;
169
u64 *cmd = cmdBuf;
170
s32 chunkLen;
171
172
for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
173
process_sequences(i - 1);
174
synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i);
175
}
176
aiBufPtr = (u32 *) aiBuf;
177
for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
178
if (i == 1) {
179
chunkLen = bufLen;
180
} else {
181
if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) {
182
chunkLen = gAudioBufferParameters.samplesPerUpdateMax;
183
} else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) {
184
chunkLen = gAudioBufferParameters.samplesPerUpdateMin;
185
} else {
186
chunkLen = gAudioBufferParameters.samplesPerUpdate;
187
}
188
}
189
for (j = 0; j < gNumSynthesisReverbs; j++) {
190
if (gSynthesisReverbs[j].useReverb != 0) {
191
prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
192
}
193
}
194
cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioBufferParameters.updatesPerFrame - i);
195
bufLen -= chunkLen;
196
aiBufPtr += chunkLen;
197
}
198
199
for (j = 0; j < gNumSynthesisReverbs; j++) {
200
if (gSynthesisReverbs[j].framesLeftToIgnore != 0) {
201
gSynthesisReverbs[j].framesLeftToIgnore--;
202
}
203
gSynthesisReverbs[j].curFrame ^= 1;
204
}
205
*writtenCmds = cmd - cmdBuf;
206
return cmd;
207
}
208
209
u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) {
210
struct ReverbRingBufferItem *item;
211
s16 startPad;
212
s16 paddedLengthA;
213
214
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
215
216
if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) {
217
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
218
if (item->lengthB != 0) {
219
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
220
}
221
aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
222
aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
223
} else {
224
startPad = (item->startPos % 8u) * 2;
225
paddedLengthA = ALIGN(startPad + item->lengthA, 4);
226
227
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex);
228
if (item->lengthB != 0) {
229
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex);
230
}
231
232
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
233
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft));
234
235
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
236
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight));
237
238
aAddMixer(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
239
aMix(cmd++, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
240
}
241
if (gSynthesisReverbs[reverbIndex].panRight != 0 || gSynthesisReverbs[reverbIndex].panLeft != 0) {
242
// Leak some audio from the left reverb channel into the right reverb channel and vice versa (pan)
243
aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_1CH);
244
aMix(cmd++, gSynthesisReverbs[reverbIndex].panRight, DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_1CH);
245
aMix(cmd++, gSynthesisReverbs[reverbIndex].panLeft, DMEM_ADDR_RESAMPLED, DMEM_ADDR_WET_RIGHT_CH, DEFAULT_LEN_1CH);
246
}
247
return cmd;
248
}
249
250
u64 *synthesis_load_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
251
struct ReverbRingBufferItem *item;
252
struct SynthesisReverb *reverb;
253
254
reverb = &gSynthesisReverbs[reverbIndex];
255
item = &reverb->items[reverb->curFrame][updateIndex];
256
// Get the oldest samples in the ring buffer into the wet channels
257
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex);
258
if (item->lengthB != 0) {
259
// Ring buffer wrapped
260
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex);
261
}
262
return cmd;
263
}
264
265
u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
266
struct ReverbRingBufferItem *item;
267
268
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
269
switch (gSynthesisReverbs[reverbIndex].downsampleRate) {
270
case 1:
271
// Put the oldest samples in the ring buffer into the wet channels
272
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
273
if (item->lengthB != 0) {
274
// Ring buffer wrapped
275
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
276
}
277
break;
278
279
default:
280
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
281
// buffering. Left and right buffers are adjacent in memory.
282
aSaveBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH,
283
VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft), DEFAULT_LEN_2CH);
284
break;
285
}
286
gSynthesisReverbs[reverbIndex].resampleFlags = 0;
287
return cmd;
288
}
289
290
u64 *func_sh_802EDF24(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
291
struct ReverbRingBufferItem *item;
292
struct SynthesisReverb *reverb;
293
294
reverb = &gSynthesisReverbs[reverbIndex];
295
item = &reverb->items[reverb->curFrame][updateIndex];
296
// Put the oldest samples in the ring buffer into the wet channels
297
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, item->startPos, item->lengthA, reverbIndex);
298
if (item->lengthB != 0) {
299
// Ring buffer wrapped
300
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + item->lengthA, 0, item->lengthB, reverbIndex);
301
}
302
return cmd;
303
}
304
305
u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
306
struct NoteSubEu *noteSubEu;
307
u8 noteIndices[56];
308
s32 temp;
309
s32 i;
310
s16 j;
311
s16 notePos = 0;
312
313
if (gNumSynthesisReverbs == 0) {
314
for (i = 0; i < gMaxSimultaneousNotes; i++) {
315
if (gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i].enabled) {
316
noteIndices[notePos++] = i;
317
}
318
}
319
} else {
320
for (j = 0; j < gNumSynthesisReverbs; j++) {
321
for (i = 0; i < gMaxSimultaneousNotes; i++) {
322
noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
323
if (noteSubEu->enabled && j == noteSubEu->reverbIndex) {
324
noteIndices[notePos++] = i;
325
}
326
}
327
}
328
329
for (i = 0; i < gMaxSimultaneousNotes; i++) {
330
noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
331
if (noteSubEu->enabled && noteSubEu->reverbIndex >= gNumSynthesisReverbs) {
332
noteIndices[notePos++] = i;
333
}
334
}
335
}
336
aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
337
i = 0;
338
for (j = 0; j < gNumSynthesisReverbs; j++) {
339
gUseReverb = gSynthesisReverbs[j].useReverb;
340
if (gUseReverb != 0) {
341
cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
342
}
343
for (; i < notePos; i++) {
344
temp = updateIndex * gMaxSimultaneousNotes;
345
if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) {
346
cmd = synthesis_process_note(noteIndices[i],
347
&gNoteSubsEu[temp + noteIndices[i]],
348
&gNotes[noteIndices[i]].synthesisState,
349
aiBuf, bufLen, cmd, updateIndex);
350
continue;
351
} else {
352
break;
353
}
354
}
355
if (gSynthesisReverbs[j].useReverb != 0) {
356
if (gSynthesisReverbs[j].unk100 != NULL) {
357
aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk100);
358
aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_LEFT_CH, gSynthesisReverbs[j].unk108);
359
}
360
if (gSynthesisReverbs[j].unk104 != NULL) {
361
aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk104);
362
aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_RIGHT_CH, gSynthesisReverbs[j].unk10C);
363
}
364
cmd = synthesis_save_reverb_samples(cmd, j, updateIndex);
365
if (gSynthesisReverbs[j].unk5 != -1) {
366
if (gSynthesisReverbs[gSynthesisReverbs[j].unk5].downsampleRate == 1) {
367
cmd = synthesis_load_reverb_samples(cmd, gSynthesisReverbs[j].unk5, updateIndex);
368
aMix(cmd++, gSynthesisReverbs[j].unk08, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_RESAMPLED, DEFAULT_LEN_2CH);
369
cmd = func_sh_802EDF24(cmd++, gSynthesisReverbs[j].unk5, updateIndex);
370
}
371
}
372
}
373
}
374
for (; i < notePos; i++) {
375
struct NoteSubEu *noteSubEu2 = &gNoteSubsEu[updateIndex * gMaxSimultaneousNotes + noteIndices[i]];
376
cmd = synthesis_process_note(noteIndices[i],
377
noteSubEu2,
378
&gNotes[noteIndices[i]].synthesisState,
379
aiBuf, bufLen, cmd, updateIndex);
380
}
381
382
temp = bufLen * 2;
383
aInterleave(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH, temp);
384
aSaveBuffer(cmd++, DMEM_ADDR_TEMP, VIRTUAL_TO_PHYSICAL2(aiBuf), temp * 2);
385
return cmd;
386
}
387
388
u64 *synthesis_process_note(s32 noteIndex, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
389
UNUSED s32 pad0[3];
390
struct AudioBankSample *audioBookSample; // sp164, sp138
391
struct AdpcmLoop *loopInfo; // sp160, sp134
392
s16 *curLoadedBook; // sp154, sp130
393
UNUSED u8 padEU[0x04];
394
UNUSED u8 pad8[0x04];
395
s32 noteFinished; // 150 t2, sp124
396
s32 restart; // 14c t3, sp120
397
s32 flags; // sp148, sp11C, t8
398
u16 resamplingRateFixedPoint; // sp5c, sp11A
399
s32 nSamplesToLoad; //s0, Ec
400
UNUSED u8 pad7[0x0c]; // sp100
401
s32 sp130; //sp128, sp104
402
UNUSED s32 tempBufLen;
403
UNUSED u32 pad9;
404
s32 t0;
405
u8 *sampleAddr; // sp120, spF4
406
s32 s6;
407
s32 samplesLenAdjusted; // 108, spEC
408
s32 nAdpcmSamplesProcessed; // signed required for US // spc0
409
s32 endPos; // sp110, spE4
410
s32 nSamplesToProcess; // sp10c/a0, spE0
411
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
412
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
413
UNUSED s32 samplesLenInt;
414
s32 s2;
415
s32 leftRight; //s0
416
s32 s5; //s4
417
u32 samplesLenFixedPoint; // v1_1
418
s32 s3; // spA0
419
s32 nSamplesInThisIteration; // v1_2
420
u32 a3;
421
u8 *v0_2;
422
s32 unk_s6; // sp90
423
s32 s5Aligned;
424
s32 sp88;
425
s32 sp84;
426
u32 temp;
427
s32 nParts; // spE8, spBC
428
s32 curPart; // spE4, spB8
429
s32 aligned;
430
UNUSED u32 padSH1;
431
s32 resampledTempLen; // spD8, spAC, sp6c
432
u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA, sp6a -- 6C
433
UNUSED u32 padSH2;
434
UNUSED u32 padSH3;
435
UNUSED u32 padSH4;
436
struct Note *note; // sp58
437
u16 sp56; // sp56
438
u16 addr;
439
u8 synthesisVolume;
440
441
curLoadedBook = NULL;
442
note = &gNotes[noteIndex];
443
flags = 0;
444
if (noteSubEu->needsInit == TRUE) {
445
flags = A_INIT;
446
synthesisState->restart = 0;
447
synthesisState->samplePosInt = 0;
448
synthesisState->samplePosFrac = 0;
449
synthesisState->curVolLeft = 0;
450
synthesisState->curVolRight = 0;
451
synthesisState->prevHeadsetPanRight = 0;
452
synthesisState->prevHeadsetPanLeft = 0;
453
synthesisState->reverbVol = noteSubEu->reverbVol;
454
synthesisState->unk5 = 0;
455
note->noteSubEu.finished = 0;
456
}
457
458
resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
459
nParts = noteSubEu->hasTwoAdpcmParts + 1;
460
samplesLenFixedPoint = (resamplingRateFixedPoint * bufLen * 2) + synthesisState->samplePosFrac;
461
nSamplesToLoad = (samplesLenFixedPoint >> 0x10);
462
synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
463
464
if ((synthesisState->unk5 == 1) && (nParts == 2)) {
465
nSamplesToLoad += 2;
466
sp56 = 2;
467
} else if ((synthesisState->unk5 == 2) && (nParts == 1)) {
468
nSamplesToLoad -= 4;
469
sp56 = 4;
470
} else {
471
sp56 = 0;
472
}
473
474
475
synthesisState->unk5 = nParts;
476
477
if (noteSubEu->isSyntheticWave) {
478
cmd = load_wave_samples(cmd, noteSubEu, synthesisState, nSamplesToLoad);
479
noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE;
480
synthesisState->samplePosInt += nSamplesToLoad;
481
} else {
482
// ADPCM note
483
audioBookSample = noteSubEu->sound.audioBankSound->sample;
484
loopInfo = audioBookSample->loop;
485
endPos = loopInfo->end;
486
sampleAddr = audioBookSample->sampleAddr;
487
resampledTempLen = 0;
488
for (curPart = 0; curPart < nParts; curPart++) {
489
nAdpcmSamplesProcessed = 0; // s8
490
s5 = 0; // s4
491
492
if (nParts == 1) {
493
samplesLenAdjusted = nSamplesToLoad;
494
} else if (nSamplesToLoad & 1) {
495
samplesLenAdjusted = (nSamplesToLoad & ~1) + (curPart * 2);
496
} else {
497
samplesLenAdjusted = nSamplesToLoad;
498
}
499
500
if (audioBookSample->codec == CODEC_ADPCM) {
501
if (curLoadedBook != (*audioBookSample->book).book) {
502
u32 nEntries;
503
switch (noteSubEu->bookOffset) {
504
case 1:
505
curLoadedBook = euUnknownData_80301950 + 1;
506
break;
507
case 2:
508
curLoadedBook = euUnknownData_80301950 + 2;
509
break;
510
case 3:
511
default:
512
curLoadedBook = audioBookSample->book->book;
513
break;
514
}
515
nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors;
516
aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook));
517
}
518
}
519
520
while (nAdpcmSamplesProcessed != samplesLenAdjusted) {
521
s32 samplesRemaining; // v1
522
s32 s0;
523
524
noteFinished = FALSE;
525
restart = FALSE;
526
s2 = synthesisState->samplePosInt & 0xf;
527
samplesRemaining = endPos - synthesisState->samplePosInt;
528
nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed;
529
530
if (s2 == 0 && synthesisState->restart == FALSE) {
531
s2 = 16;
532
}
533
s6 = 16 - s2; // a1
534
if (nSamplesToProcess < samplesRemaining) {
535
t0 = (nSamplesToProcess - s6 + 0xf) / 16;
536
s0 = t0 * 16;
537
s3 = s6 + s0 - nSamplesToProcess;
538
} else {
539
s0 = samplesRemaining - s6;
540
s3 = 0;
541
if (s0 <= 0) {
542
s0 = 0;
543
s6 = samplesRemaining;
544
}
545
t0 = (s0 + 0xf) / 16;
546
if (loopInfo->count != 0) {
547
// Loop around and restart
548
restart = 1;
549
} else {
550
noteFinished = 1;
551
}
552
}
553
switch (audioBookSample->codec) {
554
case CODEC_ADPCM:
555
unk_s6 = 9;
556
sp88 = 0x10;
557
sp84 = 0;
558
break;
559
case CODEC_S8:
560
unk_s6 = 0x10;
561
sp88 = 0x10;
562
sp84 = 0;
563
break;
564
case CODEC_SKIP: goto skip;
565
}
566
if (t0 != 0) {
567
temp = (synthesisState->samplePosInt + sp88 - s2) / 16;
568
if (audioBookSample->medium == 0) {
569
v0_2 = sp84 + (temp * unk_s6) + sampleAddr;
570
} else {
571
v0_2 = dma_sample_data((uintptr_t)(sp84 + (temp * unk_s6) + sampleAddr),
572
ALIGN(t0 * unk_s6 + 16, 4), flags, &synthesisState->sampleDmaIndex, audioBookSample->medium);
573
}
574
575
a3 = ((uintptr_t)v0_2 & 0xf);
576
aligned = ALIGN(t0 * unk_s6 + 16, 4);
577
addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
578
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3), addr, ALIGN(t0 * unk_s6 + 16, 4));
579
} else {
580
s0 = 0;
581
a3 = 0;
582
}
583
if (synthesisState->restart != FALSE) {
584
aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
585
flags = A_LOOP; // = 2
586
synthesisState->restart = FALSE;
587
}
588
nSamplesInThisIteration = s0 + s6 - s3;
589
if (nAdpcmSamplesProcessed == 0) {
590
switch (audioBookSample->codec) {
591
case CODEC_ADPCM:
592
aligned = ALIGN(t0 * unk_s6 + 16, 4);
593
addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
594
aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
595
aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
596
break;
597
case CODEC_S8:
598
aligned = ALIGN(t0 * unk_s6 + 16, 4);
599
addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
600
aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
601
aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
602
break;
603
}
604
sp130 = s2 * 2;
605
} else {
606
s5Aligned = ALIGN(s5 + 16, 4);
607
switch (audioBookSample->codec) {
608
case CODEC_ADPCM:
609
aligned = ALIGN(t0 * unk_s6 + 16, 4);
610
addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
611
aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
612
aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
613
break;
614
case CODEC_S8:
615
aligned = ALIGN(t0 * unk_s6 + 16, 4);
616
addr = (DMEM_ADDR_COMPRESSED_ADPCM_DATA - aligned) & 0xffff;
617
aSetBuffer(cmd++, 0, addr + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
618
aS8Dec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
619
break;
620
}
621
aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
622
}
623
nAdpcmSamplesProcessed += nSamplesInThisIteration;
624
switch (flags) {
625
case A_INIT: // = 1
626
sp130 = 0x20;
627
s5 = (s0 + 0x10) * 2;
628
break;
629
case A_LOOP: // = 2
630
s5 = (nSamplesInThisIteration) * 2 + s5;
631
break;
632
default:
633
if (s5 != 0) {
634
s5 = (nSamplesInThisIteration) * 2 + s5;
635
} else {
636
s5 = (s2 + (nSamplesInThisIteration)) * 2;
637
}
638
break;
639
}
640
flags = 0;
641
skip:
642
if (noteFinished) {
643
aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5,
644
(samplesLenAdjusted - nAdpcmSamplesProcessed) * 2);
645
noteSubEu->finished = 1;
646
note->noteSubEu.finished = 1;
647
func_sh_802ed644(updateIndex, noteIndex);
648
break;
649
}
650
if (restart != 0) {
651
synthesisState->restart = TRUE;
652
synthesisState->samplePosInt = loopInfo->start;
653
} else {
654
synthesisState->samplePosInt += nSamplesToProcess;
655
}
656
}
657
658
switch (nParts) {
659
case 1:
660
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130;
661
break;
662
case 2:
663
switch (curPart) {
664
case 0:
665
aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED);
666
resampledTempLen = samplesLenAdjusted;
667
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED;
668
if (noteSubEu->finished != FALSE) {
669
aClearBuffer(cmd++, noteSamplesDmemAddrBeforeResampling + resampledTempLen, samplesLenAdjusted + 0x10);
670
}
671
break;
672
case 1:
673
aDownsampleHalf(cmd++, ALIGN(samplesLenAdjusted / 2, 3), DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, resampledTempLen + DMEM_ADDR_RESAMPLED);
674
break;
675
}
676
}
677
if (noteSubEu->finished != FALSE) {
678
break;
679
}
680
}
681
}
682
flags = 0;
683
if (noteSubEu->needsInit == TRUE) {
684
flags = A_INIT;
685
noteSubEu->needsInit = FALSE;
686
}
687
flags = flags | sp56;
688
cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint,
689
noteSamplesDmemAddrBeforeResampling, flags);
690
if ((flags & 1) != 0) {
691
flags = 1;
692
}
693
694
if (noteSubEu->filter) {
695
aFilter(cmd++, 0x02, bufLen * 2, noteSubEu->filter);
696
aFilter(cmd++, flags, DMEM_ADDR_TEMP, synthesisState->synthesisBuffers->filterBuffer);
697
698
}
699
700
if (noteSubEu->bookOffset == 3) {
701
aUnknown25(cmd++, 0, bufLen * 2, DMEM_ADDR_TEMP, DMEM_ADDR_TEMP);
702
}
703
704
synthesisVolume = noteSubEu->synthesisVolume;
705
if (synthesisVolume != 0) {
706
if (synthesisVolume < 0x10) {
707
synthesisVolume = 0x10;
708
}
709
710
aHiLoGain(cmd++, synthesisVolume, (bufLen + 0x10) * 2, DMEM_ADDR_TEMP);
711
}
712
713
if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) {
714
leftRight = 1;
715
} else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) {
716
leftRight = 2;
717
} else {
718
leftRight = 0;
719
}
720
cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, DMEM_ADDR_TEMP, leftRight, flags);
721
if (noteSubEu->usesHeadsetPanEffects) {
722
if ((flags & 1) == 0) {
723
flags = 0;
724
}
725
cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight);
726
}
727
728
return cmd;
729
}
730
731
u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) {
732
s32 a3;
733
s32 repeats;
734
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples),
735
DMEM_ADDR_UNCOMPRESSED_NOTE, 128);
736
737
synthesisState->samplePosInt &= 0x3f;
738
a3 = 64 - synthesisState->samplePosInt;
739
if (a3 < nSamplesToLoad) {
740
repeats = (nSamplesToLoad - a3 + 63) / 64;
741
if (repeats != 0) {
742
aDuplicate(cmd++,
743
/*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE,
744
/*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + 128,
745
/*copies*/ repeats);
746
}
747
}
748
return cmd;
749
}
750
751
u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
752
if (pitch == 0) {
753
aClearBuffer(cmd++, DMEM_ADDR_TEMP, count);
754
} else {
755
aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
756
aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState));
757
}
758
return cmd;
759
}
760
761
u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) {
762
u16 sourceRight;
763
u16 sourceLeft;
764
u16 targetLeft;
765
u16 targetRight;
766
s16 rampLeft;
767
s16 rampRight;
768
s32 sourceReverbVol;
769
s16 rampReverb;
770
s32 reverbVolDiff = 0;
771
772
sourceLeft = synthesisState->curVolLeft;
773
sourceRight = synthesisState->curVolRight;
774
targetLeft = note->targetVolLeft;
775
targetRight = note->targetVolRight;
776
targetLeft <<= 4;
777
targetRight <<= 4;
778
779
if (targetLeft != sourceLeft) {
780
rampLeft = (targetLeft - sourceLeft) / (nSamples >> 3);
781
} else {
782
rampLeft = 0;
783
}
784
if (targetRight != sourceRight) {
785
rampRight = (targetRight - sourceRight) / (nSamples >> 3);
786
} else {
787
rampRight = 0;
788
}
789
790
sourceReverbVol = synthesisState->reverbVol;
791
if (note->reverbVol != sourceReverbVol) {
792
reverbVolDiff = ((note->reverbVol & 0x7f) - (sourceReverbVol & 0x7f)) << 9;
793
rampReverb = reverbVolDiff / (nSamples >> 3);
794
synthesisState->reverbVol = note->reverbVol;
795
} else {
796
rampReverb = 0;
797
}
798
synthesisState->curVolLeft = sourceLeft + rampLeft * (nSamples >> 3);
799
synthesisState->curVolRight = sourceRight + rampRight * (nSamples >> 3);
800
801
if (note->usesHeadsetPanEffects) {
802
aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH);
803
aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight);
804
aEnvSetup2(cmd++, sourceLeft, sourceRight);
805
806
switch (headsetPanSettings) {
807
case 1:
808
aEnvMixer(cmd++,
809
inBuf, nSamples,
810
(sourceReverbVol & 0x80) >> 7,
811
note->stereoStrongRight, note->stereoStrongLeft,
812
DMEM_ADDR_NOTE_PAN_TEMP,
813
DMEM_ADDR_RIGHT_CH,
814
DMEM_ADDR_WET_LEFT_CH,
815
DMEM_ADDR_WET_RIGHT_CH);
816
break;
817
case 2:
818
aEnvMixer(cmd++,
819
inBuf, nSamples,
820
(sourceReverbVol & 0x80) >> 7,
821
note->stereoStrongRight, note->stereoStrongLeft,
822
DMEM_ADDR_LEFT_CH,
823
DMEM_ADDR_NOTE_PAN_TEMP,
824
DMEM_ADDR_WET_LEFT_CH,
825
DMEM_ADDR_WET_RIGHT_CH);
826
break;
827
default:
828
aEnvMixer(cmd++,
829
inBuf, nSamples,
830
(sourceReverbVol & 0x80) >> 7,
831
note->stereoStrongRight, note->stereoStrongLeft,
832
DMEM_ADDR_LEFT_CH,
833
DMEM_ADDR_RIGHT_CH,
834
DMEM_ADDR_WET_LEFT_CH,
835
DMEM_ADDR_WET_RIGHT_CH);
836
break;
837
}
838
} else {
839
aEnvSetup1(cmd++, (sourceReverbVol & 0x7f) * 2, rampReverb, rampLeft, rampRight);
840
aEnvSetup2(cmd++, sourceLeft, sourceRight);
841
aEnvMixer(cmd++,
842
inBuf, nSamples,
843
(sourceReverbVol & 0x80) >> 7,
844
note->stereoStrongRight, note->stereoStrongLeft,
845
DMEM_ADDR_LEFT_CH,
846
DMEM_ADDR_RIGHT_CH,
847
DMEM_ADDR_WET_LEFT_CH,
848
DMEM_ADDR_WET_RIGHT_CH);
849
}
850
return cmd;
851
}
852
853
u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) {
854
u16 dest;
855
u16 pitch;
856
u8 prevPanShift;
857
u8 panShift;
858
UNUSED u8 unkDebug;
859
860
switch (leftRight) {
861
case 1:
862
dest = DMEM_ADDR_LEFT_CH;
863
panShift = noteSubEu->headsetPanRight;
864
note->prevHeadsetPanLeft = 0;
865
prevPanShift = note->prevHeadsetPanRight;
866
note->prevHeadsetPanRight = panShift;
867
break;
868
case 2:
869
dest = DMEM_ADDR_RIGHT_CH;
870
panShift = noteSubEu->headsetPanLeft;
871
note->prevHeadsetPanRight = 0;
872
873
prevPanShift = note->prevHeadsetPanLeft;
874
note->prevHeadsetPanLeft = panShift;
875
break;
876
default:
877
return cmd;
878
}
879
880
if (flags != 1) { // A_INIT?
881
// Slightly adjust the sample rate in order to fit a change in pan shift
882
if (panShift != prevPanShift) {
883
pitch = (((bufLen << 0xf) / 2) - 1) / ((bufLen + panShift - prevPanShift - 2) / 2);
884
aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, (bufLen + panShift) - prevPanShift);
885
aResampleZoh(cmd++, pitch, 0);
886
} else {
887
aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
888
}
889
890
if (prevPanShift != 0) {
891
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer),
892
DMEM_ADDR_NOTE_PAN_TEMP, ALIGN(prevPanShift, 4));
893
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, bufLen + panShift - prevPanShift);
894
} else {
895
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, bufLen + panShift);
896
}
897
} else {
898
// Just shift right
899
aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
900
aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift);
901
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen);
902
}
903
904
if (panShift) {
905
// Save excessive samples for next iteration
906
aSaveBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP + bufLen,
907
VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer), ALIGN(panShift, 4));
908
}
909
910
aAddMixer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, dest, (bufLen + 0x3f) & 0xffc0);
911
912
return cmd;
913
}
914
#endif
915
916