This commit is contained in:
ProjectRevoTPP
2024-09-14 21:27:52 -04:00
parent a6b323fdc0
commit feb2d0c9aa
7 changed files with 671 additions and 20 deletions

View File

@@ -270,3 +270,4 @@ ECHO_PARAMS_N = 0x80079460;
CHORUS_PARAMS_N = 0x80079488;
FLANGE_PARAMS_N = 0x800794B0;
NULL_PARAMS_N = 0x800794D8;
n_eqpower = 0x80078600;

View File

@@ -1366,9 +1366,9 @@ func_80045FF0 = 0x80045FF0; // type:func
n_alSynStopVoice = 0x80046EF0; // type:func
n_alEnvmixerPull = 0x80046F60; // type:func
n_alEnvmixerParam = 0x80047500; // type:func
func_800475A4 = 0x800475A4; // type:func
func_800477D0 = 0x800477D0; // type:func
func_80047958 = 0x80047958; // type:func
_pullSubFrame = 0x800475A4; // type:func
_getRate = 0x800477D0; // type:func
_getVol = 0x80047958; // type:func
func_800479C0 = 0x800479C0; // type:func
func_80048014 = 0x80048014; // type:func
func_80048060 = 0x80048060; // type:func
@@ -1454,10 +1454,10 @@ alN_PVoiceNew = 0x8004F084; // type:func
n_alAuxBusPull = 0x8004F1B0; // type:func
n_alSynSetFXMix = 0x8004F260; // type:func
n_alSynAddPlayer = 0x8004F2F0; // type:func
func_8004F350 = 0x8004F350; // type:func
n_alResamplePull = 0x8004F350; // type:func
func_8004F4F8 = 0x8004F4F8; // type:func
func_8004F520 = 0x8004F520; // type:func
func_8004F95C = 0x8004F95C; // type:func
n_alLoadParam = 0x8004F95C; // type:func
func_8004FB1C = 0x8004FB1C; // type:func
func_8004FC60 = 0x8004FC60; // type:func
func_8004FCD8 = 0x8004FCD8; // type:func

View File

@@ -1,11 +0,0 @@
#include "global.h"
#pragma GLOBAL_ASM("asm/us/nonmatchings/47B60/n_alEnvmixerPull.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/47B60/n_alEnvmixerParam.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/47B60/func_800475A4.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/47B60/func_800477D0.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/47B60/func_80047958.s")

View File

@@ -1,5 +1,5 @@
#include "global.h"
#pragma GLOBAL_ASM("asm/us/nonmatchings/4FF50/func_8004F350.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/4FF50/n_alResamplePull.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/4FF50/func_8004F4F8.s")

View File

@@ -2,6 +2,6 @@
#pragma GLOBAL_ASM("asm/us/nonmatchings/50120/func_8004F520.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/50120/func_8004F95C.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/50120/n_alLoadParam.s")
#pragma GLOBAL_ASM("asm/us/nonmatchings/50120/func_8004FB1C.s")

658
src/libnaudio/n_env.c Normal file
View File

