Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/audio/synthesis.c
7857 views
1
#ifndef 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
#include "game/game_init.h"
13
14
#ifndef TARGET_N64
15
#include "../pc/mixer.h"
16
#endif
17
18
#define DMEM_ADDR_TEMP 0x0
19
#define DMEM_ADDR_RESAMPLED 0x20
20
#define DMEM_ADDR_RESAMPLED2 0x160
21
#define DMEM_ADDR_UNCOMPRESSED_NOTE 0x180
22
#define DMEM_ADDR_NOTE_PAN_TEMP 0x200
23
#define DMEM_ADDR_STEREO_STRONG_TEMP_DRY 0x200
24
#define DMEM_ADDR_STEREO_STRONG_TEMP_WET 0x340
25
#define DMEM_ADDR_COMPRESSED_ADPCM_DATA 0x3f0
26
#define DMEM_ADDR_LEFT_CH 0x4c0
27
#define DMEM_ADDR_RIGHT_CH 0x600
28
#define DMEM_ADDR_WET_LEFT_CH 0x740
29
#define DMEM_ADDR_WET_RIGHT_CH 0x880
30
31
#define aSetLoadBufferPair(pkt, c, off) \
32
aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_LEFT_CH, 0, DEFAULT_LEN_1CH - c); \
33
aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \
34
aSetBuffer(pkt, 0, c + DMEM_ADDR_WET_RIGHT_CH, 0, DEFAULT_LEN_1CH - c); \
35
aLoadBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)))
36
37
#define aSetSaveBufferPair(pkt, c, d, off) \
38
aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_LEFT_CH, d); \
39
aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.left + (off))); \
40
aSetBuffer(pkt, 0, 0, c + DMEM_ADDR_WET_RIGHT_CH, d); \
41
aSaveBuffer(pkt, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.ringBuffer.right + (off)));
42
43
#define ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
44
45
struct VolumeChange {
46
u16 sourceLeft;
47
u16 sourceRight;
48
u16 targetLeft;
49
u16 targetRight;
50
};
51
52
u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex);
53
#ifdef VERSION_EU
54
u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s16 *aiBuf, s32 bufLen, u64 *cmd);
55
u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad);
56
u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags);
57
u64 *process_envelope(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, u32 flags);
58
u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight);
59
#else
60
u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd);
61
u64 *load_wave_samples(u64 *cmd, struct Note *note, s32 nSamplesToLoad);
62
u64 *final_resample(u64 *cmd, struct Note *note, s32 count, u16 pitch, u16 dmemIn, u32 flags);
63
u64 *process_envelope(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf, s32 headsetPanSettings,
64
u32 flags);
65
u64 *process_envelope_inner(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf,
66
s32 headsetPanSettings, struct VolumeChange *vol);
67
u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight);
68
#endif
69
70
#ifdef VERSION_EU
71
struct SynthesisReverb gSynthesisReverbs[4];
72
u8 sAudioSynthesisPad[0x10];
73
#else
74
struct SynthesisReverb gSynthesisReverb;
75
u8 sAudioSynthesisPad[0x20];
76
#endif
77
78
#ifdef VERSION_EU
79
s16 gVolume;
80
s8 gUseReverb;
81
s8 gNumSynthesisReverbs;
82
struct NoteSubEu *gNoteSubsEu;
83
#endif
84
85
#ifdef VERSION_EU
86
f32 gLeftVolRampings[3][1024];
87
f32 gRightVolRampings[3][1024];
88
f32 *gCurrentLeftVolRamping; // Points to any of the three left buffers above
89
f32 *gCurrentRightVolRamping; // Points to any of the three right buffers above
90
91
u8 audioString1[] = "pitch %x: delaybytes %d : olddelay %d\n";
92
u8 audioString2[] = "cont %x: delaybytes %d : olddelay %d\n";
93
#endif
94
95
#ifdef VERSION_EU
96
// Equivalent functionality as the US/JP version,
97
// just that the reverb structure is chosen from an array with index
98
void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex, s32 reverbIndex) {
99
struct ReverbRingBufferItem *item;
100
struct SynthesisReverb *reverb = &gSynthesisReverbs[reverbIndex];
101
s32 srcPos;
102
s32 dstPos;
103
s32 nSamples;
104
s32 excessiveSamples;
105
s32 UNUSED pad[3];
106
if (reverb->downsampleRate != 1) {
107
if (reverb->framesLeftToIgnore == 0) {
108
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
109
// samples.
110
item = &reverb->items[reverb->curFrame][updateIndex];
111
112
// Touches both left and right since they are adjacent in memory
113
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
114
115
for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
116
srcPos += reverb->downsampleRate, dstPos++) {
117
reverb->ringBuffer.left[item->startPos + dstPos] =
118
item->toDownsampleLeft[srcPos];
119
reverb->ringBuffer.right[item->startPos + dstPos] =
120
item->toDownsampleRight[srcPos];
121
}
122
for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += reverb->downsampleRate, dstPos++) {
123
reverb->ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
124
reverb->ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
125
}
126
}
127
}
128
129
item = &reverb->items[reverb->curFrame][updateIndex];
130
nSamples = chunkLen / reverb->downsampleRate;
131
excessiveSamples = (nSamples + reverb->nextRingBufferPos) - reverb->bufSizePerChannel;
132
if (excessiveSamples < 0) {
133
// There is space in the ring buffer before it wraps around
134
item->lengthA = nSamples * 2;
135
item->lengthB = 0;
136
item->startPos = (s32) reverb->nextRingBufferPos;
137
reverb->nextRingBufferPos += nSamples;
138
} else {
139
// Ring buffer wrapped around
140
item->lengthA = (nSamples - excessiveSamples) * 2;
141
item->lengthB = excessiveSamples * 2;
142
item->startPos = reverb->nextRingBufferPos;
143
reverb->nextRingBufferPos = excessiveSamples;
144
}
145
// These fields are never read later
146
item->numSamplesAfterDownsampling = nSamples;
147
item->chunkLen = chunkLen;
148
}
149
#else
150
void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
151
struct ReverbRingBufferItem *item;
152
s32 srcPos;
153
s32 dstPos;
154
s32 nSamples;
155
s32 numSamplesAfterDownsampling;
156
s32 excessiveSamples;
157
if (gReverbDownsampleRate != 1) {
158
if (gSynthesisReverb.framesLeftToIgnore == 0) {
159
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
160
// samples.
161
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
162
163
// Touches both left and right since they are adjacent in memory
164
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
165
166
for (srcPos = 0, dstPos = 0; dstPos < item->lengthA / 2;
167
srcPos += gReverbDownsampleRate, dstPos++) {
168
gSynthesisReverb.ringBuffer.left[dstPos + item->startPos] =
169
item->toDownsampleLeft[srcPos];
170
gSynthesisReverb.ringBuffer.right[dstPos + item->startPos] =
171
item->toDownsampleRight[srcPos];
172
}
173
for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) {
174
gSynthesisReverb.ringBuffer.left[dstPos] = item->toDownsampleLeft[srcPos];
175
gSynthesisReverb.ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
176
}
177
}
178
}
179
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
180
181
numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate;
182
if (((numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel) < 0) {
183
// There is space in the ring buffer before it wraps around
184
item->lengthA = numSamplesAfterDownsampling * 2;
185
item->lengthB = 0;
186
item->startPos = (s32) gSynthesisReverb.nextRingBufferPos;
187
gSynthesisReverb.nextRingBufferPos += numSamplesAfterDownsampling;
188
} else {
189
// Ring buffer wrapped around
190
excessiveSamples =
191
(numSamplesAfterDownsampling + gSynthesisReverb.nextRingBufferPos) - gSynthesisReverb.bufSizePerChannel;
192
nSamples = numSamplesAfterDownsampling - excessiveSamples;
193
item->lengthA = nSamples * 2;
194
item->lengthB = excessiveSamples * 2;
195
item->startPos = gSynthesisReverb.nextRingBufferPos;
196
gSynthesisReverb.nextRingBufferPos = excessiveSamples;
197
}
198
// These fields are never read later
199
item->numSamplesAfterDownsampling = numSamplesAfterDownsampling;
200
item->chunkLen = chunkLen;
201
}
202
#endif
203
204
#ifdef VERSION_EU
205
u64 *synthesis_load_reverb_ring_buffer(u64 *cmd, u16 addr, u16 srcOffset, s32 len, s32 reverbIndex) {
206
aSetBuffer(cmd++, 0, addr, 0, len);
207
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[srcOffset]));
208
209
aSetBuffer(cmd++, 0, addr + DEFAULT_LEN_1CH, 0, len);
210
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[srcOffset]));
211
212
return cmd;
213
}
214
#endif
215
216
#ifdef VERSION_EU
217
u64 *synthesis_save_reverb_ring_buffer(u64 *cmd, u16 addr, u16 destOffset, s32 len, s32 reverbIndex) {
218
aSetBuffer(cmd++, 0, 0, addr, len);
219
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.left[destOffset]));
220
221
aSetBuffer(cmd++, 0, 0, addr + DEFAULT_LEN_1CH, len);
222
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(&gSynthesisReverbs[reverbIndex].ringBuffer.right[destOffset]));
223
224
return cmd;
225
}
226
#endif
227
228
#ifdef VERSION_EU
229
void synthesis_load_note_subs_eu(s32 updateIndex) {
230
struct NoteSubEu *src;
231
struct NoteSubEu *dest;
232
s32 i;
233
234
for (i = 0; i < gMaxSimultaneousNotes; i++) {
235
src = &gNotes[i].noteSubEu;
236
dest = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
237
if (src->enabled) {
238
*dest = *src;
239
src->needsInit = FALSE;
240
} else {
241
dest->enabled = FALSE;
242
}
243
}
244
}
245
#endif
246
247
#ifndef VERSION_EU
248
s32 get_volume_ramping(u16 sourceVol, u16 targetVol, s32 arg2) {
249
// This roughly computes 2^16 * (targetVol / sourceVol) ^ (8 / arg2),
250
// but with discretizations of targetVol, sourceVol and arg2.
251
f32 ret;
252
switch (arg2) {
253
default:
254
ret = gVolRampingLhs136[targetVol >> 8] * gVolRampingRhs136[sourceVol >> 8];
255
break;
256
case 128:
257
ret = gVolRampingLhs128[targetVol >> 8] * gVolRampingRhs128[sourceVol >> 8];
258
break;
259
case 136:
260
ret = gVolRampingLhs136[targetVol >> 8] * gVolRampingRhs136[sourceVol >> 8];
261
break;
262
case 144:
263
ret = gVolRampingLhs144[targetVol >> 8] * gVolRampingRhs144[sourceVol >> 8];
264
break;
265
}
266
return ret;
267
}
268
#endif
269
270
#ifdef VERSION_EU
271
// TODO: (Scrub C) pointless mask and whitespace
272
u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
273
s32 i, j;
274
f32 *leftVolRamp;
275
f32 *rightVolRamp;
276
u32 *aiBufPtr;
277
u64 *cmd = cmdBuf;
278
s32 chunkLen;
279
s32 nextVolRampTable;
280
281
for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
282
process_sequences(i - 1);
283
synthesis_load_note_subs_eu(gAudioBufferParameters.updatesPerFrame - i);
284
}
285
aSegment(cmd++, 0, 0);
286
aiBufPtr = (u32 *) aiBuf;
287
for (i = gAudioBufferParameters.updatesPerFrame; i > 0; i--) {
288
if (i == 1) {
289
#pragma GCC diagnostic push
290
#if defined(__clang__)
291
#pragma GCC diagnostic ignored "-Wself-assign"
292
#endif
293
// self-assignment has no affect when added here, could possibly simplify a macro definition
294
chunkLen = bufLen; nextVolRampTable = nextVolRampTable; leftVolRamp = gLeftVolRampings[nextVolRampTable]; rightVolRamp = gRightVolRampings[nextVolRampTable & 0xFFFFFFFF];
295
#pragma GCC diagnostic pop
296
} else {
297
if (bufLen / i >= gAudioBufferParameters.samplesPerUpdateMax) {
298
chunkLen = gAudioBufferParameters.samplesPerUpdateMax; nextVolRampTable = 2; leftVolRamp = gLeftVolRampings[2]; rightVolRamp = gRightVolRampings[2];
299
} else if (bufLen / i <= gAudioBufferParameters.samplesPerUpdateMin) {
300
chunkLen = gAudioBufferParameters.samplesPerUpdateMin; nextVolRampTable = 0; leftVolRamp = gLeftVolRampings[0]; rightVolRamp = gRightVolRampings[0];
301
} else {
302
chunkLen = gAudioBufferParameters.samplesPerUpdate; nextVolRampTable = 1; leftVolRamp = gLeftVolRampings[1]; rightVolRamp = gRightVolRampings[1];
303
}
304
}
305
gCurrentLeftVolRamping = leftVolRamp;
306
gCurrentRightVolRamping = rightVolRamp;
307
for (j = 0; j < gNumSynthesisReverbs; j++) {
308
if (gSynthesisReverbs[j].useReverb != 0) {
309
prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
310
}
311
}
312
cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioBufferParameters.updatesPerFrame - i);
313
bufLen -= chunkLen;
314
aiBufPtr += chunkLen;
315
}
316
317
for (j = 0; j < gNumSynthesisReverbs; j++) {
318
if (gSynthesisReverbs[j].framesLeftToIgnore != 0) {
319
gSynthesisReverbs[j].framesLeftToIgnore--;
320
}
321
gSynthesisReverbs[j].curFrame ^= 1;
322
}
323
*writtenCmds = cmd - cmdBuf;
324
return cmd;
325
}
326
#else
327
// bufLen will be divisible by 16
328
u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
329
s32 chunkLen;
330
s32 i;
331
u32 *aiBufPtr = (u32 *) aiBuf;
332
u64 *cmd = cmdBuf + 1;
333
s32 v0;
334
335
aSegment(cmdBuf, 0, 0);
336
337
for (i = gAudioUpdatesPerFrame; i > 0; i--) {
338
if (i == 1) {
339
// 'bufLen' will automatically be divisible by 8, no need to round
340
chunkLen = bufLen;
341
} else {
342
v0 = bufLen / i;
343
// chunkLen = v0 rounded to nearest multiple of 8
344
chunkLen = v0 - (v0 & 7);
345
346
if ((v0 & 7) >= 4) {
347
chunkLen += 8;
348
}
349
}
350
process_sequences(i - 1);
351
if (gSynthesisReverb.useReverb != 0) {
352
prepare_reverb_ring_buffer(chunkLen, gAudioUpdatesPerFrame - i);
353
}
354
cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioUpdatesPerFrame - i);
355
bufLen -= chunkLen;
356
aiBufPtr += chunkLen;
357
}
358
if (gSynthesisReverb.framesLeftToIgnore != 0) {
359
gSynthesisReverb.framesLeftToIgnore--;
360
}
361
gSynthesisReverb.curFrame ^= 1;
362
*writtenCmds = cmd - cmdBuf;
363
return cmd;
364
}
365
#endif
366
367
368
#ifdef VERSION_EU
369
u64 *synthesis_resample_and_mix_reverb(u64 *cmd, s32 bufLen, s16 reverbIndex, s16 updateIndex) {
370
struct ReverbRingBufferItem *item;
371
s16 startPad;
372
s16 paddedLengthA;
373
374
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
375
376
aClearBuffer(cmd++, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
377
if (gSynthesisReverbs[reverbIndex].downsampleRate == 1) {
378
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
379
if (item->lengthB != 0) {
380
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
381
}
382
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
383
aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH);
384
aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH);
385
} else {
386
startPad = (item->startPos % 8u) * 2;
387
paddedLengthA = ALIGN(startPad + item->lengthA, 4);
388
389
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED, (item->startPos - startPad / 2), DEFAULT_LEN_1CH, reverbIndex);
390
if (item->lengthB != 0) {
391
cmd = synthesis_load_reverb_ring_buffer(cmd, DMEM_ADDR_RESAMPLED + paddedLengthA, 0, DEFAULT_LEN_1CH - paddedLengthA, reverbIndex);
392
}
393
394
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED + startPad, DMEM_ADDR_WET_LEFT_CH, bufLen * 2);
395
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateLeft));
396
397
aSetBuffer(cmd++, 0, DMEM_ADDR_RESAMPLED2 + startPad, DMEM_ADDR_WET_RIGHT_CH, bufLen * 2);
398
aResample(cmd++, gSynthesisReverbs[reverbIndex].resampleFlags, gSynthesisReverbs[reverbIndex].resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].resampleStateRight));
399
400
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
401
aMix(cmd++, 0, 0x7fff, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH);
402
aMix(cmd++, 0, 0x8000 + gSynthesisReverbs[reverbIndex].reverbGain, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_LEFT_CH);
403
}
404
return cmd;
405
}
406
407
u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
408
struct ReverbRingBufferItem *item;
409
410
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
411
if (gSynthesisReverbs[reverbIndex].useReverb != 0) {
412
switch (gSynthesisReverbs[reverbIndex].downsampleRate) {
413
case 1:
414
// Put the oldest samples in the ring buffer into the wet channels
415
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH, item->startPos, item->lengthA, reverbIndex);
416
if (item->lengthB != 0) {
417
// Ring buffer wrapped
418
cmd = synthesis_save_reverb_ring_buffer(cmd, DMEM_ADDR_WET_LEFT_CH + item->lengthA, 0, item->lengthB, reverbIndex);
419
}
420
break;
421
422
default:
423
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
424
// buffering. Left and right buffers are adjacent in memory.
425
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
426
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex].toDownsampleLeft));
427
gSynthesisReverbs[reverbIndex].resampleFlags = 0;
428
break;
429
}
430
}
431
return cmd;
432
}
433
#endif
434
435
#ifdef VERSION_EU
436
u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
437
struct NoteSubEu *noteSubEu;
438
u8 noteIndices[56];
439
s32 temp;
440
s32 i;
441
s16 j;
442
s16 notePos = 0;
443
444
if (gNumSynthesisReverbs == 0) {
445
for (i = 0; i < gMaxSimultaneousNotes; i++) {
446
if (gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i].enabled) {
447
noteIndices[notePos++] = i;
448
}
449
}
450
} else {
451
for (j = 0; j < gNumSynthesisReverbs; j++) {
452
for (i = 0; i < gMaxSimultaneousNotes; i++) {
453
noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
454
if (noteSubEu->enabled && j == noteSubEu->reverbIndex) {
455
noteIndices[notePos++] = i;
456
}
457
}
458
}
459
460
for (i = 0; i < gMaxSimultaneousNotes; i++) {
461
noteSubEu = &gNoteSubsEu[gMaxSimultaneousNotes * updateIndex + i];
462
if (noteSubEu->enabled && noteSubEu->reverbIndex >= gNumSynthesisReverbs) {
463
noteIndices[notePos++] = i;
464
}
465
}
466
}
467
aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
468
i = 0;
469
for (j = 0; j < gNumSynthesisReverbs; j++) {
470
gUseReverb = gSynthesisReverbs[j].useReverb;
471
if (gUseReverb != 0) {
472
cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
473
}
474
for (; i < notePos; i++) {
475
temp = updateIndex * gMaxSimultaneousNotes;
476
if (j == gNoteSubsEu[temp + noteIndices[i]].reverbIndex) {
477
cmd = synthesis_process_note(&gNotes[noteIndices[i]],
478
&gNoteSubsEu[temp + noteIndices[i]],
479
&gNotes[noteIndices[i]].synthesisState,
480
aiBuf, bufLen, cmd);
481
continue;
482
} else {
483
break;
484
}
485
}
486
if (gSynthesisReverbs[j].useReverb != 0) {
487
cmd = synthesis_save_reverb_samples(cmd, j, updateIndex);
488
}
489
}
490
for (; i < notePos; i++) {
491
temp = updateIndex * gMaxSimultaneousNotes;
492
if (IS_BANK_LOAD_COMPLETE(gNoteSubsEu[temp + noteIndices[i]].bankId) == TRUE) {
493
cmd = synthesis_process_note(&gNotes[noteIndices[i]],
494
&gNoteSubsEu[temp + noteIndices[i]],
495
&gNotes[noteIndices[i]].synthesisState,
496
aiBuf, bufLen, cmd);
497
} else {
498
gAudioErrorFlags = (gNoteSubsEu[temp + noteIndices[i]].bankId + (i << 8)) + 0x10000000;
499
}
500
}
501
502
temp = bufLen * 2;
503
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp);
504
aInterleave(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH);
505
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, temp * 2);
506
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(aiBuf));
507
return cmd;
508
}
509
#else
510
u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateIndex) {
511
UNUSED s32 pad1[1];
512
s16 ra;
513
s16 t4;
514
UNUSED s32 pad[2];
515
struct ReverbRingBufferItem *v1;
516
UNUSED s32 pad2[1];
517
s16 temp;
518
519
v1 = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
520
521
if (gSynthesisReverb.useReverb == 0) {
522
aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
523
cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
524
} else {
525
if (gReverbDownsampleRate == 1) {
526
// Put the oldest samples in the ring buffer into the wet channels
527
aSetLoadBufferPair(cmd++, 0, v1->startPos);
528
if (v1->lengthB != 0) {
529
// Ring buffer wrapped
530
aSetLoadBufferPair(cmd++, v1->lengthA, 0);
531
temp = 0;
532
}
533
534
// Use the reverb sound as initial sound for this audio update
535
aDMEMMove(cmd++, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
536
537
// (Hopefully) lower the volume of the wet channels. New reverb will later be mixed into
538
// these channels.
539
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
540
// 0x8000 here is -100%
541
aMix(cmd++, 0, /*gain*/ 0x8000 + gSynthesisReverb.reverbGain, /*in*/ DMEM_ADDR_WET_LEFT_CH,
542
/*out*/ DMEM_ADDR_WET_LEFT_CH);
543
} else {
544
// Same as above but upsample the previously downsampled samples used for reverb first
545
temp = 0; //! jesus christ
546
t4 = (v1->startPos & 7) * 2;
547
ra = ALIGN(v1->lengthA + t4, 4);
548
aSetLoadBufferPair(cmd++, 0, v1->startPos - t4 / 2);
549
if (v1->lengthB != 0) {
550
// Ring buffer wrapped
551
aSetLoadBufferPair(cmd++, ra, 0);
552
//! We need an empty statement (even an empty ';') here to make the function match (because IDO).
553
//! However, copt removes extraneous statements and dead code. So we need to trick copt
554
//! into thinking 'temp' could be undefined, and luckily the compiler optimizes out the
555
//! useless assignment.
556
ra = ra + temp;
557
}
558
aSetBuffer(cmd++, 0, t4 + DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_LEFT_CH, bufLen << 1);
559
aResample(cmd++, gSynthesisReverb.resampleFlags, (u16) gSynthesisReverb.resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.resampleStateLeft));
560
aSetBuffer(cmd++, 0, t4 + DMEM_ADDR_WET_RIGHT_CH, DMEM_ADDR_RIGHT_CH, bufLen << 1);
561
aResample(cmd++, gSynthesisReverb.resampleFlags, (u16) gSynthesisReverb.resampleRate, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.resampleStateRight));
562
aSetBuffer(cmd++, 0, 0, 0, DEFAULT_LEN_2CH);
563
aMix(cmd++, 0, /*gain*/ 0x8000 + gSynthesisReverb.reverbGain, /*in*/ DMEM_ADDR_LEFT_CH, /*out*/ DMEM_ADDR_LEFT_CH);
564
aDMEMMove(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
565
}
566
cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
567
if (gReverbDownsampleRate == 1) {
568
aSetSaveBufferPair(cmd++, 0, v1->lengthA, v1->startPos);
569
if (v1->lengthB != 0) {
570
// Ring buffer wrapped
571
aSetSaveBufferPair(cmd++, v1->lengthA, v1->lengthB, 0);
572
}
573
} else {
574
// Downsampling is done later by CPU when RSP is done, therefore we need to have double
575
// buffering. Left and right buffers are adjacent in memory.
576
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_WET_LEFT_CH, DEFAULT_LEN_2CH);
577
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex].toDownsampleLeft));
578
gSynthesisReverb.resampleFlags = 0;
579
}
580
}
581
return cmd;
582
}
583
#endif
584
585
#ifdef VERSION_EU
586
// Processes just one note, not all
587
u64 *synthesis_process_note(struct Note *note, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, UNUSED s16 *aiBuf, s32 bufLen, u64 *cmd) {
588
UNUSED s32 pad0[3];
589
#else
590
u64 *synthesis_process_notes(s16 *aiBuf, s32 bufLen, u64 *cmd) {
591
s32 noteIndex; // sp174
592
struct Note *note; // s7
593
UNUSED u8 pad0[0x08];
594
#endif
595
struct AudioBankSample *audioBookSample; // sp164, sp138
596
struct AdpcmLoop *loopInfo; // sp160, sp134
597
s16 *curLoadedBook = NULL; // sp154, sp130
598
#ifdef VERSION_EU
599
UNUSED u8 padEU[0x04];
600
#endif
601
UNUSED u8 pad8[0x04];
602
#ifndef VERSION_EU
603
u16 resamplingRateFixedPoint; // sp5c, sp11A
604
#endif
605
s32 noteFinished; // 150 t2, sp124
606
s32 restart; // 14c t3, sp120
607
s32 flags; // sp148, sp11C
608
#ifdef VERSION_EU
609
u16 resamplingRateFixedPoint; // sp5c, sp11A
610
#endif
611
UNUSED u8 pad7[0x0c]; // sp100
612
UNUSED s32 tempBufLen;
613
#ifdef VERSION_EU
614
s32 sp130; //sp128, sp104
615
UNUSED u32 pad9;
616
#else
617
UNUSED u32 pad9;
618
s32 sp130; //sp128, sp104
619
#endif
620
s32 nAdpcmSamplesProcessed; // signed required for US
621
s32 t0;
622
#ifdef VERSION_EU
623
u8 *sampleAddr; // sp120, spF4
624
s32 s6;
625
#else
626
s32 s6;
627
u8 *sampleAddr; // sp120, spF4
628
#endif
629
630
#ifdef VERSION_EU
631
s32 samplesLenAdjusted; // 108, spEC
632
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
633
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
634
UNUSED s32 samplesLenInt;
635
s32 endPos; // sp110, spE4
636
s32 nSamplesToProcess; // sp10c/a0, spE0
637
s32 s2;
638
#else
639
// Might have been used to store (samplesLenFixedPoint >> 0x10), but doing so causes strange
640
// behavior with the break near the end of the loop, causing US and JP to need a goto instead
641
UNUSED s32 samplesLenInt;
642
s32 samplesLenAdjusted; // 108
643
s32 s2;
644
s32 endPos; // sp110, spE4
645
s32 nSamplesToProcess; // sp10c/a0, spE0
646
#endif
647
648
s32 leftRight;
649
s32 s3;
650
s32 s5; //s4
651
652
u32 samplesLenFixedPoint; // v1_1
653
s32 nSamplesInThisIteration; // v1_2
654
u32 a3;
655
#ifndef VERSION_EU
656
s32 t9;
657
#endif
658
u8 *v0_2;
659
s32 nParts; // spE8, spBC
660
s32 curPart; // spE4, spB8
661
662
#ifndef VERSION_EU
663
f32 resamplingRate; // f12
664
#endif
665
s32 temp;
666
667
#ifdef VERSION_EU
668
s32 s5Aligned;
669
#endif
670
s32 resampledTempLen; // spD8, spAC
671
u16 noteSamplesDmemAddrBeforeResampling; // spD6, spAA
672
673
674
#ifndef VERSION_EU
675
for (noteIndex = 0; noteIndex < gMaxSimultaneousNotes; noteIndex++) {
676
note = &gNotes[noteIndex];
677
#ifdef VERSION_US
678
//! This function requires note->enabled to be volatile, but it breaks other functions like note_enable.
679
//! Casting to a struct with just the volatile bitfield works, but there may be a better way to match.
680
if (((struct vNote *)note)->enabled && IS_BANK_LOAD_COMPLETE(note->bankId) == FALSE) {
681
#else
682
if (IS_BANK_LOAD_COMPLETE(note->bankId) == FALSE) {
683
#endif
684
gAudioErrorFlags = (note->bankId << 8) + noteIndex + 0x1000000;
685
} else if (((struct vNote *)note)->enabled) {
686
#else
687
if (note->noteSubEu.enabled == FALSE) {
688
return cmd;
689
} else {
690
#endif
691
flags = 0;
692
#ifdef VERSION_EU
693
tempBufLen = bufLen;
694
#endif
695
696
#ifdef VERSION_EU
697
if (noteSubEu->needsInit == TRUE) {
698
#else
699
if (note->needsInit == TRUE) {
700
#endif
701
flags = A_INIT;
702
#ifndef VERSION_EU
703
note->samplePosInt = 0;
704
note->samplePosFrac = 0;
705
#else
706
synthesisState->restart = FALSE;
707
synthesisState->samplePosInt = 0;
708
synthesisState->samplePosFrac = 0;
709
synthesisState->curVolLeft = 1;
710
synthesisState->curVolRight = 1;
711
synthesisState->prevHeadsetPanRight = 0;
712
synthesisState->prevHeadsetPanLeft = 0;
713
#endif
714
}
715
716
#ifndef VERSION_EU
717
if (note->frequency < US_FLOAT(2.0)) {
718
nParts = 1;
719
if (note->frequency > US_FLOAT(1.99996)) {
720
note->frequency = US_FLOAT(1.99996);
721
}
722
resamplingRate = note->frequency;
723
} else {
724
// If frequency is > 2.0, the processing must be split into two parts
725
nParts = 2;
726
if (note->frequency >= US_FLOAT(3.99993)) {
727
note->frequency = US_FLOAT(3.99993);
728
}
729
resamplingRate = note->frequency * US_FLOAT(.5);
730
}
731
732
resamplingRateFixedPoint = (u16)(s32)(resamplingRate * 32768.0f);
733
samplesLenFixedPoint = note->samplePosFrac + (resamplingRateFixedPoint * bufLen) * 2;
734
note->samplePosFrac = samplesLenFixedPoint & 0xFFFF; // 16-bit store, can't reuse
735
#else
736
resamplingRateFixedPoint = noteSubEu->resamplingRateFixedPoint;
737
nParts = noteSubEu->hasTwoAdpcmParts + 1;
738
samplesLenFixedPoint = (resamplingRateFixedPoint * tempBufLen * 2) + synthesisState->samplePosFrac;
739
synthesisState->samplePosFrac = samplesLenFixedPoint & 0xFFFF;
740
#endif
741
742
#ifdef VERSION_EU
743
if (noteSubEu->isSyntheticWave) {
744
cmd = load_wave_samples(cmd, noteSubEu, synthesisState, samplesLenFixedPoint >> 0x10);
745
noteSamplesDmemAddrBeforeResampling = (synthesisState->samplePosInt * 2) + DMEM_ADDR_UNCOMPRESSED_NOTE;
746
synthesisState->samplePosInt += samplesLenFixedPoint >> 0x10;
747
}
748
#else
749
if (note->sound == NULL) {
750
// A wave synthesis note (not ADPCM)
751
752
cmd = load_wave_samples(cmd, note, samplesLenFixedPoint >> 0x10);
753
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + note->samplePosInt * 2;
754
note->samplePosInt += (samplesLenFixedPoint >> 0x10);
755
flags = 0;
756
}
757
#endif
758
else {
759
// ADPCM note
760
761
#ifdef VERSION_EU
762
audioBookSample = noteSubEu->sound.audioBankSound->sample;
763
#else
764
audioBookSample = note->sound->sample;
765
#endif
766
767
loopInfo = audioBookSample->loop;
768
endPos = loopInfo->end;
769
sampleAddr = audioBookSample->sampleAddr;
770
resampledTempLen = 0;
771
for (curPart = 0; curPart < nParts; curPart++) {
772
nAdpcmSamplesProcessed = 0; // s8
773
s5 = 0; // s4
774
775
if (nParts == 1) {
776
samplesLenAdjusted = samplesLenFixedPoint >> 0x10;
777
} else if ((samplesLenFixedPoint >> 0x10) & 1) {
778
samplesLenAdjusted = ((samplesLenFixedPoint >> 0x10) & ~1) + (curPart * 2);
779
}
780
else {
781
samplesLenAdjusted = (samplesLenFixedPoint >> 0x10);
782
}
783
784
if (curLoadedBook != audioBookSample->book->book) {
785
u32 nEntries; // v1
786
curLoadedBook = audioBookSample->book->book;
787
#ifdef VERSION_EU
788
nEntries = 16 * audioBookSample->book->order * audioBookSample->book->npredictors;
789
aLoadADPCM(cmd++, nEntries, VIRTUAL_TO_PHYSICAL2(curLoadedBook + noteSubEu->bookOffset));
790
#else
791
nEntries = audioBookSample->book->order * audioBookSample->book->npredictors;
792
aLoadADPCM(cmd++, nEntries * 16, VIRTUAL_TO_PHYSICAL2(curLoadedBook));
793
#endif
794
}
795
796
#ifdef VERSION_EU
797
if (noteSubEu->bookOffset) {
798
curLoadedBook = euUnknownData_80301950; // what's this? never read
799
}
800
#endif
801
802
while (nAdpcmSamplesProcessed != samplesLenAdjusted) {
803
s32 samplesRemaining; // v1
804
s32 s0;
805
806
noteFinished = FALSE;
807
restart = FALSE;
808
nSamplesToProcess = samplesLenAdjusted - nAdpcmSamplesProcessed;
809
#ifdef VERSION_EU
810
s2 = synthesisState->samplePosInt & 0xf;
811
samplesRemaining = endPos - synthesisState->samplePosInt;
812
#else
813
s2 = note->samplePosInt & 0xf;
814
samplesRemaining = endPos - note->samplePosInt;
815
#endif
816
817
#ifdef VERSION_EU
818
if (s2 == 0 && synthesisState->restart == FALSE) {
819
s2 = 16;
820
}
821
#else
822
if (s2 == 0 && note->restart == FALSE) {
823
s2 = 16;
824
}
825
#endif
826
s6 = 16 - s2; // a1
827
828
if (nSamplesToProcess < samplesRemaining) {
829
t0 = (nSamplesToProcess - s6 + 0xf) / 16;
830
s0 = t0 * 16;
831
s3 = s6 + s0 - nSamplesToProcess;
832
} else {
833
#ifndef VERSION_EU
834
s0 = samplesRemaining + s2 - 0x10;
835
#else
836
s0 = samplesRemaining - s6;
837
#endif
838
s3 = 0;
839
if (s0 <= 0) {
840
s0 = 0;
841
s6 = samplesRemaining;
842
}
843
t0 = (s0 + 0xf) / 16;
844
if (loopInfo->count != 0) {
845
// Loop around and restart
846
restart = 1;
847
} else {
848
noteFinished = 1;
849
}
850
}
851
852
if (t0 != 0) {
853
#ifdef VERSION_EU
854
temp = (synthesisState->samplePosInt - s2 + 0x10) / 16;
855
if (audioBookSample->loaded == 0x81) {
856
v0_2 = sampleAddr + temp * 9;
857
} else {
858
v0_2 = dma_sample_data(
859
(uintptr_t) (sampleAddr + temp * 9),
860
t0 * 9, flags, &synthesisState->sampleDmaIndex);
861
}
862
#else
863
temp = (note->samplePosInt - s2 + 0x10) / 16;
864
v0_2 = dma_sample_data(
865
(uintptr_t) (sampleAddr + temp * 9),
866
t0 * 9, flags, &note->sampleDmaIndex);
867
#endif
868
a3 = (u32)((uintptr_t) v0_2 & 0xf);
869
aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA, 0, t0 * 9 + a3);
870
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(v0_2 - a3));
871
} else {
872
s0 = 0;
873
a3 = 0;
874
}
875
876
#ifdef VERSION_EU
877
if (synthesisState->restart != FALSE) {
878
aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
879
flags = A_LOOP; // = 2
880
synthesisState->restart = FALSE;
881
}
882
#else
883
if (note->restart != FALSE) {
884
aSetLoop(cmd++, VIRTUAL_TO_PHYSICAL2(audioBookSample->loop->state));
885
flags = A_LOOP; // = 2
886
note->restart = FALSE;
887
}
888
#endif
889
890
nSamplesInThisIteration = s0 + s6 - s3;
891
#ifdef VERSION_EU
892
if (nAdpcmSamplesProcessed == 0) {
893
aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3,
894
DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
895
aADPCMdec(cmd++, flags,
896
VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
897
sp130 = s2 * 2;
898
} else {
899
s5Aligned = ALIGN(s5, 5);
900
aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3,
901
DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned, s0 * 2);
902
aADPCMdec(cmd++, flags,
903
VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->adpcmdecState));
904
aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5Aligned + (s2 * 2),
905
DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
906
}
907
#else
908
if (nAdpcmSamplesProcessed == 0) {
909
aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE, s0 * 2);
910
aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState));
911
sp130 = s2 * 2;
912
} else {
913
aSetBuffer(cmd++, 0, DMEM_ADDR_COMPRESSED_ADPCM_DATA + a3, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5), s0 * 2);
914
aADPCMdec(cmd++, flags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->adpcmdecState));
915
aDMEMMove(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + ALIGN(s5, 5) + (s2 * 2), DMEM_ADDR_UNCOMPRESSED_NOTE + s5, (nSamplesInThisIteration) * 2);
916
}
917
#endif
918
919
nAdpcmSamplesProcessed += nSamplesInThisIteration;
920
921
switch (flags) {
922
case A_INIT: // = 1
923
sp130 = 0;
924
s5 = s0 * 2 + s5;
925
break;
926
927
case A_LOOP: // = 2
928
s5 = nSamplesInThisIteration * 2 + s5;
929
break;
930
931
default:
932
if (s5 != 0) {
933
s5 = nSamplesInThisIteration * 2 + s5;
934
} else {
935
s5 = (s2 + nSamplesInThisIteration) * 2;
936
}
937
break;
938
}
939
flags = 0;
940
941
if (noteFinished) {
942
aClearBuffer(cmd++, DMEM_ADDR_UNCOMPRESSED_NOTE + s5,
943
(samplesLenAdjusted - nAdpcmSamplesProcessed) * 2);
944
#ifdef VERSION_EU
945
noteSubEu->finished = 1;
946
note->noteSubEu.finished = 1;
947
note->noteSubEu.enabled = 0;
948
#else
949
note->samplePosInt = 0;
950
note->finished = 1;
951
((struct vNote *)note)->enabled = 0;
952
#endif
953
break;
954
}
955
#ifdef VERSION_EU
956
if (restart) {
957
synthesisState->restart = TRUE;
958
synthesisState->samplePosInt = loopInfo->start;
959
} else {
960
synthesisState->samplePosInt += nSamplesToProcess;
961
}
962
#else
963
if (restart) {
964
note->restart = TRUE;
965
note->samplePosInt = loopInfo->start;
966
} else {
967
note->samplePosInt += nSamplesToProcess;
968
}
969
#endif
970
}
971
972
switch (nParts) {
973
case 1:
974
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_UNCOMPRESSED_NOTE + sp130;
975
break;
976
977
case 2:
978
switch (curPart) {
979
case 0:
980
aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130, DMEM_ADDR_RESAMPLED, samplesLenAdjusted + 4);
981
#ifdef VERSION_EU
982
aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->dummyResampleState));
983
#else
984
aResample(cmd++, A_INIT, 0xff60, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->dummyResampleState));
985
#endif
986
resampledTempLen = samplesLenAdjusted + 4;
987
noteSamplesDmemAddrBeforeResampling = DMEM_ADDR_RESAMPLED + 4;
988
#ifdef VERSION_EU
989
if (noteSubEu->finished != FALSE) {
990
#else
991
if (note->finished != FALSE) {
992
#endif
993
aClearBuffer(cmd++, DMEM_ADDR_RESAMPLED + resampledTempLen, samplesLenAdjusted + 0x10);
994
}
995
break;
996
997
case 1:
998
aSetBuffer(cmd++, 0, DMEM_ADDR_UNCOMPRESSED_NOTE + sp130,
999
DMEM_ADDR_RESAMPLED2,
1000
samplesLenAdjusted + 8);
1001
#ifdef VERSION_EU
1002
aResample(cmd++, A_INIT, 0xff60,
1003
VIRTUAL_TO_PHYSICAL2(
1004
synthesisState->synthesisBuffers->dummyResampleState));
1005
#else
1006
aResample(cmd++, A_INIT, 0xff60,
1007
VIRTUAL_TO_PHYSICAL2(
1008
note->synthesisBuffers->dummyResampleState));
1009
#endif
1010
aDMEMMove(cmd++, DMEM_ADDR_RESAMPLED2 + 4,
1011
DMEM_ADDR_RESAMPLED + resampledTempLen,
1012
samplesLenAdjusted + 4);
1013
break;
1014
}
1015
}
1016
1017
#ifdef VERSION_EU
1018
if (noteSubEu->finished != FALSE) {
1019
#else
1020
if (note->finished != FALSE) {
1021
#endif
1022
break;
1023
}
1024
}
1025
}
1026
1027
flags = 0;
1028
1029
#ifdef VERSION_EU
1030
if (noteSubEu->needsInit == TRUE) {
1031
flags = A_INIT;
1032
noteSubEu->needsInit = FALSE;
1033
}
1034
1035
cmd = final_resample(cmd, synthesisState, bufLen * 2, resamplingRateFixedPoint,
1036
noteSamplesDmemAddrBeforeResampling, flags);
1037
#else
1038
if (note->needsInit == TRUE) {
1039
flags = A_INIT;
1040
note->needsInit = FALSE;
1041
}
1042
1043
cmd = final_resample(cmd, note, bufLen * 2, resamplingRateFixedPoint,
1044
noteSamplesDmemAddrBeforeResampling, flags);
1045
#endif
1046
1047
#ifdef VERSION_EU
1048
if (noteSubEu->headsetPanRight != 0 || synthesisState->prevHeadsetPanRight != 0) {
1049
leftRight = 1;
1050
} else if (noteSubEu->headsetPanLeft != 0 || synthesisState->prevHeadsetPanLeft != 0) {
1051
leftRight = 2;
1052
#else
1053
if (note->headsetPanRight != 0 || note->prevHeadsetPanRight != 0) {
1054
leftRight = 1;
1055
} else if (note->headsetPanLeft != 0 || note->prevHeadsetPanLeft != 0) {
1056
leftRight = 2;
1057
#endif
1058
} else {
1059
leftRight = 0;
1060
}
1061
1062
#ifdef VERSION_EU
1063
cmd = process_envelope(cmd, noteSubEu, synthesisState, bufLen, 0, leftRight, flags);
1064
#else
1065
cmd = process_envelope(cmd, note, bufLen, 0, leftRight, flags);
1066
#endif
1067
1068
#ifdef VERSION_EU
1069
if (noteSubEu->usesHeadsetPanEffects) {
1070
cmd = note_apply_headset_pan_effects(cmd, noteSubEu, synthesisState, bufLen * 2, flags, leftRight);
1071
}
1072
#else
1073
if (note->usesHeadsetPanEffects) {
1074
cmd = note_apply_headset_pan_effects(cmd, note, bufLen * 2, flags, leftRight);
1075
}
1076
#endif
1077
}
1078
#ifndef VERSION_EU
1079
}
1080
1081
t9 = bufLen * 2;
1082
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, t9);
1083
aInterleave(cmd++, DMEM_ADDR_LEFT_CH, DMEM_ADDR_RIGHT_CH);
1084
t9 *= 2;
1085
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, t9);
1086
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(aiBuf));
1087
#endif
1088
1089
return cmd;
1090
}
1091
1092
#ifdef VERSION_EU
1093
u64 *load_wave_samples(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *synthesisState, s32 nSamplesToLoad) {
1094
s32 a3;
1095
s32 repeats;
1096
s32 i;
1097
aSetBuffer(cmd++, /*flags*/ 0, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ 0, /*count*/ 128);
1098
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(noteSubEu->sound.samples));
1099
1100
synthesisState->samplePosInt &= 0x3f;
1101
a3 = 64 - synthesisState->samplePosInt;
1102
if (a3 < nSamplesToLoad) {
1103
repeats = (nSamplesToLoad - a3 + 63) / 64;
1104
for (i = 0; i < repeats; i++) {
1105
aDMEMMove(cmd++,
1106
/*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE,
1107
/*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + (1 + i) * 128,
1108
/*count*/ 128);
1109
}
1110
}
1111
return cmd;
1112
}
1113
#else
1114
u64 *load_wave_samples(u64 *cmd, struct Note *note, s32 nSamplesToLoad) {
1115
s32 a3;
1116
s32 i;
1117
aSetBuffer(cmd++, /*flags*/ 0, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ 0,
1118
/*count*/ sizeof(note->synthesisBuffers->samples));
1119
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->samples));
1120
note->samplePosInt &= (note->sampleCount - 1);
1121
a3 = 64 - note->samplePosInt;
1122
if (a3 < nSamplesToLoad) {
1123
for (i = 0; i <= (nSamplesToLoad - a3 + 63) / 64 - 1; i++) {
1124
aDMEMMove(cmd++, /*dmemin*/ DMEM_ADDR_UNCOMPRESSED_NOTE, /*dmemout*/ DMEM_ADDR_UNCOMPRESSED_NOTE + (1 + i) * sizeof(note->synthesisBuffers->samples), /*count*/ sizeof(note->synthesisBuffers->samples));
1125
}
1126
}
1127
return cmd;
1128
}
1129
#endif
1130
1131
#ifdef VERSION_EU
1132
u64 *final_resample(u64 *cmd, struct NoteSynthesisState *synthesisState, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
1133
aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
1134
aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->finalResampleState));
1135
return cmd;
1136
}
1137
#else
1138
u64 *final_resample(u64 *cmd, struct Note *note, s32 count, u16 pitch, u16 dmemIn, u32 flags) {
1139
aSetBuffer(cmd++, /*flags*/ 0, dmemIn, /*dmemout*/ DMEM_ADDR_TEMP, count);
1140
aResample(cmd++, flags, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->finalResampleState));
1141
return cmd;
1142
}
1143
#endif
1144
1145
#ifndef VERSION_EU
1146
u64 *process_envelope(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf, s32 headsetPanSettings,
1147
UNUSED u32 flags) {
1148
UNUSED u8 pad[16];
1149
struct VolumeChange vol;
1150
vol.sourceLeft = note->curVolLeft;
1151
vol.sourceRight = note->curVolRight;
1152
vol.targetLeft = note->targetVolLeft;
1153
vol.targetRight = note->targetVolRight;
1154
note->curVolLeft = vol.targetLeft;
1155
note->curVolRight = vol.targetRight;
1156
return process_envelope_inner(cmd, note, nSamples, inBuf, headsetPanSettings, &vol);
1157
}
1158
1159
u64 *process_envelope_inner(u64 *cmd, struct Note *note, s32 nSamples, u16 inBuf,
1160
s32 headsetPanSettings, struct VolumeChange *vol) {
1161
UNUSED u8 pad[3];
1162
u8 mixerFlags;
1163
UNUSED u8 pad2[8];
1164
s32 rampLeft, rampRight;
1165
#elif defined(VERSION_EU)
1166
u64 *process_envelope(u64 *cmd, struct NoteSubEu *note, struct NoteSynthesisState *synthesisState, s32 nSamples, u16 inBuf, s32 headsetPanSettings, UNUSED u32 flags) {
1167
UNUSED u8 pad1[20];
1168
u16 sourceRight;
1169
u16 sourceLeft;
1170
UNUSED u8 pad2[4];
1171
u16 targetLeft;
1172
u16 targetRight;
1173
s32 mixerFlags;
1174
s32 rampLeft;
1175
s32 rampRight;
1176
1177
sourceLeft = synthesisState->curVolLeft;
1178
sourceRight = synthesisState->curVolRight;
1179
targetLeft = (note->targetVolLeft << 5);
1180
targetRight = (note->targetVolRight << 5);
1181
if (targetLeft == 0) {
1182
targetLeft++;
1183
}
1184
if (targetRight == 0) {
1185
targetRight++;
1186
}
1187
synthesisState->curVolLeft = targetLeft;
1188
synthesisState->curVolRight = targetRight;
1189
#endif
1190
1191
// For aEnvMixer, five buffers and count are set using aSetBuffer.
1192
// in, dry left, count without A_AUX flag.
1193
// dry right, wet left, wet right with A_AUX flag.
1194
1195
if (note->usesHeadsetPanEffects) {
1196
aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DEFAULT_LEN_1CH);
1197
1198
switch (headsetPanSettings) {
1199
case 1:
1200
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_NOTE_PAN_TEMP, nSamples * 2);
1201
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH,
1202
DMEM_ADDR_WET_RIGHT_CH);
1203
break;
1204
case 2:
1205
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
1206
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_WET_LEFT_CH,
1207
DMEM_ADDR_WET_RIGHT_CH);
1208
break;
1209
default:
1210
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
1211
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH,
1212
DMEM_ADDR_WET_RIGHT_CH);
1213
break;
1214
}
1215
} else {
1216
// It's a bit unclear what the "stereo strong" concept does.
1217
// Instead of mixing the opposite channel to the normal buffers, the sound is first
1218
// mixed into a temporary buffer and then subtracted from the normal buffer.
1219
if (note->stereoStrongRight) {
1220
aClearBuffer(cmd++, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DEFAULT_LEN_2CH);
1221
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, nSamples * 2);
1222
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_STEREO_STRONG_TEMP_WET,
1223
DMEM_ADDR_WET_RIGHT_CH);
1224
} else if (note->stereoStrongLeft) {
1225
aClearBuffer(cmd++, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DEFAULT_LEN_2CH);
1226
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
1227
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_STEREO_STRONG_TEMP_DRY, DMEM_ADDR_WET_LEFT_CH,
1228
DMEM_ADDR_STEREO_STRONG_TEMP_WET);
1229
} else {
1230
aSetBuffer(cmd++, 0, inBuf, DMEM_ADDR_LEFT_CH, nSamples * 2);
1231
aSetBuffer(cmd++, A_AUX, DMEM_ADDR_RIGHT_CH, DMEM_ADDR_WET_LEFT_CH, DMEM_ADDR_WET_RIGHT_CH);
1232
}
1233
}
1234
1235
#ifdef VERSION_EU
1236
if (targetLeft == sourceLeft && targetRight == sourceRight && !note->envMixerNeedsInit) {
1237
#else
1238
if (vol->targetLeft == vol->sourceLeft && vol->targetRight == vol->sourceRight
1239
&& !note->envMixerNeedsInit) {
1240
#endif
1241
mixerFlags = A_CONTINUE;
1242
} else {
1243
mixerFlags = A_INIT;
1244
1245
#ifdef VERSION_EU
1246
rampLeft = gCurrentLeftVolRamping[targetLeft >> 5] * gCurrentRightVolRamping[sourceLeft >> 5];
1247
rampRight = gCurrentLeftVolRamping[targetRight >> 5] * gCurrentRightVolRamping[sourceRight >> 5];
1248
#else
1249
rampLeft = get_volume_ramping(vol->sourceLeft, vol->targetLeft, nSamples);
1250
rampRight = get_volume_ramping(vol->sourceRight, vol->targetRight, nSamples);
1251
#endif
1252
1253
// The operation's parameters change meanings depending on flags
1254
#ifdef VERSION_EU
1255
aSetVolume(cmd++, A_VOL | A_LEFT, sourceLeft, 0, 0);
1256
aSetVolume(cmd++, A_VOL | A_RIGHT, sourceRight, 0, 0);
1257
aSetVolume32(cmd++, A_RATE | A_LEFT, targetLeft, rampLeft);
1258
aSetVolume32(cmd++, A_RATE | A_RIGHT, targetRight, rampRight);
1259
aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVol << 8);
1260
#else
1261
aSetVolume(cmd++, A_VOL | A_LEFT, vol->sourceLeft, 0, 0);
1262
aSetVolume(cmd++, A_VOL | A_RIGHT, vol->sourceRight, 0, 0);
1263
aSetVolume32(cmd++, A_RATE | A_LEFT, vol->targetLeft, rampLeft);
1264
aSetVolume32(cmd++, A_RATE | A_RIGHT, vol->targetRight, rampRight);
1265
aSetVolume(cmd++, A_AUX, gVolume, 0, note->reverbVolShifted);
1266
#endif
1267
}
1268
1269
#ifdef VERSION_EU
1270
if (gUseReverb && note->reverbVol != 0) {
1271
aEnvMixer(cmd++, mixerFlags | A_AUX,
1272
VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState));
1273
#else
1274
if (gSynthesisReverb.useReverb && note->reverbVol != 0) {
1275
aEnvMixer(cmd++, mixerFlags | A_AUX,
1276
VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState));
1277
#endif
1278
if (note->stereoStrongRight) {
1279
aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
1280
// 0x8000 is -100%, so subtract sound instead of adding...
1281
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
1282
/*out*/ DMEM_ADDR_LEFT_CH);
1283
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET,
1284
/*out*/ DMEM_ADDR_WET_LEFT_CH);
1285
} else if (note->stereoStrongLeft) {
1286
aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
1287
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
1288
/*out*/ DMEM_ADDR_RIGHT_CH);
1289
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_WET,
1290
/*out*/ DMEM_ADDR_WET_RIGHT_CH);
1291
}
1292
} else {
1293
#ifdef VERSION_EU
1294
aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(synthesisState->synthesisBuffers->mixEnvelopeState));
1295
#else
1296
aEnvMixer(cmd++, mixerFlags, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->mixEnvelopeState));
1297
#endif
1298
if (note->stereoStrongRight) {
1299
aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
1300
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
1301
/*out*/ DMEM_ADDR_LEFT_CH);
1302
} else if (note->stereoStrongLeft) {
1303
aSetBuffer(cmd++, 0, 0, 0, nSamples * 2);
1304
aMix(cmd++, 0, /*gain*/ 0x8000, /*in*/ DMEM_ADDR_STEREO_STRONG_TEMP_DRY,
1305
/*out*/ DMEM_ADDR_RIGHT_CH);
1306
}
1307
}
1308
return cmd;
1309
}
1310
1311
#ifdef VERSION_EU
1312
u64 *note_apply_headset_pan_effects(u64 *cmd, struct NoteSubEu *noteSubEu, struct NoteSynthesisState *note, s32 bufLen, s32 flags, s32 leftRight) {
1313
#else
1314
u64 *note_apply_headset_pan_effects(u64 *cmd, struct Note *note, s32 bufLen, s32 flags, s32 leftRight) {
1315
#endif
1316
u16 dest;
1317
u16 pitch;
1318
#ifdef VERSION_EU
1319
u8 prevPanShift;
1320
u8 panShift;
1321
UNUSED u8 unkDebug;
1322
#else
1323
u16 prevPanShift;
1324
u16 panShift;
1325
#endif
1326
1327
switch (leftRight) {
1328
case 1:
1329
dest = DMEM_ADDR_LEFT_CH;
1330
#ifdef VERSION_EU
1331
panShift = noteSubEu->headsetPanRight;
1332
#else
1333
panShift = note->headsetPanRight;
1334
#endif
1335
note->prevHeadsetPanLeft = 0;
1336
prevPanShift = note->prevHeadsetPanRight;
1337
note->prevHeadsetPanRight = panShift;
1338
break;
1339
case 2:
1340
dest = DMEM_ADDR_RIGHT_CH;
1341
#ifdef VERSION_EU
1342
panShift = noteSubEu->headsetPanLeft;
1343
#else
1344
panShift = note->headsetPanLeft;
1345
#endif
1346
note->prevHeadsetPanRight = 0;
1347
1348
prevPanShift = note->prevHeadsetPanLeft;
1349
note->prevHeadsetPanLeft = panShift;
1350
break;
1351
default:
1352
return cmd;
1353
}
1354
1355
if (flags != 1) { // A_INIT?
1356
// Slightly adjust the sample rate in order to fit a change in pan shift
1357
if (prevPanShift == 0) {
1358
// Kind of a hack that moves the first samples into the resample state
1359
aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, 8);
1360
aClearBuffer(cmd++, 8, 8); // Set pitch accumulator to 0 in the resample state
1361
aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP + 0x10,
1362
0x10); // No idea, result seems to be overwritten later
1363
1364
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_TEMP, 32);
1365
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
1366
1367
#ifdef VERSION_EU
1368
pitch = (bufLen << 0xf) / (bufLen + panShift - prevPanShift + 8);
1369
if (pitch) {
1370
}
1371
#else
1372
pitch = (bufLen << 0xf) / (panShift + bufLen - prevPanShift + 8);
1373
#endif
1374
aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP + 8, DMEM_ADDR_TEMP, panShift + bufLen - prevPanShift);
1375
aResample(cmd++, 0, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
1376
} else {
1377
if (panShift == 0) {
1378
pitch = (bufLen << 0xf) / (bufLen - prevPanShift - 4);
1379
} else {
1380
pitch = (bufLen << 0xf) / (bufLen + panShift - prevPanShift);
1381
}
1382
1383
#if defined(VERSION_EU) && !defined(AVOID_UB)
1384
if (unkDebug) { // UB
1385
}
1386
#endif
1387
aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, panShift + bufLen - prevPanShift);
1388
aResample(cmd++, 0, pitch, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panResampleState));
1389
}
1390
1391
if (prevPanShift != 0) {
1392
aSetBuffer(cmd++, 0, DMEM_ADDR_NOTE_PAN_TEMP, 0, prevPanShift);
1393
aLoadBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer));
1394
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + prevPanShift, panShift + bufLen - prevPanShift);
1395
} else {
1396
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP, panShift + bufLen - prevPanShift);
1397
}
1398
} else {
1399
// Just shift right
1400
aDMEMMove(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, DMEM_ADDR_TEMP, bufLen);
1401
aDMEMMove(cmd++, DMEM_ADDR_TEMP, DMEM_ADDR_NOTE_PAN_TEMP + panShift, bufLen);
1402
aClearBuffer(cmd++, DMEM_ADDR_NOTE_PAN_TEMP, panShift);
1403
}
1404
1405
if (panShift) {
1406
// Save excessive samples for next iteration
1407
aSetBuffer(cmd++, 0, 0, DMEM_ADDR_NOTE_PAN_TEMP + bufLen, panShift);
1408
aSaveBuffer(cmd++, VIRTUAL_TO_PHYSICAL2(note->synthesisBuffers->panSamplesBuffer));
1409
}
1410
1411
aSetBuffer(cmd++, 0, 0, 0, bufLen);
1412
aMix(cmd++, 0, /*gain*/ 0x7fff, /*in*/ DMEM_ADDR_NOTE_PAN_TEMP, /*out*/ dest);
1413
1414
return cmd;
1415
}
1416
1417
#ifndef VERSION_EU
1418
// Moved to playback.c in EU
1419
1420
void note_init_volume(struct Note *note) {
1421
note->targetVolLeft = 0;
1422
note->targetVolRight = 0;
1423
note->reverbVol = 0;
1424
note->reverbVolShifted = 0;
1425
note->unused2 = 0;
1426
note->curVolLeft = 1;
1427
note->curVolRight = 1;
1428
note->frequency = 0.0f;
1429
}
1430
1431
void note_set_vel_pan_reverb(struct Note *note, f32 velocity, f32 pan, u8 reverbVol) {
1432
s32 panIndex;
1433
f32 volLeft;
1434
f32 volRight;
1435
// Anding with 127 avoids out-of-bounds reads when pan is outside of [0, 1].
1436
// This can occur during PU movement -- see the bug comment in get_sound_pan
1437
// in external.c. An out-of-bounds read by itself doesn't crash, but if the
1438
// resulting value is a nan or denormal, performing arithmetic on it crashes
1439
// on console.
1440
#ifdef VERSION_JP
1441
panIndex = MIN((s32)(pan * 127.5), 127);
1442
#else
1443
panIndex = (s32)(pan * 127.5f) & 127;
1444
#endif
1445
1446
if (get_mirror())
1447
pan *= -1;
1448
1449
if (note->stereoHeadsetEffects && gSoundMode == SOUND_MODE_HEADSET) {
1450
s8 smallPanIndex;
1451
s8 temp = (s8)(pan * 10.0f);
1452
if (temp < 9) {
1453
smallPanIndex = temp;
1454
} else {
1455
smallPanIndex = 9;
1456
}
1457
note->headsetPanLeft = gHeadsetPanQuantization[smallPanIndex];
1458
note->headsetPanRight = gHeadsetPanQuantization[9 - smallPanIndex];
1459
note->stereoStrongRight = FALSE;
1460
note->stereoStrongLeft = FALSE;
1461
note->usesHeadsetPanEffects = TRUE;
1462
volLeft = gHeadsetPanVolume[panIndex];
1463
volRight = gHeadsetPanVolume[127 - panIndex];
1464
} else if (note->stereoHeadsetEffects && gSoundMode == SOUND_MODE_STEREO) {
1465
u8 strongLeft;
1466
u8 strongRight;
1467
strongLeft = FALSE;
1468
strongRight = FALSE;
1469
note->headsetPanLeft = 0;
1470
note->headsetPanRight = 0;
1471
note->usesHeadsetPanEffects = FALSE;
1472
volLeft = gStereoPanVolume[panIndex];
1473
volRight = gStereoPanVolume[127 - panIndex];
1474
if (panIndex < 0x20) {
1475
strongLeft = TRUE;
1476
} else if (panIndex > 0x60) {
1477
strongRight = TRUE;
1478
}
1479
note->stereoStrongRight = strongRight;
1480
note->stereoStrongLeft = strongLeft;
1481
} else if (gSoundMode == SOUND_MODE_MONO) {
1482
volLeft = .707f;
1483
volRight = .707f;
1484
} else {
1485
volLeft = gDefaultPanVolume[panIndex];
1486
volRight = gDefaultPanVolume[127 - panIndex];
1487
}
1488
1489
if (velocity < 0) {
1490
velocity = 0;
1491
}
1492
#ifdef VERSION_JP
1493
note->targetVolLeft = (u16)(velocity * volLeft) & ~0x80FF; // 0x7F00, but that doesn't match
1494
note->targetVolRight = (u16)(velocity * volRight) & ~0x80FF;
1495
#else
1496
note->targetVolLeft = (u16)(s32)(velocity * volLeft) & ~0x80FF;
1497
note->targetVolRight = (u16)(s32)(velocity * volRight) & ~0x80FF;
1498
#endif
1499
if (note->targetVolLeft == 0) {
1500
note->targetVolLeft++;
1501
}
1502
if (note->targetVolRight == 0) {
1503
note->targetVolRight++;
1504
}
1505
if (note->reverbVol != reverbVol) {
1506
note->reverbVol = reverbVol;
1507
note->reverbVolShifted = reverbVol << 8;
1508
note->envMixerNeedsInit = TRUE;
1509
return;
1510
}
1511
1512
if (note->needsInit) {
1513
note->envMixerNeedsInit = TRUE;
1514
} else {
1515
note->envMixerNeedsInit = FALSE;
1516
}
1517
}
1518
1519
void note_set_frequency(struct Note *note, f32 frequency) {
1520
note->frequency = frequency;
1521
}
1522
1523
void note_enable(struct Note *note) {
1524
note->enabled = TRUE;
1525
note->needsInit = TRUE;
1526
note->restart = FALSE;
1527
note->finished = FALSE;
1528
note->stereoStrongRight = FALSE;
1529
note->stereoStrongLeft = FALSE;
1530
note->usesHeadsetPanEffects = FALSE;
1531
note->headsetPanLeft = 0;
1532
note->headsetPanRight = 0;
1533
note->prevHeadsetPanRight = 0;
1534
note->prevHeadsetPanLeft = 0;
1535
}
1536
1537
void note_disable(struct Note *note) {
1538
if (note->needsInit == TRUE) {
1539
note->needsInit = FALSE;
1540
} else {
1541
note_set_vel_pan_reverb(note, 0, .5, 0);
1542
}
1543
note->priority = NOTE_PRIORITY_DISABLED;
1544
note->enabled = FALSE;
1545
note->finished = FALSE;
1546
note->parentLayer = NO_LAYER;
1547
note->prevParentLayer = NO_LAYER;
1548
}
1549
#endif
1550
#endif
1551
1552