mirror of https://github.com/pmret/papermario.git
2144 lines
84 KiB
C
2144 lines
84 KiB
C
#include "audio.h"
|
|
#include "audio/core.h"
|
|
|
|
BSS void (*CurrentSeqCmdHandler)(BGMPlayer*, BGMPlayerTrack*);
|
|
|
|
extern u8 EnvelopeReleaseDefaultFast[];
|
|
extern u8 BgmTicksRates[8];
|
|
extern u8 BgmCustomEnvLookup[40];
|
|
|
|
extern void (*SefCmdHandlers[])(SoundManager*, SoundPlayer*);
|
|
extern void (*SeqCmdHandlers[])(BGMPlayer*, BGMPlayerTrack*);
|
|
extern u8 SeqCmdArgCounts[];
|
|
|
|
static void au_bgm_stop_player(BGMPlayer* player);
|
|
|
|
static s32 au_bgm_bpm_to_tempo(BGMPlayer* player, u32 tempo);
|
|
|
|
static u8 au_bgm_get_random_pan(BGMPlayer* player, u8 arg1, u8 arg2);
|
|
static s16 au_bgm_get_random_pitch(s32 arg0, s32 arg1, u8 arg2);
|
|
static u8 au_bgm_get_random_vol(s32 arg0, u8 volume, u8 arg2);
|
|
static u8 au_bgm_get_random_reverb(s32 arg0, u8 arg1, u8 arg2);
|
|
|
|
void au_bgm_begin_video_frame(BGMPlayer* player) {
|
|
BGMHeader* bgmFile;
|
|
BGMFileInfo* bgmData;
|
|
s32 unkType;
|
|
u32 compID;
|
|
s32 compOffset;
|
|
u32 value;
|
|
s32 consumed;
|
|
u8 var_a1;
|
|
u8 pos;
|
|
u32 i;
|
|
|
|
compID = 0;
|
|
unkType = -1;
|
|
player->frameCounter++;
|
|
|
|
if (player->cmdBufPending != 0) {
|
|
if (player->cmdBufPending < ARRAY_COUNT(player->cmdBufData)) {
|
|
pos = player->cmdBufReadPos;
|
|
for (var_a1 = 0; var_a1 < player->cmdBufPending; var_a1++) {
|
|
value = player->cmdBufData[pos];
|
|
if (value != 0) {
|
|
if (value < 16) {
|
|
unkType = value & 3;
|
|
compID = value >> 2;
|
|
}
|
|
pos++;
|
|
if (pos >= ARRAY_COUNT(player->cmdBufData)) {
|
|
pos = 0;
|
|
}
|
|
}
|
|
}
|
|
consumed = player->cmdBufWritePos - player->cmdBufReadPos;
|
|
if (consumed < 0) {
|
|
consumed += ARRAY_COUNT(player->cmdBufData);
|
|
}
|
|
player->cmdBufPending -= consumed;
|
|
player->cmdBufReadPos = player->cmdBufWritePos;
|
|
} else {
|
|
player->cmdBufPending = 0;
|
|
}
|
|
|
|
if (unkType != -1) {
|
|
if (unkType != 0) {
|
|
if (unkType != player->unk_58) {
|
|
player->unk_58 = unkType & 0xFF;
|
|
player->unk_5A = unkType & 0xFF;
|
|
player->masterState = BGM_PLAY_STATE_INIT;
|
|
player->nextUpdateStep = BGM_DEFAULT_UPDATE_STEP;
|
|
if (unkType == 2) {
|
|
bgmFile = player->globals->dataBGM[1];
|
|
} else {
|
|
bgmFile = player->globals->dataBGM[0];
|
|
}
|
|
player->bgmFile = bgmFile;
|
|
bgmData = &bgmFile->info;
|
|
au_bgm_set_tick_resolution(player, BGM_DEFAULT_UPDATE_STEP, BgmTicksRates[*(player->tickRatePtr) & 7]);
|
|
|
|
compOffset = bgmData->compositions[compID];
|
|
if (compOffset == 0) {
|
|
compOffset = bgmData->compositions[0];
|
|
}
|
|
player->compStartPos = AU_FILE_RELATIVE(bgmFile, compOffset << 2);
|
|
player->compReadPos = AU_FILE_RELATIVE(bgmFile, compOffset << 2);
|
|
|
|
if (bgmData->drums != 0) {
|
|
player->drumsInfo = AU_FILE_RELATIVE(player->bgmFile, bgmData->drums << 2);
|
|
player->bgmDrumCount = bgmData->drumCount;
|
|
for (i = 0; i < player->bgmDrumCount; i++) {
|
|
BGMDrumInfo* drum = &player->drumsInfo[i];
|
|
player->drums[i] = drum;
|
|
}
|
|
for (; i < ARRAY_COUNT(player->drums); i++) {
|
|
player->drums[i] = player->drums[0];
|
|
}
|
|
} else {
|
|
player->drumsInfo = NULL;
|
|
player->bgmDrumCount = 0;
|
|
}
|
|
|
|
if (bgmData->instruments != 0) {
|
|
player->instrumentsInfo = AU_FILE_RELATIVE(player->bgmFile, bgmData->instruments << 2);
|
|
player->bgmInstrumentCount = bgmData->instrumentCount;
|
|
return;
|
|
}
|
|
player->instrumentsInfo = NULL;
|
|
player->bgmInstrumentCount = 0;
|
|
}
|
|
} else {
|
|
if (player->unk_58 != 0) {
|
|
player->masterState = BGM_PLAY_STATE_STOP;
|
|
player->nextUpdateCounter = 1;
|
|
player->nextUpdateStep = 1;
|
|
} else {
|
|
au_bgm_stop_player(player);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BGMPlayer* au_bgm_get_player_with_song_name(s32 songString) {
|
|
if (songString != gBGMPlayerA->globals->dataBGM[0]->name) {
|
|
if (songString == gBGMPlayerA->globals->dataBGM[1]->name) {
|
|
return gBGMPlayerB;
|
|
}
|
|
} else {
|
|
return gBGMPlayerA;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
AuResult au_bgm_process_init_song(SongStartRequest* request) {
|
|
BGMPlayer* player;
|
|
BGMFileInfo* fileInfo;
|
|
s32 songName;
|
|
s32 variation;
|
|
s32 duration;
|
|
s32 volume0;
|
|
s32 volume1;
|
|
AuResult status;
|
|
u32 i;
|
|
|
|
status = AU_RESULT_OK;
|
|
songName = request->songName;
|
|
variation = request->variation;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
fileInfo = &player->bgmFile->info;
|
|
duration = request->duration;
|
|
if (duration != 0) {
|
|
if (duration > SND_MAX_DURATION) {
|
|
duration = SND_MAX_DURATION;
|
|
} else if (duration < SND_MIN_DURATION) {
|
|
duration = SND_MIN_DURATION;
|
|
}
|
|
}
|
|
volume0 = request->startVolume;
|
|
if (volume0 > AU_MAX_VOLUME_8) {
|
|
volume0 = AU_MAX_VOLUME_8;
|
|
}
|
|
if (volume0 != 0) {
|
|
volume0 = AU_VOL_8_TO_16(volume0);
|
|
}
|
|
volume1 = request->finalVolume;
|
|
if (volume1 > AU_MAX_VOLUME_8) {
|
|
volume1 = AU_MAX_VOLUME_8;
|
|
}
|
|
if (volume1 != 0) {
|
|
volume1 = AU_VOL_8_TO_16(volume1);
|
|
} else {
|
|
volume1 = AU_MAX_VOLUME_16;
|
|
}
|
|
|
|
au_fade_init(&player->fadeInfo, duration, volume0, volume1);
|
|
player->fadeInfo.envelopeTarget = AU_MAX_VOLUME_16;
|
|
player->fadeInfo.envelopeTicks = 1;
|
|
au_bgm_set_tick_resolution(player, BGM_DEFAULT_UPDATE_STEP, BgmTicksRates[fileInfo->timingPreset & 7]);
|
|
|
|
if (variation < BGM_VARIATION_0 || variation > BGM_VARIATION_3 || fileInfo->compositions[variation] == 0) {
|
|
variation = BGM_VARIATION_0;
|
|
}
|
|
player->curVariation = variation;
|
|
|
|
player->compStartPos = AU_FILE_RELATIVE(player->bgmFile, fileInfo->compositions[variation] << 2);
|
|
player->compReadPos = player->compStartPos;
|
|
|
|
if (fileInfo->drums != 0) {
|
|
player->drumsInfo = AU_FILE_RELATIVE(player->bgmFile, fileInfo->drums << 2);
|
|
player->bgmDrumCount = fileInfo->drumCount;
|
|
|
|
for (i = 0; i < player->bgmDrumCount; i++) {
|
|
BGMDrumInfo* drum = &player->drumsInfo[i];
|
|
player->drums[i] = drum;
|
|
}
|
|
for (; i < ARRAY_COUNT(player->drums); i++) {
|
|
player->drums[i] = player->drums[0];
|
|
}
|
|
} else {
|
|
player->drumsInfo = NULL;
|
|
player->bgmDrumCount = 0;
|
|
}
|
|
|
|
if (fileInfo->instruments != 0) {
|
|
player->instrumentsInfo = AU_FILE_RELATIVE(player->bgmFile, fileInfo->instruments << 2);
|
|
player->bgmInstrumentCount = fileInfo->instrumentCount;
|
|
} else {
|
|
player->instrumentsInfo = NULL;
|
|
player->bgmInstrumentCount = 0;
|
|
}
|
|
|
|
player->songName = songName;
|
|
au_bgm_player_initialize(player);
|
|
} else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
AuResult au_bgm_stop_song(s32 songName) {
|
|
BGMPlayer* player;
|
|
AuResult status = AU_RESULT_OK;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
if (songName == player->songName) {
|
|
au_bgm_stop_player(player);
|
|
}
|
|
} else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void au_bgm_stop_all(void) {
|
|
au_bgm_stop_player(gBGMPlayerA);
|
|
au_bgm_stop_player(gBGMPlayerB);
|
|
}
|
|
|
|
static void au_bgm_stop_player(BGMPlayer* player) {
|
|
if (player->masterState != BGM_PLAY_STATE_IDLE) {
|
|
player->masterState = BGM_PLAY_STATE_STOP;
|
|
player->nextUpdateCounter = 1;
|
|
player->nextUpdateStep = 1;
|
|
au_fade_clear(&player->fadeInfo);
|
|
}
|
|
}
|
|
|
|
AuResult au_bgm_is_song_playing(s32 songName) {
|
|
BGMPlayer* player;
|
|
AuResult result = AU_RESULT_OK;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
result = (songName == player->songName);
|
|
} else {
|
|
result = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
result = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
b32 au_bgm_player_is_active(BGMPlayer* player) {
|
|
if (player->songName != NULL && player->masterState != 0) {
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
AuResult au_bgm_process_fade_out(SongFadeOutRequest* request) {
|
|
AuResult status;
|
|
BGMPlayer* player;
|
|
u32 songName = request->songName;
|
|
u32 duration = request->duration;
|
|
s16 volume = request->finalVolume;
|
|
|
|
status = AU_RESULT_OK;
|
|
if (songName != 0) {
|
|
if (duration >= SND_MIN_DURATION && duration <= SND_MAX_DURATION) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
if (player->songName == songName) {
|
|
if (player->masterState != BGM_PLAY_STATE_IDLE) {
|
|
if (!player->paused) {
|
|
player->fadeInfo.baseTarget = volume;
|
|
player->fadeInfo.baseTicks = (duration * 1000) / AU_FRAME_USEC;
|
|
player->fadeInfo.baseStep = ((volume << 0x10) - player->fadeInfo.baseVolume) / player->fadeInfo.baseTicks;
|
|
player->fadeInfo.onCompleteCallback = request->doneCallback;
|
|
if (request->onPush == 1) {
|
|
player->pushSongName = songName;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_INVALID_SONG_DURATION;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
AuResult au_bgm_complete_push(s32 songName) {
|
|
SongSuspendRequest s;
|
|
|
|
s.songName = songName;
|
|
s.duration = 0;
|
|
s.startVolume = 0;
|
|
s.finalVolume = 0;
|
|
s.index = BGM_SNAPSHOT_0;
|
|
s.pauseMode = FALSE;
|
|
|
|
return au_bgm_process_suspend(&s, 0); // force stop
|
|
}
|
|
|
|
AuResult au_bgm_process_suspend(SongSuspendRequest* request, b32 skipStop) {
|
|
AuResult status;
|
|
BGMPlayer* player;
|
|
BGMPlayer* snapshot;
|
|
s32 songName;
|
|
s32 index;
|
|
u32 i;
|
|
u32 j;
|
|
|
|
songName = request->songName;
|
|
index = request->index;
|
|
status = AU_RESULT_OK;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
if (!request->pauseMode) {
|
|
snapshot = au_get_snapshot_by_index(index);
|
|
if (snapshot != NULL) {
|
|
if (songName == player->songName) {
|
|
if (!skipStop) {
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
BGMPlayerTrack* track = &player->tracks[i];
|
|
if (track->bgmReadPos != NULL) {
|
|
for (j = track->firstVoice; j < track->lastVoice; j++) {
|
|
track->changed.all = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
player->globals->snapshots[index].priority = player->priority;
|
|
player->globals->snapshots[index].assigned = 1;
|
|
player->pushSongName = 0;
|
|
au_copy_words(player, snapshot, sizeof(*player));
|
|
if (!skipStop) {
|
|
au_bgm_stop_player(player);
|
|
}
|
|
}
|
|
} else {
|
|
status = AU_ERROR_INVALID_SONG_DURATION;
|
|
}
|
|
} else {
|
|
if (songName == player->songName) {
|
|
if (player->masterState != BGM_PLAY_STATE_IDLE) {
|
|
player->paused = TRUE;
|
|
au_bgm_reset_all_voices(player);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
AuResult au_bgm_process_resume(SongResumeRequest* request) {
|
|
AuResult status;
|
|
BGMPlayer* player;
|
|
BGMPlayer* snapshot;
|
|
s32 index;
|
|
s32 songName;
|
|
s32 volume0;
|
|
s32 volume1;
|
|
s32 duration;
|
|
|
|
songName = request->songName;
|
|
index = request->index;
|
|
status = AU_RESULT_OK;
|
|
|
|
if (songName != 0) {
|
|
if (!request->pauseMode) {
|
|
snapshot = au_get_snapshot_by_index(index);
|
|
if (snapshot != NULL && snapshot->globals->snapshots[index].assigned == 1) {
|
|
player = au_get_client_by_priority(snapshot->globals->snapshots[index].priority);
|
|
if (player != NULL) {
|
|
if (!au_bgm_player_is_active(player)) {
|
|
status = au_reload_song_files(snapshot->songID, snapshot->bgmFile);
|
|
duration = request->duration;
|
|
if (duration != 0) {
|
|
if (duration > SND_MAX_DURATION) {
|
|
duration = SND_MAX_DURATION;
|
|
} else if (duration < SND_MIN_DURATION) {
|
|
duration = SND_MIN_DURATION;
|
|
}
|
|
}
|
|
volume0 = request->startVolume;
|
|
if (volume0 > AU_MAX_VOLUME_8) {
|
|
volume0 = AU_MAX_VOLUME_8;
|
|
}
|
|
if (volume0 != 0) {
|
|
volume0 = AU_VOL_8_TO_16(volume0);
|
|
}
|
|
volume1 = request->finalVolume;
|
|
if (volume1 > AU_MAX_VOLUME_8) {
|
|
volume1 = AU_MAX_VOLUME_8;
|
|
}
|
|
if (volume1 != 0) {
|
|
volume1 = AU_VOL_8_TO_16(volume1);
|
|
} else {
|
|
volume1 = AU_MAX_VOLUME_16;
|
|
}
|
|
player->globals->resumeCopyTo = player;
|
|
player->globals->resumeCopyFrom = snapshot;
|
|
player->globals->resumeSongName = songName;
|
|
player->globals->resumeFadeTime = duration;
|
|
player->globals->resumeFadeStart = volume0;
|
|
player->globals->resumeFadeEnd = volume1;
|
|
player->globals->resumeRequested = TRUE;
|
|
} else {
|
|
status = AU_ERROR_7;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_6;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_INVALID_SONG_DURATION;
|
|
}
|
|
} else {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
if (songName == player->songName) {
|
|
if (player->paused) {
|
|
player->paused = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void au_bgm_restore_copied_player(AuGlobals* globals) {
|
|
BGMPlayer* player;
|
|
BGMPlayerTrack* track;
|
|
SeqNote* note;
|
|
u32 i;
|
|
u32 j;
|
|
s32 k;
|
|
|
|
player = globals->resumeCopyTo;
|
|
au_copy_words(globals->resumeCopyFrom, globals->resumeCopyTo, sizeof(*player));
|
|
if (globals->resumeSongName == player->songName) {
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
track = &player->tracks[i];
|
|
if (track->bgmReadPos != NULL) {
|
|
for (j = track->firstVoice; j < track->lastVoice; j++) {
|
|
note = &player->notes[j];
|
|
note->length = 0;
|
|
}
|
|
}
|
|
}
|
|
for (k = 0; k < ARRAY_COUNT(player->effectIndices); k++) {
|
|
if (player->effectIndices[k] != 0xFF) {
|
|
player->seqCmdArgs.MasterEffect.index = player->effectIndices[k];
|
|
player->seqCmdArgs.MasterEffect.value = player->effectValues[k];
|
|
au_BGMCmd_E6_MasterEffect(player, track);
|
|
}
|
|
}
|
|
au_fade_init(&player->fadeInfo, globals->resumeFadeTime, globals->resumeFadeStart, globals->resumeFadeEnd);
|
|
}
|
|
globals->resumeRequested = FALSE;
|
|
}
|
|
|
|
AuResult au_bgm_adjust_volume(SongStartRequest* request) {
|
|
BGMPlayer* player;
|
|
AuResult status = AU_RESULT_OK;
|
|
|
|
if (request->songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(request->songName);
|
|
if (player != NULL) {
|
|
au_fade_calc_envelope(&player->fadeInfo, request->duration, request->finalVolume);
|
|
}
|
|
else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void au_bgm_player_init(BGMPlayer* player, s32 priority, s32 busID, AuGlobals* globals) {
|
|
s16 i;
|
|
|
|
player->globals = globals;
|
|
au_bgm_set_tick_resolution(player, BGM_DEFAULT_UPDATE_STEP, BGM_DEFAULT_TICKS_PER_BEAT);
|
|
player->busVolume = AU_MAX_BUS_VOLUME;
|
|
player->masterTempo = BGM_DEFAULT_TEMPO;
|
|
player->masterVolume = AU_MAX_VOLUME_8 << 24;
|
|
player->frameCounter = 0;
|
|
player->songPlayingCounter = 0;
|
|
player->songName = 0;
|
|
player->pushSongName = 0;
|
|
player->unk_58 = 0;
|
|
player->unk_5A = 0;
|
|
player->compReadPos = NULL;
|
|
player->compStartPos = NULL;
|
|
player->phraseStartPos = 0;
|
|
player->masterTempoTicks = 0;
|
|
player->masterTempoTarget = 0;
|
|
player->masterTempoStep = 0;
|
|
player->masterVolumeTicks = 0;
|
|
player->masterVolumeTarget = 0;
|
|
player->masterVolumeStep = 0;
|
|
player->masterPitchShift = 0;
|
|
player->detune = 0;
|
|
player->paused = FALSE;
|
|
player->trackVolsConfig = NULL;
|
|
player->bFadeConfigSetsVolume = FALSE;
|
|
player->masterState = BGM_PLAY_STATE_IDLE;
|
|
player->priority = priority;
|
|
player->busID = busID;
|
|
*(s32*)player->compLoopCounters = 0;
|
|
player->unused_222 = 0;
|
|
player->conditionalLoopFlags = 0;
|
|
player->playbackRate = 1.0f;
|
|
player->polyphonyCounts[BGM_POLYPHONY_0] = 0;
|
|
player->polyphonyCounts[BGM_POLYPHONY_1] = 1;
|
|
player->polyphonyCounts[BGM_POLYPHONY_UNUSED_A] = 0;
|
|
player->polyphonyCounts[BGM_POLYPHONY_UNUSED_B] = 0;
|
|
player->polyphonyCounts[BGM_POLYPHONY_UNUSED_C] = 0;
|
|
player->polyphonyCounts[BGM_POLYPHONY_2] = 2;
|
|
player->polyphonyCounts[BGM_POLYPHONY_3] = 3;
|
|
player->polyphonyCounts[BGM_POLYPHONY_4] = 4;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
BGMPlayerTrack* track = &player->tracks[i];
|
|
|
|
track->insVolume = 0;
|
|
track->delayTime = 0;
|
|
track->insCoarseDetune = 0;
|
|
track->insFineDetune = 0;
|
|
track->insPan = 0;
|
|
track->insReverb = 0;
|
|
track->patch = 0;
|
|
track->isDrumTrack = FALSE;
|
|
track->volume = AU_MAX_VOLUME_8;
|
|
track->pressOverride = 0;
|
|
|
|
if (i < ARRAY_COUNT(player->cmdBufData)) {
|
|
player->cmdBufData[i] = 0;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->notes); i++) {
|
|
SeqNote* note = &player->notes[i];
|
|
|
|
note->volume = 0;
|
|
note->detune = 0;
|
|
note->length = 0;
|
|
note->randDetune = 0;
|
|
note->velocity = 0;
|
|
note->pendingTick = FALSE;
|
|
}
|
|
|
|
au_fade_set_envelope(&player->fadeInfo, AU_MAX_VOLUME_16);
|
|
snd_bgm_clear_legacy_commands(player);
|
|
}
|
|
|
|
void au_bgm_set_effect_indices(BGMPlayer* player, u8* list) {
|
|
s32 i;
|
|
s32 remaining;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->effectIndices); i++) {
|
|
s8 idx = *list++;
|
|
|
|
if (idx < 0) {
|
|
break;
|
|
}
|
|
player->effectIndices[i] = idx;
|
|
}
|
|
|
|
remaining = ARRAY_COUNT(player->effectIndices) - i;
|
|
if (remaining > 0) {
|
|
while (remaining-- != 0) {
|
|
player->effectIndices[i++] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void au_bgm_update_fade(BGMPlayer* player) {
|
|
player->fadeInfo.baseTicks--;
|
|
|
|
if (player->fadeInfo.baseTicks != 0) {
|
|
player->fadeInfo.baseVolume += player->fadeInfo.baseStep;
|
|
} else {
|
|
player->fadeInfo.baseVolume = player->fadeInfo.baseTarget << 16;
|
|
|
|
if (player->fadeInfo.onCompleteCallback != NULL) {
|
|
player->fadeInfo.onCompleteCallback();
|
|
}
|
|
|
|
// Was this fade tagged as a push?
|
|
if (player->pushSongName != 0) {
|
|
au_bgm_complete_push(player->pushSongName);
|
|
} else if (player->fadeInfo.baseVolume == 0) {
|
|
au_bgm_stop_player(player);
|
|
}
|
|
}
|
|
au_bgm_update_bus_volumes(player);
|
|
}
|
|
|
|
void au_bgm_update_bus_volumes(BGMPlayer* player) {
|
|
u16 volume = (
|
|
((u32)player->fadeInfo.baseVolume >> 16) *
|
|
((u32)player->fadeInfo.envelopeVolume >> 16)
|
|
) >> 15;
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->effectIndices); i++) {
|
|
s8 busID = player->effectIndices[i];
|
|
|
|
if (busID < 0) {
|
|
return;
|
|
}
|
|
au_fade_set_volume(busID, volume, player->busVolume);
|
|
}
|
|
}
|
|
|
|
s32 au_bgm_player_audio_frame_update(BGMPlayer* player) {
|
|
u16 hasMore = TRUE;
|
|
s32 retVal = FALSE;
|
|
|
|
// update pseudorandom numbers with fast 'good enough' method
|
|
player->randomValue1 = (player->randomValue1 & 0xFFFF) + (player->songPlayingCounter & 0xFFFF) + (player->frameCounter & 0xFFFF);
|
|
player->randomValue2 = (player->randomValue2 & 0xFFFF) + ((player->songPlayingCounter << 4) & 0xFFFF) + ((player->frameCounter >> 4) & 0xFFFF);
|
|
do {
|
|
switch (player->masterState) {
|
|
case BGM_PLAY_STATE_IDLE:
|
|
hasMore = FALSE;
|
|
break;
|
|
case BGM_PLAY_STATE_ACTIVE:
|
|
if (!player->paused) {
|
|
au_bgm_player_update_playing(player);
|
|
if (player->masterState == BGM_PLAY_STATE_ACTIVE) {
|
|
hasMore = FALSE;
|
|
}
|
|
} else {
|
|
hasMore = FALSE;
|
|
}
|
|
break;
|
|
case BGM_PLAY_STATE_FETCH:
|
|
au_bgm_player_read_composition(player);
|
|
break;
|
|
case BGM_PLAY_STATE_INIT:
|
|
au_bgm_player_initialize(player);
|
|
hasMore = FALSE;
|
|
break;
|
|
case BGM_PLAY_STATE_STOP:
|
|
au_bgm_player_update_stop(player);
|
|
break;
|
|
default:
|
|
retVal = TRUE;
|
|
hasMore = FALSE;
|
|
break;
|
|
}
|
|
} while (hasMore);
|
|
return retVal;
|
|
}
|
|
|
|
void au_bgm_player_initialize(BGMPlayer* player) {
|
|
s32* buf;
|
|
s32 cmd;
|
|
s32 keepReading;
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
BGMPlayerTrack* track = &player->tracks[i];
|
|
track->instrument = NO_INSTRUMENT;
|
|
track->insVolume = AU_MAX_VOLUME_16 << 16; // @bug? incorrect format for 8.24 fixed, should be (AU_MAX_VOLUME_8 << 24)
|
|
track->insPan = 0x40;
|
|
track->insReverb = 0;
|
|
track->patch = 0;
|
|
track->insCoarseDetune = 0;
|
|
track->insFineDetune = 0;
|
|
track->volume = AU_MAX_VOLUME_8;
|
|
track->pressOverride = 0;
|
|
track->proxVolume = AU_MAX_VOLUME_16 << 16;
|
|
track->savedPos = NULL;
|
|
track->prevReadPos = NULL;
|
|
track->detourLength = 0;
|
|
track->detune = 0;
|
|
track->tremoloDepth = 0;
|
|
track->tremoloDelay = 0;
|
|
track->tremoloRate = 0;
|
|
track->insVolumeStep = 0;
|
|
track->insVolumeTarget = 0;
|
|
track->insVolumeTicks = 0;
|
|
track->proxVolumeStep = 0;
|
|
track->proxVolumeTarget = 0;
|
|
track->proxVolumeTicks = 0;
|
|
track->proxMixSetChanged = FALSE;
|
|
track->proxMixValChanged = FALSE;
|
|
track->proxVol1 = 0;
|
|
track->proxVol2 = 0;
|
|
track->polyVoiceCount = 0;
|
|
track->polyphonicIdx = 0;
|
|
track->randomPanAmount = 0;
|
|
track->isDrumTrack = FALSE;
|
|
track->linkedTrackID = 0;
|
|
track->muted = FALSE;
|
|
track->busID = player->busID;
|
|
track->index = i;
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->notes); i++) {
|
|
SeqNote* note = &player->notes[i];
|
|
note->ins = NO_INSTRUMENT;
|
|
note->pitchRatio = 2.0f;
|
|
note->randDetune = 0;
|
|
note->velocity = 0;
|
|
note->length = 0;
|
|
note->tremoloDepth = 0;
|
|
}
|
|
|
|
au_bgm_reset_all_voices(player);
|
|
player->playbackRate = 128.0f; // set to 1.0 later om...
|
|
player->masterTempo = BGM_DEFAULT_TEMPO;
|
|
player->masterTempoBPM = BGM_DEFAULT_BPM;
|
|
player->unused_21E = 0x80;
|
|
player->masterVolume = AU_MAX_VOLUME_8 << 24;
|
|
player->pushSongName = 0;
|
|
player->tickRatePtr = NULL;
|
|
player->masterTempoTarget = 0;
|
|
player->masterPitchShift = 0;
|
|
player->detune = 0;
|
|
player->masterVolumeTicks = 0;
|
|
player->masterVolumeTarget = 0;
|
|
player->masterVolumeStep = 0;
|
|
player->proxMixValue = 0;
|
|
player->proxMixID = 0;
|
|
player->proxMixVolume = 0;
|
|
player->compActiveLoopEndPos[3] = NULL;
|
|
player->compActiveLoopEndPos[2] = NULL;
|
|
player->compActiveLoopEndPos[1] = NULL;
|
|
player->compActiveLoopEndPos[0] = NULL;
|
|
*(s32*)player->compLoopCounters = 0;
|
|
player->compLoopDepth = 0;
|
|
player->unused_222 = 0;
|
|
player->conditionalLoopFlags = 0;
|
|
player->trackVolsConfig = NULL;
|
|
player->bFadeConfigSetsVolume = FALSE;
|
|
player->initLinkMute = TRUE;
|
|
player->writingCustomEnvelope = 0;
|
|
player->playbackRate = 1.0f;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->customEnvelopeWritePos); i++) {
|
|
au_bgm_clear_custom_note_press(player, i);
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->effectValues); i++) {
|
|
player->effectValues[i] = 0;
|
|
}
|
|
|
|
player->paused = FALSE;
|
|
player->songPlayingCounter = 0;
|
|
for (i = 0; i < ARRAY_COUNT(player->compLoopStartLabels); i++) {
|
|
player->compLoopStartLabels[i] = player->compReadPos;
|
|
}
|
|
|
|
// find labels
|
|
buf = player->compReadPos;
|
|
keepReading = TRUE;
|
|
while (keepReading) {
|
|
cmd = *buf++;
|
|
if (cmd == 0) {
|
|
keepReading = FALSE;
|
|
} else if ((cmd & 0xF0000000) == BGM_COMP_START_LOOP << 28) {
|
|
player->compLoopStartLabels[cmd & 0x1F] = buf;
|
|
}
|
|
}
|
|
|
|
player->masterState = BGM_PLAY_STATE_FETCH;
|
|
}
|
|
|
|
void au_bgm_clear_custom_note_press(BGMPlayer* player, s32 index) {
|
|
s32 i;
|
|
u16* pos = player->customPressEnvelopes[index];
|
|
player->customEnvelopeWritePos[index] = 0;
|
|
|
|
for (i = 0; i < 9; i++) {
|
|
*pos++ = 0xFF00;
|
|
}
|
|
}
|
|
|
|
void au_bgm_set_tick_resolution(BGMPlayer* player, s32 mBeatsPerMinute, u32 ticksPerBeat) {
|
|
// compute how many audio frames before the next tick
|
|
u32 mFramesPerTick = BGM_MFRAMES_PER_MINUTE / ticksPerBeat;
|
|
|
|
// Clamp samples per tick to stay in a valid range
|
|
if (mFramesPerTick > 500000) {
|
|
mFramesPerTick = 500000;
|
|
} else if (mFramesPerTick < 80000) {
|
|
mFramesPerTick = 80000;
|
|
}
|
|
|
|
// Clamp to sample rate
|
|
if (mFramesPerTick < mBeatsPerMinute) {
|
|
mBeatsPerMinute = mFramesPerTick;
|
|
}
|
|
|
|
// breakdown of units:
|
|
//
|
|
// tickUpdateInterval / nextUpdateStep = framesPerTick
|
|
//
|
|
// 1000 x frames beat min frames
|
|
// ------------- x ------ x --------------- = ------
|
|
// min tick 1000 x beat tick
|
|
|
|
player->nextUpdateStep = mBeatsPerMinute;
|
|
player->tickUpdateInterval = mFramesPerTick;
|
|
player->nextUpdateCounter = mFramesPerTick;
|
|
|
|
player->maxTempo = mFramesPerTick / BGM_UPDATE_SCALE;
|
|
}
|
|
|
|
// runs whenever a new composition begins playing
|
|
void au_bgm_player_read_composition(BGMPlayer* player) {
|
|
u16 continueReading = TRUE;
|
|
u32 cmd;
|
|
|
|
player->masterTempoStep = 0;
|
|
player->masterTempoTicks = 0;
|
|
|
|
while (continueReading) {
|
|
cmd = *player->compReadPos++;
|
|
if (cmd == BGM_COMP_END) {
|
|
player->masterState = BGM_PLAY_STATE_STOP;
|
|
continueReading = FALSE;
|
|
} else {
|
|
switch (cmd >> 12) {
|
|
case BGM_COMP_PLAY_PHRASE << 16:
|
|
au_bgm_load_phrase(player, cmd);
|
|
player->masterState = BGM_PLAY_STATE_ACTIVE;
|
|
continueReading = FALSE;
|
|
break;
|
|
case BGM_COMP_START_LOOP << 16:
|
|
break;
|
|
case BGM_COMP_WAIT << 16:
|
|
continueReading = FALSE;
|
|
break;
|
|
case BGM_COMP_END_LOOP << 16:
|
|
au_bgm_end_composition_loop(player, cmd);
|
|
break;
|
|
case BGM_COMP_END_COND_LOOP_FALSE << 16:
|
|
if (!(player->conditionalLoopFlags & 1)) {
|
|
au_bgm_end_composition_loop(player, cmd);
|
|
}
|
|
break;
|
|
case BGM_COMP_END_COND_LOOP_TRUE << 16:
|
|
if (player->conditionalLoopFlags & 1) {
|
|
au_bgm_end_composition_loop(player, cmd);
|
|
}
|
|
break;
|
|
default:
|
|
continueReading = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void au_bgm_end_composition_loop(BGMPlayer* player, u32 cmd) {
|
|
s32 labelIndex = cmd & 0x1F; // 01F (bits 0-4)
|
|
s32 iterCount = (cmd >> 5) & 0x7F; // FE0 (bits 5-11)
|
|
u32 depth;
|
|
|
|
depth = player->compLoopDepth;
|
|
if (player->compActiveLoopEndPos[depth] != NULL) {
|
|
if (player->compActiveLoopEndPos[depth] == player->compReadPos) {
|
|
if (player->compLoopCounters[depth] != 0) {
|
|
player->compLoopCounters[depth]--;
|
|
if ((player->compLoopCounters[depth]) == 0) {
|
|
player->compActiveLoopEndPos[depth] = NULL;
|
|
if (depth > 0) {
|
|
depth--;
|
|
}
|
|
} else {
|
|
player->compReadPos = player->compLoopStartLabels[labelIndex];
|
|
}
|
|
} else {
|
|
player->compReadPos = player->compLoopStartLabels[labelIndex];
|
|
}
|
|
} else if (depth < 4) {
|
|
depth++;
|
|
player->compActiveLoopEndPos[depth] = player->compReadPos;
|
|
player->compLoopCounters[depth] = iterCount;
|
|
player->compReadPos = player->compLoopStartLabels[labelIndex];
|
|
}
|
|
} else {
|
|
player->compActiveLoopEndPos[depth] = player->compReadPos;
|
|
player->compLoopCounters[depth] = iterCount;
|
|
player->compReadPos = player->compLoopStartLabels[labelIndex];
|
|
}
|
|
player->compLoopDepth = depth;
|
|
}
|
|
|
|
void au_bgm_load_phrase(BGMPlayer* player, u32 cmd) {
|
|
BGMPlayerTrack* track;
|
|
u32 trackInfo;
|
|
s32* trackList;
|
|
u32 linkedID;
|
|
s32 count;
|
|
s32 curVoice;
|
|
s32 bFoundLinkedTrack;
|
|
s32 i;
|
|
|
|
curVoice = 0;
|
|
bFoundLinkedTrack = FALSE;
|
|
player->phraseStartPos = AU_FILE_RELATIVE(player->compStartPos, (cmd & 0xFFFF) << 2);
|
|
trackList = player->phraseStartPos;
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
track = &player->tracks[i];
|
|
trackInfo = *trackList++;
|
|
track->bgmReadPos = (AuFilePos) (trackInfo >> 0x10);
|
|
if (track->bgmReadPos != NULL) {
|
|
if ((trackInfo & 0x100) == 0) {
|
|
track->polyphonicIdx = (trackInfo & (0x7 << 0xD)) >> 0xD;
|
|
track->isDrumTrack = (trackInfo >> 7) & 1;
|
|
linkedID = (trackInfo & (0xF << 9)) >> 9;
|
|
track->linkedTrackID = 0;
|
|
if (linkedID != 0) {
|
|
BGMPlayerTrack* linkedTrack = &player->tracks[linkedID - 1];
|
|
if ((linkedID - 1) < i) {
|
|
track->polyVoiceCount = linkedTrack->polyVoiceCount;
|
|
track->firstVoice = linkedTrack->firstVoice;
|
|
track->lastVoice = linkedTrack->lastVoice;
|
|
|
|
track->bgmReadPos = (track->bgmReadPos + (s32)player->phraseStartPos);
|
|
track->delayTime = 1;
|
|
|
|
track->linkedTrackID = linkedID;
|
|
if (player->initLinkMute) {
|
|
track->muted = TRUE;
|
|
}
|
|
bFoundLinkedTrack = TRUE;
|
|
} else {
|
|
track->bgmReadPos = NULL;
|
|
}
|
|
} else {
|
|
count = player->polyphonyCounts[track->polyphonicIdx];
|
|
track->polyVoiceCount = count;
|
|
track->firstVoice = curVoice;
|
|
curVoice += count;
|
|
track->lastVoice = curVoice;
|
|
|
|
track->bgmReadPos = (track->bgmReadPos + (s32)player->phraseStartPos);
|
|
track->delayTime = 1;
|
|
}
|
|
} else {
|
|
track->bgmReadPos = NULL;
|
|
}
|
|
}
|
|
}
|
|
player->totalVoices = curVoice;
|
|
if (bFoundLinkedTrack) {
|
|
player->initLinkMute = FALSE;
|
|
}
|
|
}
|
|
|
|
void au_bgm_player_update_stop(BGMPlayer* player) {
|
|
s32 i;
|
|
|
|
player->paused = FALSE;
|
|
player->songName = 0;
|
|
player->pushSongName = 0;
|
|
player->unk_58 = 0;
|
|
player->unk_5A = 0;
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
player->tracks[i].bgmReadPos = NULL;
|
|
}
|
|
au_bgm_reset_all_voices(player);
|
|
player->masterState = BGM_PLAY_STATE_IDLE;
|
|
player->nextUpdateStep = BGM_DEFAULT_UPDATE_STEP;
|
|
}
|
|
|
|
#define POST_BGM_READ() \
|
|
if (track->detourLength != 0) {\
|
|
track->detourLength--;\
|
|
if (track->detourLength == 0) {\
|
|
track->bgmReadPos = track->savedPos;\
|
|
}\
|
|
}
|
|
|
|
/// play next tick
|
|
void au_bgm_player_update_playing(BGMPlayer *player) {
|
|
s32 bVolumeFading;
|
|
u8 sp1F;
|
|
s16 notePitch;
|
|
u8 bFinished;
|
|
|
|
AuVoice* voice;
|
|
BGMDrumInfo* drumInfo;
|
|
BGMPlayerTrack* track;
|
|
SeqNote* note;
|
|
s32 var_a0;
|
|
s32 temp;
|
|
s32 tremoloDetune;
|
|
s32 bAcquiredVoiceIdx;
|
|
u8 opcode;
|
|
u8 noteVelocity;
|
|
s32 noteLength;
|
|
u32 i;
|
|
u8 voiceIdx;
|
|
s32 temp2;
|
|
bVolumeFading = FALSE;
|
|
bFinished = FALSE;
|
|
|
|
if (player->masterTempoTicks != 0) {
|
|
player->masterTempoTicks--;
|
|
if (player->masterTempoTicks == 0) {
|
|
player->masterTempo = player->masterTempoTarget;
|
|
player->masterTempoTarget = 0;
|
|
player->masterTempoStep = 0;
|
|
} else {
|
|
player->masterTempo += player->masterTempoStep;
|
|
}
|
|
player->nextUpdateStep = BGM_TEMPO_TO_UPDATE_UNITS(player->masterTempo);
|
|
}
|
|
if (player->masterVolumeTicks != 0) {
|
|
player->masterVolumeTicks--;
|
|
if (player->masterVolumeTicks == 0) {
|
|
player->masterVolume = player->masterVolumeTarget;
|
|
player->masterVolumeTarget = 0;
|
|
player->masterVolumeStep = 0;
|
|
} else {
|
|
player->masterVolume += player->masterVolumeStep;
|
|
}
|
|
bVolumeFading = TRUE;
|
|
}
|
|
player->volumeChanged = FALSE;
|
|
if (player->trackVolsConfig != NULL) {
|
|
if (player->bFadeConfigSetsVolume) {
|
|
// setting track volumes
|
|
s32 lenLimit = 16;
|
|
while (lenLimit-- != 0) {
|
|
i = *player->trackVolsConfig++;
|
|
if (i == 0) {
|
|
break;
|
|
}
|
|
track = &player->tracks[i - 1];
|
|
player->seqCmdArgs.TrackVolumeFade.time = 48;
|
|
player->seqCmdArgs.TrackVolumeFade.value = *(player->trackVolsConfig++);
|
|
if (track->bgmReadPos != 0) {
|
|
au_BGMCmd_F6_InstrumentVolumeLerp(player, track);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// clearing track volumes
|
|
s32 lenLimit = 16;
|
|
while (lenLimit-- != 0) {
|
|
i = *player->trackVolsConfig++;
|
|
if (i == 0) {
|
|
break;
|
|
}
|
|
track = &player->tracks[i - 1];
|
|
player->seqCmdArgs.TrackVolumeFade.time = 48;
|
|
player->trackVolsConfig++; // ignore arg
|
|
player->seqCmdArgs.TrackVolumeFade.value = 0;
|
|
if (track->bgmReadPos != 0) {
|
|
au_BGMCmd_F6_InstrumentVolumeLerp(player, track);
|
|
}
|
|
}
|
|
}
|
|
player->trackVolsConfig = NULL;
|
|
player->bFadeConfigSetsVolume = FALSE;
|
|
}
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
track = &player->tracks[i];
|
|
if (track->bgmReadPos != NULL) {
|
|
track->changed.all = 0;
|
|
if (bVolumeFading || player->volumeChanged) {
|
|
track->changed.volume = TRUE;
|
|
} else {
|
|
track->changed.volume = FALSE;
|
|
}
|
|
if (track->insVolumeTicks != 0) {
|
|
track->insVolumeTicks--;
|
|
if (track->insVolumeTicks == 0) {
|
|
track->insVolume = track->insVolumeTarget;
|
|
} else {
|
|
track->insVolume += track->insVolumeStep;
|
|
}
|
|
track->changed.volume = TRUE;
|
|
}
|
|
if (track->proxVolumeTicks != 0) {
|
|
track->proxVolumeTicks--;
|
|
if (track->proxVolumeTicks == 0) {
|
|
track->proxVolume = track->proxVolumeTarget << 16;
|
|
} else {
|
|
track->proxVolume += track->proxVolumeStep;
|
|
}
|
|
track->changed.volume = TRUE;
|
|
}
|
|
track->delayTime--;
|
|
if (track->delayTime <= 0) {
|
|
sp1F = track->firstVoice;
|
|
while (track->delayTime == 0) {
|
|
opcode = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
|
|
if (opcode < 0x80) {
|
|
if (opcode == 0) {
|
|
if (track->prevReadPos != 0) {
|
|
track->bgmReadPos = track->prevReadPos;
|
|
track->prevReadPos = 0;
|
|
} else {
|
|
bFinished = TRUE;
|
|
break;
|
|
}
|
|
} else {
|
|
if (opcode >= 0x78) {
|
|
// long delay
|
|
track->delayTime = (((opcode & 7) << 8) + *(track->bgmReadPos++)) + 0x78;
|
|
POST_BGM_READ();
|
|
|
|
} else {
|
|
// delay
|
|
track->delayTime = opcode;
|
|
}
|
|
}
|
|
} else {
|
|
// note
|
|
if (opcode < 0xD4) {
|
|
notePitch = (opcode & 0x7F);
|
|
noteVelocity = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
noteLength = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
if (!(noteLength < 0xC0)) {
|
|
noteLength = (((u8)noteLength & ~0xC0) << 8) + *(track->bgmReadPos++) + 0xC0;
|
|
POST_BGM_READ();
|
|
}
|
|
bAcquiredVoiceIdx = FALSE;
|
|
if (!track->muted) {
|
|
// find first free voice
|
|
for (voiceIdx = sp1F; voiceIdx < track->lastVoice; voiceIdx++) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
sp1F++;
|
|
if (voice->priority == AU_PRIORITY_FREE) {
|
|
bAcquiredVoiceIdx = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bAcquiredVoiceIdx) {
|
|
if (track->polyphonicIdx >= BGM_POLYPHONY_2) {
|
|
// try stealing a voice with lower priority
|
|
for (voiceIdx = track->firstVoice; voiceIdx < track->lastVoice; voiceIdx++) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
if (voice->priority < player->priority) {
|
|
au_reset_voice(voice, voiceIdx);
|
|
bAcquiredVoiceIdx = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
// try stealing a voice with equal priority and zero note length
|
|
if (!bAcquiredVoiceIdx) {
|
|
for (voiceIdx = track->firstVoice; voiceIdx < track->lastVoice; voiceIdx++) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
if (voice->priority == player->priority) {
|
|
note = &player->notes[voiceIdx];
|
|
if (note->length == 0) {
|
|
au_reset_voice(voice, voiceIdx);
|
|
bAcquiredVoiceIdx = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// try stealing a voice with equal priority and lowest note length
|
|
if (!bAcquiredVoiceIdx) {
|
|
s32 shortestLength = 0xFFFF;
|
|
u8 voice_it;
|
|
AuVoice* curVoice;
|
|
SeqNote* curNote;
|
|
for (voice_it = track->firstVoice; voice_it < track->lastVoice; voice_it++) {
|
|
curVoice = &player->globals->voices[voice_it];
|
|
if (curVoice->priority == player->priority) {
|
|
curNote = &player->notes[voice_it];
|
|
if (!curNote->pendingTick && curNote->length < shortestLength) {
|
|
shortestLength = curNote->length;
|
|
voice = curVoice;
|
|
note = curNote;
|
|
voiceIdx = voice_it;
|
|
bAcquiredVoiceIdx = TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (bAcquiredVoiceIdx) {
|
|
note->length = 0;
|
|
au_reset_voice(voice, voiceIdx);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
voiceIdx = track->firstVoice;
|
|
voice = &player->globals->voices[voiceIdx];
|
|
note = &player->notes[voiceIdx];
|
|
note->length = 0;
|
|
if (voice->priority <= player->priority) {
|
|
au_reset_voice(voice, voiceIdx);
|
|
bAcquiredVoiceIdx = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (bAcquiredVoiceIdx) {
|
|
note = &player->notes[voiceIdx];
|
|
note->tremoloDepth = 0;
|
|
if (noteVelocity > 0) {
|
|
note->velocity = noteVelocity + 1;
|
|
} else {
|
|
note->velocity = 0;
|
|
}
|
|
note->length = noteLength;
|
|
if (track->isDrumTrack) {
|
|
if (notePitch < 72) { // = 6 * 12
|
|
drumInfo = &player->globals->dataPER->drums[notePitch];
|
|
} else {
|
|
drumInfo = player->drums[notePitch - 72]; // = 6 * 12
|
|
}
|
|
note->ins = au_get_instrument(player->globals, drumInfo->bankPatch >> 8, drumInfo->bankPatch & 0xFF, &voice->envelope);
|
|
if (drumInfo->randVolume != 0) {
|
|
note->volume = note->velocity * au_bgm_get_random_vol(player->randomValue1, drumInfo->volume, drumInfo->randVolume);
|
|
} else {
|
|
note->volume = note->velocity * drumInfo->volume;
|
|
}
|
|
// combining formats: 7.24 * 7.24 * 15.16 * 7.0 * 15.0 --> 16.16
|
|
// first step, shifting fractional factors by 21:
|
|
// 7.24 * 7.24 * 15.16 --> 7.3 * 7.3 * 10.0 --> 24.6
|
|
// shifting this down by 20 transforms 24.6 --> 10.0
|
|
// now for the second step with whole:
|
|
// 10.0 * 7.0 * 15.0 --> 32.0
|
|
// and a final shift by 16 transforms 32.0 --> 16.16
|
|
voice->clientVolume = ((
|
|
((player->masterVolume >> 21) // 7.24 --> 7.3
|
|
* (track->insVolume >> 21) // 7.24 --> 7.3
|
|
* (track->proxVolume >> 21)) >> 20) // 15.16 --> 10.0 (fractional part truncated?)
|
|
* (track->volume * note->volume)) >> 16;
|
|
note->detune =
|
|
drumInfo->keyBase
|
|
+ track->insCoarseDetune
|
|
+ track->insFineDetune
|
|
- note->ins->keyBase;
|
|
temp = (note->detune + track->detune) + player->detune;
|
|
if (drumInfo->randTune != 0) {
|
|
note->randDetune = au_bgm_get_random_pitch(player->randomValue1, temp, drumInfo->randTune);
|
|
temp = note->randDetune;
|
|
}
|
|
note->pitchRatio = au_compute_pitch_ratio(temp) * note->ins->pitchRatio;
|
|
if (drumInfo->randPan != 0) {
|
|
voice->pan = au_bgm_get_random_pan(player, drumInfo->pan, drumInfo->randPan);
|
|
} else {
|
|
voice->pan = drumInfo->pan;
|
|
}
|
|
if (drumInfo->randReverb != 0) {
|
|
voice->reverb = au_bgm_get_random_reverb(player->randomValue1, drumInfo->reverb, drumInfo->randReverb);
|
|
} else {
|
|
voice->reverb = drumInfo->reverb;
|
|
}
|
|
} else {
|
|
// combining formats: 7.24 * 7.24 * 15.16 * 7.0 * 15.0 --> 16.16
|
|
// first step, shifting fractional factors by 21:
|
|
// 7.24 * 7.24 * 15.16 --> 7.3 * 7.3 * 10.0 --> 24.6
|
|
// shifting this down by 20 transforms 24.6 --> 10.0
|
|
// now for the second step with whole:
|
|
// 10.0 * 7.0 * 7.0 --> 24.0
|
|
// and a final shift by 9 transforms 24.0 --> 15.16
|
|
voice->clientVolume = note->volume = ((
|
|
((player->masterVolume >> 21) // 7.24 --> 7.3
|
|
* (track->insVolume >> 21) // 7.24 --> 7.3
|
|
* (track->proxVolume >> 21)) >> 20) // 15.16 --> 10.0 (fractional part truncated?)
|
|
* (track->volume * note->velocity)) >> 9;
|
|
note->ins = track->instrument;
|
|
note->detune =
|
|
(notePitch * 100)
|
|
+ track->insCoarseDetune
|
|
+ player->masterPitchShift
|
|
+ track->insFineDetune
|
|
- note->ins->keyBase;
|
|
note->pitchRatio = au_compute_pitch_ratio(
|
|
note->detune
|
|
+ track->detune
|
|
+ player->detune)
|
|
* track->instrument->pitchRatio;
|
|
|
|
if (track->randomPanAmount != 0) {
|
|
voice->pan = au_bgm_get_random_pan(player, track->insPan, track->randomPanAmount);
|
|
} else {
|
|
voice->pan = track->insPan;
|
|
}
|
|
voice->reverb = track->insReverb;
|
|
|
|
if (track->pressOverride != 0) {
|
|
voice->envelope.cmdListPress = (u8*) player->customPressEnvelopes[track->pressOverride - 1];
|
|
} else {
|
|
voice->envelope.cmdListPress = track->envelope.cmdListPress;
|
|
}
|
|
voice->envelope.cmdListRelease = track->envelope.cmdListRelease;
|
|
}
|
|
voice->instrument = note->ins;
|
|
voice->pitchRatio = note->pitchRatio;
|
|
voice->busID = track->busID;
|
|
if (note->length > 1) {
|
|
note->pendingTick = TRUE;
|
|
note->tremoloDepth = track->tremoloDepth;
|
|
note->tremoloPhase = 0;
|
|
note->tremoloDelay = track->tremoloDelay;
|
|
voice->syncFlags = AU_VOICE_SYNC_FLAG_ALL;
|
|
voice->priority = player->priority;
|
|
voice->clientPriority = voice->priority;
|
|
}
|
|
}
|
|
} else {
|
|
//TODO variable is nargs, but reusing temp is required to match
|
|
temp = SeqCmdArgCounts[opcode - 0xE0];
|
|
if (temp != 0) {
|
|
player->seqCmdArgs.raw[0] = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
} else {
|
|
goto bgm_args_done;
|
|
}
|
|
if (temp > 1) {
|
|
player->seqCmdArgs.raw[1] = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
} else {
|
|
goto bgm_args_done;
|
|
}
|
|
if (temp > 2) {
|
|
player->seqCmdArgs.raw[2] = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
} else {
|
|
goto bgm_args_done;
|
|
}
|
|
if (temp > 3) {
|
|
player->seqCmdArgs.raw[3] = *(track->bgmReadPos++);
|
|
POST_BGM_READ();
|
|
}
|
|
bgm_args_done:
|
|
CurrentSeqCmdHandler = SeqCmdHandlers[opcode - 0xE0];
|
|
CurrentSeqCmdHandler(player, track);
|
|
}
|
|
}
|
|
} // end while
|
|
}
|
|
|
|
for (voiceIdx = track->firstVoice; voiceIdx < track->lastVoice; voiceIdx++) {
|
|
if (!track->muted) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
if (voice->priority == player->priority) {
|
|
note = &player->notes[voiceIdx];
|
|
if (!note->pendingTick) {
|
|
if (note->length > 0) {
|
|
note->length--;
|
|
if (note->length == 0) {
|
|
voice->envelopeFlags |= AU_VOICE_ENV_FLAG_KEY_RELEASED;
|
|
}
|
|
}
|
|
if (track->isDrumTrack) {
|
|
if (track->changed.tune || (player->detune != 0)) {
|
|
note->pitchRatio = au_compute_pitch_ratio(((note->detune + note->randDetune) + track->detune) + player->detune) * note->ins->pitchRatio;
|
|
if (voice->pitchRatio != note->pitchRatio) {
|
|
voice->pitchRatio = note->pitchRatio;
|
|
voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
|
|
}
|
|
}
|
|
if (track->changed.volume) {
|
|
// combining formats: 7.24 * 7.24 * 15.16 * 7.0 * 15.0 --> 16.16
|
|
// first step, shifting fractional factors by 21:
|
|
// 7.24 * 7.24 * 15.16 --> 7.3 * 7.3 * 10.0 --> 24.6
|
|
// shifting this down by 20 transforms 24.6 --> 10.0
|
|
// now for the second step with whole:
|
|
// 10.0 * 7.0 * 15.0 --> 32.0
|
|
// and a final shift by 16 transforms 32.0 --> 16.16
|
|
voice->clientVolume = (
|
|
((((player->masterVolume >> 21) // 7.24 --> 7.3
|
|
* (track->insVolume >> 21)) // 7.24 --> 7.3
|
|
* (track->proxVolume >> 21)) >> 20) // 15.16 --> 10.0 (fractional part truncated?)
|
|
* (track->volume * note->volume)) >> 16;
|
|
voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
|
|
}
|
|
} else {
|
|
// Modulate pitch using a triange wave for tremolo effect
|
|
if (note->tremoloDepth != 0) {
|
|
if (note->tremoloDelay != 0) {
|
|
note->tremoloDelay--;
|
|
} else {
|
|
u8 quadrant;
|
|
note->tremoloPhase += track->tremoloRate;
|
|
opcode = (note->tremoloPhase << 2) + 3; // +3 just to fill lower 2 bits
|
|
|
|
// Determine what part of the triangle wave we are in (using top 2 bits of u8)
|
|
quadrant = note->tremoloPhase >> 6;
|
|
|
|
// Invert the triangle for quadrants 1 and 3 (ugly code required to match)
|
|
/* visualized: //// --> /\/\ */
|
|
if ((quadrant == 1) || (quadrant == 3)) {
|
|
u8 temp2 = ~opcode;
|
|
tremoloDetune = temp2 + 1;
|
|
} else {
|
|
tremoloDetune = opcode;
|
|
}
|
|
|
|
// Scale by depth
|
|
tremoloDetune = (tremoloDetune * track->tremoloDepth) >> 8;
|
|
|
|
// Invert sign for the second half of triangle wave
|
|
if ((quadrant == 2) || (quadrant == 3)) {
|
|
tremoloDetune = -tremoloDetune;
|
|
}
|
|
|
|
// Apply pitch detune from tremolo
|
|
note->pitchRatio = au_compute_pitch_ratio(tremoloDetune + ((note->detune + track->detune) + player->detune)) * note->ins->pitchRatio;
|
|
if (voice->pitchRatio != note->pitchRatio) {
|
|
voice->pitchRatio = note->pitchRatio;
|
|
voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
|
|
}
|
|
}
|
|
} else if (track->changed.tune || (player->detune != 0)) {
|
|
|
|
note->pitchRatio = au_compute_pitch_ratio((note->detune + track->detune) + player->detune) * note->ins->pitchRatio;
|
|
if (voice->pitchRatio != note->pitchRatio) {
|
|
voice->pitchRatio = note->pitchRatio;
|
|
voice->syncFlags |= AU_VOICE_SYNC_FLAG_PITCH;
|
|
}
|
|
}
|
|
if (track->changed.volume) {
|
|
// combining formats: 7.24 * 7.24 * 15.16 * 7.0 * 15.0 --> 16.16
|
|
// first step, shifting fractional factors by 21:
|
|
// 7.24 * 7.24 * 15.16 --> 7.3 * 7.3 * 10.0 --> 24.6
|
|
// shifting this down by 20 transforms 24.6 --> 10.0
|
|
// now for the second step with whole:
|
|
// 10.0 * 7.0 * 7.0 --> 24.0
|
|
// and a final shift by 9 transforms 24.0 --> 15.16
|
|
note->volume = ((
|
|
(player->masterVolume >> 21) // 7.24 --> 7.3
|
|
* (track->insVolume >> 21) // 7.24 --> 7.3
|
|
* (track->proxVolume >> 21)) >> 20)
|
|
* (track->volume * note->velocity) >> 9;
|
|
voice->clientVolume = note->volume;
|
|
voice->envelopeFlags |= AU_VOICE_ENV_FLAG_VOL_CHANGED;
|
|
voice->pan = track->insPan;
|
|
voice->reverb = track->insReverb;
|
|
} else if (track->changed.pan || track->changed.reverb) {
|
|
voice->pan = track->insPan;
|
|
voice->reverb = track->insReverb;
|
|
voice->syncFlags |= AU_VOICE_SYNC_FLAG_PAN_FXMIX;
|
|
}
|
|
}
|
|
}
|
|
note->pendingTick = FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bFinished) {
|
|
player->masterState = BGM_PLAY_STATE_FETCH;
|
|
}
|
|
}
|
|
|
|
static const f32 padding[] = {0.0f}; // at least after au_bgm_player_audio_frame_update
|
|
|
|
void au_BGMCmd_E0_MasterTempo(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
u32 bpm = player->seqCmdArgs.MasterTempo.value;
|
|
s32 tempo;
|
|
|
|
player->masterTempoBPM = bpm;
|
|
tempo = au_bgm_bpm_to_tempo(player, bpm);
|
|
player->masterTempo = tempo;
|
|
player->nextUpdateStep = BGM_TEMPO_TO_UPDATE_UNITS(tempo);
|
|
player->masterTempoTicks = 0;
|
|
player->masterTempoTarget = 0;
|
|
player->masterTempoStep = 0;
|
|
}
|
|
|
|
static s32 au_bgm_bpm_to_tempo(BGMPlayer* player, u32 tempo) {
|
|
u32 maxTempo = player->maxTempo;
|
|
u32 ret = tempo;
|
|
|
|
ret *= player->playbackRate;
|
|
|
|
if (maxTempo < ret) {
|
|
ret = maxTempo;
|
|
} else if (ret == 0) {
|
|
ret = 1;
|
|
}
|
|
|
|
return ret * 100;
|
|
}
|
|
|
|
void au_BGMCmd_E1_MasterVolume(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
s8_24 volume = player->seqCmdArgs.MasterVolume.value & 0x7F;
|
|
|
|
if (volume != 0) {
|
|
volume = volume << 24;
|
|
}
|
|
|
|
player->masterVolume = volume;
|
|
player->masterVolumeTicks = 0;
|
|
player->masterVolumeTarget = 0;
|
|
player->masterVolumeStep = 0;
|
|
player->volumeChanged = TRUE;
|
|
track->changed.volume = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_E2_MasterDetune(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
player->masterPitchShift = (s8)player->seqCmdArgs.MasterPitchShift.cent * 100;
|
|
}
|
|
|
|
void au_BGMCmd_E3(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
player->globals->effectChanges[player->busID].type = player->seqCmdArgs.UnkCmdE3.effectType;
|
|
player->globals->effectChanges[player->busID].changed = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_E6_MasterEffect(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
u8 index = player->seqCmdArgs.MasterEffect.index;
|
|
u32 busID = player->effectIndices[index];
|
|
|
|
if ((index < 4) && (busID < 0x80)) {
|
|
if (player->globals->effectChanges[busID].type != player->seqCmdArgs.MasterEffect.value) {
|
|
player->globals->effectChanges[busID].type = player->seqCmdArgs.MasterEffect.value;
|
|
player->globals->effectChanges[busID].changed = TRUE;
|
|
}
|
|
player->effectValues[index] = player->seqCmdArgs.MasterEffect.value;
|
|
}
|
|
}
|
|
|
|
void au_BGMCmd_E4_MasterTempoFade(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
s32 time = player->seqCmdArgs.MasterTempoFade.time;
|
|
s32 tempo = au_bgm_bpm_to_tempo(player, player->seqCmdArgs.MasterTempoFade.value);
|
|
|
|
if (time <= 0) {
|
|
time = 1;
|
|
}
|
|
|
|
player->masterTempoTicks = time;
|
|
player->masterTempoTarget = tempo;
|
|
player->masterTempoStep = (tempo - player->masterTempo) / time;
|
|
}
|
|
|
|
void au_BGMCmd_E5_MasterVolumeFade(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
s32 time = player->seqCmdArgs.MasterVolumeFade.time;
|
|
s8_24 volume = player->seqCmdArgs.MasterVolumeFade.value & 0x7F;
|
|
|
|
if (volume != 0) {
|
|
volume = volume << 24;
|
|
}
|
|
|
|
if (time <= 0) {
|
|
time = 1;
|
|
}
|
|
|
|
player->masterVolumeTicks = time;
|
|
player->masterVolumeTarget = volume;
|
|
player->masterVolumeStep = (volume - player->masterVolume) / time;
|
|
}
|
|
|
|
void au_BGMCmd_E8_TrackOverridePatch(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->patch = player->seqCmdArgs.OverridePatch.patch;
|
|
track->instrument = au_get_instrument(player->globals, player->seqCmdArgs.OverridePatch.bank, track->patch, &track->envelope);
|
|
}
|
|
|
|
void au_BGMCmd_E9_InstrumentVolume(BGMPlayer* arg0, BGMPlayerTrack* track) {
|
|
s8_24 volume = arg0->seqCmdArgs.InstrumentVolume.value & 0x7F;
|
|
|
|
if (volume != 0) {
|
|
volume = volume << 24;
|
|
}
|
|
|
|
track->insVolume = volume;
|
|
track->changed.volume = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_F6_InstrumentVolumeLerp(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
s32 time = player->seqCmdArgs.TrackVolumeFade.time;
|
|
s8_24 volume = player->seqCmdArgs.TrackVolumeFade.value & 0x7F;
|
|
|
|
if (volume != 0) {
|
|
volume = volume << 24;
|
|
}
|
|
|
|
if (volume != track->insVolume) {
|
|
if (time <= 0) {
|
|
time = 1;
|
|
}
|
|
|
|
track->insVolumeTicks = time;
|
|
track->insVolumeTarget = volume;
|
|
track->insVolumeStep = (volume - track->insVolume) / time;
|
|
}
|
|
}
|
|
|
|
void au_BGMCmd_EA_InstrumentPan(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->insPan = player->seqCmdArgs.InstrumentPan.value & 0x7F;
|
|
track->randomPanAmount = 0;
|
|
track->changed.pan = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_EB_InstrumentReverb(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->insReverb = player->seqCmdArgs.InstrumentReverb.value & 0x7F;
|
|
track->changed.reverb = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_EC_TrackVolume(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->volume = player->seqCmdArgs.TrackVolume.value & 0x7F;
|
|
track->changed.volume = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_ED_InstrumentCoarseTune(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->insCoarseDetune = player->seqCmdArgs.InstrumentCoarseTune.semitone * AU_SEMITONE_CENTS;
|
|
}
|
|
|
|
void au_BGMCmd_EE_InstrumentFineTune(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->insFineDetune = player->seqCmdArgs.InstrumentFineTune.cent;
|
|
}
|
|
|
|
void au_BGMCmd_EC_TrackDetune(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->detune = player->seqCmdArgs.TrackDetune.cents;
|
|
track->changed.tune = TRUE;
|
|
}
|
|
|
|
void au_BGMCmd_F0_TrackTremolo(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->tremoloDelay = player->seqCmdArgs.TrackTremolo.delay;
|
|
track->tremoloRate = player->seqCmdArgs.TrackTremolo.speed;
|
|
track->tremoloDepth = player->seqCmdArgs.TrackTremolo.depth;
|
|
}
|
|
|
|
void au_BGMCmd_F1_TrackTremoloRate(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->tremoloRate = player->seqCmdArgs.TrackTremoloRate.value;
|
|
}
|
|
|
|
void au_BGMCmd_F2_TrackTremoloDepth(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->tremoloDepth = player->seqCmdArgs.TrackTremoloDepth.value;
|
|
}
|
|
|
|
void au_BGMCmd_F3_TrackTremoloStop(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->tremoloDepth = 0;
|
|
}
|
|
|
|
void au_BGMCmd_F4_SubTrackRandomPan(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
track->insPan = player->seqCmdArgs.RandomPan.pan0 & 0x7F;
|
|
track->randomPanAmount = player->seqCmdArgs.RandomPan.pan1 & 0x7F;
|
|
}
|
|
|
|
void au_BGMCmd_F5_UseInstrument(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
BGMInstrumentInfo* instrument;
|
|
s32 volume;
|
|
u32 insIndex;
|
|
u32 patch;
|
|
u32 bank;
|
|
|
|
insIndex = player->seqCmdArgs.UseInstrument.index;
|
|
if (insIndex < BGM_MAX_INSTRUMNETS) {
|
|
if (insIndex < player->bgmInstrumentCount) {
|
|
instrument = &player->instrumentsInfo[insIndex];
|
|
} else {
|
|
instrument = &player->globals->defaultPRGEntry;
|
|
}
|
|
} else {
|
|
insIndex -= BGM_MAX_INSTRUMNETS;
|
|
if (insIndex < PRG_MAX_COUNT) {
|
|
instrument = &player->globals->dataPRG[insIndex];
|
|
} else {
|
|
instrument = &player->globals->defaultPRGEntry;
|
|
}
|
|
}
|
|
bank = instrument->bankPatch >> 8;
|
|
patch = (u8)instrument->bankPatch;
|
|
volume = instrument->volume & 0x7F;
|
|
track->patch = patch;
|
|
track->instrument = au_get_instrument(player->globals, bank, patch, &track->envelope);
|
|
if (volume != 0) {
|
|
volume <<= 24;
|
|
}
|
|
track->insVolume = volume;
|
|
track->insPan = instrument->pan & 0x7F;
|
|
track->insReverb = instrument->reverb & 0x7F;
|
|
track->insCoarseDetune = instrument->coarseTune * AU_SEMITONE_CENTS;
|
|
track->insFineDetune = instrument->fineTune;
|
|
track->changed.all |= 0x10101; // volume, pan, and reverb
|
|
}
|
|
|
|
void au_BGMCmd_F7_ReverbType(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
u8 index = player->seqCmdArgs.ReverbType.index;
|
|
s8 busID = player->effectIndices[index];
|
|
|
|
if ((index < ARRAY_COUNT(player->effectIndices)) && (busID >= 0)) {
|
|
track->busID = busID;
|
|
} else {
|
|
track->busID = player->busID;
|
|
}
|
|
}
|
|
|
|
void au_BGMCmd_FD_EventTrigger(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
snd_song_trigger_music_event(player->priority, track->index, player->seqCmdArgs.EventTrigger.eventInfo >> 8);
|
|
}
|
|
|
|
// jump to another part of the track and return after a specified read length
|
|
void au_BGMCmd_FE_Detour(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
AuFilePos readPos = AU_FILE_RELATIVE(player->bgmFile, player->seqCmdArgs.Detour.offset);
|
|
|
|
track->detourLength = player->seqCmdArgs.Detour.length;
|
|
track->savedPos = track->bgmReadPos;
|
|
track->bgmReadPos = readPos;
|
|
}
|
|
|
|
// jump to another part of the track, selected by player->branchVar
|
|
void au_BGMCmd_FC_Branch(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
AuFilePos args;
|
|
u32 i;
|
|
|
|
// get jump table
|
|
args = AU_FILE_RELATIVE(player->bgmFile, player->seqCmdArgs.Branch.offset);
|
|
if (player->proxMixID < player->seqCmdArgs.Branch.tableCount) {
|
|
args += player->proxMixID * 3;
|
|
}
|
|
// read new position from jump table
|
|
track->prevReadPos = track->bgmReadPos;
|
|
track->bgmReadPos = AU_FILE_RELATIVE(player->bgmFile, (args[0] << 8) + args[1]);
|
|
track->isDrumTrack = args[2];
|
|
|
|
if (track->proxMixSetChanged) {
|
|
track->proxMixSetChanged = FALSE;
|
|
track->proxVolume = 0;
|
|
for (i = track->firstVoice; i < track->lastVoice; i++) {
|
|
AuVoice* voice = &player->globals->voices[i];
|
|
if ((voice->priority == player->priority) && (voice->cmdPtr != NULL)) {
|
|
au_reset_voice(voice, i);
|
|
}
|
|
}
|
|
}
|
|
if (track->proxMixValChanged) {
|
|
track->proxMixValChanged = FALSE;
|
|
au_bgm_set_prox_mix_fade(player, track, player->proxMixVolume, 144);
|
|
}
|
|
// reset an odd subset of parameters
|
|
track->insCoarseDetune = 0;
|
|
track->insFineDetune = 0;
|
|
track->pressOverride = 0;
|
|
track->detune = 0;
|
|
track->tremoloDepth = 0;
|
|
track->insVolumeTicks = 0;
|
|
track->randomPanAmount = 0;
|
|
track->busID = player->busID;
|
|
}
|
|
|
|
void au_BGMCmd_FF_Special(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
u32 writePos;
|
|
u8 delaySide;
|
|
u8 delayTime;
|
|
u32 i;
|
|
|
|
u32 type = player->seqCmdArgs.Special.type;
|
|
u32 arg1 = player->seqCmdArgs.Special.arg1;
|
|
u32 arg2 = player->seqCmdArgs.Special.arg2;
|
|
|
|
switch (type) {
|
|
case BGM_SPECIAL_SET_STEREO_DELAY:
|
|
if ((arg1 < ARRAY_COUNT(player->effectIndices)) && ((s8)player->effectIndices[arg1] >= 0)) {
|
|
player->globals->channelDelayBusID = player->effectIndices[arg1];
|
|
if (arg2 != 0) {
|
|
delayTime = arg2 & 0xF;
|
|
delaySide = ((arg2 >> 4) & 1) + 1;
|
|
if ((player->globals->channelDelayTime != delayTime) || (player->globals->channelDelaySide != delaySide)) {
|
|
player->globals->channelDelayTime = delayTime;
|
|
player->globals->channelDelaySide = delaySide;
|
|
player->globals->channelDelayPending = TRUE;
|
|
}
|
|
} else {
|
|
if (player->globals->channelDelaySide != AU_DELAY_CHANNEL_NONE) {
|
|
player->globals->channelDelaySide = AU_DELAY_CHANNEL_NONE;
|
|
player->globals->channelDelayPending = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case BGM_SPECIAL_SEEK_CUSTOM_ENV:
|
|
if (arg1 - 1 < ARRAY_COUNT(player->customPressEnvelopes)) {
|
|
player->writingCustomEnvelope = arg1;
|
|
au_bgm_clear_custom_note_press(player, arg1 - 1);
|
|
} else {
|
|
player->writingCustomEnvelope = 0;
|
|
}
|
|
break;
|
|
case BGM_SPECIAL_WRITE_CUSTOM_ENV:
|
|
i = player->writingCustomEnvelope;
|
|
if (i - 1 < ARRAY_COUNT(player->customPressEnvelopes)) {
|
|
i--; // convert ID --> array index, needed to match
|
|
writePos = player->customEnvelopeWritePos[i];
|
|
if (writePos < ARRAY_COUNT(player->customPressEnvelopes[i]) - 1) {
|
|
if (arg1 >= ARRAY_COUNT(BgmCustomEnvLookup)) {
|
|
player->customPressEnvelopes[i][writePos] = (arg1 << 8) + arg2;
|
|
} else {
|
|
player->customPressEnvelopes[i][writePos] = (BgmCustomEnvLookup[arg1] << 8) + arg2;
|
|
}
|
|
player->customEnvelopeWritePos[i] = writePos + 1;
|
|
}
|
|
}
|
|
break;
|
|
case BGM_SPECIAL_USE_CUSTOM_ENV:
|
|
if (arg1 <= ARRAY_COUNT(player->customPressEnvelopes)) {
|
|
track->pressOverride = arg1;
|
|
} else {
|
|
track->pressOverride = 0;
|
|
}
|
|
break;
|
|
case BGM_SPECIAL_TRIGGER_SOUND:
|
|
if (player->soundManager != NULL) {
|
|
for (i = 0; i < ARRAY_COUNT(player->soundManager->bgmSounds); i++) {
|
|
if ((player->soundManager->bgmSounds[i].index) == 0) {
|
|
player->soundManager->bgmSounds[i].index = arg1;
|
|
player->soundManager->bgmSounds[i].volume =
|
|
((s32)(
|
|
((u32)player->fadeInfo.baseVolume >> 16) *
|
|
((u32)player->fadeInfo.envelopeVolume >> 16)
|
|
) + AU_MAX_VOLUME_16) >> 0x17;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case BGM_SPECIAL_PROX_MIX_OVERRIDE:
|
|
if (arg1 == 0) {
|
|
if (track->proxMixValChanged) {
|
|
track->proxMixValChanged = FALSE;
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
BGMPlayerTrack* otherTrack = &player->tracks[i];
|
|
if (player->proxMixVolume == AU_MAX_VOLUME_8) {
|
|
if (otherTrack->proxVol1 != 0) {
|
|
otherTrack->proxMixValChanged = FALSE;
|
|
au_bgm_set_prox_mix_fade(player, otherTrack, otherTrack->proxVol1, 72);
|
|
}
|
|
} else {
|
|
if (otherTrack->proxVol2 != 0) {
|
|
otherTrack->proxMixValChanged = FALSE;
|
|
au_bgm_set_prox_mix_fade(player, otherTrack, otherTrack->proxVol2, 72);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
track->proxVol1 = arg1;
|
|
track->proxVol2 = arg2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void au_BGMCmd_NOP(BGMPlayer* player, BGMPlayerTrack* track) {
|
|
}
|
|
|
|
/*
|
|
Uses bit masks:
|
|
3F00 = 0011 1111 0000 0000 -> 0011 1111
|
|
000C = 0000 0000 0000 1100 -> 1100 0000
|
|
*/
|
|
static u8 au_bgm_get_random_pan(BGMPlayer* player, u8 pan, u8 amplitude) {
|
|
s32 seed = player->randomValue1;
|
|
s32 tap7 = seed >> 7;
|
|
s32 tap2 = seed >> 2;
|
|
s32 parity = (tap7 + tap2) & 1;
|
|
s32 lo = (seed >> 8) & 0x3F; // bitmask 0x3F00
|
|
s32 hi = (seed << 4) & 0xC0; // bitmask 0x000C
|
|
s32 random = lo + hi;
|
|
s32 base = pan;
|
|
s32 retPan;
|
|
|
|
if (parity) {
|
|
retPan = base + ((amplitude * random) >> 8);
|
|
} else {
|
|
retPan = base - ((amplitude * random) >> 8);
|
|
}
|
|
if (retPan < AU_PAN_MIN) {
|
|
retPan = AU_PAN_MIN;
|
|
} else if (retPan > AU_PAN_MAX) {
|
|
retPan = AU_PAN_MAX;
|
|
}
|
|
return retPan;
|
|
}
|
|
|
|
/*
|
|
Uses bit masks:
|
|
3C0 = 0000 0011 1100 0000 -> 0001 1111
|
|
03C = 0000 0000 0011 1100 -> 1110 0000
|
|
*/
|
|
static s16 au_bgm_get_random_pitch(s32 seed, s32 pitch, u8 amplitude) {
|
|
s32 tap4 = seed >> 4;
|
|
s32 tap1 = seed >> 1;
|
|
s32 parity = (tap4 + tap1) & 1;
|
|
s32 lo = (seed >> 6) & 0xF; // bitmask 0x3C0
|
|
s32 hi = (seed << 2) & 0xF0; // bitmask 0x03C
|
|
s32 random = lo + hi;
|
|
s32 retVal;
|
|
|
|
if (parity) {
|
|
retVal = pitch + ((amplitude * 5 * random) >> 8);
|
|
} else {
|
|
retVal = pitch - ((amplitude * 5 * random) >> 8);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
/*
|
|
Uses bit masks:
|
|
1F00 = 0001 1111 0000 0000 -> 0001 1111
|
|
00E0 = 0000 0000 1110 0000 -> 1110 0000
|
|
*/
|
|
static u8 au_bgm_get_random_vol(s32 seed, u8 volume, u8 amplitude) {
|
|
s32 lo = (seed >> 8) & 0x1F; // bitmask 0x1F00
|
|
s32 hi = seed & 0xE0;
|
|
s32 random = lo + hi;
|
|
|
|
return volume * (0x8000 - amplitude * random);
|
|
}
|
|
|
|
/*
|
|
Uses bit masks:
|
|
0380 = 0000 0011 1000 0000 -> 0000 0111
|
|
001F = 0000 0000 0001 1111 -> 1111 1000
|
|
*/
|
|
static u8 au_bgm_get_random_reverb(s32 seed, u8 reverb, u8 amplitude) {
|
|
s32 lo = (seed >> 7) & 7; // bitmask 0x380
|
|
s32 hi = (seed << 3) & 0xF8; // bitmask 0x01F
|
|
s32 random = lo + hi;
|
|
|
|
return reverb * (0x8000 - (amplitude * random));
|
|
}
|
|
|
|
void au_bgm_set_proximity_mix(s32 songName, u32 mix) {
|
|
BGMPlayer* player;
|
|
BGMPlayerTrack* track;
|
|
s32 changed = FALSE;
|
|
u8 mixID = mix & 0xFF;
|
|
s32 i;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if ((player != NULL) && (player->proxMixValue != mix)) {
|
|
player->proxMixValue = mix;
|
|
if (player->proxMixID != mixID) {
|
|
player->proxMixID = mixID;
|
|
changed = TRUE;
|
|
}
|
|
player->proxMixVolume = (mix >> 0x18) & 0x7F;
|
|
for (i = 0; i < ARRAY_COUNT(player->tracks); i++) {
|
|
track = &player->tracks[i];
|
|
if (changed) {
|
|
track->proxMixSetChanged = TRUE;
|
|
}
|
|
track->proxMixValChanged = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void au_bgm_set_playback_rate(BGMPlayer* player, f32 rate) {
|
|
if (rate > 2.0) {
|
|
rate = 2.0f;
|
|
} else if (rate < 0.25) {
|
|
rate = 0.25f;
|
|
}
|
|
|
|
player->playbackRate = rate;
|
|
player->masterTempo = au_bgm_bpm_to_tempo(player, player->masterTempoBPM);
|
|
player->nextUpdateStep = BGM_TEMPO_TO_UPDATE_UNITS(player->masterTempo);
|
|
player->masterTempoTicks = 0;
|
|
player->masterTempoTarget = 0;
|
|
player->masterTempoStep = 0;
|
|
}
|
|
|
|
void au_bgm_player_set_detune(BGMPlayer* player, s32 detune) {
|
|
if (detune > AU_OCTAVE_CENTS) {
|
|
detune = AU_OCTAVE_CENTS;
|
|
} else if (detune < -2 * AU_OCTAVE_CENTS) {
|
|
detune = -2 * AU_OCTAVE_CENTS;
|
|
}
|
|
|
|
player->detune = detune;
|
|
}
|
|
|
|
void au_bgm_change_track_volume(BGMPlayer* player, s32 trackIdx, s16 time, u8 volume) {
|
|
BGMPlayerTrack* track = &player->tracks[trackIdx];
|
|
|
|
if (track->bgmReadPos != 0) {
|
|
player->seqCmdArgs.TrackVolumeFade.time = time;
|
|
player->seqCmdArgs.TrackVolumeFade.value = volume;
|
|
au_BGMCmd_F6_InstrumentVolumeLerp(player, track);
|
|
}
|
|
}
|
|
|
|
void au_bgm_set_track_volumes(BGMPlayer* player, u8* trackVols, s32 mode) {
|
|
player->trackVolsConfig = trackVols;
|
|
player->bFadeConfigSetsVolume = mode;
|
|
}
|
|
|
|
void au_bgm_set_prox_mix_fade(BGMPlayer* player, BGMPlayerTrack* track, s32 target, s32 duration) {
|
|
if (target != 0) {
|
|
target = AU_VOL_8_TO_16(target);
|
|
}
|
|
if (duration <= 0) {
|
|
duration = 1;
|
|
} else if (duration > 1000) {
|
|
duration = 1000;
|
|
}
|
|
if (target == track->proxVolume) {
|
|
track->proxVolumeTicks = 0;
|
|
return;
|
|
}
|
|
track->proxVolumeTicks = duration;
|
|
track->proxVolumeTarget = target;
|
|
track->proxVolumeStep = ((target << 0x10) - track->proxVolume) / duration;
|
|
}
|
|
|
|
void au_bgm_reset_all_voices(BGMPlayer* player) {
|
|
u8 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(player->globals->voices); i++) {
|
|
AuVoice* voice = &player->globals->voices[i];
|
|
if (voice->priority == player->priority) {
|
|
au_reset_voice(voice, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
AuResult au_bgm_set_linked_tracks(SongSwapLinkedRequest* request) {
|
|
BGMPlayer* player;
|
|
BGMPlayerTrack* track;
|
|
BGMPlayerTrack* linkTrack;
|
|
AuVoice* voice;
|
|
s32 trackIdx;
|
|
s32 voiceIdx;
|
|
s8 oldVolume;
|
|
|
|
s32 songName = request->songName;
|
|
b32 enabled = request->enabled;
|
|
AuResult status = AU_RESULT_OK;
|
|
|
|
if (songName != 0) {
|
|
player = au_bgm_get_player_with_song_name(songName);
|
|
if (player != NULL) {
|
|
for (trackIdx = 0; trackIdx < ARRAY_COUNT(player->tracks); trackIdx++) {
|
|
track = &player->tracks[trackIdx];
|
|
if (track->bgmReadPos != NULL) {
|
|
if (track->linkedTrackID != 0) {
|
|
linkTrack = &player->tracks[track->linkedTrackID - 1];
|
|
if (enabled) {
|
|
if (track->muted) {
|
|
track->muted = FALSE;
|
|
linkTrack->muted = TRUE;
|
|
// release all voices for linked track
|
|
for (voiceIdx = linkTrack->firstVoice; voiceIdx < linkTrack->lastVoice; voiceIdx++) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
if (voice->priority == player->priority) {
|
|
voice->envelope.cmdListRelease = EnvelopeReleaseDefaultFast;
|
|
voice->envelopeFlags |= AU_VOICE_ENV_FLAG_KEY_RELEASED;
|
|
}
|
|
}
|
|
// fade in main track
|
|
oldVolume = track->insVolume >> 24;
|
|
au_BGMCmd_E9_InstrumentVolume(player, track);
|
|
player->seqCmdArgs.raw[0] = 0;
|
|
player->seqCmdArgs.TrackVolumeFade.time = 96;
|
|
player->seqCmdArgs.TrackVolumeFade.value = oldVolume;
|
|
au_BGMCmd_F6_InstrumentVolumeLerp(player, track);
|
|
}
|
|
} else {
|
|
if (!track->muted) {
|
|
track->muted = TRUE;
|
|
linkTrack->muted = FALSE;
|
|
// release all voices for main track
|
|
for (voiceIdx = track->firstVoice; voiceIdx < track->lastVoice; voiceIdx++) {
|
|
voice = &player->globals->voices[voiceIdx];
|
|
if (voice->priority == player->priority) {
|
|
voice->envelope.cmdListRelease = EnvelopeReleaseDefaultFast;
|
|
voice->envelopeFlags |= AU_VOICE_ENV_FLAG_KEY_RELEASED;
|
|
}
|
|
}
|
|
// fade in linked track
|
|
oldVolume = linkTrack->insVolume >> 24;
|
|
au_BGMCmd_E9_InstrumentVolume(player, linkTrack);
|
|
player->seqCmdArgs.raw[0] = 0;
|
|
player->seqCmdArgs.TrackVolumeFade.time = 96;
|
|
player->seqCmdArgs.TrackVolumeFade.value = oldVolume;
|
|
au_BGMCmd_F6_InstrumentVolumeLerp(player, linkTrack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
status = AU_ERROR_SONG_NOT_PLAYING;
|
|
}
|
|
} else {
|
|
status = AU_ERROR_NULL_SONG_NAME;
|
|
}
|
|
|
|
return status;
|
|
}
|