@@ -0,0 +1,658 @@
#include "global.h"
/*====================================================================
*
* 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"
#include <os.h>
#include <stdio.h>
#include <math.h>
#ifdef _DEBUG
#include <assert.h>
#endif
#ifdef AUD_PROFILE
extern u32 cnt_index, env_num, env_cnt, env_max, env_min, lastCnt[];
extern u32 rate_num, rate_cnt, rate_max, rate_min;
extern u32 vol_num, vol_cnt, vol_max, vol_min;
#endif
#define N_EQPOWER_LENGTH 128
s16 n_eqpower[ N_EQPOWER_LENGTH ] = {
32767, 32764, 32757, 32744, 32727, 32704,
32677, 32644, 32607, 32564, 32517, 32464,
32407, 32344, 32277, 32205, 32127, 32045,
31958, 31866, 31770, 31668, 31561, 31450,
31334, 31213, 31087, 30957, 30822, 30682,
30537, 30388, 30234, 30075, 29912, 29744,
29572, 29395, 29214, 29028, 28838, 28643,
28444, 28241, 28033, 27821, 27605, 27385,
27160, 26931, 26698, 26461, 26220, 25975,
25726, 25473, 25216, 24956, 24691, 24423,
24151, 23875, 23596, 23313, 23026, 22736,
22442, 22145, 21845, 21541, 21234, 20924,
20610, 20294, 19974, 19651, 19325, 18997,
18665, 18331, 17993, 17653, 17310, 16965,
16617, 16266, 15913, 15558, 15200, 14840,
14477, 14113, 13746, 13377, 13006, 12633,
12258, 11881, 11503, 11122, 10740, 10357,
9971, 9584, 9196, 8806, 8415, 8023,
7630, 7235, 6839, 6442, 6044, 5646,
5246, 4845, 4444, 4042, 3640, 3237,
2833, 2429, 2025, 1620, 1216, 810,
405, 0
};
#ifndef N_MICRO
extern f64 __pow(f64, f64);
extern f64 _frexpf(f64 value, s32 *eptr);
extern f64 _ldexpf(f64 in, s32 ex);
#endif
/*
* prototypes for private enveloper functions
*/
static Acmd *_pullSubFrame(N_PVoice *pv, s16 *inp, s16 *outp, s32 outCount,
Acmd *p) ;
static s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel);
#ifndef N_MICRO
static f32 _getVol(f32 ivol, s32 samples, s16 ratem, u16 ratel);
#else
static s16 _getVol(s16 ivol, s32 samples, s16 ratem, u16 ratel);
#endif
/***********************************************************************
* Enveloper filter public interfaces
***********************************************************************/
Acmd *n_alEnvmixerPull(N_PVoice *filter, s32 sampleOffset, Acmd *p)
{
Acmd *ptr = p;
N_PVoice *e = (N_PVoice *)filter;
s16 inp;
s32 lastOffset;
s32 thisOffset = sampleOffset;
s32 samples;
s16 loutp = 0;
s32 fVol;
ALParam *thisParam;
s32 outCount = FIXED_SAMPLE;
#ifdef AUD_PROFILE
lastCnt[++cnt_index] = osGetCount();
#endif
/*
* Force the input to be the resampler output
*/
#ifndef N_MICRO
inp = AL_RESAMPLER_OUT;
#else
inp = N_AL_RESAMPLER_OUT;
#endif
while (e->em_ctrlList != 0) {
lastOffset = thisOffset;
thisOffset = e->em_ctrlList->delta;
#ifdef FINAL_ROUND
samples = SAMPLE184(thisOffset - lastOffset);
if(!samples)
thisOffset = lastOffset;
#else
samples = thisOffset - lastOffset;
#endif
if (samples > outCount)
break;
#ifdef _DEBUG
assert(samples >= 0);
#ifndef N_MICRO
assert(samples <= AL_MAX_RSP_SAMPLES);
#else
assert(samples <= FIXED_SAMPLE);
#endif
#endif /* _DEBUG */
switch (e->em_ctrlList->type) {
case (AL_FILTER_START_VOICE_ALT):
{
ALStartParamAlt *param = (ALStartParamAlt *)e->em_ctrlList;
ALFilter *f = (ALFilter *) e;
s32 tmp;
if (param->unity) {
e->rs_upitch = 1;
}
n_alLoadParam(e, AL_FILTER_SET_WAVETABLE, param->wave);
e->em_motion = AL_PLAYING;
e->em_first = 1;
e->em_delta = 0;
#ifdef FINAL_ROUND
e->em_segEnd = SAMPLE184(param->samples);
#else
e->em_segEnd = param->samples;
#endif
tmp = ((s32)param->volume * (s32)param->volume) >> 15;
e->em_volume = (s16) tmp;
e->em_pan = param->pan;
e->em_dryamt = n_eqpower[param->fxMix];
e->em_wetamt = n_eqpower[N_EQPOWER_LENGTH - param->fxMix - 1];
if (param->samples) {
e->em_cvolL = 1;
e->em_cvolR = 1;
} else {
/*
* Attack time is zero. Simply set the
* volume. We don't want an attack segment.
*/
e->em_cvolL = (e->em_volume * n_eqpower[e->em_pan]) >> 15;
e->em_cvolR = (e->em_volume *
n_eqpower[N_EQPOWER_LENGTH - e->em_pan - 1]) >> 15;
}
e->rs_ratio = param->pitch;
}
break;
case (AL_FILTER_SET_FXAMT):
case (AL_FILTER_SET_PAN):
case (AL_FILTER_SET_VOLUME):
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
if (e->em_delta >= e->em_segEnd){
/*
* We should have reached our target, calculate
* target in case e->em_segEnd was 0
*/
e->em_ltgt = (e->em_volume * n_eqpower[e->em_pan]) >> 15;
e->em_rtgt = (e->em_volume *
n_eqpower[N_EQPOWER_LENGTH - e->em_pan - 1]) >> 15;
e->em_delta = e->em_segEnd; /* To prevent overflow */
e->em_cvolL = e->em_ltgt;
e->em_cvolR = e->em_rtgt;
} else {
/*
* Estimate the current volume
*/
e->em_cvolL = _getVol(e->em_cvolL, e->em_delta, e->em_lratm, e->em_lratl);
e->em_cvolR = _getVol(e->em_cvolR, e->em_delta, e->em_rratm, e->em_rratl);
}
/*
* We can't have volume of zero, because the envelope
* would never go anywhere from there
*/
if( e->em_cvolL == 0 ) e->em_cvolL = 1;
if( e->em_cvolR == 0 ) e->em_cvolR = 1;
if (e->em_ctrlList->type == AL_FILTER_SET_PAN)
/*
* This should result in a change to the current
* segment rate and target
*/
e->em_pan = (s16) e->em_ctrlList->data.i;
if (e->em_ctrlList->type == AL_FILTER_SET_VOLUME){
/*
* Switching to a new segment
*/
e->em_delta = 0;
/*
* Map volume non-linearly to give something close to
* loudness
*/
fVol = (e->em_ctrlList->data.i);
fVol = (fVol*fVol)>>15;
e->em_volume = (s16) fVol;
#ifdef FINAL_ROUND
e->em_segEnd = SAMPLE184(e->em_ctrlList->moredata.i);
#else
e->em_segEnd = e->em_ctrlList->moredata.i;
#endif
}
if (e->em_ctrlList->type == AL_FILTER_SET_FXAMT){
e->em_dryamt = n_eqpower[e->em_ctrlList->data.i];
e->em_wetamt = n_eqpower[N_EQPOWER_LENGTH - e->em_ctrlList->data.i - 1];
}
/*
* Force a volume update
*/
e->em_first = 1;
break;
case (AL_FILTER_START_VOICE):
{
ALStartParam *p = (ALStartParam *)e->em_ctrlList;
/*
* Changing to PLAYING (since the previous state was
* persumable STOPPED, we'll just bump the output
* pointer rather than pull a subframe of zeros).
*/
if (p->unity) {
e->rs_upitch = 1;
}
n_alLoadParam(e, AL_FILTER_SET_WAVETABLE, p->wave);
e->em_motion = AL_PLAYING;
}
break;
case (AL_FILTER_STOP_VOICE):
{
/*
* Changing to STOPPED and reset the filter
*/
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
n_alEnvmixerParam(e, AL_FILTER_RESET, 0);
}
break;
case (AL_FILTER_FREE_VOICE):
{
N_ALFreeParam *param = (N_ALFreeParam *)e->em_ctrlList;
param->pvoice->offset = 0;
_n_freePVoice((N_PVoice *)param->pvoice);
}
break;
#if 1
case (AL_FILTER_SET_PITCH):
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
e->rs_ratio = e->em_ctrlList->data.f;
break;
case (AL_FILTER_SET_UNITY_PITCH):
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
e->rs_upitch = 1;
break;
case (AL_FILTER_SET_WAVETABLE):
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
n_alLoadParam(e, AL_FILTER_SET_WAVETABLE,
(void *)e->em_ctrlList->data.i);
break;
#endif
default:
/*
* Pull the reuired number of samples and then pass the message
* on down the chain
*/
ptr = _pullSubFrame(e, &inp, &loutp, samples, ptr);
n_alEnvmixerParam(e, e->em_ctrlList->type,
(void *) e->em_ctrlList->data.i);
break;
}
loutp += (samples<<1);
outCount -= samples;
/*
* put the param record back on the free list
*/
thisParam = e->em_ctrlList;
e->em_ctrlList = e->em_ctrlList->next;
if (e->em_ctrlList == 0)
e->em_ctrlTail = 0;
_n_freeParam(thisParam);
}
ptr = _pullSubFrame(e, &inp, &loutp, outCount, ptr);
/*
* Prevent overflow in e->em_delta
*/
if (e->em_delta > e->em_segEnd)
e->em_delta = e->em_segEnd;
#ifdef AUD_PROFILE
PROFILE_AUD(env_num, env_cnt, env_max, env_min);
#endif
return ptr;
}
s32
n_alEnvmixerParam(N_PVoice *filter, s32 paramID, void *param)
{
N_PVoice *e = filter;
switch (paramID) {
case (AL_FILTER_ADD_UPDATE):
if (e->em_ctrlTail) {
e->em_ctrlTail->next = (ALParam *)param;
} else {
e->em_ctrlList = (ALParam *)param;
}
e->em_ctrlTail = (ALParam *)param;
break;
case (AL_FILTER_RESET):
e->em_first = 1;
e->em_motion = AL_STOPPED;
e->em_volume = 1;
e->em_segEnd = 0;
e->rs_delta = 0.0;
e->rs_first = 1;
e->rs_upitch = 0;
n_alLoadParam(e, AL_FILTER_RESET, param);
break;
case (AL_FILTER_START):
e->em_motion = AL_PLAYING;
break;
default:
#if 1
n_alLoadParam(e, paramID, param);
#else
n_alResampleParam(e, paramID, param);
#endif
break;
}
return 0;
}
static
Acmd* _pullSubFrame(N_PVoice *filter, s16 *inp, s16 *outp, s32 outCount,
Acmd *p)
{
Acmd *ptr = p;
N_PVoice *e = filter;
#ifndef N_MICRO
s16 *inpp = AL_RESAMPLER_OUT;
#else
s16 *inpp = N_AL_RESAMPLER_OUT;
#endif
/* filter must be playing and request non-zero output samples to pull. */
if (e->em_motion != AL_PLAYING || !outCount)
return ptr;
/*
* ask all filters upstream from us to build their command
* lists.
*/
ptr = n_alResamplePull(e,inp, p);
/*
* construct our portion of the command list
*/
#ifndef N_MICRO
aSetBuffer(ptr++, A_MAIN, *inp, AL_MAIN_L_OUT, FIXED_SAMPLE<<1);
aSetBuffer(ptr++, A_AUX, AL_MAIN_R_OUT , AL_AUX_L_OUT ,
AL_AUX_R_OUT );
#endif
if (e->em_first){
e->em_first = 0;
/*
* Calculate derived parameters
*/
e->em_ltgt = (e->em_volume * n_eqpower[e->em_pan]) >> 15;
e->em_lratm = _getRate((f64)e->em_cvolL, (f64)e->em_ltgt,
e->em_segEnd, &(e->em_lratl));
e->em_rtgt = (e->em_volume *
n_eqpower[N_EQPOWER_LENGTH - e->em_pan - 1]) >> 15;
e->em_rratm = _getRate((f64)e->em_cvolR, (f64)e->em_rtgt, e->em_segEnd,
&(e->em_rratl));
#ifndef N_MICRO
aSetVolume(ptr++, A_LEFT | A_VOL, e->em_cvolL, 0, 0);
aSetVolume(ptr++, A_RIGHT | A_VOL, e->em_cvolR, 0, 0);
aSetVolume(ptr++, A_LEFT | A_RATE, e->em_ltgt, e->em_lratm, e->em_lratl);
aSetVolume(ptr++, A_RIGHT | A_RATE, e->em_rtgt, e->em_rratm, e->em_rratl);
aSetVolume(ptr++, A_AUX, e->em_dryamt, 0, e->em_wetamt);
aEnvMixer (ptr++, A_INIT | A_AUX, osVirtualToPhysical(e->em_state));
}
else
aEnvMixer(ptr++, A_CONTINUE | A_AUX, osVirtualToPhysical(e->em_state));
#else
// needs to be on same line.
n_aSetVolume(ptr++, A_RATE, e->em_ltgt, e->em_lratm, e->em_lratl); n_aSetVolume(ptr++, A_LEFT | A_VOL, e->em_cvolL, e->em_dryamt, e->em_wetamt); n_aSetVolume(ptr++, A_RIGHT | A_VOL, e->em_rtgt, e->em_rratm, e->em_rratl); n_aEnvMixer (ptr++, A_INIT, e->em_cvolR, osVirtualToPhysical(e->em_state)); } else n_aEnvMixer(ptr++, A_CONTINUE, 0, osVirtualToPhysical(e->em_state));
#endif
/*
* bump the input buffer pointer
*/
*inp += (FIXED_SAMPLE<<1);
e->em_delta += FIXED_SAMPLE;
return ptr;
}
#ifndef N_MICRO
#define EXP_MASK 0x7f800000
#define MANT_MASK 0x807fffff
static
s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel)
{
s16 s;
f64 invn = 1.0/count, eps, a, fs, mant;
s32 i_invn, ex, indx;
#ifdef AUD_PROFILE
lastCnt[++cnt_index] = osGetCount();
#endif
if (count == 0){
if (tgt >= vol){
*ratel = 0xffff;
return 0x7fff;
}
else{
*ratel = 0;
return 0;
}
}
if (tgt < 1.0)
tgt = 1.0;
if (vol <= 0) vol = 1; /* zero and neg values not allowed */
#define NBITS (3)
#define NPOS (1<<NBITS)
#define NFRACBITS (30)
#define M_LN2 0.69314718055994530942
/*
* rww's parametric pow()
Goal: compute a = (tgt/vol)^(1/count)
Approach:
(tgt/vol)^(1/count) =
((tgt/vol)^(1/2^30))^(2^30*1/count)
(tgt/vol)^(1/2^30) ~= 1 + eps
where
eps ~= ln(tgt/vol)/2^30
ln(tgt/vol) = ln2(tgt/vol) * ln(2)
ln2(tgt/vol) = fp_exponent( tgt/vol ) +
ln2( fp_mantissa( tgt/vol ) )
fp_mantissa() and fp_exponent() are
calculated via tricky bit manipulations of
the floating point number. ln2() is
approximated by a look up table.
Note that this final (1+eps) value needs
to be raised to the 2^30/count power. This
is done by operating on the binary representaion
of this number in the final while loop.
Enjoy!
*/
{
f64 logtab[] = { -0.912537, -0.752072, -0.607683, -0.476438,
-0.356144, -0.245112, -0.142019, -0.045804 };
i_invn = (s32) _ldexpf( invn, NFRACBITS );
mant = _frexpf( tgt/vol, &ex );
indx = (s32) (_ldexpf( mant, NBITS+1 ) ); /* NPOS <= indx < 2*NPOS */
eps = (logtab[indx - NPOS] + ex) * M_LN2;
eps /= _ldexpf( 1, NFRACBITS ); /* eps / 2^NFRACBITS */
fs = (1.0 + eps);
a = 1.0;
while( i_invn ) {
if( i_invn & 1 )
a = a * fs;
fs *= fs;
i_invn >>= 1;
}
}
a *= (a *= (a *= a));
s = (s16) a;
*ratel = (s16)(0xffff * (a - (f32) s));
#ifdef AUD_PROFILE
PROFILE_AUD(rate_num, rate_cnt, rate_max, rate_min);
#endif
return (s16)a;
}
#else
static
s16 _getRate(f64 vol, f64 tgt, s32 count, u16* ratel)
{
s16 s, tmp;
f64 invn, a, f;
#ifdef AUD_PROFILE
lastCnt[++cnt_index] = osGetCount();
#endif
if (count == 0){
if (tgt >= vol){
*ratel = 0xffff;
return 0x7fff;
}
else{
*ratel = 0;
return 0x8000;
}
}
invn = 1.0 / count;
if (tgt < 1.0)
tgt = 1.0;
if (vol <= 0.0) vol = 1.0; /* zero and neg values not allowed */
a = (tgt - vol) * invn * 8.0;
s = (s16)a;
f = a - (f64)s;
s -= 1;
f += 1.0;
tmp = (s16)f;
s += tmp;
f -= (f64)tmp;
#ifdef AUD_PROFILE
PROFILE_AUD( rate_num, rate_cnt, rate_max, rate_min);
#endif
*ratel = (u16)(0xffff * f);
return s;
}
#endif
#ifndef N_MICRO
static
f32 _getVol(f32 ivol, s32 samples, s16 ratem, u16 ratel)
{
f32 r, a;
s32 i;
#ifdef AUD_PROFILE
lastCnt[++cnt_index] = osGetCount();
#endif
/*
* Rate values are actually rate^8
*/
samples >>=3;
if (samples == 0){
return ivol;
}
r = ((f32) (ratem<<16) + (f32) ratel)/65536;
a = 1.0;
for (i=0; i<32; i++){
if( samples & 1 )
a *= r;
samples >>= 1;
if (samples == 0)
break;
r *= r;
}
ivol *= a;
#ifdef AUD_PROFILE
PROFILE_AUD(vol_num, vol_cnt, vol_max, vol_min);
#endif
return ivol;
}
#else
static
s16 _getVol(s16 ivol, s32 samples, s16 ratem, u16 ratel)
{
s32 tmp1;
#ifdef AUD_PROFILE
lastCnt[++cnt_index] = osGetCount();
#endif
samples >>= 3;
if (samples == 0){
return ivol;
}
tmp1 = ratel * samples;
tmp1 >>= 16;
tmp1 += ratem * samples;
ivol += tmp1;
#ifdef AUD_PROFILE
PROFILE_AUD(vol_num, vol_cnt, vol_max, vol_min);
#endif
return ivol;
}
#endif

