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#include "audio/core.h"
4
5#define SWAP16(in, out) \
6{ \
7 s16 t = out; \
8 out = in; \
9 in = t; \
10}
11
12static Acmd* _loadDelayLineBuffer(AuFX* fx, s16* oldPos, s32 buff, s32 count, Acmd* cmdBufPos);
13static f32 updateTriangleModulation(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#define SCALE 16384
30
31#define INPUT_PARAM 0
32#define OUTPUT_PARAM 1
33#define FBCOEF_PARAM 2
34#define FFCOEF_PARAM 3
35#define GAIN_PARAM 4
36#define CHORUSRATE_PARAM 5
37#define CHORUSDEPTH_PARAM 6
38#define LPFILT_PARAM 7
39
41 /* sections length */
42 3, 11,
43 /* chorus chorus filter
44 input output fbcoef ffcoef gain rate depth coef */
45 0, 9, 9830, -9830, 0, 0, 0, 0,
46 3, 7, 3276, -3276, 0x3FFF, 0, 0, 0,
47 0, 10, 5000, 0, 0, 0, 0, 0x5000
48};
49
51 /* sections length */
52 4, 14,
53 /* chorus chorus filter
54 input output fbcoef ffcoef gain rate depth coef */
55 0, 9, 9830, -9830, 0, 0, 0, 0,
56 2, 6, 3276, -3276, 0x3FFF, 0, 0, 0,
57 9, 12, 3276, -3276, 0x3FFF, 0, 0, 0,
58 0, 13, 6000, 0, 0, 0, 0, 0x5000
59};
60
61// unused
63 /* sections length */
64 4, 17,
65 /* chorus chorus filter
66 input output fbcoef ffcoef gain rate depth coef */
67 0, 11, 9830, -9830, 0, 0, 0, 0,
68 4, 9, 3276, -3276, 0x3FFF, 0, 0, 0,
69 11, 15, 3276, -3276, 0x3FFF, 0, 0, 0,
70 0, 16, 8000, 0, 0, 0, 0, 0x5000
71};
72
74 /* sections length */
75 1, 14,
76 /* chorus chorus filter
77 input output fbcoef ffcoef gain rate depth coef */
78 0, 13, 20000, 0, 0x7FFF, 0, 0, 0x7FFF
79};
80
82 /* sections length */
83 1, 3,
84 /* chorus chorus filter
85 input output fbcoef ffcoef gain rate depth coef */
86 0, 1, 16384, 0, 0x7FFF, 7600, 700, 0
87};
88
90 /* sections length */
91 1, 3,
92 /* chorus chorus filter
93 input output fbcoef ffcoef gain rate depth coef */
94 0, 1, 0, 0x5FFF, 0x7FFF, 380, 500, 0
95};
96
98 /* sections length */
99 0, 0,
100 /* chorus chorus filter
101 input output fbcoef ffcoef gain rate depth coef */
102 0, 0, 0, 0, 0, 0, 0, 0
103};
104
105// up to four custom effects can be defined and installed here at runtime
109
110static void _init_lpfilter(AuLowPass* filter) {
113 u32 temp;
114 s32 i;
115
116 filter->first = 1;
117 temp = filter->fc;
120 filter->fgain = SCALE - timeConstant;
121
122 for (i = 0; i < 8; i++) {
123 filter->fccoef[i] = 0;
124 }
125
126 filter->fccoef[8] = timeConstant;
127
128 // ith value is 16384 * (timeConstant / 16384)^(i-7)
129 // ex: i = 9 --> timeConstant^2 / 16384
131 for (i = 9; i < ARRAY_COUNT(filter->fccoef); i++) {
133 filter->fccoef[i] = attenuation * SCALE;
134 }
135}
136
138void au_fx_create(AuFX* fx, u8 effectType, ALHeap* heap) {
139 AuDelay* delay;
140 u16 i;
141
142 // allocate space for 4 AuDelay
143 fx->delays = alHeapAlloc(heap, AU_FX_MAX_TAPS, sizeof(AuDelay));
144 fx->base = alHeapAlloc(heap, AU_FX_LENGTH, sizeof(s16));
145
146 for (i = 0; i < AU_FX_MAX_TAPS; i++) {
147 delay = &fx->delays[i];
148 delay->resamplerTemplate = alHeapAlloc(heap, 1, sizeof(AuResampler));
149 delay->resamplerTemplate->state = alHeapAlloc(heap, 1, sizeof(RESAMPLE_STATE));
150 delay->lowpassTemplate = alHeapAlloc(heap, 1, sizeof(AuLowPass));
151 delay->lowpassTemplate->fstate = alHeapAlloc(heap, 1, sizeof(POLEF_STATE));
152 }
153
154 au_fx_load_preset(fx, effectType);
155}
156
157// no known calls to this function
159 filter->base = alHeapAlloc(heap, AU_FILTER_LENGTH, sizeof(s16));
160 filter->lowpassTemplate = alHeapAlloc(heap, 1, sizeof(AuLowPass));
161 filter->lowpassTemplate->fstate = alHeapAlloc(heap, 1, sizeof(POLEF_STATE));
162 au_filter_init(filter, 0, 0, 0x5000);
163}
164
165// no known entry point to this function, called only by au_filter_create
166void au_filter_init(AuFilter* filter, s16 arg1, s16 arg2, s16 cutoff) {
167 filter->unused_06 = arg1;
168 filter->unused_08 = arg2;
169
170 if (cutoff != 0) {
171 filter->activeLowpass = filter->lowpassTemplate;
172 filter->activeLowpass->fc = cutoff;
173 _init_lpfilter(filter->activeLowpass);
174 return;
175 }
176
177 filter->activeLowpass = NULL;
178}
179
180// reset fx without reallocating AuFX
181void au_fx_load_preset(AuFX* fx, u8 effectType) {
182 s32* params;
183 s32* clr;
184 s32 i, j;
185 clr = (s32*)fx->base;
186
187 switch (effectType) {
188 case AU_FX_SMALLROOM:
189 params = SMALL_ROOM_PARAMS;
190 break;
191 case AU_FX_BIGROOM:
192 params = BIG_ROOM_PARAMS;
193 break;
194 case AU_FX_ECHO:
195 params = ECHO_PARAMS;
196 break;
197 case AU_FX_CHORUS:
198 params = CHORUS_PARAMS;
199 break;
200 case AU_FX_FLANGE:
201 params = FLANGE_PARAMS;
202 break;
203 case AU_FX_CUSTOM_0:
204 params = AU_FX_CUSTOM_PARAMS[0];
205 break;
206 case AU_FX_CUSTOM_1:
207 params = AU_FX_CUSTOM_PARAMS[1];
208 break;
209 case AU_FX_CUSTOM_2:
210 params = AU_FX_CUSTOM_PARAMS[2];
211 break;
212 case AU_FX_CUSTOM_3:
213 params = AU_FX_CUSTOM_PARAMS[3];
214 break;
216 params = BIG_ROOM_PARAMS;
217 break;
218 default:
219 params = NULL_PARAMS;
220 break;
221 }
222
223 j = 0;
224 fx->delayCount = params[j++];
225 fx->length = params[j++] * AUDIO_SAMPLES;
226 fx->input = fx->base;
227
228 for (i = 0; i < AU_FX_LENGTH/2; i++) {
229 *clr++ = 0;
230 }
231
232 for (i = 0; i < fx->delayCount; i++) {
233 AuDelay* delay = &fx->delays[i];
234 delay->input = params[j++] * AUDIO_SAMPLES;
235 delay->output = params[j++] * AUDIO_SAMPLES;
236 delay->fbcoef = (u16) params[j++];
237 delay->ffcoef = (u16) params[j++];
238 delay->gain = (u16) params[j++];
239
240 if (params[j]) {
241 delay->rsinc = (2.0 * (params[j++] / 1000.0f)) / gActiveSynDriverPtr->outputRate;
242 delay->rsgain = ((f32)params[j++] / CONVERT) * (delay->output - delay->input);
243 delay->rsval = 1.0f;
244 delay->rsdelta = 0.0f;
245 delay->activeResampler = delay->resamplerTemplate;
246 delay->resamplerTemplate->delta = 0.0;
247 delay->activeResampler->first = TRUE;
248 } else {
249 delay->activeResampler = NULL;
250 j++;
251 j++;
252 }
253
254 if (params[j]) {
255 delay->activeLowpass = delay->lowpassTemplate;
256 delay->activeLowpass->fc = params[j++];
257 _init_lpfilter(delay->activeLowpass);
258 } else {
259 delay->activeLowpass = NULL;
260 j++;
261 }
262 }
263}
264
282 Acmd* cmdBufPos = ptr;
284
285 s16* inPtr;
286 s16* outPtr;
287
288 // DMEM temp buffer layout:
292
293 s16* prevOutPtr = 0;
295
296 // save wet input from voice mixing into circular delay buffer
298
299 // clear the wet output buffer for this frame
301
302 for (delayIdx = 0; delayIdx < fx->delayCount; delayIdx++) {
303 AuDelay* delay = &fx->delays[delayIdx];
305
306 // calculate read positions for input and output taps, wrapping the circular buffer if necessary
307 inPtr = &fx->input[-delay->input];
308 if (inPtr < fx->base) {
309 inPtr += fx->length;
310 }
311 outPtr = &fx->input[-delay->output];
312 if (outPtr < fx->base) {
313 outPtr += fx->length;
314 }
315
316 // if output is same as previous tap, reuse loaded data by swapping buffers
317 if (inPtr == prevOutPtr) {
319 } else {
320 // load from input tap into buffer
322 }
323
324 if (delay->activeResampler) {
325 // triangle wave modulation for chorus/flange
326 s32 ratio;
327 s32 length, count;
328 f32 delta, fratio, fincount;
330 s16 tmp;
331 s16* rsOutPtr;
332
333 // modulate delay time (triangle wave)
334 length = delay->output - delay->input;
335 delta = updateTriangleModulation(delay, AUDIO_SAMPLES);
336 delta /= length;
337 delta = (s32)(delta * fUnityPitch);
338 delta = delta / UNITY_PITCH;
339
340 fratio = 1.0 - delta;
341
342 // calculate fractional resampling count
344 count = (s32) fincount;
345 delay->activeResampler->delta = fincount - count;
346
347 // prepare delay line for resampling (wrap if needed)
348 rsOutPtr = &fx->input[-(delay->output - delay->rsdelta)];
349 ramAlign = ((s32) rsOutPtr & 7) >> 1;
351 if (rsOutPtr < fx->base) {
352 rsOutPtr += fx->length;
353 }
354
355 // load from delay line
356 cmdBufPos = _loadDelayLineBuffer(fx, rsOutPtr, resampleBuffer, count + ramAlign, cmdBufPos);
357
358 // process resampler
359 ratio = fratio * fUnityPitch;
360 tmp = outputTapBuffer >> 8;
362 delay->activeResampler->first, ratio, resampleBuffer + (ramAlign<<1), tmp);
363 delay->activeResampler->first = FALSE;
364 delay->rsdelta += count - AUDIO_SAMPLES;
365 } else {
366 // no resampling -- just load from output pointer
368 }
369
370 // feedforward: input -> output
371 if (delay->ffcoef) {
373
374 // save output if no additional processing needed
375 if (delay->activeResampler == NULL && delay->activeLowpass == NULL) {
377 }
378 }
379
380 // feedback: output -> input
381 if (delay->fbcoef) {
384 }
385
386 // Save processed output back into delay line (if not resampled)
387 if (delay->activeLowpass != NULL) {
388 // modified _n_filterBuffer
392 delay->activeLowpass->first = 0;
393 }
394
395 // save output (if not already saved earlier)
396 if (!delay->activeResampler) {
398 }
399
400 // mix input from this delay into wet output buffer
401 if (delay->gain) {
402 aMix(cmdBufPos++, 0, (u16)delay->gain, outputTapBuffer, outDmem);
403 }
404 prevOutPtr = &fx->input[delay->output];
405 }
406
407 // advance position in ring buffer
408 fx->input += AUDIO_SAMPLES;
409 if (fx->input >= &fx->base[fx->length]) {
410 fx->input = fx->base;
411 }
412
413 return cmdBufPos;
414}
415
417 switch (paramID) {
418 case INPUT_PARAM:
419 fx->delays[index].input = value & 0xFFFFFFF8;
420 break;
421 case OUTPUT_PARAM:
422 fx->delays[index].output = value & 0xFFFFFFF8;
423 break;
424 case FFCOEF_PARAM:
425 fx->delays[index].ffcoef = value;
426 break;
427 case FBCOEF_PARAM:
428 fx->delays[index].fbcoef = value;
429 break;
430 case GAIN_PARAM:
431 fx->delays[index].gain = value;
432 break;
433 case CHORUSRATE_PARAM:
434 fx->delays[index].rsinc = (2.0 * (value / 1000.0f)) / gActiveSynDriverPtr->outputRate;
435 break;
437 fx->delays[index].rsgain = ((f32)value / CONVERT) * (fx->delays[index].output - fx->delays[index].input);
438 break;
439 case LPFILT_PARAM:
440 if (fx->delays[index].activeLowpass) {
441 fx->delays[index].activeLowpass->fc = value;
442 _init_lpfilter(fx->delays[index].activeLowpass);
443 }
444 break;
445 }
446 return 0;
447}
448
453static Acmd* _loadDelayLineBuffer(AuFX* fx, s16* oldPos, s32 buf, s32 count, Acmd* cmdBufPos) {
454 Acmd *ptr = cmdBufPos;
455 s16* newPos = oldPos + count;
456 s16* delayEnd = &fx->base[fx->length];
457
458 if (delayEnd < newPos) {
462 n_aLoadBuffer(ptr++, after<<1, buf + (before<<1), osVirtualToPhysical(fx->base));
463 } else {
464 n_aLoadBuffer(ptr++, count<<1, buf, osVirtualToPhysical(oldPos));
465 }
466
467 return ptr;
468}
469
470// updates rsval, producing a triangle wave between ±1
471// time delta specified in samples
472static f32 updateTriangleModulation(AuDelay* delay, s32 numSamples) {
473 f32 result;
474
475 delay->rsval += delay->rsinc * numSamples;
476 delay->rsval = (delay->rsval > 2.0) ? delay->rsval - 4.0 : delay->rsval;
477
478 result = delay->rsval;
479 if (result < 0.0f) {
480 result = -result;
481 }
482
483 result -= 1.0;
484
485 return delay->rsgain * result;
486}
BSS s32 PopupMenu_SelectedIndex
f32 delta
Definition audio.h:595
f32 rsval
Definition audio.h:524
s32 rsdelta
Definition audio.h:525
@ AU_FX_CUSTOM_3
Definition audio.h:164
@ AU_FX_FLANGE
Definition audio.h:159
@ AU_FX_CUSTOM_2
Definition audio.h:163
@ AU_FX_CUSTOM_1
Definition audio.h:162
@ AU_FX_ECHO
Definition audio.h:160
@ AU_FX_CHORUS
Definition audio.h:158
@ AU_FX_SMALLROOM
Definition audio.h:156
@ AU_FX_OTHER_BIGROOM
Definition audio.h:165
@ AU_FX_BIGROOM
Definition audio.h:157
@ AU_FX_CUSTOM_0
Definition audio.h:161
#define AU_FX_LENGTH
Definition audio.h:19
AuSynDriver * gActiveSynDriverPtr
Definition syn_driver.c:14
s16 fccoef[16]
Definition audio.h:545
s16 fc
Definition audio.h:542
struct AuResampler * resamplerTemplate
Definition audio.h:530
s32 outputRate
Definition audio.h:637
u32 output
Definition audio.h:518
s16 fbcoef
Definition audio.h:520
s16 ffcoef
Definition audio.h:519
#define AUDIO_SAMPLES
Definition audio.h:16
s32 first
Definition audio.h:547
b32 first
Definition audio.h:596
f32 rsgain
Definition audio.h:526
struct AuResampler * activeResampler
Definition audio.h:529
f32 rsinc
Definition audio.h:523
u32 input
Definition audio.h:517
POLEF_STATE * fstate
Definition audio.h:546
s16 gain
Definition audio.h:521
#define AU_FILTER_LENGTH
Definition audio.h:21
struct AuLowPass * lowpassTemplate
Definition audio.h:528
RESAMPLE_STATE * state
Definition audio.h:593
#define AU_FX_MAX_TAPS
Definition audio.h:18
s16 fgain
Definition audio.h:543
struct AuLowPass * activeLowpass
Definition audio.h:527
Definition audio.h:533
void * alHeapAlloc(ALHeap *heap, s32 count, s32 size)
Definition syn_driver.c:765
#define SCALE
Definition reverb.c:29
#define FBCOEF_PARAM
Definition reverb.c:33
s32 au_fx_param_hdl(AuFX *fx, s16 index, s16 paramID, s32 value)
Definition reverb.c:416
#define CONVERT
Definition reverb.c:27
void au_filter_create(AuFilter *filter, ALHeap *heap)
Definition reverb.c:158
#define INPUT_PARAM
Definition reverb.c:31
#define CHORUSRATE_PARAM
Definition reverb.c:36
#define OUTPUT_PARAM
Definition reverb.c:32
void au_filter_init(AuFilter *filter, s16 arg1, s16 arg2, s16 cutoff)
Definition reverb.c:166
s32 ECHO_PARAMS[]
Definition reverb.c:73
s32 CHORUS_PARAMS[]
Definition reverb.c:81
s32 * AU_FX_CUSTOM_PARAMS[]
Definition reverb.c:106
#define SWAP16(in, out)
Definition reverb.c:5
s32 BIG_ROOM_PARAMS[]
Definition reverb.c:50
s32 FLANGE_PARAMS[]
Definition reverb.c:89
s32 D_8007F0C0[]
Definition reverb.c:62
#define CHORUSDEPTH_PARAM
Definition reverb.c:37
#define GAIN_PARAM
Definition reverb.c:35
void au_fx_load_preset(AuFX *fx, u8 effectType)
Definition reverb.c:181
#define FFCOEF_PARAM
Definition reverb.c:34
void au_fx_create(AuFX *fx, u8 effectType, ALHeap *heap)
Definition reverb.c:138
#define LPFILT_PARAM
Definition reverb.c:38
s32 NULL_PARAMS[]
Definition reverb.c:97
Acmd * au_pull_fx(AuFX *fx, Acmd *ptr, s16 wetDmem, s16 tempDmem)
Applies a chain of delay-line based effects to audio and mixes into output.
Definition reverb.c:281
s32 SMALL_ROOM_PARAMS[]
Definition reverb.c:40
#define ARRAY_COUNT(arr)
Definition macros.h:40