From b723b304e59db06cea139d81076364a6786ec91c Mon Sep 17 00:00:00 2001 From: ProjectRevoTPP Date: Sat, 14 Sep 2024 17:39:39 -0400 Subject: [PATCH] n_synthesizer.c --- Makefile | 2 +- linker_scripts/us/symbol_addrs_code.txt | 24 +- src/49DC0.c | 17 -- src/4F7F0.c | 3 +- src/4F870.c | 2 +- src/4FDB0.c | 2 +- src/50990.c | 2 +- src/50CC0.c | 2 +- src/51850.c | 2 +- src/libnaudio/n_synthesizer.c | 302 ++++++++++++++++++++++++ tools/m2ctx.py | 1 + yamls/us/rom.yaml | 4 +- 12 files changed, 324 insertions(+), 39 deletions(-) delete mode 100644 src/49DC0.c create mode 100644 src/libnaudio/n_synthesizer.c diff --git a/Makefile b/Makefile index 167259d..321106b 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ WARNINGS := -fullwarn -verbose -woff 624,649,838,712,516,513,596,564,594 ASFLAGS := -march=vr4300 -32 -G0 COMMON_DEFINES := -D_MIPS_SZLONG=32 GBI_DEFINES := -DF3DEX_GBI_2 -RELEASE_DEFINES := -DNDEBUG -D_FINALROM +RELEASE_DEFINES := -DNDEBUG -D_FINALROM -DN_MICRO AS_DEFINES := -DMIPSEB -D_LANGUAGE_ASSEMBLY -D_ULTRA64 C_DEFINES := -DLANGUAGE_C -D_LANGUAGE_C LIBULTRA_DEFINES := -DBUILD_VERSION=VERSION_$(ULTRALIB_VERSION) diff --git a/linker_scripts/us/symbol_addrs_code.txt b/linker_scripts/us/symbol_addrs_code.txt index ce06983..6be75fb 100644 --- a/linker_scripts/us/symbol_addrs_code.txt +++ b/linker_scripts/us/symbol_addrs_code.txt @@ -1385,13 +1385,13 @@ func_80048B90 = 0x80048B90; // type:func func_80048FA0 = 0x80048FA0; // type:func func_800490CC = 0x800490CC; // type:func n_alSynNew = 0x800491C0; // type:func -func_80049490 = 0x80049490; // type:func -func_800495F8 = 0x800495F8; // type:func -func_80049628 = 0x80049628; // type:func -func_80049648 = 0x80049648; // type:func -func_800496AC = 0x800496AC; // type:func -func_800496E0 = 0x800496E0; // type:func -func_80049734 = 0x80049734; // type:func +n_alAudioFrame = 0x80049490; // type:func +__n_allocParam = 0x800495F8; // type:func +_n_freeParam = 0x80049628; // type:func +_n_collectPVoices = 0x80049648; // type:func +_n_freePVoice = 0x800496AC; // type:func +_n_timeToSamplesNoRound = 0x800496E0; // type:func +_n_timeToSamples = 0x80049734; // type:func func_80049760 = 0x80049760; // type:func func_800497E0 = 0x800497E0; // type:func func_8004980C = 0x8004980C; // type:func @@ -1450,8 +1450,8 @@ func_8004E810 = 0x8004E810; // type:func func_8004EBC8 = 0x8004EBC8; // type:func func_8004EBF0 = 0x8004EBF0; // type:func func_8004EC70 = 0x8004EC70; // type:func -func_8004F084 = 0x8004F084; // type:func -func_8004F1B0 = 0x8004F1B0; // type:func +alN_PVoiceNew = 0x8004F084; // type:func +n_alAuxBusPull = 0x8004F1B0; // type:func func_8004F260 = 0x8004F260; // type:func func_8004F2F0 = 0x8004F2F0; // type:func func_8004F350 = 0x8004F350; // type:func @@ -1464,12 +1464,12 @@ func_8004FCD8 = 0x8004FCD8; // type:func func_8004FD44 = 0x8004FD44; // type:func func_8004FD64 = 0x8004FD64; // type:func n_alSynDelete = 0x8004FD90; // type:func -func_8004FDA0 = 0x8004FDA0; // type:func +n_alSynAllocFX = 0x8004FDA0; // type:func func_8004FE00 = 0x8004FE00; // type:func func_8004FF20 = 0x8004FF20; // type:func func_8004FF40 = 0x8004FF40; // type:func func_80050020 = 0x80050020; // type:func -func_800500C0 = 0x800500C0; // type:func +n_alFxPull = 0x800500C0; // type:func func_800503A0 = 0x800503A0; // type:func func_80050600 = 0x80050600; // type:func func_80050818 = 0x80050818; // type:func @@ -1477,7 +1477,7 @@ func_80050960 = 0x80050960; // type:func func_80050A8C = 0x80050A8C; // type:func func_80050B40 = 0x80050B40; // type:func func_80050BA0 = 0x80050BA0; // type:func -func_80050C50 = 0x80050C50; // type:func +n_alSavePull = 0x80050C50; // type:func func_80050CA0 = 0x80050CA0; // type:func func_80050F20 = 0x80050F20; // type:func LeoReadWrite = 0x80050FC0; // type:func diff --git a/src/49DC0.c b/src/49DC0.c deleted file mode 100644 index 72824c0..0000000 --- a/src/49DC0.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "global.h" - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/n_alSynNew.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_80049490.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_800495F8.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_80049628.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_80049648.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_800496AC.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_800496E0.s") - -#pragma GLOBAL_ASM("asm/us/nonmatchings/49DC0/func_80049734.s") diff --git a/src/4F7F0.c b/src/4F7F0.c index 242d498..82bb1ca 100644 --- a/src/4F7F0.c +++ b/src/4F7F0.c @@ -21,13 +21,12 @@ struct UnkStruct8004EBF0 { struct UnkStructUnk8* unk8; }; void func_80047500(void*, u8, void*, void*); -struct UnkArray4* func_800495F8(); void func_8004EBF0(struct UnkStruct8004EBF0* arg0, f32 arg1) { struct UnkArray4* temp_v0; if (arg0->unk8 != NULL) { - temp_v0 = func_800495F8(); + temp_v0 = (struct UnkArray4*)__n_allocParam(); // TODO: Fix this if (temp_v0 != NULL) { temp_v0->unk4 = (s32)(n_syn->paramSamples + arg0->unk8->unk88); temp_v0->unk8 = 7; diff --git a/src/4F870.c b/src/4F870.c index f43426d..b7bc659 100644 --- a/src/4F870.c +++ b/src/4F870.c @@ -2,4 +2,4 @@ #pragma GLOBAL_ASM("asm/us/nonmatchings/4F870/func_8004EC70.s") -#pragma GLOBAL_ASM("asm/us/nonmatchings/4F870/func_8004F084.s") +#pragma GLOBAL_ASM("asm/us/nonmatchings/4F870/alN_PVoiceNew.s") diff --git a/src/4FDB0.c b/src/4FDB0.c index 0c90b4a..6a937bc 100644 --- a/src/4FDB0.c +++ b/src/4FDB0.c @@ -1,3 +1,3 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/us/nonmatchings/4FDB0/func_8004F1B0.s") +#pragma GLOBAL_ASM("asm/us/nonmatchings/4FDB0/n_alAuxBusPull.s") diff --git a/src/50990.c b/src/50990.c index 05e7fb5..8b01f1b 100644 --- a/src/50990.c +++ b/src/50990.c @@ -2,4 +2,4 @@ #pragma GLOBAL_ASM("asm/us/nonmatchings/50990/n_alSynDelete.s") -#pragma GLOBAL_ASM("asm/us/nonmatchings/50990/func_8004FDA0.s") +#pragma GLOBAL_ASM("asm/us/nonmatchings/50990/n_alSynAllocFX.s") diff --git a/src/50CC0.c b/src/50CC0.c index 7c5f362..8c9e736 100644 --- a/src/50CC0.c +++ b/src/50CC0.c @@ -1,6 +1,6 @@ #include "50CC0.h" -#pragma GLOBAL_ASM("asm/us/nonmatchings/50CC0/func_800500C0.s") +#pragma GLOBAL_ASM("asm/us/nonmatchings/50CC0/n_alFxPull.s") #pragma GLOBAL_ASM("asm/us/nonmatchings/50CC0/func_800503A0.s") diff --git a/src/51850.c b/src/51850.c index e99d70c..e1c0212 100644 --- a/src/51850.c +++ b/src/51850.c @@ -1,3 +1,3 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/us/nonmatchings/51850/func_80050C50.s") +#pragma GLOBAL_ASM("asm/us/nonmatchings/51850/n_alSavePull.s") diff --git a/src/libnaudio/n_synthesizer.c b/src/libnaudio/n_synthesizer.c new file mode 100644 index 0000000..88857f5 --- /dev/null +++ b/src/libnaudio/n_synthesizer.c @@ -0,0 +1,302 @@ +/*==================================================================== + * + * Copyright 1993, Silicon Graphics, Inc. + * All Rights Reserved. + * + * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, + * Inc.; the contents of this file may not be disclosed to third + * parties, copied or duplicated in any form, in whole or in part, + * without the prior written permission of Silicon Graphics, Inc. + * + * RESTRICTED RIGHTS LEGEND: + * Use, duplication or disclosure by the Government is subject to + * restrictions as set forth in subdivision (c)(1)(ii) of the Rights + * in Technical Data and Computer Software clause at DFARS + * 252.227-7013, and/or in similar or successor clauses in the FAR, + * DOD or NASA FAR Supplement. Unpublished - rights reserved under the + * Copyright Laws of the United States. + *====================================================================*/ +#include "n_synthInternals.h" +#ifdef _DEBUG +#include +#endif + +#define ONLY_ONE_PLAYER + +#ifdef AUD_PROFILE +#include +extern u32 cnt_index, drvr_num, drvr_cnt, drvr_max, drvr_min, lastCnt[]; +extern u32 client_num, client_cnt, client_max, client_min; +#endif + +#ifndef MIN +# define MIN(a,b) (((a)<(b))?(a):(b)) +#endif + +static s32 __n_nextSampleTime(ALPlayer **client); +static s32 _n_timeToSamplesNoRound(s32 micros); + +/*********************************************************************** + * Synthesis driver public interfaces + ***********************************************************************/ +void n_alSynNew(ALSynConfig *c) +{ + s32 i; + N_ALVoice *vv; + N_PVoice *pv; + N_ALVoice *vvoices; + N_PVoice *pvoices; + ALHeap *hp = c->heap; + ALSave *save; + ALFilter *sources; + N_PVoice *m_sources; + ALParam *params; + ALParam *paramPtr; + + n_syn->head = NULL; + n_syn->numPVoices = c->maxPVoices; + n_syn->curSamples = 0; + n_syn->paramSamples = 0; + n_syn->outputRate = c->outputRate; +#ifndef N_MICRO + n_syn->maxOutSamples = AL_MAX_RSP_SAMPLES; +#else + n_syn->maxOutSamples = FIXED_SAMPLE; +#endif + n_syn->dma = (ALDMANew) c->dmaproc; + +/******* save new *******************************/ + n_syn->sv_dramout = 0; + n_syn->sv_first = 1; + +/******* aux new *******************************/ + n_syn->auxBus = (N_ALAuxBus *)alHeapAlloc(hp, 1, sizeof(N_ALAuxBus)); + + n_syn->auxBus->sourceCount = 0; + n_syn->auxBus->maxSources = c->maxPVoices; + n_syn->auxBus->sources = (N_PVoice **) + alHeapAlloc(hp, c->maxPVoices, sizeof(N_PVoice *)); + +/******* main new *******************************/ + n_syn->mainBus = (N_ALMainBus *)alHeapAlloc(hp, 1, sizeof(N_ALMainBus)); + +/******* fx new *******************************/ + + if (c->fxType != AL_FX_NONE){ + n_syn->auxBus->fx = n_alSynAllocFX(0, c, hp); + n_syn->mainBus->filter.handler = (N_ALCmdHandler)n_alFxPull; + } else { + n_syn->mainBus->filter.handler = (N_ALCmdHandler)n_alAuxBusPull; + } + + n_syn->pFreeList.next = 0; + n_syn->pFreeList.prev = 0; + n_syn->pLameList.next = 0; + n_syn->pLameList.prev = 0; + n_syn->pAllocList.next = 0; + n_syn->pAllocList.prev = 0; + + pvoices = alHeapAlloc(hp, c->maxPVoices, sizeof(N_PVoice)); + for (i = 0; i < c->maxPVoices; i++) { + pv = &pvoices[i]; + alLink((ALLink *)pv, &n_syn->pFreeList); + pv->vvoice = 0; + alN_PVoiceNew(pv, n_syn->dma, hp); + n_syn->auxBus->sources[n_syn->auxBus->sourceCount++] = pv; + } + + params = alHeapAlloc(hp, c->maxUpdates, sizeof(ALParam)); + n_syn->paramList = 0; + for (i = 0; i < c->maxUpdates; i++) { + paramPtr= ¶ms[i]; + paramPtr->next = n_syn->paramList; + n_syn->paramList = paramPtr; + } + n_syn->heap = hp; +} + +Acmd *n_alAudioFrame(Acmd *cmdList, s32 *cmdLen, s16 *outBuf, s32 outLen) +{ + ALPlayer *client; + s16 tmp = 0; /* Starting buffer in DMEM */ + Acmd *cmdlEnd = cmdList; + Acmd *cmdPtr; + s32 nOut; + s16 *lOutBuf = outBuf; + +#ifdef AUD_PROFILE + lastCnt[++cnt_index] = osGetCount(); +#endif + + if (n_syn->head == 0) { + *cmdLen = 0; + return cmdList; /* nothing to do */ + } + + /* + * run down list of clients and execute callback if needed this + * subframe. Here we do all the work for the frame at the + * start. Time offsets that occur before the next frame are + * executed "early". + */ + +#ifdef AUD_PROFILE + lastCnt[++cnt_index] = osGetCount(); +#endif + + /* + * paramSamples = time of next parameter change. + * curSamples = current sample time. + * so paramSamples - curSamples is the time until the next parameter change. + * if the next parameter change occurs within this frame time (outLen), + * then call back the client that contains the parameter change. + * Note, paramSamples must be rounded down to 16 sample boundary for use + * during the client handler. + */ + +#ifndef ONLY_ONE_PLAYER + for (n_syn->paramSamples = __n_nextSampleTime(&client); + n_syn->paramSamples - n_syn->curSamples < outLen; + n_syn->paramSamples = __n_nextSampleTime(&client)) + { + n_syn->paramSamples &= ~0xf; + client->samplesLeft += _n_timeToSamplesNoRound((*client->handler)(client)); + } +#else + client = n_syn->head; + while(client->samplesLeft - n_syn->curSamples < outLen) + { + n_syn->paramSamples = (client->samplesLeft & ~0xf); + client->samplesLeft += _n_timeToSamplesNoRound((*client->handler)(client)); + } +#endif + + /* for safety's sake, always store paramSamples aligned to 16 sample boundary. + * this way, if an voice handler routine gets called outside the N_ALVoiceHandler + * routine (alSynAllocVoice) it will get timestamped with an aligned value and + * will be processed immediately next audio frame. + */ + n_syn->paramSamples &= ~0xf; + +#ifdef AUD_PROFILE + PROFILE_AUD(client_num, client_cnt, client_max, client_min); +#endif + + /* + * Now build the command list in small chunks + */ + while (outLen > 0){ + nOut = MIN(n_syn->maxOutSamples, outLen); + + /* + * construct the command list for each physical voice by calling + * the head of the filter chain. + */ + cmdPtr = cmdlEnd; +#ifndef N_MICRO + aSegment(cmdPtr++, 0, 0); +#endif + n_syn->sv_dramout = (s32)lOutBuf; + cmdlEnd = n_alSavePull(n_syn->curSamples, cmdPtr); + + outLen -= nOut; + lOutBuf += nOut<<1; /* For Stereo */ + n_syn->curSamples += nOut; + + } + *cmdLen = (s32) (cmdlEnd - cmdList); + + _n_collectPVoices(); /* collect free physical voices */ + +#ifdef AUD_PROFILE + PROFILE_AUD(drvr_num, drvr_cnt, drvr_max, drvr_min); +#endif + return cmdlEnd; +} + +/*********************************************************************** + * Synthesis driver private interfaces + ***********************************************************************/ + +ALParam *__n_allocParam(void) +{ + ALParam *update = 0; + + if (n_syn->paramList) { + update = n_syn->paramList; + n_syn->paramList = n_syn->paramList->next; + update->next = 0; + } + return update; +} + +void _n_freeParam(ALParam *param) +{ + param->next = n_syn->paramList; + n_syn->paramList = param; +} + +void _n_collectPVoices(void) +{ + ALLink *dl; + N_PVoice *pv; + + while ((dl = n_syn->pLameList.next) != 0) { + pv = (N_PVoice *)dl; + + /* ### remove from mixer */ + + alUnlink(dl); + alLink(dl, &n_syn->pFreeList); + } +} + +void _n_freePVoice(N_PVoice *pvoice) +{ + /* + * move the voice from the allocated list to the lame list + */ + alUnlink((ALLink *)pvoice); + alLink((ALLink *)pvoice, &n_syn->pLameList); +} + + +/* + Add 0.5 to adjust the average affect of + the truncation error produced by casting + a float to an int. +*/ +s32 _n_timeToSamplesNoRound(s32 micros) +{ + f32 tmp = ((f32)micros) * n_syn->outputRate / 1000000.0 + 0.5; + + return (s32)tmp; +} + +s32 _n_timeToSamples(s32 micros) +{ + return _n_timeToSamplesNoRound(micros) & ~0xf; +} + +#ifndef ONLY_ONE_PLAYER +static s32 __n_nextSampleTime(ALPlayer **client) +{ + ALMicroTime delta = 0x7fffffff; /* max delta for s32 */ + ALPlayer *cl; + u32 tt; + +#ifdef _DEBUG + assert(n_syn->head); +#endif + *client = 0; + + for (cl = n_syn->head; cl != 0; cl = cl->next) { + if ((cl->samplesLeft - n_syn->curSamples) < delta) { + *client = cl; + delta = cl->samplesLeft - n_syn->curSamples; + } + } + + return (*client)->samplesLeft; +} +#endif diff --git a/tools/m2ctx.py b/tools/m2ctx.py index f5e8826..8c2f6be 100755 --- a/tools/m2ctx.py +++ b/tools/m2ctx.py @@ -27,6 +27,7 @@ CPP_FLAGS = [ "-Ibuild", "-Iinclude/PR", "-Isrc", + "-Isrc/libnaudio", "-I.", "-DM2C", "-Ilib/ultralib/include", diff --git a/yamls/us/rom.yaml b/yamls/us/rom.yaml index a43d41b..1139358 100644 --- a/yamls/us/rom.yaml +++ b/yamls/us/rom.yaml @@ -95,7 +95,7 @@ - [0x49190, hasm, ../../src/unk_49190] - [0x49790, c] - [0x49BA0, c] - - [0x49DC0, c] + - [0x49DC0, c, libnaudio/n_synthesizer] - [0x4A360, c] - [0x4A3E0, c] - [0x4B940, c, 4B940] @@ -410,7 +410,7 @@ - [0x7D880, rodata, rom_rodata_7D880] - [0x7DF80, rodata, rom_rodata_7DF80] - [0x7DFD0, .rodata, 49790] - - [0x7E0C0, rodata, rom_rodata_7E0C0] + - [0x7E0C0, .rodata, libnaudio/n_synthesizer] - [0x7E0D0, rodata, rom_rodata_7E0D0] - [0x7E0E0, .rodata, 4BA90] - [0x7E110, .rodata, 4BDC0]