View File

@@ -89,7 +89,7 @@
- [0x45720, c] # music code
- [0x46680, c] # speech code
- [0x47AF0, c, libnaudio/n_synstopvoice]
- [0x47B60, c] # sound code
- [0x47B60, c, libnaudio/n_env] # sound code
- [0x485C0, c] # moves code
- [0x48C60, c] # move effects code
- [0x490A0, c] # audio functions to 0x50C00
@@ -344,6 +344,8 @@
- [0x78890, data, rom_data_78890]
- [0x79180, .data, libnaudio/n_sl]
- [0x79190, data, rom_data_79190]
- [0x79200, .data, libnaudio/n_env]
- [0x79300, data, rom_data_79300]
- [0x79630, .data, 49790]
- [0x79660, data, rom_data_79660]
- [0x79AE0, .data, 4CBC0]
@@ -414,7 +416,8 @@
- [0x7D230, .rodata, 373A0]
- [0x7D340, rodata, rom_rodata_7D340]
- [0x7D3E0, rodata, rom_rodata_7D3E0]
- [0x7D880, rodata, rom_rodata_7D880]
- [0x7D880, .rodata, libnaudio/n_env]
- [0x7D8D0, rodata, rom_rodata_7D8D0]
- [0x7DF80, rodata, rom_rodata_7DF80]
- [0x7DFD0, .rodata, 49790]
- [0x7E0C0, .rodata, libnaudio/n_synthesizer]