Paper Mario DX
Paper Mario (N64) modding
 
Loading...
Searching...
No Matches
pull_voice.c
Go to the documentation of this file.
1#include "audio.h"
2#include "audio/core.h"
3
4#define LFSAMPLES 4
5#define AUEQPOWER_LENGTH 128
6
7// lookup table for constant-power panning
8// these are values for cosine from 0 to pi/2 multiplied by 32767
9// called n_eqpower in libultra
11 32767, 32764, 32757, 32744, 32727, 32704, 32677, 32644,
12 32607, 32564, 32517, 32464, 32407, 32344, 32277, 32205,
13 32127, 32045, 31958, 31866, 31770, 31668, 31561, 31450,
14 31334, 31213, 31087, 30957, 30822, 30682, 30537, 30388,
15 30234, 30075, 29912, 29744, 29572, 29395, 29214, 29028,
16 28838, 28643, 28444, 28241, 28033, 27821, 27605, 27385,
17 27160, 26931, 26698, 26461, 26220, 25975, 25726, 25473,
18 25216, 24956, 24691, 24423, 24151, 23875, 23596, 23313,
19 23026, 22736, 22442, 22145, 21845, 21541, 21234, 20924,
20 20610, 20294, 19974, 19651, 19325, 18997, 18665, 18331,
21 17993, 17653, 17310, 16965, 16617, 16266, 15913, 15558,
22 15200, 14840, 14477, 14113, 13746, 13377, 13006, 12633,
23 12258, 11881, 11503, 11122, 10740, 10357, 9971, 9584,
24 9196, 8806, 8415, 8023, 7630, 7235, 6839, 6442,
25 6044, 5646, 5246, 4845, 4444, 4042, 3640, 3237,
26 2833, 2429, 2025, 1620, 1216, 810, 405, 0
27};
28
29static Acmd* _decodeChunk(Acmd* cmdBufPos, AuLoadFilter* filter, s32 tsam, s32 nbytes, s16 output, s16 input, s32 flags);
30static s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel);
31
32// decode, resample, and mix
34 Acmd* ptr = cmdBufPos;
35 AuLoadFilter* decoder;
36 AuResampler* resampler;
37 AuEnvMixer* envMixer;
38 s16 inp;
40 s16 outp;
43 s32 incr;
44
45 envMixer = &pvoice->envMixer;
46 resampler = &pvoice->resampler;
47 decoder = &pvoice->decoder;
48
49 // return if voice is not playing
50 if (envMixer->motion != AL_PLAYING) {
51 return ptr;
52 }
53
54 // buffer to store decoded (or raw) samples before mixing
56
57 if (resampler->ratio > MAX_RATIO) {
58 resampler->ratio = MAX_RATIO;
59 }
60
61 // convert pitch ratio to fixed-point resampling increment
62 resampler->ratio = (s32)(resampler->ratio * UNITY_PITCH);
63 resampler->ratio = resampler->ratio / UNITY_PITCH;
64
65 // determine how many output samples are needed for this frame
66 finCount = resampler->delta + resampler->ratio * (f32)AUDIO_SAMPLES;
68 resampler->delta = finCount - (f32) outCount;
69
70 if (outCount != 0) {
71 if (decoder->instrument->type == AL_ADPCM_WAVE) {
72 s32 nSam;
73 s32 nbytes;
75 s32 op;
76 s32 tsam;
77 s32 nLeft;
78 s32 bEnd;
79 s32 nOver;
84
85 // load ADPCM predictor
86 aLoadADPCM(ptr++, decoder->bookSize, K0_TO_PHYS(decoder->instrument->predictor));
87
88 // will loop be triggered during this frame? if so, only process up to loop end
89 looped = (decoder->loop.end < outCount + decoder->sample) && (decoder->loop.count != 0);
90
91 if (looped) {
92 nSam = decoder->loop.end - decoder->sample;
93 } else {
94 nSam = outCount;
95 }
96
97 if (decoder->lastsam != 0) {
98 nLeft = ADPCMFSIZE - decoder->lastsam;
99 } else {
100 nLeft = 0;
101 }
102
103 tsam = nSam - nLeft;
104 if (tsam < 0) {
105 tsam = 0;
106 }
107
108 nframes = (tsam + ADPCMFSIZE - 1) >> LFSAMPLES;
110
111 if (looped) {
112 ptr = _decodeChunk(ptr, decoder, tsam, nbytes, outp, inp, decoder->first);
113 if (decoder->lastsam != 0) {
114 outp += (decoder->lastsam << 1);
115 } else {
116 outp += (ADPCMFSIZE << 1);
117 }
118
119 decoder->lastsam = decoder->loop.start & 0xF;
120 decoder->memin = (s32)decoder->instrument->wavData + ADPCMFBYTES * ((s32)(decoder->loop.start >> LFSAMPLES) + 1);
121 decoder->sample = decoder->loop.start;
122
123 // continue decoding looped portion if needed
124 bEnd = outp;
125 while (outCount > nSam) {
126 outCount -= nSam;
127 op = (bEnd + ((nframes + 1) << (LFSAMPLES + 1)) + 16) & ~0x1F;
128 bEnd += nSam << 1;
129 if (decoder->loop.count != -1 && decoder->loop.count != 0) {
130 decoder->loop.count--;
131 }
132 nSam = MIN(outCount, decoder->loop.end - decoder->loop.start);
133 tsam = nSam - ADPCMFSIZE + decoder->lastsam;
134 if (tsam < 0) {
135 tsam = 0;
136 }
137 nframes = (tsam + ADPCMFSIZE - 1) >> LFSAMPLES;
139 ptr = _decodeChunk(ptr, decoder, tsam, nbytes, op, inp, decoder->first | A_LOOP);
140 aDMEMMove(ptr++, op + (decoder->lastsam << 1), bEnd, nSam << 1);
141 }
142 decoder->lastsam = (outCount + decoder->lastsam) & 0xF;
143 decoder->sample += outCount;
144 decoder->memin += ADPCMFBYTES * nframes;
145 } else {
147 overFlow = decoder->memin + nbytes - ((s32)decoder->instrument->wavData + decoder->instrument->wavDataLength);
148
149 if (overFlow <= 0) {
150 overFlow = 0;
151 } else {
152 envMixer->motion = AL_STOPPED;
153 }
155 if (nOver > nSam + nLeft) {
156 nOver = nSam + nLeft;
157 }
158 nbytes -= overFlow;
159 if (nOver - (nOver & 0xF) < outCount) {
160 decoded = TRUE;
161 ptr = _decodeChunk(ptr, decoder, nSam - nOver, nbytes, outp, inp, decoder->first);
162 if (decoder->lastsam != 0) {
163 outp += decoder->lastsam << 1;
164 } else {
165 outp += ADPCMFSIZE << 1;
166 }
167 decoder->lastsam = (outCount + decoder->lastsam) & 0xF;
168 decoder->sample += outCount;
169 decoder->memin += ADPCMFBYTES * nframes;
170 } else {
171 decoder->lastsam = 0;
172 decoder->memin += ADPCMFBYTES * nframes;
173 }
174
175 if (nOver != 0) {
176 decoder->lastsam = 0;
177 if (decoded) {
178 startZero = (nLeft + nSam - nOver) << 1;
179 } else {
180 startZero = 0;
181 }
182 aClearBuffer(ptr++, startZero + outp, nOver << 1);
183 }
184 }
185 } else {
186 s32 nSam;
187 s32 nbytes;
188 s32 op;
190 s32 dramLoc;
193 if (decoder->loop.end < outCount + decoder->sample && decoder->loop.count != 0) {
194 nSam = decoder->loop.end - decoder->sample;
195 nbytes = nSam << 1;
196 if (nSam > 0) {
197 dramLoc = decoder->dmaFunc(decoder->memin, nbytes, decoder->dmaState, decoder->instrument->useDma);
198 dramAlign = dramLoc & 7;
199 nbytes += dramAlign;
200 n_aLoadBuffer(ptr++, nbytes + 8 - (nbytes & 7), outp, dramLoc - dramAlign);
201 } else {
202 dramAlign = 0;
203 }
204 outp += dramAlign;
205 decoder->memin = (s32)decoder->instrument->wavData + (decoder->loop.start << 1);
206 decoder->sample = decoder->loop.start;
207 op = outp;
208 while (outCount > nSam){
209 op += nSam << 1;
210 outCount -= nSam;
211 if (decoder->loop.count != -1 && decoder->loop.count != 0) {
212 decoder->loop.count--;
213 }
214 nSam = MIN(outCount, decoder->loop.end - decoder->loop.start);
215 nbytes = nSam << 1;
216 dramLoc = decoder->dmaFunc(decoder->memin, nbytes, decoder->dmaState, decoder->instrument->useDma);
217 dramAlign = dramLoc & 7;
218 nbytes += dramAlign;
219 if ((op & 7) != 0) {
220 dmemAlign = 8 - (op & 7);
221 } else {
222 dmemAlign = 0;
223 }
224 n_aLoadBuffer(ptr++, nbytes + 8 - (nbytes & 7), op + dmemAlign, dramLoc - dramAlign);
225
226 if (dramAlign != 0 || dmemAlign != 0) {
227 aDMEMMove(ptr++, op + dramAlign + dmemAlign, op, nSam * 2);
228 }
229 }
230 decoder->sample += outCount;
231 decoder->memin += outCount << 1;
232 } else {
233 nbytes = outCount << 1;
234 overFlow = decoder->memin + nbytes - ((s32)decoder->instrument->wavData + decoder->instrument->wavDataLength);
235 if (overFlow <= 0) {
236 overFlow = 0;
237 } else {
238 envMixer->motion = AL_STOPPED;
239 }
240 if (nbytes < overFlow) {
242 }
243 if (overFlow < nbytes) {
244 if (outCount > 0) {
245 nbytes -= overFlow;
246 dramLoc = decoder->dmaFunc(decoder->memin, nbytes, decoder->dmaState, decoder->instrument->useDma);
247 dramAlign = dramLoc & 7;
248 nbytes += dramAlign;
249 n_aLoadBuffer(ptr++, nbytes + 8 - (nbytes & 7), outp, dramLoc - dramAlign);
250 } else {
251 dramAlign = 0;
252 }
253 outp += dramAlign;
254 decoder->sample += outCount;
255 decoder->memin += outCount << 1;
256 } else {
257 decoder->memin += outCount << 1;
258 }
259
260 if (overFlow != 0) {
261 startZero = (outCount << 1) - overFlow;
262 if (startZero < 0) {
263 startZero = 0;
264 }
266 }
267 }
268 }
269 }
270
271 // resample audio from source buffer to output buffer
272 incr = (s32)(resampler->ratio * UNITY_PITCH);
273 n_aResample(ptr++, osVirtualToPhysical(resampler->state), resampler->first, incr, outp, 0);
274 resampler->first = FALSE;
275
276 // set up envelope mixing
277 if (envMixer->dirty) {
278 envMixer->dirty = FALSE;
279 if (!AuSynUseStereo) {
280 envMixer->ltgt = (envMixer->volume * AuEqPower[AUEQPOWER_LENGTH / 2]) >> 15;
281 envMixer->rtgt = (envMixer->volume * AuEqPower[AUEQPOWER_LENGTH / 2]) >> 15;
282 } else {
283 envMixer->ltgt = (envMixer->volume * AuEqPower[envMixer->pan]) >> 15;
284 envMixer->rtgt = (envMixer->volume * AuEqPower[AUEQPOWER_LENGTH - envMixer->pan - 1]) >> 15;
285 }
286 envMixer->lratm = _getRate(envMixer->cvolL, envMixer->ltgt, envMixer->segEnd, &envMixer->lratl);
287 envMixer->rratm = _getRate(envMixer->cvolR, envMixer->rtgt, envMixer->segEnd, &envMixer->rratl);
288 n_aSetVolume(ptr++, A_RATE, envMixer->ltgt, envMixer->lratm, envMixer->lratl);
289 n_aSetVolume(ptr++, A_VOL | A_LEFT, envMixer->cvolL, envMixer->dryamt, envMixer->wetamt);
290 n_aSetVolume(ptr++, A_VOL | A_RIGHT, envMixer->rtgt, envMixer->rratm, envMixer->rratl);
291 n_aEnvMixer(ptr++, A_INIT, envMixer->cvolR, osVirtualToPhysical(envMixer->state));
292 } else {
293 n_aEnvMixer(ptr++, A_CONTINUE, 0, osVirtualToPhysical(envMixer->state));
294 }
295
296 // advance envelope segment
297 envMixer->delta += AUDIO_SAMPLES;
298 if (envMixer->segEnd < envMixer->delta) {
299 envMixer->delta = envMixer->segEnd;
300 }
301
302 // if stopped, reset state
303 if (envMixer->motion == AL_STOPPED) {
304 envMixer->dirty = TRUE;
305 envMixer->volume = 1;
306 resampler->delta = 0.0f;
307 resampler->first = TRUE;
308 decoder->lastsam = 0;
309 decoder->first = 1;
310 decoder->sample = 0;
311 decoder->memin = (s32) decoder->instrument->wavData;
312 decoder->loop.count = decoder->instrument->loopCount;
313 au_release_voice(pvoice->index);
314 }
315 return ptr;
316}
317
319static Acmd* _decodeChunk(Acmd* cmdBufPos, AuLoadFilter* filter, s32 tsam, s32 nbytes, s16 output, s16 input, s32 flags) {
320 s32 endAddr;
323
324 if (nbytes > 0) {
325 endAddr = filter->dmaFunc((s32) filter->memin, nbytes, filter->dmaState, filter->instrument->useDma);
326 endAlign = endAddr & 7;
327 nbytes += endAlign;
328 paddedSize = nbytes + 8 - (nbytes & 7);
330 } else {
331 endAlign = 0;
332 }
333
334 if (flags & A_LOOP) {
335 aSetLoop(cmdBufPos++, K0_TO_PHYS(filter->lstate));
336 }
337
338 n_aADPCMdec(cmdBufPos++, filter->state, flags, tsam << 1, endAlign, output);
339
340 filter->first = 0;
341 return cmdBufPos;
342}
343
344// computes an audio volume ramp rate
345// used for smooth volume transitions in envelope segments
346static s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel) {
347 f64 inv;
348 f64 a;
349 f64 b;
350 s16 c_int;
351 s16 a_int;
352 s16 b_int;
353
354 if (count == 0) {
355 if (tgt >= vol) {
356 *ratel = 0xFFFF;
357 return 0x7FFF;
358 } else {
359 *ratel = 0;
360 return 0;
361 }
362 }
363 inv = (1.0 / count);
364
365 if (tgt < 1.0) {
366 tgt = 1.0;
367 }
368 if (vol <= 0.0) {
369 vol = 1.0;
370 }
371
372 a = (tgt - vol) * inv * 8.0;
373 a_int = a;
374 c_int = (a_int - 1);
375
376 b = (a - a_int) + 1.0;
377 b_int = b;
378 c_int += b_int;
379
380 *ratel = (b - b_int) * 0xFFFF;
381 return c_int;
382}
BSS s32 PopupMenu_SelectedIndex
s16 * predictor
Definition audio.h:681
f32 delta
Definition audio.h:595
s16 dryamt
Definition audio.h:606
volatile u8 AuSynUseStereo
Definition system.c:10
f32 ratio
Definition audio.h:594
#define N_AL_DECODER_OUT
Definition audio.h:32
s16 wetamt
Definition audio.h:607
b8 useDma
Definition audio.h:689
s32 segEnd
Definition audio.h:615
s16 rtgt
Definition audio.h:613
s16 cvolR
Definition audio.h:605
s16 lratm
Definition audio.h:609
s32 bookSize
Definition audio.h:582
#define AUDIO_SAMPLES
Definition audio.h:16
u32 wavDataLength
Definition audio.h:676
s32 loopCount
Definition audio.h:680
s16 rratm
Definition audio.h:612
s16 volume
Definition audio.h:603
b32 first
Definition audio.h:596
s16 pan
Definition audio.h:602
s32 delta
Definition audio.h:614
ENVMIX_STATE * state
Definition audio.h:601
s32 lastsam
Definition audio.h:586
struct Instrument * instrument
Definition audio.h:581
#define ADPCMFBYTES
Definition audio.h:57
s16 cvolL
Definition audio.h:604
s16 rratl
Definition audio.h:611
s16 lratl
Definition audio.h:608
u8 * wavData
Definition audio.h:675
ALDMAproc2 dmaFunc
Definition audio.h:583
ALRawLoop loop
Definition audio.h:580
s32 motion
Definition audio.h:617
NUDMAState * dmaState
Definition audio.h:584
#define N_AL_DECODER_IN
Definition audio.h:29
s32 memin
Definition audio.h:588
RESAMPLE_STATE * state
Definition audio.h:593
b32 dirty
Definition audio.h:616
s16 ltgt
Definition audio.h:610
u8 type
Definition audio.h:688
s32 first
Definition audio.h:587
s32 sample
Definition audio.h:585
void au_release_voice(u8 index)
Definition engine.c:29
s8 flags
Definition demo_api.c:15
#define LFSAMPLES
Definition pull_voice.c:4
Acmd * au_pull_voice(AuPVoice *pvoice, Acmd *cmdBufPos)
Definition pull_voice.c:33
#define AUEQPOWER_LENGTH
Definition pull_voice.c:5
s16 AuEqPower[128]
Definition pull_voice.c:10