diff --git a/configure.py b/configure.py index 241ffc0f..f6d6b2da 100644 --- a/configure.py +++ b/configure.py @@ -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"), diff --git a/include/jaudio_NES/audiocommon.h b/include/jaudio_NES/audiocommon.h index ae5e086c..a4b37bd3 100644 --- a/include/jaudio_NES/audiocommon.h +++ b/include/jaudio_NES/audiocommon.h @@ -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 diff --git a/include/jaudio_NES/audiostruct.h b/include/jaudio_NES/audiostruct.h index e14e7e71..8dc8f80d 100644 --- a/include/jaudio_NES/audiostruct.h +++ b/include/jaudio_NES/audiostruct.h @@ -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; diff --git a/include/jaudio_NES/audiotable.h b/include/jaudio_NES/audiotable.h index 9bfb34a8..d4675958 100644 --- a/include/jaudio_NES/audiotable.h +++ b/include/jaudio_NES/audiotable.h @@ -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 diff --git a/include/jaudio_NES/channel.h b/include/jaudio_NES/channel.h index 74610bfb..bfab8930 100644 --- a/include/jaudio_NES/channel.h +++ b/include/jaudio_NES/channel.h @@ -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 diff --git a/include/jaudio_NES/memory.h b/include/jaudio_NES/memory.h index e9b461b1..cdac9215 100644 --- a/include/jaudio_NES/memory.h +++ b/include/jaudio_NES/memory.h @@ -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); diff --git a/src/static/jaudio_NES/internal/channel.c b/src/static/jaudio_NES/internal/channel.c new file mode 100644 index 00000000..52995849 --- /dev/null +++ b/src/static/jaudio_NES/internal/channel.c @@ -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 + +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)); + } +} diff --git a/src/static/jaudio_NES/internal/memory.c b/src/static/jaudio_NES/internal/memory.c index 642427e0..0adebabb 100644 --- a/src/static/jaudio_NES/internal/memory.c +++ b/src/static/jaudio_NES/internal/memory.c @@ -95,7 +95,7 @@ void* Nas_2ndHeapAlloc(ALHeap*, s32) * Address: ........ * Size: 00003C */ -void Nas_NcHeapAlloc(ALHeap*, s32) +void* Nas_NcHeapAlloc(ALHeap*, s32) { // UNUSED FUNCTION } diff --git a/src/static/jaudio_NES/internal/sub_sys.c b/src/static/jaudio_NES/internal/sub_sys.c index 1536f88f..4d4c5c98 100644 --- a/src/static/jaudio_NES/internal/sub_sys.c +++ b/src/static/jaudio_NES/internal/sub_sys.c @@ -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; diff --git a/src/static/jaudio_NES/internal/system.c b/src/static/jaudio_NES/internal/system.c index c7d5eabf..1536a1f5 100644 --- a/src/static/jaudio_NES/internal/system.c +++ b/src/static/jaudio_NES/internal/system.c @@ -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; diff --git a/src/static/jaudio_NES/internal/track.c b/src/static/jaudio_NES/internal/track.c index 3b42970c..8761f88f 100644 --- a/src/static/jaudio_NES/internal/track.c +++ b/src/static/jaudio_NES/internal/track.c @@ -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];