Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
reverb.c
Go to the documentation of this file.
1#include "common.h"
2#include "audio.h"
3
4#define SWAP16(in, out) \
5{ \
6 s16 t = out; \
7 out = in; \
8 in = t; \
9}
10
11static void _init_lpfilter(AuLowPass* lp);
12static Acmd* _saveBuffer(AuFX* fx, s16* oldPos, s32 buff, s32 count, Acmd* cmdBufPos);
13static f32 func_80059BD4(AuDelay* delay, s32 rsdelta);
14
15/*
16* the following constant is derived from:
17*
18* ratio = 2^(cents/1200)
19*
20* and therefore for hundredths of a cent
21* x
22* ln(ratio) = ---------------
23* (120,000)/ln(2)
24* where
25* 120,000/ln(2) = 173123.40...
26*/
27#define CONVERT 173123.404906676
28
29/*
30 * WARNING: THE FOLLOWING CONSTANT MUST BE KEPT IN SYNC
31 * WITH SCALING IN MICROCODE!!!
32 */
33#define SCALE 16384
34
35// #define ms *(((s32)((f32)44.1))&~0x7)
36
38 /* sections length */
39 3, 11,
40 /* chorus chorus filter
41 input output fbcoef ffcoef gain rate depth coef */
42 0, 9, 9830, -9830, 0, 0, 0, 0,
43 3, 7, 3276, -3276, 0x3FFF, 0, 0, 0,
44 0, 10, 5000, 0, 0, 0, 0, 0x5000
45};
46
48 /* sections length */
49 4, 14,
50 /* chorus chorus filter
51 input output fbcoef ffcoef gain rate depth coef */
52 0, 9, 9830, -9830, 0, 0, 0, 0,
53 2, 6, 3276, -3276, 0x3FFF, 0, 0, 0,
54 9, 12, 3276, -3276, 0x3FFF, 0, 0, 0,
55 0, 13, 6000, 0, 0, 0, 0, 0x5000
56};
57
58// unused
59s32 D_8007F0C0[] = {
60 /* sections length */
61 4, 17,
62 /* chorus chorus filter
63 input output fbcoef ffcoef gain rate depth coef */
64 0, 11, 9830, -9830, 0, 0, 0, 0,
65 4, 9, 3276, -3276, 0x3FFF, 0, 0, 0,
66 11, 15, 3276, -3276, 0x3FFF, 0, 0, 0,
67 0, 16, 8000, 0, 0, 0, 0, 0x5000
68};
69
70s32 ECHO_PARAMS[] = {
71 /* sections length */
72 1, 14,
73 /* chorus chorus filter
74 input output fbcoef ffcoef gain rate depth coef */
75 0, 13, 20000, 0, 0x7FFF, 0, 0, 0x7FFF
76};
77
79 /* sections length */
80 1, 3,
81 /* chorus chorus filter
82 input output fbcoef ffcoef gain rate depth coef */
83 0, 1, 16384, 0, 0x7FFF, 7600, 700, 0
84};
85
87 /* sections length */
88 1, 3,
89 /* chorus chorus filter
90 input output fbcoef ffcoef gain rate depth coef */
91 0, 1, 0, 0x5FFF, 0x7FFF, 380, 500, 0
92};
93
94s32 NULL_PARAMS[] = {
95 /* sections length */
96 0, 0,
97 /* chorus chorus filter
98 input output fbcoef ffcoef gain rate depth coef */
99 0, 0, 0, 0, 0, 0, 0, 0
100};
101
102// up to four custom effects can be defined and installed here at runtime
106
107static void _init_lpfilter(AuLowPass* lp) {
108 f64 attenuation;
109 s16 timeConstant;
110 u32 temp;
111 s32 i;
112
113 lp->first = 1;
114 temp = lp->fc;
115 timeConstant = temp;
116 timeConstant = timeConstant >> 1;
117 lp->fgain = SCALE - timeConstant;
118
119 for (i = 0; i < ARRAY_COUNT(lp->fccoef) / 2; i++) {
120 lp->fccoef[i] = 0;
121 }
122
123 lp->fccoef[8] = timeConstant;
124
125 // ith value is 16384 * (timeConstant / 16384)^(i-7)
126 // ex: i = 9 --> timeConstant^2 / 16384
127 attenuation = ((f64)timeConstant / SCALE);
128 for (i = 9; i < ARRAY_COUNT(lp->fccoef); i++) {
129 attenuation *= ((f64)timeConstant /SCALE);
130 lp->fccoef[i] = attenuation * SCALE;
131 }
132}
133
134// definately AuFX, evidenced by call to func_8005904C
135// this is n_alFxNew
137void func_80058E84(AuFX* fx, u8 effectType, ALHeap* heap) {
138 AuDelay* delay;
139 u16 i;
140
141 // allocate space for 4 AuDelay
142 fx->delays = alHeapAlloc(heap, AU_FX_DELAY_COUNT, sizeof(AuDelay));
143 fx->base = alHeapAlloc(heap, AU_FX_LENGTH, sizeof(s16));
144
145 for (i = 0; i < AU_FX_DELAY_COUNT; i++) {
146 delay = &fx->delays[i];
147 delay->resampler_2C = alHeapAlloc(heap, 1, sizeof(AuResampler));
148 delay->resampler_2C->state = alHeapAlloc(heap, 1, sizeof(RESAMPLE_STATE));
149 delay->lowpass_24 = alHeapAlloc(heap, 1, sizeof(AuLowPass));
150 delay->lowpass_24->fstate = alHeapAlloc(heap, 1, sizeof(POLEF_STATE));
151 }
152
153 func_8005904C(fx, effectType);
154}
155
156// no known calls to this function
157void func_80058F88(AlUnkKappa* kappa, ALHeap* heap) {
158 kappa->unk_00 = alHeapAlloc(heap, 0x1420, sizeof(s16));
159 kappa->lowpass_10 = alHeapAlloc(heap, 1, sizeof(AuLowPass));
160 kappa->lowpass_10->fstate = alHeapAlloc(heap, 1, sizeof(POLEF_STATE));
161 func_80059008(kappa, 0, 0, 0x5000);
162}
163
164// no known entry point to this function, called only by func_80058F88
165void func_80059008(AlUnkKappa* kappa, s16 arg1, s16 arg2, s16 fc) {
166 kappa->unk_06 = arg1;
167 kappa->unk_08 = arg2;
168
169 if (fc != 0) {
170 kappa->lowpass_0C = kappa->lowpass_10;
171 kappa->lowpass_0C->fc = fc;
172 _init_lpfilter(kappa->lowpass_0C);
173 return;
174 }
175
176 kappa->lowpass_0C = NULL;
177}
178
179// part of n_alFxNew, extracted to allow reseting fx without reallocating AuFX
180void func_8005904C(AuFX* fx, u8 effectType) {
181 s32* params;
182 s32* clr;
183 s32 i, j;
184 clr = (s32*)fx->base;
185
186 switch (effectType) {
187 case AU_FX_SMALLROOM:
188 params = SMALL_ROOM_PARAMS;
189 break;
190 case AU_FX_BIGROOM:
191 params = BIG_ROOM_PARAMS;
192 break;
193 case AU_FX_ECHO:
194 params = ECHO_PARAMS;
195 break;
196 case AU_FX_CHORUS:
197 params = CHORUS_PARAMS;
198 break;
199 case AU_FX_FLANGE:
200 params = FLANGE_PARAMS;
201 break;
202 case AU_FX_CUSTOM_0:
203 params = AU_FX_CUSTOM_PARAMS[0];
204 break;
205 case AU_FX_CUSTOM_1:
206 params = AU_FX_CUSTOM_PARAMS[1];
207 break;
208 case AU_FX_CUSTOM_2:
209 params = AU_FX_CUSTOM_PARAMS[2];
210 break;
211 case AU_FX_CUSTOM_3:
212 params = AU_FX_CUSTOM_PARAMS[3];
213 break;
215 params = BIG_ROOM_PARAMS;
216 break;
217 default:
218 params = NULL_PARAMS;
219 break;
220 }
221
222 j = 0;
223 fx->delayCount = params[j++];
224 fx->length = params[j++] * AUDIO_SAMPLES;
225 fx->input = fx->base;
226
227 for (i = 0; i < AU_FX_LENGTH/2; i++) {
228 *clr++ = 0;
229 }
230
231 for (i = 0; i < fx->delayCount; i++) {
232 AuDelay* delay = &fx->delays[i];
233 delay->input = params[j++] * AUDIO_SAMPLES;
234 delay->output = params[j++] * AUDIO_SAMPLES;
235 delay->fbcoef = (u16) params[j++];
236 delay->ffcoef = (u16) params[j++];
237 delay->gain = (u16) params[j++];
238
239 if (params[j]) {
240 delay->rsinc = (2.0 * (params[j++] / 1000.0f)) / gActiveSynDriverPtr->outputRate;
241 delay->rsgain = ((f32)params[j++] / CONVERT) * (delay->output - delay->input);
242 delay->rsval = 1.0f;
243 delay->rsdelta = 0.0f;
244 delay->resampler_28 = delay->resampler_2C;
245 delay->resampler_2C->delta = 0.0;
246 delay->resampler_28->first = 1;
247 } else {
248 delay->resampler_28 = NULL;
249 j++;
250 j++;
251 }
252
253 if (params[j]) {
254 delay->lowpass_20 = delay->lowpass_24;
255 delay->lowpass_20->fc = params[j++];
256 _init_lpfilter(delay->lowpass_20);
257 } else {
258 delay->lowpass_20 = NULL;
259 j++;
260 }
261 }
262}
263
264// au_pull_fx -- based on alFxPull
265// AuFX from gSynDriverPtr
266
267Acmd* au_pull_fx(AuFX* fx, Acmd* ptr, s16 outputBuf, s16 arg3) {
268 Acmd* cmdBufPos = ptr;
269 s16 delayIdx;
270
271 s16* inPtr;
272 s16* outPtr;
273
274 s16 buff1 = arg3 + N_AL_TEMP_0;
275 s16 buff2 = arg3 + N_AL_TEMP_1;
276 s16 rbuff = arg3 + N_AL_TEMP_2;
277 s16* prevOutPtr = 0;
278 s16 outputBufCopy = outputBuf;
279
280 n_aSaveBuffer(cmdBufPos++, FIXED_SAMPLE<<1, outputBuf, osVirtualToPhysical(fx->input));
281 aClearBuffer(cmdBufPos++, outputBuf, FIXED_SAMPLE<<1);
282
283 for (delayIdx = 0; delayIdx < fx->delayCount; delayIdx++) {
284 AuDelay* delay = &fx->delays[delayIdx];
285 f32 fUnityPitch = UNITY_PITCH;
286
287 inPtr = &fx->input[-delay->input];
288 if (inPtr < fx->base) {
289 inPtr += fx->length;
290 }
291 outPtr = &fx->input[-delay->output];
292 if (outPtr < fx->base) {
293 outPtr += fx->length;
294 }
295 if (inPtr == prevOutPtr) {
296 SWAP16(buff1, buff2);
297 } else {
298 n_aLoadBuffer(cmdBufPos++, FIXED_SAMPLE<<1, buff1, osVirtualToPhysical(inPtr));
299 }
300 if (delay->resampler_28) {
301 // modified _n_loadOutputBuffer
302 s32 ratio;
303 s32 length, count;
304 f32 delta, fratio, fincount;
305 s32 ramAlign;
306 s16 tmp;
307 s16* rsOutPtr;
308
309 length = delay->output - delay->input;
310 delta = func_80059BD4(delay, AUDIO_SAMPLES);
311 delta /= length;
312 delta = (s32)(delta * fUnityPitch);
313 delta = delta / UNITY_PITCH;
314 fratio = 1.0 - delta;
315 fincount = delay->resampler_28->delta + (fratio * AUDIO_SAMPLES);
316 count = (s32) fincount;
317 delay->resampler_28->delta = fincount - count;
318
319 rsOutPtr = &fx->input[-(delay->output - delay->rsdelta)];
320 ramAlign = ((s32) rsOutPtr & 7) >> 1;
321
322 rsOutPtr -= ramAlign;
323 if (rsOutPtr < fx->base) {
324 rsOutPtr += fx->length;
325 }
326
327 cmdBufPos = _saveBuffer(fx, rsOutPtr, rbuff, count + ramAlign, cmdBufPos);
328 ratio = fratio * fUnityPitch;
329
330 tmp = buff2 >> 8;
331 n_aResample(cmdBufPos++, osVirtualToPhysical(delay->resampler_28->state),
332 delay->resampler_28->first, ratio, rbuff + (ramAlign<<1), tmp);
333
334 delay->resampler_28->first = 0;
335 delay->rsdelta += count - AUDIO_SAMPLES;
336 } else {
337 n_aLoadBuffer(cmdBufPos++, FIXED_SAMPLE<<1, buff2, osVirtualToPhysical(outPtr));
338 }
339 if (delay->ffcoef) {
340 aMix(cmdBufPos++, 0, (u16)delay->ffcoef, buff1, buff2);
341
342 if (delay->resampler_28 == NULL && delay->lowpass_20 == NULL) {
343 n_aSaveBuffer(cmdBufPos++, FIXED_SAMPLE<<1, buff2, osVirtualToPhysical(outPtr));
344 }
345 }
346 if (delay->fbcoef) {
347 aMix(cmdBufPos++, 0, (u16)delay->fbcoef, buff2, buff1);
348 n_aSaveBuffer(cmdBufPos++, FIXED_SAMPLE<<1, buff1, osVirtualToPhysical(inPtr));
349 }
350 if (delay->lowpass_20 != NULL) {
351 // modified _n_filterBuffer
352 s16 tmp = buff2 >> 8;
353 n_aLoadADPCM(cmdBufPos++, 32, osVirtualToPhysical(delay->lowpass_20->fccoef));
354 n_aPoleFilter(cmdBufPos++, delay->lowpass_20->first, delay->lowpass_20->fgain, tmp, osVirtualToPhysical(delay->lowpass_20->fstate));
355 delay->lowpass_20->first = 0;
356 }
357 if (!delay->resampler_28) {
358 n_aSaveBuffer(cmdBufPos++, FIXED_SAMPLE<<1, buff2, osVirtualToPhysical(outPtr));
359 }
360 if (delay->gain) {
361 aMix(cmdBufPos++, 0, (u16)delay->gain, buff2, outputBufCopy);
362 }
363 prevOutPtr = &fx->input[delay->output];
364 }
365
366 fx->input += AUDIO_SAMPLES;
367 if (fx->input >= &fx->base[fx->length]) {
368 fx->input = fx->base;
369 }
370 return cmdBufPos;
371}
372
373
374#define INPUT_PARAM 0
375#define OUTPUT_PARAM 1
376#define FBCOEF_PARAM 2
377#define FFCOEF_PARAM 3
378#define GAIN_PARAM 4
379#define CHORUSRATE_PARAM 5
380#define CHORUSDEPTH_PARAM 6
381#define LPFILT_PARAM 7
382
383// based on alFxParamHdl
384s32 au_fx_param_hdl(AuFX* fx, s16 index, s16 paramID, s32 value) {
385 switch (paramID) {
386 case INPUT_PARAM:
387 fx->delays[index].input = value & 0xFFFFFFF8;
388 break;
389 case OUTPUT_PARAM:
390 fx->delays[index].output = value & 0xFFFFFFF8;
391 break;
392 case FFCOEF_PARAM:
393 fx->delays[index].ffcoef = value;
394 break;
395 case FBCOEF_PARAM:
396 fx->delays[index].fbcoef = value;
397 break;
398 case GAIN_PARAM:
399 fx->delays[index].gain = value;
400 break;
401 case CHORUSRATE_PARAM:
402 fx->delays[index].rsinc = (2.0 * (value / 1000.0f)) / gActiveSynDriverPtr->outputRate;
403 break;
405 fx->delays[index].rsgain = ((f32)value / CONVERT) * (fx->delays[index].output - fx->delays[index].input);
406 break;
407 case LPFILT_PARAM:
408 if (fx->delays[index].lowpass_20) {
409 fx->delays[index].lowpass_20->fc = value;
410 _init_lpfilter(fx->delays[index].lowpass_20);
411 }
412 break;
413 }
414 return 0;
415}
416
417// TODO: _n_loadBuffer
418static Acmd* _saveBuffer(AuFX* fx, s16* oldPos, s32 buf, s32 count, Acmd* cmdBufPos) {
419 Acmd *ptr = cmdBufPos;
420 s16* newPos = oldPos + count;
421 s16* delayEnd = &fx->base[fx->length];
422
423 if (delayEnd < newPos) {
424 s32 before = delayEnd - oldPos;
425 s32 after = newPos - delayEnd;
426 n_aLoadBuffer(ptr++, before<<1, buf, osVirtualToPhysical(oldPos));
427 n_aLoadBuffer(ptr++, after<<1, buf + (before<<1), osVirtualToPhysical(fx->base));
428 } else {
429 n_aLoadBuffer(ptr++, count<<1, buf, osVirtualToPhysical(oldPos));
430 }
431
432 return ptr;
433}
434
435// updates rsval, producing a triangle wave between ±1
436// time delta specified in samples
437//TODO rename to _updateTriWaveModulation
438static f32 func_80059BD4(AuDelay* delay, s32 rsdelta) {
439 f32 result;
440
441 delay->rsval += delay->rsinc * rsdelta;
442 delay->rsval = (delay->rsval > 2.0) ? delay->rsval - 4.0 : delay->rsval;
443
444 result = delay->rsval;
445 if (result < 0.0f) {
446 result = -result;
447 }
448
449 result = result - 1.0;
450
451 return delay->rsgain * result;
452}
void * alHeapAlloc(ALHeap *heap, s32 count, s32 size)
Definition 31650.c:743
f32 delta
Definition audio.h:470
f32 rsval
Definition audio.h:397
UNK_TYPE_PTR unk_00
Definition audio.h:427
s32 rsdelta
Definition audio.h:398
@ AU_FX_CUSTOM_3
Definition audio.h:96
@ AU_FX_FLANGE
Definition audio.h:91
@ AU_FX_CUSTOM_2
Definition audio.h:95
@ AU_FX_CUSTOM_1
Definition audio.h:94
@ AU_FX_ECHO
Definition audio.h:92
@ AU_FX_CHORUS
Definition audio.h:90
@ AU_FX_SMALLROOM
Definition audio.h:88
@ AU_FX_OTHER_BIGROOM
Definition audio.h:97
@ AU_FX_BIGROOM
Definition audio.h:89
@ AU_FX_CUSTOM_0
Definition audio.h:93
#define AU_FX_LENGTH
Definition audio.h:20
AuSynDriver * gActiveSynDriverPtr
Definition 31650.c:14
s16 fccoef[16]
Definition audio.h:421
struct AuResampler * resampler_28
Definition audio.h:402
s16 fc
Definition audio.h:417
struct AuLowPass * lowpass_24
Definition audio.h:401
s32 outputRate
Definition audio.h:512
u32 output
Definition audio.h:391
s16 fbcoef
Definition audio.h:393
s16 ffcoef
Definition audio.h:392
#define AUDIO_SAMPLES
Definition audio.h:44
s32 first
Definition audio.h:423
s32 first
Definition audio.h:471
f32 rsgain
Definition audio.h:399
#define N_AL_TEMP_1
Definition audio.h:32
AuLowPass * lowpass_10
Definition audio.h:433
struct AuLowPass * lowpass_20
Definition audio.h:400
AuLowPass * lowpass_0C
Definition audio.h:432
u8 delayCount
Definition audio.h:412
#define N_AL_TEMP_0
Definition audio.h:30
AuDelay * delays
Definition audio.h:411
struct AuResampler * resampler_2C
Definition audio.h:403
f32 rsinc
Definition audio.h:396
u32 input
Definition audio.h:390
s16 unk_06
Definition audio.h:429
POLEF_STATE * fstate
Definition audio.h:422
s16 gain
Definition audio.h:394
#define FIXED_SAMPLE
Definition audio.h:26
#define AU_FX_DELAY_COUNT
Definition audio.h:19
s16 * input
Definition audio.h:409
s16 unk_08
Definition audio.h:430
#define N_AL_TEMP_2
Definition audio.h:33
RESAMPLE_STATE * state
Definition audio.h:468
s16 * base
Definition audio.h:408
s32 length
Definition audio.h:410
s16 fgain
Definition audio.h:418
Definition audio.h:407
#define SCALE
Definition reverb.c:33
#define FBCOEF_PARAM
Definition reverb.c:376
s32 au_fx_param_hdl(AuFX *fx, s16 index, s16 paramID, s32 value)
Definition reverb.c:384
#define CONVERT
Definition reverb.c:27
void func_8005904C(AuFX *fx, u8 effectType)
Definition reverb.c:180
#define INPUT_PARAM
Definition reverb.c:374
#define CHORUSRATE_PARAM
Definition reverb.c:379
#define OUTPUT_PARAM
Definition reverb.c:375
void func_80058E84(AuFX *fx, u8 effectType, ALHeap *heap)
Definition reverb.c:137
s32 ECHO_PARAMS[]
Definition reverb.c:70
s32 CHORUS_PARAMS[]
Definition reverb.c:78
s32 * AU_FX_CUSTOM_PARAMS[]
Definition reverb.c:103
#define SWAP16(in, out)
Definition reverb.c:4
s32 BIG_ROOM_PARAMS[]
Definition reverb.c:47
void func_80059008(AlUnkKappa *kappa, s16 arg1, s16 arg2, s16 fc)
Definition reverb.c:165
s32 FLANGE_PARAMS[]
Definition reverb.c:86
s32 D_8007F0C0[]
Definition reverb.c:59
#define CHORUSDEPTH_PARAM
Definition reverb.c:380
#define GAIN_PARAM
Definition reverb.c:378
void func_80058F88(AlUnkKappa *kappa, ALHeap *heap)
Definition reverb.c:157
#define FFCOEF_PARAM
Definition reverb.c:377
Acmd * au_pull_fx(AuFX *fx, Acmd *ptr, s16 outputBuf, s16 arg3)
Definition reverb.c:267
#define LPFILT_PARAM
Definition reverb.c:381
s32 NULL_PARAMS[]
Definition reverb.c:94
s32 SMALL_ROOM_PARAMS[]
Definition reverb.c:37
#define ARRAY_COUNT(arr)
Definition macros.h:40