diff --git a/README.md b/README.md index 3d1bf736..562473ea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# banjo (89.9076%) +# banjo (90.0795%) diff --git a/include/file_and_line.h b/include/file_and_line.h index ecb5f3b2..a67656c6 100644 --- a/include/file_and_line.h +++ b/include/file_and_line.h @@ -1,6 +1,6 @@ #ifndef _FILE_AND_LINE_H_ #define _FILE_AND_LINE_H_ - +#include extern void func_8033F000(const char *, const char *, int); diff --git a/progress/progress_core1.svg b/progress/progress_core1.svg index 4b1ca596..ac72062c 100644 --- a/progress/progress_core1.svg +++ b/progress/progress_core1.svg @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ core1 - 76.3559% - 76.3559% + 77.5401% + 77.5401% \ No newline at end of file diff --git a/progress/progress_total.svg b/progress/progress_total.svg index f0b50deb..5fd45b2d 100644 --- a/progress/progress_total.svg +++ b/progress/progress_total.svg @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ Banjo-Kazooie (us.v10) - 89.9076% - 89.9076% + 90.0795% + 90.0795% \ No newline at end of file diff --git a/src/core1/done/audio/n_reverb.c b/src/core1/done/audio/n_reverb.c new file mode 100644 index 00000000..f6677a10 --- /dev/null +++ b/src/core1/done/audio/n_reverb.c @@ -0,0 +1,375 @@ +#include +#include "n_libaudio.h" +#include "n_synth.h" + + +#define RANGE 2.0 +extern ALGlobals *alGlobals; + +#ifdef AUD_PROFILE +extern u32 cnt_index, reverb_num, reverb_cnt, reverb_max, reverb_min, lastCnt[]; +extern u32 load_num, load_cnt, load_max, load_min, save_num, save_cnt, save_max, save_min; +#endif + +/* + * macros + */ +#define SWAP(in, out) \ +{ \ + s16 t = out; \ + out = in; \ + in = t; \ +} + +#define N_REVERB_OUTCOUNT 0xb8 + +Acmd *_n_loadOutputBuffer(ALFx *r, ALDelay *d, s32 buff, Acmd *p); //_loadOutputBuffer +Acmd *_n_loadBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p); //_loadBuffer +Acmd *__n_saveBuffer(ALFx *r, s16 *curr_ptr, s32 buff, Acmd *p); //__saveBuffer +Acmd *__n_filterBuffer(ALLowPass *lp, s32 buff, Acmd *p); //__filterBuffer +f32 _doModFunc(ALDelay *d, s32 count); + +// static s32 L_INC[] = { L0_INC, L1_INC, L2_INC }; + +/*********************************************************************** + * Reverb filter public interfaces + ***********************************************************************/ +Acmd *n_alFxPull(void) +{ + ALFx *r = (ALFx *)n_syn->auxBus->fx; + ALFilter *source = r->filter.source; + s16 i, buff1, buff2, input, output; + s16 *in_ptr, *out_ptr, gain, *prev_out_ptr = 0; + ALDelay *d, *pd; + Acmd *ptr; + + + +#ifdef AUD_PROFILE + lastCnt[++cnt_index] = osGetCount(); +#endif + + // assert(source); + ptr = n_alAuxBusPull(); + /* + * pull channels going into this effect first + */ + // ptr = (*source->handler)(source, outp, outCount, sampleOffset, p); + + input = N_AL_AUX_L_OUT; + output = N_AL_AUX_R_OUT; + buff1 = N_AL_TEMP_0; + buff2 = N_AL_TEMP_1; + + // aSetBuffer(ptr++, 0, 0, 0, outCount<<1); /* set the buffer size */ + aMix(ptr++, 0, 0xda83, N_AL_AUX_L_OUT, input); /* .707L = L - .293L */ + aMix(ptr++, 0, 0x5a82, N_AL_AUX_R_OUT, input); /* mix the AuxL and AuxR into the AuxL */ + /* and write the mixed value to the delay line at r->input */ + ptr = __n_saveBuffer(r, r->input, input, ptr); + + aClearBuffer(ptr++, output, N_REVERB_OUTCOUNT << 1); /* clear the AL_AUX_R_OUT */ + + + for (i = 0; i < r->section_count; i++) { + d = &r->delay[i]; /* get the ALDelay structure */ + in_ptr = &r->input[-d->input]; + out_ptr = &r->input[-d->output]; + + if (in_ptr == prev_out_ptr) { + SWAP(buff1, buff2); + } else { /* load data at in_ptr into buff1 */ + ptr = _n_loadBuffer(r, in_ptr, buff1, N_REVERB_OUTCOUNT, ptr); + } + ptr = _n_loadOutputBuffer(r, d, buff2, ptr); + + if (d->ffcoef) { + aMix(ptr++, 0, (u16)d->ffcoef, buff1, buff2); + if (!d->rs && !d->lp) { + ptr = __n_saveBuffer(r, out_ptr, buff2, ptr); + } + } + + if (d->fbcoef) { + aMix(ptr++, 0, (u16)d->fbcoef, buff2, buff1); + ptr = __n_saveBuffer(r, in_ptr, buff1, ptr); + } + + if (d->lp) + ptr = __n_filterBuffer(d->lp, buff2, ptr); + + if (!d->rs) + ptr = __n_saveBuffer(r, out_ptr, buff2, ptr); + + if (d->gain) + aMix(ptr++, 0, (u16)d->gain, buff2, output); + + prev_out_ptr = &r->input[d->output]; + } + + /* + * bump the master delay line input pointer + * modulo the length + */ + r->input += N_REVERB_OUTCOUNT; + if (r->input > &r->base[r->length]) + r->input -= r->length; + + /* + * output already in AL_AUX_R_OUT + * just copy to AL_AUX_L_OUT + */ + aDMEMMove(ptr++, output, N_AL_AUX_L_OUT, N_REVERB_OUTCOUNT<<1); + +#ifdef AUD_PROFILE + PROFILE_AUD(reverb_num, reverb_cnt, reverb_max, reverb_min); +#endif + return ptr; +} + + +/* + * This routine gets called by alSynSetFXParam. No checking takes place to + * verify the validity of the paramID or the param value. input and output + * values must be 8 byte aligned, so round down any param passed. + */ +s32 n_alFxParamHdl(void *filter, s32 paramID, void *param) +{ + ALFx *f = (ALFx *) filter; + s32 p = (paramID - 2) % 8; + s32 s = (paramID - 2) / 8; + s32 val = *(s32*)param; + +#define INPUT_PARAM 0 +#define OUTPUT_PARAM 1 +#define FBCOEF_PARAM 2 +#define FFCOEF_PARAM 3 +#define GAIN_PARAM 4 +#define CHORUSRATE_PARAM 5 +#define CHORUSDEPTH_PARAM 6 +#define LPFILT_PARAM 7 + + switch(p) + { + case INPUT_PARAM: + f->delay[s].input = (u32)val & 0xFFFFFFF8; + break; + case OUTPUT_PARAM: + f->delay[s].output = (u32)val & 0xFFFFFFF8; + break; + case FFCOEF_PARAM: + f->delay[s].ffcoef = (s16)val; + break; + case FBCOEF_PARAM: + f->delay[s].fbcoef = (s16)val; + break; + case GAIN_PARAM: + f->delay[s].gain = (s16)val; + break; + case CHORUSRATE_PARAM: + /* f->delay[s].rsinc = ((f32)val)/0xffffff; */ + f->delay[s].rsinc = ((((f32)val)/1000) * RANGE)/n_syn->outputRate; + break; + +/* + * the following constant is derived from: + * + * ratio = 2^(cents/1200) + * + * and therefore for hundredths of a cent + * x + * ln(ratio) = --------------- + * (120,000)/ln(2) + * where + * 120,000/ln(2) = 173123.40... + */ +#define CONVERT 173123.404906676 +#define LENGTH (f->delay[s].output - f->delay[s].input) + + case CHORUSDEPTH_PARAM: + /*f->delay[s].rsgain = (((f32)val) / CONVERT) * LENGTH; */ + f->delay[s].rsgain = (((f32)val) / CONVERT) * LENGTH; + break; + case LPFILT_PARAM: + if(f->delay[s].lp) + { + f->delay[s].lp->fc = (s16)val; + _init_lpfilter(f->delay[s].lp); + } + break; + } + return 0; +} + +Acmd *_n_loadOutputBuffer(ALFx *r, ALDelay *d, s32 buff, Acmd *p) +{ + Acmd *ptr = p; + s32 ratio, count, rbuff = N_AL_TEMP_2; + s16 *out_ptr; + f32 fincount, fratio, delta; + s32 ramalign = 0, length; + s32 inCount = 0xb8; + s8 tmp; + static f32 val=0.0, lastval=-10.0; + static f32 blob=0; +/* + * The following section implements the chorus resampling. Modulate where you pull + * the samples from, since you need varying amounts of samples. + */ + if (d->rs) { + length = d->output - d->input; + delta = _doModFunc(d, inCount); /* get the number of samples to modulate by */ + /* + * find ratio of delta to delay length and quantize + * to same resolution as resampler + */ + delta /= length; /* convert delta from number of samples to a pitch ratio */ + delta = (s32)(delta * UNITY_PITCH); /* quantize to value microcode will use */ + delta = delta / UNITY_PITCH; + fratio = 1.0 - delta; /* pitch ratio needs to be centered around 1, not zero */ + + /* d->rs->delta is the difference between the fractional and integer value + * of the samples needed. fratio * incount + rs->delta gives the number of samples + * needed for this frame. + */ + fincount = d->rs->delta + (fratio * (f32)inCount); + count = (s32) fincount; /* quantize to s32 */ + d->rs->delta = fincount - (f32)count; /* calculate the round off and store */ + + /* + * d->rsdelta is amount the out_ptr has deviated from its starting position. + * You calc the out_ptr by taking d->output - d->rsdelta, and then using the + * negative of that as an index into the delay buffer. loadBuffer that uses this + * value then bumps it up if it is below the delay buffer. + */ + out_ptr = &r->input[-(d->output - d->rsdelta)]; + ramalign = (((s32)out_ptr & 0x7) >> 1); /* calculate the number of samples needed + to align the buffer*/ +#ifdef _DEBUG +#if 0 + if(length > 0) { + if (length - d->rsdelta > (s32)r->length) { + __osError(ERR_ALMODDELAYOVERFLOW, 1, length - d->rsdelta - r->length); + } + } + else if(length < 0) { + if ((-length) - d->rsdelta > (s32)r->length) { + __osError(ERR_ALMODDELAYOVERFLOW, 1, (-length) - d->rsdelta - r->length); + } + } +#endif +#endif + /* load the rbuff with samples, note that there will be ramalign worth of + * samples at the begining which you don't care about. */ + ptr = _n_loadBuffer(r, out_ptr - ramalign, rbuff, count + ramalign, ptr); + + /* convert fratio to 16 bit fraction for microcode use */ + ratio = (s32)(fratio * UNITY_PITCH); + /* set the buffers, and do the resample */ + // aSetBuffer(ptr++, 0, rbuff + (ramalign<<1), buff, inCount<<1); + tmp = (buff>>8); + n_aResample(ptr++, osVirtualToPhysical(d->rs->state), d->rs->first, ratio, rbuff + (ramalign<<1), tmp); + + d->rs->first = 0; /* turn off first time flag */ + d->rsdelta += count - inCount; /* add the number of samples to d->rsdelta */ + } else { + out_ptr = &r->input[-d->output]; + ptr = _n_loadBuffer(r, out_ptr, buff, inCount, ptr); + } + + return ptr; +} +/* + * This routine is for loading data from the delay line buff. If the + * address of curr_ptr < r->base, it will force it to be within r->base + * space, If the load goes past the end of r->base it will wrap around. + * Cause count bytes of data at curr_ptr (within the delay line) to be + * loaded into buff. (Buff is a dmem buffer) + */ +Acmd *_n_loadBuffer(ALFx *r, s16 *curr_ptr, s32 buff, s32 count, Acmd *p) +{ + Acmd *ptr = p; + s32 after_end, before_end; + s16 *updated_ptr, *delay_end; + +#ifdef AUD_PROFILE + lastCnt[++cnt_index] = osGetCount(); +#endif + + delay_end = &r->base[r->length]; + +#ifdef _DEBUG + if(curr_ptr > delay_end) + __osError(ERR_ALMODDELAYOVERFLOW, 1, delay_end - curr_ptr); +#endif + + if (curr_ptr < r->base) + curr_ptr += r->length; + updated_ptr = curr_ptr + count; + + if (updated_ptr > delay_end) { + after_end = updated_ptr - delay_end; + before_end = delay_end - curr_ptr; + + n_aLoadBuffer(ptr++, before_end << 1, buff, osVirtualToPhysical(curr_ptr)); + n_aLoadBuffer(ptr++, after_end<<1, buff + (before_end<<1), osVirtualToPhysical(r->base)); + } else { + n_aLoadBuffer(ptr++, count<<1, buff, osVirtualToPhysical(curr_ptr)); + } + +#ifdef AUD_PROFILE + PROFILE_AUD(load_num, load_cnt, load_max, load_min); +#endif + return ptr; + +} + +/* + * This routine is for writing data to the delay line buff. If the + * address of curr_ptr < r->base, it will force it to be within r->base + * space. If the write goes past the end of r->base, it will wrap around + * Cause count bytes of data at buff to be written to delay line, curr_ptr. + */ +Acmd *__n_saveBuffer(ALFx *r, s16 *curr_ptr, s32 buff, Acmd *p) +{ + Acmd *ptr = p; + s32 after_end, before_end; + s16 *updated_ptr, *delay_end; + +#ifdef AUD_PROFILE + lastCnt[++cnt_index] = osGetCount(); +#endif + + delay_end = &r->base[r->length]; + if (curr_ptr < r->base) /* probably just security */ + curr_ptr += r->length; /* shouldn't occur */ + updated_ptr = curr_ptr + 0xb8; + + if (updated_ptr > delay_end) { /* if the data wraps past end of r->base */ + after_end = updated_ptr - delay_end; + before_end = delay_end - curr_ptr; + + n_aSaveBuffer(ptr++, before_end<<1, buff, osVirtualToPhysical(curr_ptr)); + n_aSaveBuffer(ptr++, after_end<<1, buff+(before_end<<1), osVirtualToPhysical(r->base)); + } else { + n_aSaveBuffer(ptr++, 0xb8 << 1, buff, osVirtualToPhysical(curr_ptr)); + } + +#ifdef AUD_PROFILE + PROFILE_AUD(save_num, save_cnt, save_max, save_min); +#endif + return ptr; + +} + +Acmd *__n_filterBuffer(ALLowPass *lp, s32 buff, Acmd *p) +{ + Acmd* ptr = p; + s8 t8; + + n_aLoadADPCM(ptr++, 32, osVirtualToPhysical(lp->fcvec.fccoef)); + t8 = buff>>8; + n_aPoleFilter(ptr++, lp->first, lp->fgain, t8, osVirtualToPhysical(lp->fstate)); + lp->first = 0; + + return ptr; +} \ No newline at end of file diff --git a/src/core1/done/audio/n_seqplayer.c b/src/core1/done/audio/n_seqplayer.c index 282008fa..69b4da09 100644 --- a/src/core1/done/audio/n_seqplayer.c +++ b/src/core1/done/audio/n_seqplayer.c @@ -865,7 +865,6 @@ ALSound *__n_lookupSoundQuick(N_ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan) s16 __n_vsVol(N_ALVoiceState *vs, N_ALSeqPlayer *seqp) { u32 t1, t2; - ALChanState *temp_a2; t1 = (vs->tremelo*vs->velocity*vs->envGain*seqp->chanState[vs->channel].unkA) >> 13; t2 = (vs->sound->sampleVolume*seqp->vol*seqp->chanState[vs->channel].vol) >> 14; diff --git a/src/core1/n_reverb.c b/src/core1/n_reverb.c deleted file mode 100644 index 7a263343..00000000 --- a/src/core1/n_reverb.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include "functions.h" -#include "variables.h" - - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025F6D0.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025F784.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025F8B0.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025F9F4.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025FC10.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_reverb/func_8025FE6C.s") diff --git a/subyaml/core1.us.v10.yaml b/subyaml/core1.us.v10.yaml index 9fec730e..7629ed38 100644 --- a/subyaml/core1.us.v10.yaml +++ b/subyaml/core1.us.v10.yaml @@ -94,7 +94,7 @@ segments: - [0x21AF0, c, done/audio/code_21AF0] #DONE - [0x21B50, c, done/audio/code_21B50] #DONE - [0x21C50, c, done/audio/n_synallocfx] #DONE - - [0x21CB0, c, n_reverb] + - [0x21CB0, c, done/audio/n_reverb] - [0x22740, c, done/audio/n_auxbus] #DONE - [0x227F0, c, done/audio/n_drvrNew] #DONE - [0x22D50, c, done/audio/n_save] #DONE @@ -285,7 +285,7 @@ segments: - [0x3A950, .rodata, code_1D5D0] - [0x3A9B0, .rodata, done/audio/n_synthesizer] - [0x3A9C0, bin, data_3A9C0] # .rodata, done/audio/n_csplayer] - - [0x3AD30, bin, data_3AD30] + - [0x3AD30, .rodata, done/audio/n_reverb] - [0x3AD60, .rodata, done/audio/n_drvrNew] - [0x3AD80, bin, data_3AD80] - [0x3ADD0, .rodata, done/audio/n_seqplayer]