mirror of https://github.com/pmret/papermario.git
440 lines
14 KiB
C
440 lines
14 KiB
C
#include "common.h"
|
|
#include "npc.h"
|
|
#include "audio.h"
|
|
|
|
void bgm_update_volume(void);
|
|
void bgm_set_target_volume(s32 volume);
|
|
|
|
BSS s16 MusicDefaultVolume;
|
|
BSS s16 MusicTargetVolume;
|
|
BSS s16 MusicMaxVolume;
|
|
BSS s16 MusicCurrentVolume;
|
|
|
|
MusicControlData gMusicControlData[2];
|
|
|
|
MusicControlData BlankMusicControlData = {
|
|
.flags = 0,
|
|
.state = MUSIC_STATE_IDLE,
|
|
.fadeOutTime = -1,
|
|
.fadeInTime = 0,
|
|
.fadeStartVolume = 0,
|
|
.fadeEndVolume = 0,
|
|
.requestedSongID = AU_SONG_NONE,
|
|
.variation = -1,
|
|
.songName = -1,
|
|
.battleSongID = 0,
|
|
.battleVariation = 0,
|
|
.savedSongID = 0,
|
|
.savedVariation = 0,
|
|
.savedSongName = 0
|
|
};
|
|
|
|
/// Lists the songs that are forced to use the variation determined by `map.songVariation & 1`.
|
|
/// @see bgm_get_map_default_variation
|
|
s32 SongsUsingVariationFlag[] = {
|
|
SONG_SPECIAL_BATTLE,
|
|
SONG_TUBBA_BLUBBA_BATTLE,
|
|
SONG_JR_TROOPA_BATTLE,
|
|
SONG_YOSHI_KIDS_FOUND,
|
|
SONG_ITEM_UPGRADE,
|
|
SONG_NEW_PARTNER,
|
|
};
|
|
|
|
s16 NextVolumeUpdateTimer = 0;
|
|
|
|
/// If the given song ID is present in SongsUsingVariationFlag, returns the current
|
|
/// map's `songVariation & 1` value. Otherwise, returns -1.
|
|
///
|
|
/// @see SongsUsingVariationFlag
|
|
/// @returns -1: no override; 0: override to variation 0; 1 override to variation 1
|
|
s32 bgm_get_map_default_variation(s32 songID) {
|
|
u32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(SongsUsingVariationFlag); i++) {
|
|
if (SongsUsingVariationFlag[i] == songID) {
|
|
MapConfig* map = &gAreas[gGameStatusPtr->areaID].maps[gGameStatusPtr->mapID];
|
|
|
|
return map->songVariation & 1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void bgm_reset_sequence_players(void) {
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gMusicControlData); i++) {
|
|
gMusicControlData[i] = BlankMusicControlData;
|
|
}
|
|
|
|
MusicTargetVolume = VOL_LEVEL_FULL;
|
|
MusicMaxVolume = VOL_LEVEL_FULL;
|
|
MusicCurrentVolume = VOL_LEVEL_FULL;
|
|
snd_set_bgm_volume(VOL_LEVEL_FULL);
|
|
}
|
|
|
|
void bgm_reset_volume(void) {
|
|
MusicTargetVolume = VOL_LEVEL_FULL;
|
|
MusicMaxVolume = VOL_LEVEL_FULL;
|
|
}
|
|
|
|
//TODO refactor out constants
|
|
void bgm_update_music_control(void) {
|
|
MusicControlData* music = gMusicControlData;
|
|
s32 i = 0;
|
|
s16 stateFadeOut = MUSIC_STATE_AWAIT_FADEOUT;
|
|
s16 pushedFlag = MUSIC_FLAG_PUSHING;
|
|
s32 flags;
|
|
|
|
for (i; i < ARRAY_COUNT(gMusicControlData); i++, music++) {
|
|
switch (music->state) {
|
|
case MUSIC_STATE_IDLE:
|
|
break;
|
|
case MUSIC_STATE_STOP_CURRENT:
|
|
if (music->flags & MUSIC_FLAG_PLAYING) {
|
|
if (music->fadeOutTime < 250) {
|
|
if (!(music->flags & MUSIC_FLAG_PUSHING)) {
|
|
if (snd_song_stop(music->songName) == AU_RESULT_OK) {
|
|
music->state = stateFadeOut;
|
|
}
|
|
} else {
|
|
if (snd_song_push_stop(music->songName) == AU_RESULT_OK) {
|
|
music->state = stateFadeOut;
|
|
}
|
|
}
|
|
} else if (!(music->flags & MUSIC_FLAG_PUSHING)) {
|
|
if (snd_song_request_fade_out(music->songName, music->fadeOutTime, NULL) == AU_RESULT_OK) {
|
|
music->state = stateFadeOut;
|
|
}
|
|
} else {
|
|
if (snd_song_request_push_fade_out(music->songName, 250) == AU_RESULT_OK) {
|
|
music->state = stateFadeOut;
|
|
}
|
|
}
|
|
} else {
|
|
if (music->flags & MUSIC_FLAG_PUSHING) {
|
|
// nothing was playing in this case, so remember to skip the next pop
|
|
music->flags |= MUSIC_FLAG_IGNORE_POP;
|
|
}
|
|
music->flags &= ~pushedFlag;
|
|
music->state = MUSIC_STATE_PLAY_NEXT;
|
|
}
|
|
break;
|
|
case MUSIC_STATE_AWAIT_FADEOUT:
|
|
flags = music->flags;
|
|
music->flags &= ~pushedFlag;
|
|
if (flags & MUSIC_FLAG_PLAYING) {
|
|
if (snd_song_is_playing(music->songName) == AU_RESULT_OK) {
|
|
music->flags &= ~MUSIC_FLAG_PLAYING;
|
|
music->state = MUSIC_STATE_DELAY_2;
|
|
}
|
|
} else {
|
|
music->state = MUSIC_STATE_PLAY_NEXT;
|
|
}
|
|
break;
|
|
case MUSIC_STATE_DELAY_2:
|
|
music->state = MUSIC_STATE_DELAY_1;
|
|
break;
|
|
case MUSIC_STATE_DELAY_1:
|
|
music->state = MUSIC_STATE_PLAY_NEXT;
|
|
break;
|
|
case MUSIC_STATE_PLAY_NEXT:
|
|
if (!(music->flags & MUSIC_FLAG_POPPING)) {
|
|
if (music->requestedSongID <= AU_SONG_NONE) {
|
|
// new song is AU_SONG_NONE, play nothing
|
|
music->state = MUSIC_STATE_IDLE;
|
|
} else {
|
|
music->songName = snd_song_load(music->requestedSongID, i);
|
|
// snd_song_lond may return either songName or an AuResult error code.
|
|
// since song names are 4-character big-endian identifiers packed into an s32, we require
|
|
// the upper half of the return value to be nonzero for songs which loaded without error.
|
|
// this reserves return values from 0 to 0xFFFF for AuResult codes.
|
|
if (music->songName > 0xFFFFU) {
|
|
if ((music->flags & MUSIC_FLAG_FADE_IN_NEXT)) {
|
|
snd_song_request_fade_in(music->songName, music->variation,
|
|
music->fadeInTime, music->fadeStartVolume, music->fadeEndVolume);
|
|
music->flags &= ~MUSIC_FLAG_FADE_IN_NEXT;
|
|
} else {
|
|
// if we aren't fading in, just start at the default volume level
|
|
bgm_set_target_volume(MusicDefaultVolume);
|
|
}
|
|
/// @bug this is called even if we are trying to fade in, immediately overriding any fade parameters
|
|
if (snd_song_request_play(music->songName, music->variation) == AU_RESULT_OK) {
|
|
music->flags |= MUSIC_FLAG_PLAYING;
|
|
music->state = MUSIC_STATE_IDLE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (music->flags & MUSIC_FLAG_IGNORE_POP) {
|
|
music->state = MUSIC_STATE_IDLE;
|
|
music->flags &= ~(MUSIC_FLAG_IGNORE_POP | MUSIC_FLAG_POPPING);
|
|
} else if (snd_song_request_pop(music->savedSongName) == AU_RESULT_OK) {
|
|
music->requestedSongID = music->savedSongID;
|
|
music->variation = music->savedVariation;
|
|
music->songName = music->savedSongName;
|
|
music->state = MUSIC_STATE_IDLE;
|
|
music->flags |= MUSIC_FLAG_PLAYING;
|
|
music->flags &= ~MUSIC_FLAG_POPPING;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
bgm_update_volume();
|
|
}
|
|
|
|
s32 _bgm_set_song(s32 playerIndex, s32 songID, s32 variation, s32 fadeOutTime, s16 volume) {
|
|
MusicControlData* music;
|
|
s32 mapSongVariation;
|
|
|
|
if (gGameStatusPtr->demoState != DEMO_STATE_NONE) {
|
|
return 1;
|
|
}
|
|
|
|
music = &gMusicControlData[playerIndex];
|
|
|
|
if (!gGameStatusPtr->musicEnabled) {
|
|
snd_song_stop(music->songName);
|
|
music->flags &= ~MUSIC_FLAG_PLAYING;
|
|
return 1;
|
|
}
|
|
|
|
mapSongVariation = bgm_get_map_default_variation(songID);
|
|
if (mapSongVariation >= 0) {
|
|
variation = mapSongVariation;
|
|
}
|
|
|
|
if (music->requestedSongID == songID && music->variation == variation) {
|
|
bgm_set_target_volume(volume);
|
|
|
|
if (music->flags & MUSIC_FLAG_PUSHING) {
|
|
snd_song_request_snapshot(music->songName);
|
|
music->flags &= ~MUSIC_FLAG_PUSHING;
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
MusicDefaultVolume = volume;
|
|
music->requestedSongID = songID;
|
|
music->variation = variation;
|
|
music->fadeOutTime = fadeOutTime;
|
|
music->state = MUSIC_STATE_STOP_CURRENT;
|
|
music->flags &= ~MUSIC_FLAG_ENABLE_PROX_MIX;
|
|
|
|
return 1;
|
|
}
|
|
|
|
s32 bgm_set_song(s32 playerIndex, s32 songID, s32 variation, s32 fadeOutTime, s16 volume) {
|
|
gMusicControlData[playerIndex].flags &= ~MUSIC_FLAG_POPPING;
|
|
|
|
return _bgm_set_song(playerIndex, songID, variation, fadeOutTime, volume);
|
|
}
|
|
|
|
b32 bgm_fade_in_song(s32 playerIndex, s32 songID, s32 variation, s32 fadeInTime, s16 fadeStartVolume, s16 fadeEndVolume) {
|
|
MusicControlData* music;
|
|
s32 mapSongVariation;
|
|
|
|
if (gGameStatusPtr->demoState) {
|
|
return TRUE;
|
|
}
|
|
|
|
music = &gMusicControlData[playerIndex];
|
|
|
|
if (!gGameStatusPtr->musicEnabled) {
|
|
snd_song_stop(music->songName);
|
|
music->flags &= ~MUSIC_FLAG_PLAYING;
|
|
return TRUE;
|
|
}
|
|
|
|
mapSongVariation = bgm_get_map_default_variation(songID);
|
|
if (mapSongVariation >= 0) {
|
|
variation = mapSongVariation;
|
|
}
|
|
|
|
music->fadeInTime = fadeInTime;
|
|
music->fadeStartVolume = fadeStartVolume;
|
|
music->fadeEndVolume = fadeEndVolume;
|
|
music->requestedSongID = songID;
|
|
music->variation = variation;
|
|
music->flags |= MUSIC_FLAG_FADE_IN_NEXT;
|
|
music->state = MUSIC_STATE_STOP_CURRENT;
|
|
music->flags &= ~MUSIC_FLAG_ENABLE_PROX_MIX;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
s32 bgm_adjust_proximity(s32 playerIndex, s32 mix, s16 state) {
|
|
MusicControlData* music = &gMusicControlData[playerIndex];
|
|
|
|
if (!(music->flags & MUSIC_FLAG_PLAYING)) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (!(music->flags & MUSIC_FLAG_ENABLE_PROX_MIX)) {
|
|
return FALSE;
|
|
}
|
|
|
|
switch (state) {
|
|
case MUSIC_PROXIMITY_FAR:
|
|
snd_song_set_proximity_mix_far(music->songName, mix);
|
|
break;
|
|
case MUSIC_PROXIMITY_NEAR:
|
|
snd_song_set_proximity_mix_near(music->songName, mix);
|
|
break;
|
|
case MUSIC_PROXIMITY_FULL:
|
|
snd_song_set_proximity_mix_full(music->songName, mix);
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
AuResult bgm_set_track_volumes(s32 playerIndex, s16 trackVolSet) {
|
|
MusicControlData* music = &gMusicControlData[playerIndex];
|
|
|
|
if (!(music->flags & MUSIC_FLAG_PLAYING)) {
|
|
return AU_RESULT_OK;
|
|
}
|
|
|
|
return snd_song_set_track_volumes(music->songName, trackVolSet);
|
|
}
|
|
|
|
AuResult bgm_clear_track_volumes(s32 playerIndex, s16 trackVolSet) {
|
|
MusicControlData* music = &gMusicControlData[playerIndex];
|
|
|
|
if (!(music->flags & MUSIC_FLAG_PLAYING)) {
|
|
return AU_RESULT_OK;
|
|
}
|
|
|
|
return snd_song_clear_track_volumes(music->songName, trackVolSet);
|
|
}
|
|
|
|
AuResult bgm_set_linked_mode(s32 playerIndex, b16 mode) {
|
|
MusicControlData* music = &gMusicControlData[playerIndex];
|
|
|
|
if (!(music->flags & MUSIC_FLAG_PLAYING)) {
|
|
return AU_RESULT_OK;
|
|
}
|
|
|
|
return snd_song_set_linked_mode(music->songName, mode);
|
|
}
|
|
|
|
s32 bgm_init_music_players(void) {
|
|
bgm_set_song(0, AU_SONG_NONE, 0, 250, VOL_LEVEL_FULL);
|
|
bgm_set_song(1, AU_SONG_NONE, 0, 250, VOL_LEVEL_FULL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void bgm_quiet_max_volume(void) {
|
|
MusicMaxVolume = VOL_LEVEL_4;
|
|
}
|
|
|
|
void bgm_reset_max_volume(void) {
|
|
MusicMaxVolume = VOL_LEVEL_FULL;
|
|
}
|
|
|
|
void bgm_set_target_volume(s32 volume) {
|
|
MusicTargetVolume = volume;
|
|
}
|
|
|
|
void bgm_update_volume(void) {
|
|
s16 toVolume;
|
|
|
|
if (NextVolumeUpdateTimer != 0) {
|
|
NextVolumeUpdateTimer--;
|
|
return;
|
|
}
|
|
|
|
toVolume = MusicTargetVolume;
|
|
if (toVolume > MusicMaxVolume) {
|
|
toVolume = MusicMaxVolume;
|
|
}
|
|
|
|
if (MusicCurrentVolume != toVolume) {
|
|
if (MusicCurrentVolume >= toVolume) {
|
|
MusicCurrentVolume--;
|
|
} else {
|
|
MusicCurrentVolume++;
|
|
}
|
|
snd_set_bgm_volume(MusicCurrentVolume);
|
|
NextVolumeUpdateTimer = 3;
|
|
}
|
|
}
|
|
|
|
b32 bgm_is_any_song_playing(void) {
|
|
MusicControlData* music = gMusicControlData;
|
|
s32 i;
|
|
|
|
for (i = 0; i < ARRAY_COUNT(gMusicControlData); i++, music++) {
|
|
if (music->flags & MUSIC_FLAG_PLAYING) {
|
|
if (snd_song_is_playing(music->songName)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void bgm_pop_song(void) {
|
|
MusicControlData* music = gMusicControlData;
|
|
|
|
if (gGameStatusPtr->demoState == DEMO_STATE_NONE) {
|
|
music->flags |= MUSIC_FLAG_POPPING;
|
|
_bgm_set_song(0, music->savedSongID, music->savedVariation, 0, VOL_LEVEL_FULL);
|
|
}
|
|
}
|
|
|
|
void bgm_push_song(s32 songID, s32 variation) {
|
|
MusicControlData* music = gMusicControlData;
|
|
|
|
if (gGameStatusPtr->demoState == DEMO_STATE_NONE) {
|
|
music->savedSongID = music->requestedSongID;
|
|
music->savedVariation = music->variation;
|
|
music->savedSongName = music->songName;
|
|
music->flags |= MUSIC_FLAG_PUSHING;
|
|
bgm_set_song(0, songID, variation, 500, VOL_LEVEL_FULL);
|
|
}
|
|
}
|
|
|
|
void bgm_pop_battle_song(void) {
|
|
MusicControlData* music = gMusicControlData;
|
|
|
|
if (gGameStatusPtr->demoState == DEMO_STATE_NONE) {
|
|
if (gOverrideFlags & GLOBAL_OVERRIDES_DONT_RESUME_SONG_AFTER_BATTLE) {
|
|
gOverrideFlags &= ~GLOBAL_OVERRIDES_DONT_RESUME_SONG_AFTER_BATTLE;
|
|
} else {
|
|
music->flags |= MUSIC_FLAG_POPPING;
|
|
_bgm_set_song(0, music->savedSongID, music->savedVariation, 0, VOL_LEVEL_FULL);
|
|
snd_ambient_resume(0, 250);
|
|
}
|
|
}
|
|
}
|
|
|
|
void bgm_push_battle_song(void) {
|
|
MusicControlData* music = gMusicControlData;
|
|
|
|
if (gGameStatusPtr->demoState == DEMO_STATE_NONE) {
|
|
if (!(gOverrideFlags & GLOBAL_OVERRIDES_DONT_RESUME_SONG_AFTER_BATTLE)) {
|
|
snd_ambient_pause(0, 250);
|
|
music->savedSongID = music->requestedSongID;
|
|
music->savedVariation = music->variation;
|
|
music->savedSongName = music->songName;
|
|
music->flags |= MUSIC_FLAG_PUSHING;
|
|
bgm_set_song(0, music->battleSongID, music->battleVariation, 500, VOL_LEVEL_FULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
void bgm_set_battle_song(s32 songID, s32 variation) {
|
|
MusicControlData* music = gMusicControlData;
|
|
|
|
music->battleSongID = songID;
|
|
music->battleVariation = variation;
|
|
}
|
|
|
|
void bgm_NOOP(void) {
|
|
}
|