mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-07-02 18:46:03 -04:00
jaudio_NES: implement & link channel
This commit is contained in:
+1
-1
@@ -764,7 +764,7 @@ config.libs = [
|
||||
Object(Matching, "jaudio_NES/internal/bankdrv.c", extra_cflags=["-pragma \"scheduling 7400\""]),
|
||||
Object(Matching, "jaudio_NES/internal/bankread.c"),
|
||||
Object(Matching, "jaudio_NES/internal/centcalc.c"),
|
||||
Object(NonMatching, "jaudio_NES/internal/channel.c"),
|
||||
Object(Matching, "jaudio_NES/internal/channel.c"),
|
||||
Object(Matching, "jaudio_NES/internal/cmdstack.c"),
|
||||
Object(Matching, "jaudio_NES/internal/connect.c"),
|
||||
Object(NonMatching, "jaudio_NES/internal/driver.c"),
|
||||
|
||||
@@ -138,6 +138,15 @@ typedef enum LpsCacheState {
|
||||
/* 3 */ LPS_CACHE_STATE_DONE
|
||||
} LpsCacheState;
|
||||
|
||||
typedef enum PhaseType {
|
||||
PHASE_TYPE_0,
|
||||
PHASE_TYPE_1,
|
||||
PHASE_TYPE_2,
|
||||
PHASE_TYPE_3,
|
||||
|
||||
PHASE_TYPE_NUM
|
||||
} PhaseType;
|
||||
|
||||
#define VOICE_TYPE_PERCUSSION 0
|
||||
#define VOICE_TYPE_SOUND_EFF 1
|
||||
#define VOICE_TYPE_INSTRUMENT_START 2
|
||||
|
||||
@@ -16,8 +16,8 @@ typedef struct link_ link;
|
||||
|
||||
/* sizeof(struct link_) == 0x10 */
|
||||
struct link_ {
|
||||
/* 0x00 */ link* next;
|
||||
/* 0x04 */ link* prev;
|
||||
/* 0x00 */ link* prev;
|
||||
/* 0x04 */ link* next;
|
||||
union {
|
||||
/* 0x08 */ s32 numAfter; /* when link is head */
|
||||
/* 0x08 */ void* pData; /* when link is node */
|
||||
@@ -127,17 +127,24 @@ typedef struct wtstr_ {
|
||||
|
||||
/* sizeof(phase) == 0x01 */
|
||||
typedef struct phase_ {
|
||||
union {
|
||||
struct {
|
||||
/* 0x00 */ u8 _unused : 2;
|
||||
/* 0x00 */ u8 type : 2;
|
||||
/* 0x00 */ u8 strong_right : 1;
|
||||
/* 0x00 */ u8 strong_left : 1;
|
||||
/* 0x00 */ u8 strong_reverb_right : 1;
|
||||
/* 0x00 */ u8 strong_reverb_left : 1;
|
||||
};
|
||||
/* 0x00 */ u8 asU8;
|
||||
};
|
||||
// union {
|
||||
// struct {
|
||||
// /* 0x00 */ u8 _unused : 2;
|
||||
// /* 0x00 */ u8 type : 2;
|
||||
// /* 0x00 */ u8 strong_right : 1;
|
||||
// /* 0x00 */ u8 strong_left : 1;
|
||||
// /* 0x00 */ u8 strong_reverb_right : 1;
|
||||
// /* 0x00 */ u8 strong_reverb_left : 1;
|
||||
// } flags;
|
||||
// /* 0x00 */ u8 asU8;
|
||||
// };
|
||||
|
||||
/* 0x00 */ u8 _unused : 2;
|
||||
/* 0x00 */ u8 type : 2;
|
||||
/* 0x00 */ u8 strong_right : 1;
|
||||
/* 0x00 */ u8 strong_left : 1;
|
||||
/* 0x00 */ u8 strong_reverb_right : 1;
|
||||
/* 0x00 */ u8 strong_reverb_left : 1;
|
||||
} phase;
|
||||
|
||||
/* sizeof(sweep) == 0x0C */
|
||||
@@ -218,10 +225,10 @@ typedef struct commonch_ {
|
||||
/* 0x00 */ u8 strong_right : 1;
|
||||
/* 0x00 */ u8 strong_left : 1;
|
||||
/* 0x00 */ u8 strong_reverb_right : 1;
|
||||
/* 0x00 */ u8 storng_reverb_left : 1;
|
||||
/* 0x00 */ u8 strong_reverb_left : 1;
|
||||
|
||||
/* 0x01 */ u8 reverb_idx : 3;
|
||||
/* 0x01 */ u8 book_ofs : 2;
|
||||
/* 0x01 */ u8 __book_ofs : 2;
|
||||
/* 0x01 */ u8 is_synth_wave : 1;
|
||||
/* 0x01 */ u8 has_two_parts : 1;
|
||||
/* 0x01 */ u8 use_haas_effect : 1;
|
||||
@@ -243,7 +250,7 @@ typedef struct commonch_ {
|
||||
/* 0x14 */ s16* filter;
|
||||
/* 0x18 */ u8 _18;
|
||||
/* 0x19 */ u8 surround_effect_idx;
|
||||
/* 0x1A */ u8 _1A;
|
||||
/* 0x1A */ u8 book_ofs;
|
||||
/* 0x1B */ u8 _1B[4];
|
||||
} commonch;
|
||||
|
||||
@@ -289,7 +296,7 @@ typedef struct playbackparams_ {
|
||||
/* 0x04 */ phase stereo_phase;
|
||||
/* 0x05 */ u8 comb_filter_size;
|
||||
/* 0x06 */ u16 comb_filter_gain;
|
||||
/* 0x08 */ f32 frequency_scale;
|
||||
/* 0x08 */ f32 pitch;
|
||||
/* 0x0C */ f32 velocity;
|
||||
/* 0x10 */ s16* filter;
|
||||
/* 0x14 */ s16* filter_buf;
|
||||
@@ -331,18 +338,10 @@ struct channel_ {
|
||||
|
||||
/* sizeof(drvparam) == 0x1C */
|
||||
typedef struct drvparam_ {
|
||||
/* 0x00 */ u8 _00;
|
||||
/* 0x01 */ u8 _01;
|
||||
/* 0x02 */ u8 _02;
|
||||
/* 0x03 */ u8 _03;
|
||||
/* 0x04 */ phase phase;
|
||||
/* 0x08 */ f32 pitch;
|
||||
/* 0x0C */ f32 volume;
|
||||
/* 0x10 */ int _10;
|
||||
/* 0x14 */ int _14;
|
||||
/* 0x18 */ u8 _18;
|
||||
/* 0x00 */ playbackparams playback;
|
||||
/* 0x18 */ u8 comb_filter_size;
|
||||
/* 0x19 */ u8 _19;
|
||||
/* 0x1A */ u16 _1A;
|
||||
/* 0x1A */ u16 comb_filter_gain;
|
||||
} drvparam;
|
||||
|
||||
/* sizeof(voicetable) == 0x20 */
|
||||
@@ -357,19 +356,19 @@ typedef struct voicetable_ {
|
||||
/* 0x18 */ wtstr high_pitch_tuned_sample;
|
||||
} voicetable;
|
||||
|
||||
/* sizeof(percvoicetable) == 0x10 */
|
||||
typedef struct percvoicetable_ {
|
||||
/* sizeof(perctable) == 0x10 */
|
||||
typedef struct perctable_ {
|
||||
/* 0x00 */ u8 adsr_decay_idx;
|
||||
/* 0x01 */ u8 pan;
|
||||
/* 0x02 */ u8 is_relocated;
|
||||
/* 0x04 */ wtstr tuned_sample;
|
||||
/* 0x0C */ envdat* envelope;
|
||||
} percvoicetable;
|
||||
} perctable;
|
||||
|
||||
/* sizeof(veffvoicetable) == 0x08 */
|
||||
typedef struct veffvoicetable_ {
|
||||
/* sizeof(percvoicetable) == 0x08 */
|
||||
typedef struct percvoicetable_ {
|
||||
/* 0x00 */ wtstr tuned_sample;
|
||||
} veffvoicetable;
|
||||
} percvoicetable;
|
||||
|
||||
/* sizeof(voiceinfo) == 0x14 */
|
||||
typedef struct voiceinfo_ {
|
||||
@@ -379,8 +378,8 @@ typedef struct voiceinfo_ {
|
||||
/* 0x03 */ u8 wave_bank_id1;
|
||||
/* 0x04 */ u16 num_sfx;
|
||||
/* 0x08 */ voicetable** instruments;
|
||||
/* 0x0C */ percvoicetable** percussion;
|
||||
/* 0x10 */ veffvoicetable* effects;
|
||||
/* 0x0C */ perctable** percussion;
|
||||
/* 0x10 */ percvoicetable* effects;
|
||||
} voiceinfo;
|
||||
|
||||
/* sizeof(delayparam) == 0x1C */
|
||||
@@ -928,6 +927,8 @@ typedef struct AudioGlobals {
|
||||
/* 0x92AC */ s32 _92AC;
|
||||
} AudioGlobals;
|
||||
|
||||
#define NA_NO_NOTE ((note*)-1)
|
||||
|
||||
// typedef union SOUNDID_ {
|
||||
// struct {
|
||||
// u8 wave_id;
|
||||
|
||||
@@ -14,4 +14,12 @@ extern u8 DEFAULT_GTABLE[];
|
||||
extern u8 BDB_SEQDATA[];
|
||||
extern s16* WAVEMEM_TABLE[];
|
||||
|
||||
extern commonch NA_SVCINIT_TABLE[];
|
||||
extern commonch NA_CHINIT_TABLE[];
|
||||
extern u16 CDELAYTABLE[];
|
||||
|
||||
extern f32 PhoneLeft[];
|
||||
extern f32 WideLeft[];
|
||||
extern f32 StereoLeft[];
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,8 +9,8 @@ extern channel* Nas_AllocationOnRequest(note* n);
|
||||
|
||||
extern wtstr* NoteToVoice(voicetable* voicetbl, s32 note);
|
||||
extern voicetable* ProgToVp(s32 prog, s32 note);
|
||||
extern percvoicetable* PercToPp(s32 perc, s32 note);
|
||||
extern veffvoicetable* VpercToVep(s32 vperc, s32 note);
|
||||
extern perctable* PercToPp(s32 perc, s32 note);
|
||||
extern percvoicetable* VpercToVep(s32 vperc, s32 note);
|
||||
|
||||
extern void Nas_UpdateChannel(void);
|
||||
|
||||
@@ -19,5 +19,8 @@ extern void Nas_AllocVoices(chnode* node, s32 num);
|
||||
extern void Nas_InitChNode(chnode* node);
|
||||
extern void Nas_Release_Channel(note* n);
|
||||
extern void Nas_Release_Channel_Force(note* n);
|
||||
extern void Nas_EntryTrack(channel* chan, note* n);
|
||||
|
||||
extern void Nas_CutList(link* l);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
extern void Nas_HeapInit(ALHeap* heap, u8* base, s32 len);
|
||||
extern void* Nas_HeapAlloc(ALHeap* heap, s32 size);
|
||||
extern void* Nas_HeapAlloc_CL(ALHeap* heap, s32 size);
|
||||
extern void* Nas_NcHeapAlloc(ALHeap* heap, s32 size);
|
||||
extern void* Nas_2ndHeapAlloc(ALHeap* heap, s32 size);
|
||||
extern void* Nas_Alloc_Single(s32 size, s32 bank_id, u8* wave_addr, s8 medium, s32 cache);
|
||||
|
||||
|
||||
@@ -0,0 +1,980 @@
|
||||
#include "jaudio_NES/channel.h"
|
||||
|
||||
#include "jaudio_NES/system.h"
|
||||
#include "jaudio_NES/audiostruct.h"
|
||||
#include "jaudio_NES/audiowork.h"
|
||||
#include "jaudio_NES/audioconst.h"
|
||||
#include "jaudio_NES/memory.h"
|
||||
#include "jaudio_NES/os.h"
|
||||
#include "jaudio_NES/effect.h"
|
||||
#include "jaudio_NES/track.h"
|
||||
#include "jaudio_NES/sub_sys.h"
|
||||
#include "jaudio_NES/audioheaders.h"
|
||||
#include <dolphin/os.h>
|
||||
|
||||
static void Nas_smzSetPitch(channel* chan, f32 pitch);
|
||||
static void Nas_AddListHead(link* list, link* l);
|
||||
|
||||
static void Nas_smzSetParam(channel* chan, drvparam* param) {
|
||||
f32 volL;
|
||||
f32 volR;
|
||||
s32 strongL;
|
||||
s32 strongR;
|
||||
s32 halfPanIdx;
|
||||
f32 velocity;
|
||||
u8 pan;
|
||||
u8 panScale;
|
||||
u8 reverbVol;
|
||||
phase stereoPhase;
|
||||
s32 phaseEffects;
|
||||
|
||||
phaseEffects = chan->playback_ch.stereo_headset_effects;
|
||||
Nas_smzSetPitch(chan, param->playback.pitch);
|
||||
|
||||
velocity = param->playback.velocity;
|
||||
pan = param->playback.pan;
|
||||
reverbVol = param->playback.target_reverb_volume;
|
||||
stereoPhase = param->playback.stereo_phase;
|
||||
panScale = pan & 0x7F;
|
||||
chan->common_ch.strong_right = FALSE;
|
||||
chan->common_ch.strong_left = FALSE;
|
||||
chan->common_ch.strong_reverb_right = stereoPhase.strong_reverb_right;
|
||||
chan->common_ch.strong_reverb_left = stereoPhase.strong_reverb_left;
|
||||
|
||||
|
||||
if (phaseEffects && AG.sound_mode == SOUND_OUTPUT_HEADSET) {
|
||||
halfPanIdx = panScale >> 1;
|
||||
if (halfPanIdx > 0x3F) {
|
||||
halfPanIdx = 0x3F;
|
||||
}
|
||||
|
||||
chan->common_ch.haas_effect_right_delay_size = CDELAYTABLE[halfPanIdx];
|
||||
chan->common_ch.haas_effect_left_delay_size = CDELAYTABLE[0x3F - halfPanIdx];
|
||||
chan->common_ch.use_haas_effect = TRUE;
|
||||
|
||||
volL = PhoneLeft[panScale];
|
||||
volR = PhoneLeft[0x7F - panScale];
|
||||
} else if (phaseEffects && AG.sound_mode == SOUND_OUTPUT_STEREO) {
|
||||
strongL = strongR = FALSE;
|
||||
chan->common_ch.haas_effect_left_delay_size = 0;
|
||||
chan->common_ch.haas_effect_right_delay_size = 0;
|
||||
chan->common_ch.use_haas_effect = FALSE;
|
||||
volL = WideLeft[panScale];
|
||||
volR = WideLeft[0x7F - panScale];
|
||||
|
||||
if (panScale < 0x20) {
|
||||
strongL = TRUE;
|
||||
} else if (panScale > 0x60) {
|
||||
strongR = TRUE;
|
||||
}
|
||||
|
||||
chan->common_ch.strong_right = strongR;
|
||||
chan->common_ch.strong_left = strongL;
|
||||
|
||||
switch (stereoPhase.type) {
|
||||
case PHASE_TYPE_0:
|
||||
break;
|
||||
case PHASE_TYPE_1:
|
||||
chan->common_ch.strong_right = stereoPhase.strong_right;
|
||||
chan->common_ch.strong_left = stereoPhase.strong_left;
|
||||
break;
|
||||
case PHASE_TYPE_2:
|
||||
chan->common_ch.strong_right = strongR | stereoPhase.strong_right;
|
||||
chan->common_ch.strong_left = strongL | stereoPhase.strong_left;
|
||||
break;
|
||||
case PHASE_TYPE_3:
|
||||
chan->common_ch.strong_right = strongR ^ stereoPhase.strong_right;
|
||||
chan->common_ch.strong_left = strongL ^ stereoPhase.strong_left;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (AG.sound_mode) {
|
||||
case SOUND_OUTPUT_MONO:
|
||||
chan->common_ch.strong_reverb_right = FALSE;
|
||||
chan->common_ch.strong_reverb_left = FALSE;
|
||||
volL = 0.707f;
|
||||
volR = 0.707f;
|
||||
break;
|
||||
default:
|
||||
chan->common_ch.strong_right = stereoPhase.strong_right;
|
||||
chan->common_ch.strong_left = stereoPhase.strong_left;
|
||||
volL = StereoLeft[panScale];
|
||||
volR = StereoLeft[0x7F - panScale];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (velocity < 0.0f) {
|
||||
velocity = 0.0f;
|
||||
}
|
||||
|
||||
if (velocity > 1.0f) {
|
||||
velocity = 1.0f;
|
||||
}
|
||||
|
||||
chan->common_ch.target_volume_left = (s32)((velocity * volL) * (0x1000 - 0.001f));
|
||||
chan->common_ch.target_volume_right = (s32)((velocity * volR) * (0x1000 - 0.001f));
|
||||
|
||||
chan->common_ch.gain = param->playback.gain;
|
||||
chan->common_ch.filter = param->playback.filter_buf;
|
||||
chan->common_ch.comb_filter_size = param->comb_filter_size;
|
||||
chan->common_ch.comb_filter_gain = param->comb_filter_gain;
|
||||
chan->common_ch.target_reverb_volume = reverbVol;
|
||||
chan->common_ch.surround_effect_idx = param->playback.surround_effect_idx;
|
||||
}
|
||||
|
||||
static void Nas_smzSetPitch(channel* chan, f32 pitch) {
|
||||
f32 rate = 0.0f;
|
||||
|
||||
if (pitch < 2.0f) {
|
||||
chan->common_ch.has_two_parts = FALSE;
|
||||
if (pitch > 1.99998f) {
|
||||
rate = 1.99998f;
|
||||
} else {
|
||||
rate = pitch;
|
||||
}
|
||||
} else {
|
||||
chan->common_ch.has_two_parts = TRUE;
|
||||
if (pitch > 3.99996f) {
|
||||
rate = 1.99998f;
|
||||
} else {
|
||||
rate = pitch / 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
chan->common_ch.frequency_fixed_point = (s32)(rate * 32768.0f);
|
||||
}
|
||||
|
||||
extern void Nas_StartVoice(channel* chan) {
|
||||
if (chan->playback_ch.current_parent_note->adsr_env.decay_idx == 0) {
|
||||
Nas_EnvInit(&chan->playback_ch.adsr_envp, chan->playback_ch.current_parent_note->sub_track->adsr_env.envelope, &chan->playback_ch.adsr_volume_scale_unused);
|
||||
} else {
|
||||
Nas_EnvInit(&chan->playback_ch.adsr_envp, chan->playback_ch.current_parent_note->adsr_env.envelope, &chan->playback_ch.adsr_volume_scale_unused);
|
||||
}
|
||||
|
||||
chan->playback_ch.status = 0;
|
||||
chan->playback_ch.adsr_envp.state.flags.status = ADSR_STATUS_INITIAL;
|
||||
chan->common_ch = NA_SVCINIT_TABLE[0];
|
||||
}
|
||||
|
||||
extern void Nas_StopVoice(channel* chan) {
|
||||
if (chan->common_ch.needs_init == TRUE) {
|
||||
chan->common_ch.needs_init = FALSE;
|
||||
}
|
||||
|
||||
chan->common_ch.enabled = FALSE;
|
||||
chan->common_ch.finished = FALSE;
|
||||
chan->playback_ch.priority = 0;
|
||||
chan->playback_ch.status = 0;
|
||||
chan->playback_ch.current_parent_note = NA_NO_NOTE;
|
||||
chan->playback_ch.previous_parent_note = NA_NO_NOTE;
|
||||
chan->playback_ch.adsr_envp.state.flags.status = ADSR_STATUS_DISABLED;
|
||||
chan->playback_ch.adsr_envp.current = 0;
|
||||
}
|
||||
|
||||
// TODO: this needs to be checked to see if we can cleanup the control flow,
|
||||
// the excessive gotos may be unnecessary
|
||||
extern void Nas_UpdateChannel(void) {
|
||||
playbackparams* main_param_p;
|
||||
channel* chan;
|
||||
commonch* common_chan;
|
||||
playbackch* playback_chan;
|
||||
drvparam param;
|
||||
u8 bookOfs;
|
||||
f32 scale;
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < AG.num_channels; i++) {
|
||||
chan = &AG.channels[i];
|
||||
playback_chan = &chan->playback_ch;
|
||||
|
||||
if (playback_chan->current_parent_note != NA_NO_NOTE) {
|
||||
if ((u32)playback_chan->current_parent_note < 0x7FFFFFFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chan != playback_chan->current_parent_note->channel && playback_chan->status == 0) {
|
||||
playback_chan->adsr_envp.state.flags.release = TRUE;
|
||||
playback_chan->adsr_envp.fadeout_velocity = AG.audio_params.updates_per_frame_inverse;
|
||||
playback_chan->priority = 1;
|
||||
playback_chan->status = 2;
|
||||
goto skip;
|
||||
} else if (!playback_chan->current_parent_note->enabled && playback_chan->status == 0 && playback_chan->priority != 0) {
|
||||
// nothing
|
||||
} else if (playback_chan->current_parent_note->sub_track->group == NULL) {
|
||||
Nas_ReleaseSubTrack(playback_chan->current_parent_note->sub_track);
|
||||
playback_chan->priority = 1;
|
||||
playback_chan->status = 1;
|
||||
continue;
|
||||
} else if ((!playback_chan->current_parent_note->sub_track->muted && (!playback_chan->current_parent_note->sub_track->group->flags.muted || (playback_chan->current_parent_note->sub_track->mute_flags & AUDIO_MUTE_FLAG_STOP_NOTE) == 0))) {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
Nas_Release_Channel_Force(playback_chan->current_parent_note);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddListHead(&chan->link.pNode->releaseList, &chan->link);
|
||||
playback_chan->priority = 1;
|
||||
playback_chan->status = 2;
|
||||
goto skip;
|
||||
} else if (playback_chan->status == 0) {
|
||||
if (playback_chan->priority != 0) {
|
||||
continue;
|
||||
} else {
|
||||
goto skip;
|
||||
}
|
||||
} else {
|
||||
goto skip;
|
||||
}
|
||||
|
||||
step2:
|
||||
{
|
||||
common_chan = &chan->common_ch;
|
||||
|
||||
if (playback_chan->status >= 1 || common_chan->finished) {
|
||||
if (playback_chan->adsr_envp.state.flags.status == ADSR_STATUS_DISABLED || common_chan->finished) {
|
||||
if (playback_chan->wanted_parent_note != NA_NO_NOTE) {
|
||||
Nas_StopVoice(chan);
|
||||
|
||||
if (playback_chan->wanted_parent_note->sub_track != NULL) {
|
||||
Nas_EntryTrack(chan, playback_chan->wanted_parent_note);
|
||||
Nas_ChannelModInit(chan);
|
||||
Nas_SweepInit(chan);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&chan->link.pNode->useList, &chan->link);
|
||||
playback_chan->wanted_parent_note = NA_NO_NOTE;
|
||||
} else {
|
||||
Nas_StopVoice(chan);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&chan->link.pNode->freeList, &chan->link);
|
||||
playback_chan->wanted_parent_note = NA_NO_NOTE;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (playback_chan->current_parent_note != NA_NO_NOTE) {
|
||||
playback_chan->current_parent_note->_00bit1 = TRUE;
|
||||
}
|
||||
|
||||
Nas_StopVoice(chan);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&chan->link.pNode->freeList, &chan->link);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (playback_chan->adsr_envp.state.flags.status == ADSR_STATUS_DISABLED) {
|
||||
if (playback_chan->current_parent_note != NA_NO_NOTE) {
|
||||
playback_chan->current_parent_note->_00bit1 = TRUE;
|
||||
}
|
||||
|
||||
Nas_StopVoice(chan);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&chan->link.pNode->freeList, &chan->link);
|
||||
continue;
|
||||
}
|
||||
|
||||
scale = Nas_EnvProcess(&playback_chan->adsr_envp);
|
||||
Nas_ChannelModulation(chan);
|
||||
main_param_p = &playback_chan->params;
|
||||
|
||||
switch (playback_chan->status) {
|
||||
case 1:
|
||||
case 2:
|
||||
param.playback.pitch = main_param_p->pitch;
|
||||
param.playback.velocity = main_param_p->velocity;
|
||||
param.playback.pan = main_param_p->pan;
|
||||
param.playback.target_reverb_volume = main_param_p->target_reverb_volume;
|
||||
param.playback.stereo_phase = main_param_p->stereo_phase;
|
||||
param.playback.gain = main_param_p->gain;
|
||||
param.playback.filter_buf = main_param_p->filter;
|
||||
param.comb_filter_size = main_param_p->comb_filter_size;
|
||||
param.comb_filter_gain = main_param_p->comb_filter_gain;
|
||||
param.playback.surround_effect_idx = main_param_p->surround_effect_idx;
|
||||
bookOfs = common_chan->book_ofs;
|
||||
break;
|
||||
default: {
|
||||
note* n = playback_chan->current_parent_note;
|
||||
sub* subtrack = n->sub_track;
|
||||
|
||||
param.playback.pitch = n->note_frequency_scale;
|
||||
param.playback.velocity = n->note_velocity;
|
||||
param.playback.pan = n->note_pan;
|
||||
|
||||
if (n->surround_effect_idx == 128) {
|
||||
param.playback.surround_effect_idx = subtrack->surround_effect_idx;
|
||||
} else {
|
||||
param.playback.surround_effect_idx = n->surround_effect_idx;
|
||||
}
|
||||
|
||||
if (n->stereo_phase.type == 0) {
|
||||
param.playback.stereo_phase = subtrack->stereo_phase;
|
||||
} else {
|
||||
param.playback.stereo_phase = n->stereo_phase;
|
||||
}
|
||||
|
||||
if (n->_0A.flags.bit2 == TRUE) {
|
||||
param.playback.target_reverb_volume = subtrack->target_reverb_vol;
|
||||
} else {
|
||||
param.playback.target_reverb_volume = n->target_reverb_volume;
|
||||
}
|
||||
|
||||
if (n->_0A.flags.bit9 == TRUE) {
|
||||
param.playback.gain = subtrack->gain;
|
||||
} else {
|
||||
param.playback.gain = 0;
|
||||
}
|
||||
|
||||
param.playback.filter_buf = subtrack->filter;
|
||||
param.comb_filter_size = subtrack->comb_filter_size;
|
||||
param.comb_filter_gain = subtrack->comb_filter_gain;
|
||||
bookOfs = subtrack->book_ofs;
|
||||
|
||||
if (subtrack->group->flags.muted && (subtrack->mute_flags & AUDIO_MUTE_FLAG_STOP_SAMPLES)) {
|
||||
param.playback.pitch = 0.0f;
|
||||
param.playback.velocity = 0.0f;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
param.playback.pitch *= playback_chan->vibrato_frequency_scale * playback_chan->portamento_frequency_scale;
|
||||
param.playback.pitch *= AG.audio_params.resample_rate;
|
||||
param.playback.velocity *= scale;
|
||||
Nas_smzSetParam(chan, ¶m);
|
||||
common_chan->book_ofs = bookOfs;
|
||||
continue;
|
||||
}
|
||||
|
||||
skip:
|
||||
if (playback_chan->priority != 0) {
|
||||
goto step2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern wtstr* NoteToVoice(voicetable* vtbl, s32 note) {
|
||||
wtstr* voice_p;
|
||||
|
||||
if (note < vtbl->normal_range_low) {
|
||||
voice_p = &vtbl->low_pitch_tuned_sample;
|
||||
} else if (note <= vtbl->normal_range_high) {
|
||||
voice_p = &vtbl->normal_pitch_tuned_sample;
|
||||
} else {
|
||||
voice_p = &vtbl->high_pitch_tuned_sample;
|
||||
}
|
||||
|
||||
return voice_p;
|
||||
}
|
||||
|
||||
extern voicetable* ProgToVp(s32 prog, s32 inst) {
|
||||
voicetable* vtbl;
|
||||
|
||||
if (prog == 0xFF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!Nas_CheckIDbank(prog)) {
|
||||
AG.audio_error_flags = 0x10000000 + prog;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (inst >= AG.voice_info[prog].num_instruments) {
|
||||
AG.audio_error_flags = 0x03000000 + (prog << 8) + inst;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vtbl = AG.voice_info[prog].instruments[inst];
|
||||
if (vtbl == NULL) {
|
||||
AG.audio_error_flags = 0x01000000 + (prog << 8) + inst;
|
||||
return vtbl;
|
||||
}
|
||||
|
||||
return vtbl;
|
||||
}
|
||||
|
||||
extern perctable* PercToPp(s32 prog, s32 drum) {
|
||||
perctable* vtbl;
|
||||
|
||||
if (prog == 0xFF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!Nas_CheckIDbank(prog)) {
|
||||
AG.audio_error_flags = 0x10000000 + prog;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (drum >= AG.voice_info[prog].num_drums) {
|
||||
AG.audio_error_flags = 0x04000000 + (prog << 8) + drum;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((u32)AG.voice_info[prog].percussion < OS_BASE_CACHED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vtbl = AG.voice_info[prog].percussion[drum];
|
||||
if (vtbl == NULL) {
|
||||
AG.audio_error_flags = 0x05000000 + (prog << 8) + drum;
|
||||
return vtbl;
|
||||
}
|
||||
|
||||
return vtbl;
|
||||
}
|
||||
|
||||
extern percvoicetable* VpercToVep(s32 prog, s32 sfx) {
|
||||
percvoicetable* vtbl;
|
||||
|
||||
if (prog == 0xFF) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!Nas_CheckIDbank(prog)) {
|
||||
AG.audio_error_flags = 0x10000000 + prog;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sfx >= AG.voice_info[prog].num_sfx) {
|
||||
AG.audio_error_flags = 0x04000000 + (prog << 8) + sfx;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((u32)AG.voice_info[prog].effects < OS_BASE_CACHED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vtbl = &AG.voice_info[prog].effects[sfx];
|
||||
if (vtbl == NULL) {
|
||||
// this should be impossible to trigger
|
||||
AG.audio_error_flags = 0x05000000 + (prog << 8) + sfx;
|
||||
}
|
||||
|
||||
if (vtbl->tuned_sample.wavetable == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vtbl;
|
||||
}
|
||||
|
||||
extern s32 OverwriteBank(s32 type, s32 bankId, s32 idx, s32 table) {
|
||||
if (bankId == 0xFF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!Nas_CheckIDbank(bankId)) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case VOICE_TYPE_PERCUSSION:
|
||||
if (idx >= AG.voice_info[bankId].num_drums) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
AG.voice_info[bankId].percussion[idx] = (perctable*)table;
|
||||
break;
|
||||
case VOICE_TYPE_SOUND_EFF:
|
||||
if (idx >= AG.voice_info[bankId].num_sfx) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
AG.voice_info[bankId].effects[idx] = *(percvoicetable*)table;
|
||||
break;
|
||||
default:
|
||||
if (idx >= AG.voice_info[bankId].num_instruments) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
AG.voice_info[bankId].instruments[idx] = (voicetable*)table;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __Nas_Release_Channel_Main(note* n, int target) {
|
||||
channel* chan;
|
||||
playbackparams* param;
|
||||
sub* subtrack;
|
||||
s32 i;
|
||||
|
||||
if (n == NA_NO_NOTE) {
|
||||
return;
|
||||
}
|
||||
|
||||
n->_00bit3 = FALSE;
|
||||
|
||||
if (n->channel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
chan = n->channel;
|
||||
param = &chan->playback_ch.params;
|
||||
|
||||
if (chan->playback_ch.wanted_parent_note == n) {
|
||||
chan->playback_ch.wanted_parent_note = NA_NO_NOTE;
|
||||
}
|
||||
|
||||
if (chan->playback_ch.current_parent_note != n) {
|
||||
if (chan->playback_ch.current_parent_note != NA_NO_NOTE || chan->playback_ch.wanted_parent_note != NA_NO_NOTE ||
|
||||
chan->playback_ch.previous_parent_note != n || target == ADSR_STATUS_DECAY) {
|
||||
return;
|
||||
}
|
||||
|
||||
chan->playback_ch.adsr_envp.fadeout_velocity = AG.audio_params.updates_per_frame_inverse;
|
||||
chan->playback_ch.adsr_envp.state.flags.release = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (chan->playback_ch.adsr_envp.state.flags.status != ADSR_STATUS_DECAY) {
|
||||
param->pitch = n->note_frequency_scale;
|
||||
param->velocity = n->note_velocity;
|
||||
param->pan = n->note_pan;
|
||||
|
||||
if (n->sub_track != NULL) {
|
||||
subtrack = n->sub_track;
|
||||
if (n->_0A.flags.bit2 == TRUE) {
|
||||
param->target_reverb_volume = subtrack->target_reverb_vol;
|
||||
} else {
|
||||
param->target_reverb_volume = n->target_reverb_volume;
|
||||
}
|
||||
|
||||
if (n->surround_effect_idx == 128) {
|
||||
param->surround_effect_idx = subtrack->surround_effect_idx;
|
||||
} else {
|
||||
param->surround_effect_idx = n->surround_effect_idx;
|
||||
}
|
||||
|
||||
if (n->_0A.flags.bit9 == TRUE) {
|
||||
param->gain = subtrack->gain;
|
||||
} else {
|
||||
param->gain = 0;
|
||||
}
|
||||
|
||||
param->filter = subtrack->filter;
|
||||
if (param->filter != NULL) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
param->filter_buf[i] = param->filter[i];
|
||||
}
|
||||
|
||||
param->filter = param->filter_buf;
|
||||
}
|
||||
|
||||
param->comb_filter_gain = subtrack->comb_filter_gain;
|
||||
param->comb_filter_size = subtrack->comb_filter_size;
|
||||
|
||||
if (subtrack->group->flags.muted && (subtrack->mute_flags & AUDIO_MUTE_FLAG_STOP_SAMPLES)) {
|
||||
chan->common_ch.finished = TRUE;
|
||||
}
|
||||
|
||||
if (*(u8*)&n->stereo_phase == 0) {
|
||||
param->stereo_phase = subtrack->stereo_phase;
|
||||
} else {
|
||||
param->stereo_phase = n->stereo_phase;
|
||||
}
|
||||
|
||||
chan->playback_ch.priority = subtrack->priority2;
|
||||
} else {
|
||||
param->stereo_phase = n->stereo_phase;
|
||||
chan->playback_ch.priority = 1;
|
||||
}
|
||||
|
||||
chan->playback_ch.previous_parent_note = chan->playback_ch.current_parent_note;
|
||||
chan->playback_ch.current_parent_note = NA_NO_NOTE;
|
||||
if (target == ADSR_STATUS_RELEASE) {
|
||||
chan->playback_ch.adsr_envp.fadeout_velocity = AG.audio_params.updates_per_frame_inverse;
|
||||
chan->playback_ch.adsr_envp.state.flags.release = TRUE;
|
||||
chan->playback_ch.status = 2;
|
||||
} else {
|
||||
chan->playback_ch.status = 1;
|
||||
chan->playback_ch.adsr_envp.state.flags.decay = TRUE;
|
||||
if (n->adsr_env.decay_idx == 0) {
|
||||
chan->playback_ch.adsr_envp.fadeout_velocity = AG.adsr_decay_table[n->sub_track->adsr_env.decay_idx];
|
||||
} else {
|
||||
chan->playback_ch.adsr_envp.fadeout_velocity = AG.adsr_decay_table[n->adsr_env.decay_idx];
|
||||
}
|
||||
|
||||
chan->playback_ch.adsr_envp.sustain = (f32)(s32)n->sub_track->adsr_env.sustain * chan->playback_ch.adsr_envp.current / 256.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == ADSR_STATUS_DECAY) {
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddListHead(&chan->link.pNode->releaseList, &chan->link);
|
||||
}
|
||||
}
|
||||
|
||||
extern void Nas_Release_Channel(note* n) {
|
||||
__Nas_Release_Channel_Main(n, ADSR_STATUS_DECAY);
|
||||
}
|
||||
|
||||
extern void Nas_Release_Channel_Force(note* n) {
|
||||
__Nas_Release_Channel_Main(n, ADSR_STATUS_RELEASE);
|
||||
}
|
||||
|
||||
static void __Nas_InitList(link* l) {
|
||||
l->prev = l;
|
||||
l->next = l;
|
||||
l->numAfter = 0;
|
||||
}
|
||||
|
||||
extern void Nas_InitChNode(chnode* node) {
|
||||
__Nas_InitList(&node->freeList);
|
||||
__Nas_InitList(&node->releaseList);
|
||||
__Nas_InitList(&node->relwaitList);
|
||||
__Nas_InitList(&node->useList);
|
||||
|
||||
node->freeList.pNode = node;
|
||||
node->releaseList.pNode = node;
|
||||
node->relwaitList.pNode = node;
|
||||
node->useList.pNode = node;
|
||||
}
|
||||
|
||||
extern void Nas_InitChannelList(void) {
|
||||
s32 i;
|
||||
|
||||
Nas_InitChNode(&AG.channel_node);
|
||||
for (i = 0; i < AG.num_channels; i++) {
|
||||
AG.channels[i].link.pData = &AG.channels[i];
|
||||
AG.channels[i].link.prev = NULL;
|
||||
Nas_AddList(&AG.channel_node.freeList, &AG.channels[i].link);
|
||||
}
|
||||
}
|
||||
|
||||
extern void Nas_DeAllocAllVoices(chnode* node) {
|
||||
s32 i;
|
||||
link* src;
|
||||
link* cur;
|
||||
link* dst;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
src = &node->freeList;
|
||||
dst = &AG.channel_node.freeList;
|
||||
break;
|
||||
case 1:
|
||||
src = &node->releaseList;
|
||||
dst = &AG.channel_node.releaseList;
|
||||
break;
|
||||
case 2:
|
||||
src = &node->relwaitList;
|
||||
dst = &AG.channel_node.relwaitList;
|
||||
break;
|
||||
case 3:
|
||||
src = &node->useList;
|
||||
dst = &AG.channel_node.useList;
|
||||
break;
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
cur = src->next;
|
||||
if ((s32)cur == (s32)src || cur == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
Nas_CutList(cur);
|
||||
Nas_AddList(dst, cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void Nas_AllocVoices(chnode* node, s32 count) {
|
||||
s32 i;
|
||||
s32 j;
|
||||
channel* chan;
|
||||
link* src;
|
||||
link* dst;
|
||||
|
||||
Nas_DeAllocAllVoices(node);
|
||||
|
||||
for (i = 0, j = 0; j < count; i++) {
|
||||
if (i == 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
src = &AG.channel_node.freeList;
|
||||
dst = &node->freeList;
|
||||
break;
|
||||
case 1:
|
||||
src = &AG.channel_node.releaseList;
|
||||
dst = &node->releaseList;
|
||||
break;
|
||||
case 2:
|
||||
src = &AG.channel_node.relwaitList;
|
||||
dst = &node->relwaitList;
|
||||
break;
|
||||
case 3:
|
||||
src = &AG.channel_node.useList;
|
||||
dst = &node->useList;
|
||||
break;
|
||||
}
|
||||
|
||||
while (j < count) {
|
||||
chan = (channel*)Nas_GetList(src);
|
||||
if (chan == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
Nas_AddList(dst, &chan->link);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Nas_AddListHead(link* list, link* l) {
|
||||
if (l->prev == NULL) {
|
||||
l->prev = list;
|
||||
l->next = list->next;
|
||||
list->next->prev = l;
|
||||
list->next = l;
|
||||
list->numAfter++;
|
||||
l->pNode = list->pNode;
|
||||
}
|
||||
}
|
||||
|
||||
extern void Nas_CutList(link* l) {
|
||||
if (l->prev != NULL) {
|
||||
l->prev->next = l->next;
|
||||
l->next->prev = l->prev;
|
||||
l->prev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static channel* __Nas_GetLowerPrio(link* l, s32 prio) {
|
||||
link* cur = l->next;
|
||||
link* best;
|
||||
|
||||
if (cur == l) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (best = cur; cur != l; cur = cur->next) {
|
||||
if (((channel*)cur->pData)->playback_ch.priority <= ((channel*)best->pData)->playback_ch.priority) {
|
||||
best = cur;
|
||||
}
|
||||
}
|
||||
|
||||
if (best == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (((channel*)best->pData)->playback_ch.priority >= prio) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (channel*)best->pData;
|
||||
}
|
||||
|
||||
extern void Nas_EntryTrack(channel* chan, note* n) {
|
||||
s32 instId;
|
||||
sub* subtrack = n->sub_track;
|
||||
playbackch* playback = &chan->playback_ch;
|
||||
commonch* common = &chan->common_ch;
|
||||
|
||||
playback->previous_parent_note = NA_NO_NOTE;
|
||||
playback->current_parent_note = n;
|
||||
playback->priority = subtrack->note_priority;
|
||||
n->note_properties_need_init = TRUE;
|
||||
n->_00bit3 = TRUE;
|
||||
n->channel = chan;
|
||||
subtrack->channel = chan;
|
||||
subtrack->note = n;
|
||||
n->note_velocity = 0.0f;
|
||||
Nas_StartVoice(chan);
|
||||
instId = n->inst_or_wave;
|
||||
|
||||
if (instId == 0xFF) {
|
||||
instId = subtrack->inst_or_wave;
|
||||
}
|
||||
|
||||
common->tuned_sample = n->tuned_sample;
|
||||
if (instId >= 0x80 && instId < 0xC0) {
|
||||
common->is_synth_wave = TRUE;
|
||||
} else {
|
||||
common->is_synth_wave = FALSE;
|
||||
}
|
||||
|
||||
if (subtrack->sample_start_pos == 1) {
|
||||
playback->start_sample_pos = common->tuned_sample->wavetable->loop->loop_start;
|
||||
} else {
|
||||
playback->start_sample_pos = subtrack->sample_start_pos;
|
||||
if (playback->start_sample_pos >= common->tuned_sample->wavetable->loop->loop_end) {
|
||||
playback->start_sample_pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
playback->_80 = (int)(n->velocity_square2 * 11.5f);
|
||||
if (playback->_80 > 15) {
|
||||
playback->_80 = 15;
|
||||
}
|
||||
|
||||
playback->bank_id = subtrack->bank_id;
|
||||
playback->stereo_headset_effects = subtrack->stereo_effects;
|
||||
common->reverb_idx = subtrack->reverb_idx & 3;
|
||||
}
|
||||
|
||||
static void __Nas_InterTrack(channel* chan, note* n) {
|
||||
playbackch* playback = &chan->playback_ch;
|
||||
|
||||
Nas_Release_Channel_Force(playback->current_parent_note);
|
||||
playback->wanted_parent_note = n;
|
||||
}
|
||||
|
||||
static void __Nas_InterReleaseTrack(channel* chan, note* n) {
|
||||
playbackch* playback = &chan->playback_ch;
|
||||
|
||||
playback->wanted_parent_note = n;
|
||||
playback->priority = n->sub_track->note_priority;
|
||||
playback->adsr_envp.fadeout_velocity = AG.audio_params.updates_per_frame_inverse;
|
||||
playback->adsr_envp.state.flags.release = TRUE;
|
||||
}
|
||||
|
||||
static channel* __Nas_ChLookFree(chnode* node, note* n) {
|
||||
channel* chan = (channel*)Nas_GetList(&node->freeList);
|
||||
|
||||
if (chan != NULL) {
|
||||
Nas_EntryTrack(chan, n);
|
||||
Nas_AddListHead(&node->useList, &chan->link);
|
||||
}
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static channel* __Nas_ChLookRelease(chnode* node, note* n) {
|
||||
channel* chan = __Nas_GetLowerPrio(&node->releaseList, n->sub_track->note_priority);
|
||||
|
||||
if (chan != NULL) {
|
||||
__Nas_InterReleaseTrack(chan, n);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&node->relwaitList, &chan->link);
|
||||
}
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
static channel* __Nas_ChLookRelWait(chnode* node, note* n) {
|
||||
channel* relWaitChan;
|
||||
channel* useChan;
|
||||
s32 relWaitPrio;
|
||||
s32 usePrio;
|
||||
|
||||
relWaitPrio = usePrio = 16;
|
||||
|
||||
relWaitChan = __Nas_GetLowerPrio(&node->relwaitList, n->sub_track->note_priority);
|
||||
if (relWaitChan != NULL) {
|
||||
relWaitPrio = relWaitChan->playback_ch.priority;
|
||||
}
|
||||
|
||||
useChan = __Nas_GetLowerPrio(&node->useList, n->sub_track->note_priority);
|
||||
if (useChan != NULL) {
|
||||
usePrio = useChan->playback_ch.priority;
|
||||
}
|
||||
|
||||
if (relWaitChan == NULL && useChan == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (usePrio < relWaitPrio) {
|
||||
Nas_CutList(&useChan->link);
|
||||
__Nas_InterTrack(useChan, n);
|
||||
Nas_AddList(&node->relwaitList, &useChan->link);
|
||||
useChan->playback_ch.priority = n->sub_track->note_priority;
|
||||
return useChan;
|
||||
} else {
|
||||
relWaitChan->playback_ch.wanted_parent_note = n;
|
||||
relWaitChan->playback_ch.priority = n->sub_track->note_priority;
|
||||
return relWaitChan;
|
||||
}
|
||||
}
|
||||
|
||||
extern channel* Nas_AllocationOnRequest(note* n) {
|
||||
channel* chan;
|
||||
u32 policy = n->sub_track->note_alloc_policy;
|
||||
|
||||
if (policy & 1) {
|
||||
chan = n->channel;
|
||||
if (chan != NULL && chan->playback_ch.previous_parent_note == n &&
|
||||
chan->playback_ch.wanted_parent_note == NA_NO_NOTE) {
|
||||
__Nas_InterReleaseTrack(chan, n);
|
||||
Nas_CutList(&chan->link);
|
||||
Nas_AddList(&chan->link.pNode->relwaitList, &chan->link);
|
||||
return chan;
|
||||
}
|
||||
}
|
||||
|
||||
if (policy & 2) {
|
||||
if (!(chan = __Nas_ChLookFree(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&n->sub_track->channel_node, n))) {
|
||||
goto null_return;
|
||||
}
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (policy & 4) {
|
||||
if (!(chan = __Nas_ChLookFree(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookFree(&n->sub_track->group->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&n->sub_track->group->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&n->sub_track->group->channel_node, n))) {
|
||||
goto null_return;
|
||||
}
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (policy & 8) {
|
||||
if (!(chan = __Nas_ChLookFree(&AG.channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&AG.channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&AG.channel_node, n))) {
|
||||
goto null_return;
|
||||
}
|
||||
return chan;
|
||||
}
|
||||
|
||||
if (!(chan = __Nas_ChLookFree(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookFree(&n->sub_track->group->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookFree(&AG.channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&n->sub_track->group->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelease(&AG.channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&n->sub_track->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&n->sub_track->group->channel_node, n)) &&
|
||||
!(chan = __Nas_ChLookRelWait(&AG.channel_node, n))) {
|
||||
goto null_return;
|
||||
}
|
||||
|
||||
return chan;
|
||||
|
||||
null_return:
|
||||
n->_00bit3 = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern void Nas_ChannelInit(void) {
|
||||
s32 i;
|
||||
channel* chan;
|
||||
|
||||
for (i = 0; i < AG.num_channels; i++) {
|
||||
chan = &AG.channels[i];
|
||||
chan->common_ch = NA_CHINIT_TABLE[0];
|
||||
chan->playback_ch.priority = 0;
|
||||
chan->playback_ch.status = 0;
|
||||
chan->playback_ch.current_parent_note = NA_NO_NOTE;
|
||||
chan->playback_ch.wanted_parent_note = NA_NO_NOTE;
|
||||
chan->playback_ch.previous_parent_note = NA_NO_NOTE;
|
||||
chan->playback_ch.wave_id = 0;
|
||||
chan->playback_ch.params.velocity = 0.0f;
|
||||
chan->playback_ch.adsr_volume_scale_unused = 0;
|
||||
chan->playback_ch.adsr_envp.state.as_byte = 0;
|
||||
chan->playback_ch.vibrato_tmtable.active = FALSE;
|
||||
chan->playback_ch.portamento_sweep.current = 0;
|
||||
chan->playback_ch.portamento_sweep.speed = 0;
|
||||
chan->playback_ch.stereo_headset_effects = FALSE;
|
||||
chan->playback_ch.start_sample_pos = 0;
|
||||
chan->driver_ch.synth_params = (synthparams*)Nas_NcHeapAlloc(&AG.misc_heap, sizeof(synthparams));
|
||||
chan->playback_ch.params.filter_buf = (s16*)Nas_NcHeapAlloc(&AG.misc_heap, 8 * sizeof(s16));
|
||||
}
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void* Nas_2ndHeapAlloc(ALHeap*, s32)
|
||||
* Address: ........
|
||||
* Size: 00003C
|
||||
*/
|
||||
void Nas_NcHeapAlloc(ALHeap*, s32)
|
||||
void* Nas_NcHeapAlloc(ALHeap*, s32)
|
||||
{
|
||||
// UNUSED FUNCTION
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ static void __SetSubParam(sub* subtrack, AudioPort* port) {
|
||||
subtrack->comb_filter_gain = port->param.asU16;
|
||||
break;
|
||||
case AUDIOCMD_OP_SUB_SET_STEREO:
|
||||
subtrack->stereo_phase.asU8 = port->param.asU8;
|
||||
*(u8*)&subtrack->stereo_phase = port->param.asU8;
|
||||
break;
|
||||
case AUDIOCMD_OP_SUB_SET_SET_START_POS:
|
||||
subtrack->sample_start_pos = port->param.asS32;
|
||||
|
||||
@@ -406,7 +406,7 @@ s32 Nas_LoadVoice(s32 bank_id, s32 instId, s32 drumId) {
|
||||
__Nas_LoadVoice_Inner(voice->high_pitch_tuned_sample.wavetable, bank_id);
|
||||
}
|
||||
} else if (instId == 0x7F) {
|
||||
percvoicetable* perc = PercToPp(bank_id, drumId);
|
||||
perctable* perc = PercToPp(bank_id, drumId);
|
||||
|
||||
if (perc == NULL) {
|
||||
return -1;
|
||||
@@ -809,8 +809,8 @@ static void Nas_BankOfsToAddr_Inner(s32 bank_id, u8* ctrl_p, WaveMedia* wave_med
|
||||
u32 ofs;
|
||||
u32 inst_ofs;
|
||||
voicetable* inst;
|
||||
percvoicetable* percvt;
|
||||
veffvoicetable* sfx;
|
||||
perctable* percvt;
|
||||
percvoicetable* sfx;
|
||||
s32 i;
|
||||
s32 n_perc_inst, n_voice_inst, n_sfx_inst;
|
||||
n_voice_inst = AG.voice_info[bank_id].num_instruments;
|
||||
@@ -823,14 +823,14 @@ static void Nas_BankOfsToAddr_Inner(s32 bank_id, u8* ctrl_p, WaveMedia* wave_med
|
||||
*BANK_ENTRY(ctrl_p, 0) = OFS2RAM(ctrl_p, ofs);
|
||||
|
||||
for (i = 0; i < n_perc_inst; i++) {
|
||||
inst_ofs = (u32)((percvoicetable**)*BANK_ENTRY(ctrl_p, 0))[i];
|
||||
inst_ofs = (u32)((perctable**)*BANK_ENTRY(ctrl_p, 0))[i];
|
||||
if (inst_ofs == 0) {
|
||||
continue; // empty percussion/drum entry
|
||||
}
|
||||
|
||||
inst_ofs += (u32)ctrl_p;//OFS2RAM(ctrl_p, ofs);
|
||||
percvt = (percvoicetable*)inst_ofs;
|
||||
((percvoicetable**)*BANK_ENTRY(ctrl_p, 0))[i] = percvt;
|
||||
percvt = (perctable*)inst_ofs;
|
||||
((perctable**)*BANK_ENTRY(ctrl_p, 0))[i] = percvt;
|
||||
|
||||
// Percussion may already have been relocated since percussion
|
||||
// can appear in list multiple times
|
||||
@@ -851,8 +851,8 @@ static void Nas_BankOfsToAddr_Inner(s32 bank_id, u8* ctrl_p, WaveMedia* wave_med
|
||||
*BANK_ENTRY(ctrl_p, 1) = OFS2RAM(ctrl_p, ofs);
|
||||
|
||||
for (i = 0; i < n_sfx_inst; i++) {
|
||||
inst_ofs = (u32)(((veffvoicetable*)*BANK_ENTRY(ctrl_p, 1)) + i);
|
||||
sfx = (veffvoicetable*)inst_ofs;
|
||||
inst_ofs = (u32)(((percvoicetable*)*BANK_ENTRY(ctrl_p, 1)) + i);
|
||||
sfx = (percvoicetable*)inst_ofs;
|
||||
|
||||
// check for null sfx or null sample wave table pointer
|
||||
if (sfx == NULL || sfx->tuned_sample.wavetable == NULL) {
|
||||
@@ -897,8 +897,8 @@ static void Nas_BankOfsToAddr_Inner(s32 bank_id, u8* ctrl_p, WaveMedia* wave_med
|
||||
}
|
||||
}
|
||||
|
||||
AG.voice_info[bank_id].percussion = (percvoicetable**)*BANK_ENTRY(ctrl_p, 0);
|
||||
AG.voice_info[bank_id].effects = (veffvoicetable*)*BANK_ENTRY(ctrl_p, 1);
|
||||
AG.voice_info[bank_id].percussion = (perctable**)*BANK_ENTRY(ctrl_p, 0);
|
||||
AG.voice_info[bank_id].effects = (percvoicetable*)*BANK_ENTRY(ctrl_p, 1);
|
||||
AG.voice_info[bank_id].instruments = (voicetable**)BANK_ENTRY(ctrl_p, 2);
|
||||
}
|
||||
|
||||
@@ -1330,7 +1330,7 @@ static smzwavetable* __GetWaveTable(s32 bank_id, s32 inst_id) {
|
||||
|
||||
return vt->normal_pitch_tuned_sample.wavetable;
|
||||
} else if (inst_id <= 255) {
|
||||
percvoicetable* pvt = PercToPp(bank_id, inst_id - 128);
|
||||
perctable* pvt = PercToPp(bank_id, inst_id - 128);
|
||||
|
||||
if (pvt == NULL) {
|
||||
return NULL;
|
||||
@@ -1338,7 +1338,7 @@ static smzwavetable* __GetWaveTable(s32 bank_id, s32 inst_id) {
|
||||
|
||||
return pvt->tuned_sample.wavetable;
|
||||
} else {
|
||||
veffvoicetable* evt = VpercToVep(bank_id, inst_id - 256);
|
||||
percvoicetable* evt = VpercToVep(bank_id, inst_id - 256);
|
||||
|
||||
if (evt == NULL) {
|
||||
return NULL;
|
||||
@@ -1885,9 +1885,9 @@ void WaveReload(s32 bank_id, s32 async, WaveMedia* wavemedia) {
|
||||
s32 n_drums;
|
||||
s32 n_instruments;
|
||||
s32 n_sfx;
|
||||
percvoicetable* percussion;
|
||||
perctable* percussion;
|
||||
voicetable* instrument;
|
||||
veffvoicetable* sfx;
|
||||
percvoicetable* sfx;
|
||||
Bgloadreq* preload;
|
||||
Bgloadreq* top_preload;
|
||||
smzwavetable* wavetable;
|
||||
|
||||
@@ -250,7 +250,7 @@ static void Nas_InitSubTrack(sub* subtrack) {
|
||||
subtrack->stereo_effects = FALSE;
|
||||
subtrack->large_notes = FALSE;
|
||||
subtrack->book_ofs = 0;
|
||||
subtrack->stereo_phase.asU8 = 0;
|
||||
*(u8*)&subtrack->stereo_phase = 0;
|
||||
subtrack->changes.as_byte = 0xFF;
|
||||
subtrack->macro_player.depth = 0;
|
||||
subtrack->volume = 1.0f;
|
||||
@@ -324,7 +324,7 @@ static s32 Nas_EntryNoteTrack(sub* subtrack, int note_idx) {
|
||||
entry_note->ignore_drum_pan = FALSE;
|
||||
entry_note->_00bit1 = FALSE;
|
||||
entry_note->note_properties_need_init = FALSE;
|
||||
entry_note->stereo_phase.asU8 = 0;
|
||||
*(u8*)&entry_note->stereo_phase = 0;
|
||||
entry_note->portamento_sweep.mode = 0;
|
||||
entry_note->macro_player.depth = 0;
|
||||
entry_note->gate_time = 128;
|
||||
@@ -464,7 +464,7 @@ extern void Nas_ReleaseGroup(group* grp) {
|
||||
}
|
||||
|
||||
extern void Nas_AddList(link* root, link* list) {
|
||||
if (list->next != nullptr) {
|
||||
if (list->prev != nullptr) {
|
||||
static BOOL first = TRUE;
|
||||
|
||||
if (first) {
|
||||
@@ -478,25 +478,25 @@ extern void Nas_AddList(link* root, link* list) {
|
||||
OSReport("List %x\n", list);
|
||||
OSReport("Root %x\n", root);
|
||||
} else {
|
||||
root->next->prev = list;
|
||||
list->next = root->next;
|
||||
list->prev = root;
|
||||
root->next = list;
|
||||
root->prev->next = list;
|
||||
list->prev = root->prev;
|
||||
list->next = root;
|
||||
root->prev = list;
|
||||
root->numAfter++;
|
||||
list->pNode = root->pNode;
|
||||
}
|
||||
}
|
||||
|
||||
extern void* Nas_GetList(link* root) {
|
||||
link* list = root->next;
|
||||
link* list = root->prev;
|
||||
|
||||
if (list == root) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
list->next->prev = root;
|
||||
root->next = list->next;
|
||||
list->next = nullptr;
|
||||
list->prev->next = root;
|
||||
root->prev = list->prev;
|
||||
list->prev = nullptr;
|
||||
root->numAfter--;
|
||||
return list->pData;
|
||||
}
|
||||
@@ -504,14 +504,14 @@ extern void* Nas_GetList(link* root) {
|
||||
static void Nas_InitNoteList(void) {
|
||||
s32 i;
|
||||
|
||||
AG.note_link.next = &AG.note_link;
|
||||
AG.note_link.prev = &AG.note_link;
|
||||
AG.note_link.next = &AG.note_link;
|
||||
AG.note_link.numAfter = 0;
|
||||
AG.note_link.pNode = nullptr;
|
||||
|
||||
for (i = 0; i < AUDIO_NOTE_MAX; i++) {
|
||||
AG.notes[i].link.pData = &AG.notes[i];
|
||||
AG.notes[i].link.next = nullptr;
|
||||
AG.notes[i].link.prev = nullptr;
|
||||
Nas_AddList(&AG.note_link, &AG.notes[i].link);
|
||||
}
|
||||
}
|
||||
@@ -749,7 +749,7 @@ static s32 __Command_Seq(note* n) {
|
||||
n->ignore_drum_pan = TRUE;
|
||||
break;
|
||||
case 0xCD:
|
||||
n->stereo_phase.asU8 = Nas_ReadByteData(m);
|
||||
*(u8*)&n->stereo_phase = Nas_ReadByteData(m);
|
||||
break;
|
||||
case 0xCE:
|
||||
cmdArgU8 = 128 + Nas_ReadByteData(m);
|
||||
@@ -785,8 +785,8 @@ static s32 __SetVoice(note* n, s32 arg) {
|
||||
f32 freq_scale2;
|
||||
wtstr* tuned_sample;
|
||||
voicetable* instrument;
|
||||
percvoicetable* percussion;
|
||||
veffvoicetable* effect;
|
||||
perctable* percussion;
|
||||
percvoicetable* effect;
|
||||
sub* subtrack;
|
||||
group* grp;
|
||||
u16 effect_id;
|
||||
@@ -1450,7 +1450,7 @@ static void Nas_SubSeq(sub* subtrack) {
|
||||
subtrack->stereo_effects = FALSE;
|
||||
}
|
||||
|
||||
subtrack->stereo_phase.asU8 = cmdArgU8 & 0x7F;
|
||||
*(u8*)&subtrack->stereo_phase = cmdArgU8 & 0x7F;
|
||||
break;
|
||||
case 0xD1: // set note allocation policy
|
||||
cmdArgU8 = (u8)cmdArgs[0];
|
||||
|
||||
Reference in New Issue
Block a user