mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-11-25 05:25:14 +00:00
Fixed various audio bugs; DynOS can now detect texture duplicates to decrease generated bin files size (#110)
Fixed the following audio bugs: Bug: Rom-hacks sequences don't seem to be affected by volume scaling and muting Fix: Force the BGM sequences to follow the vanilla behavior: Volume can't go higher than default volume Volume is reduced to 31% when the game is paused Audio is stopped when the game is paused outside the Castle levels Bug: (Pointed out by Draco) Mario's voice clips are not replaced by the player's character's in the following instances: fall to death barrier, "here we go" in the ending cutscene, "let's a go" after selecting a star, "okey dokey" after starting the game. Fix: The first two ones now call play_character_sound(m, CHAR_SOUND_...) instead of play_sound(SOUND_MARIO_..., pos). The last two ones couldn't be fixed the same way for two reasons: First, the corresponding sounds were not referenced in the sound table, second, the sound played is always cut-off after a few frames (due to how sm64 resets the sound banks after loading a level). Added SOUND_*_LETS_A_GO and SOUND_*_OKEY_DOKEY sounds for each playable character as Bass samples. Character Bass sounds work the same way as vanilla sounds (i.e. can be played with play_character_sound), but they cannot be prematurely stopped by sm64 sound banks shenanigans. This fixes the cut-off for both the star select and the castle grounds entry, plays the sound corresponding to the player's character, and doesn't need to extend or edit the sound table. DynOS can detect texture duplicates when generating a bin or lvl file. When a duplicate is detected, the name of the original texture node is written instead of the whole PNG data, decreasing significantly the resulting file size.
This commit is contained in:
parent
f63bffc64c
commit
4fbafc2708
20 changed files with 255 additions and 36 deletions
4
Makefile
4
Makefile
|
@ -1194,6 +1194,7 @@ ifeq ($(TARGET_N64),1)
|
||||||
$(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin
|
$(BUILD_DIR)/lib/rsp.o: $(BUILD_DIR)/rsp/rspboot.bin $(BUILD_DIR)/rsp/fast3d.bin $(BUILD_DIR)/rsp/audio.bin
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
$(BUILD_DIR)/src/game/characters.o: $(SOUND_SAMPLE_TABLES)
|
||||||
$(SOUND_BIN_DIR)/sound_data.o: $(SOUND_BIN_DIR)/sound_data.ctl.inc.c $(SOUND_BIN_DIR)/sound_data.tbl.inc.c $(SOUND_BIN_DIR)/sequences.bin.inc.c $(SOUND_BIN_DIR)/bank_sets.inc.c
|
$(SOUND_BIN_DIR)/sound_data.o: $(SOUND_BIN_DIR)/sound_data.ctl.inc.c $(SOUND_BIN_DIR)/sound_data.tbl.inc.c $(SOUND_BIN_DIR)/sequences.bin.inc.c $(SOUND_BIN_DIR)/bank_sets.inc.c
|
||||||
$(BUILD_DIR)/levels/scripts.o: $(BUILD_DIR)/include/level_headers.h
|
$(BUILD_DIR)/levels/scripts.o: $(BUILD_DIR)/include/level_headers.h
|
||||||
|
|
||||||
|
@ -1321,6 +1322,9 @@ endif
|
||||||
$(BUILD_DIR)/%.table: %.aiff
|
$(BUILD_DIR)/%.table: %.aiff
|
||||||
$(call print,Extracting codebook:,$<,$@)
|
$(call print,Extracting codebook:,$<,$@)
|
||||||
$(V)$(AIFF_EXTRACT_CODEBOOK) $< >$@
|
$(V)$(AIFF_EXTRACT_CODEBOOK) $< >$@
|
||||||
|
$(call print,Piping:,$<,$@.inc.c)
|
||||||
|
$(V)hexdump -v -e '1/1 "0x%X,"' $< > $@.inc.c
|
||||||
|
$(V)echo >> $@.inc.c
|
||||||
|
|
||||||
$(BUILD_DIR)/%.aifc: $(BUILD_DIR)/%.table %.aiff
|
$(BUILD_DIR)/%.aifc: $(BUILD_DIR)/%.table %.aiff
|
||||||
$(call print,Encoding VADPCM:,$<,$@)
|
$(call print,Encoding VADPCM:,$<,$@)
|
||||||
|
|
|
@ -2615,7 +2615,13 @@ CHAR_SOUND_SO_LONGA_BOWSER = 40
|
||||||
CHAR_SOUND_IMA_TIRED = 41
|
CHAR_SOUND_IMA_TIRED = 41
|
||||||
|
|
||||||
--- @type CharacterSound
|
--- @type CharacterSound
|
||||||
CHAR_SOUND_MAX = 42
|
CHAR_SOUND_LETS_A_GO = 42
|
||||||
|
|
||||||
|
--- @type CharacterSound
|
||||||
|
CHAR_SOUND_OKEY_DOKEY = 43
|
||||||
|
|
||||||
|
--- @type CharacterSound
|
||||||
|
CHAR_SOUND_MAX = 44
|
||||||
|
|
||||||
--- @class CharacterType
|
--- @class CharacterType
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,9 @@
|
||||||
--- @field public soundHoohoo integer
|
--- @field public soundHoohoo integer
|
||||||
--- @field public soundHrmm integer
|
--- @field public soundHrmm integer
|
||||||
--- @field public soundImaTired integer
|
--- @field public soundImaTired integer
|
||||||
|
--- @field public soundLetsAGo integer
|
||||||
--- @field public soundMamaMia integer
|
--- @field public soundMamaMia integer
|
||||||
|
--- @field public soundOkeyDokey integer
|
||||||
--- @field public soundOnFire integer
|
--- @field public soundOnFire integer
|
||||||
--- @field public soundOoof integer
|
--- @field public soundOoof integer
|
||||||
--- @field public soundOoof2 integer
|
--- @field public soundOoof2 integer
|
||||||
|
|
|
@ -11,6 +11,7 @@ extern "C" {
|
||||||
#define FUNCTION_CODE (u32) 0x434E5546
|
#define FUNCTION_CODE (u32) 0x434E5546
|
||||||
#define POINTER_CODE (u32) 0x52544E50
|
#define POINTER_CODE (u32) 0x52544E50
|
||||||
#define LUA_VAR_CODE (u32) 0x5641554C
|
#define LUA_VAR_CODE (u32) 0x5641554C
|
||||||
|
#define TEX_REF_CODE (u32) 0x52584554
|
||||||
|
|
||||||
#define MOD_PACK_INDEX 99
|
#define MOD_PACK_INDEX 99
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,22 @@ void DynOS_Tex_Write(FILE* aFile, GfxData* aGfxData, DataNode<TexData> *aNode) {
|
||||||
aNode->mName.Write(aFile);
|
aNode->mName.Write(aFile);
|
||||||
|
|
||||||
// Data
|
// Data
|
||||||
|
// Look for texture duplicates
|
||||||
|
// If that's the case, store the name of the texture node instead of the whole PNG data
|
||||||
|
// (Don't bother to look for duplicates if there is no data to write)
|
||||||
|
if (!aNode->mData->mPngData.Empty()) {
|
||||||
|
for (const auto& _Node : aGfxData->mTextures) {
|
||||||
|
if (_Node->mLoadIndex < aNode->mLoadIndex && // Check load order: duplicates should reference only an already loaded node
|
||||||
|
_Node->mData != NULL && // Check node data
|
||||||
|
aNode->mData->mPngData.Count() == _Node->mData->mPngData.Count() && // Check PNG data lengths
|
||||||
|
memcmp(aNode->mData->mPngData.begin(), _Node->mData->mPngData.begin(), aNode->mData->mPngData.Count()) == 0) // Check PNG data content
|
||||||
|
{
|
||||||
|
WriteBytes<u32>(aFile, TEX_REF_CODE);
|
||||||
|
_Node->mName.Write(aFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
aNode->mData->mPngData.Write(aFile);
|
aNode->mData->mPngData.Write(aFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,19 +236,41 @@ DataNode<TexData>* DynOS_Tex_Load(FILE *aFile, GfxData *aGfxData) {
|
||||||
// Data
|
// Data
|
||||||
_Node->mData = New<TexData>();
|
_Node->mData = New<TexData>();
|
||||||
_Node->mData->mUploaded = false;
|
_Node->mData->mUploaded = false;
|
||||||
_Node->mData->mPngData.Read(aFile);
|
|
||||||
if (!_Node->mData->mPngData.Empty()) {
|
// Check for the texture ref magic
|
||||||
u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4);
|
s32 _FileOffset = (s32) ftell(aFile);
|
||||||
_Node->mData->mRawFormat = G_IM_FMT_RGBA;
|
u32 _TexRefCode = ReadBytes<u32>(aFile);
|
||||||
_Node->mData->mRawSize = G_IM_SIZ_32b;
|
if (_TexRefCode == TEX_REF_CODE) {
|
||||||
_Node->mData->mRawData = Array<u8>(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4));
|
|
||||||
free(_RawData);
|
// That's a duplicate, find the original node and copy its content
|
||||||
} else { // Probably a palette
|
String _NodeName; _NodeName.Read(aFile);
|
||||||
_Node->mData->mRawData = Array<u8>();
|
for (const auto& _LoadedNode : aGfxData->mTextures) {
|
||||||
_Node->mData->mRawWidth = 0;
|
if (_LoadedNode->mName == _NodeName) {
|
||||||
_Node->mData->mRawHeight = 0;
|
_Node->mData->mPngData = _LoadedNode->mData->mPngData;
|
||||||
_Node->mData->mRawFormat = 0;
|
_Node->mData->mRawData = _LoadedNode->mData->mRawData;
|
||||||
_Node->mData->mRawSize = 0;
|
_Node->mData->mRawWidth = _LoadedNode->mData->mRawWidth;
|
||||||
|
_Node->mData->mRawHeight = _LoadedNode->mData->mRawHeight;
|
||||||
|
_Node->mData->mRawFormat = _LoadedNode->mData->mRawFormat;
|
||||||
|
_Node->mData->mRawSize = _LoadedNode->mData->mRawSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fseek(aFile, _FileOffset, SEEK_SET);
|
||||||
|
_Node->mData->mPngData.Read(aFile);
|
||||||
|
if (!_Node->mData->mPngData.Empty()) {
|
||||||
|
u8 *_RawData = stbi_load_from_memory(_Node->mData->mPngData.begin(), _Node->mData->mPngData.Count(), &_Node->mData->mRawWidth, &_Node->mData->mRawHeight, NULL, 4);
|
||||||
|
_Node->mData->mRawFormat = G_IM_FMT_RGBA;
|
||||||
|
_Node->mData->mRawSize = G_IM_SIZ_32b;
|
||||||
|
_Node->mData->mRawData = Array<u8>(_RawData, _RawData + (_Node->mData->mRawWidth * _Node->mData->mRawHeight * 4));
|
||||||
|
free(_RawData);
|
||||||
|
} else { // Probably a palette
|
||||||
|
_Node->mData->mRawData = Array<u8>();
|
||||||
|
_Node->mData->mRawWidth = 0;
|
||||||
|
_Node->mData->mRawHeight = 0;
|
||||||
|
_Node->mData->mRawFormat = 0;
|
||||||
|
_Node->mData->mRawSize = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Append
|
// Append
|
||||||
|
|
|
@ -836,7 +836,9 @@
|
||||||
| CHAR_SOUND_SNORING3 | 39 |
|
| CHAR_SOUND_SNORING3 | 39 |
|
||||||
| CHAR_SOUND_SO_LONGA_BOWSER | 40 |
|
| CHAR_SOUND_SO_LONGA_BOWSER | 40 |
|
||||||
| CHAR_SOUND_IMA_TIRED | 41 |
|
| CHAR_SOUND_IMA_TIRED | 41 |
|
||||||
| CHAR_SOUND_MAX | 42 |
|
| CHAR_SOUND_LETS_A_GO | 42 |
|
||||||
|
| CHAR_SOUND_OKEY_DOKEY | 43 |
|
||||||
|
| CHAR_SOUND_MAX | 44 |
|
||||||
|
|
||||||
### [enum CharacterType](#CharacterType)
|
### [enum CharacterType](#CharacterType)
|
||||||
| Identifier | Value |
|
| Identifier | Value |
|
||||||
|
|
|
@ -436,7 +436,9 @@
|
||||||
| soundHoohoo | `integer` | read-only |
|
| soundHoohoo | `integer` | read-only |
|
||||||
| soundHrmm | `integer` | read-only |
|
| soundHrmm | `integer` | read-only |
|
||||||
| soundImaTired | `integer` | read-only |
|
| soundImaTired | `integer` | read-only |
|
||||||
|
| soundLetsAGo | `integer` | read-only |
|
||||||
| soundMamaMia | `integer` | read-only |
|
| soundMamaMia | `integer` | read-only |
|
||||||
|
| soundOkeyDokey | `integer` | read-only |
|
||||||
| soundOnFire | `integer` | read-only |
|
| soundOnFire | `integer` | read-only |
|
||||||
| soundOoof | `integer` | read-only |
|
| soundOoof | `integer` | read-only |
|
||||||
| soundOoof2 | `integer` | read-only |
|
| soundOoof2 | `integer` | read-only |
|
||||||
|
|
|
@ -63,6 +63,16 @@ static void sequence_channel_process_sound(struct SequenceChannel *seqChannel) {
|
||||||
f32 panFromChannel;
|
f32 panFromChannel;
|
||||||
s32 i;
|
s32 i;
|
||||||
|
|
||||||
|
// Rom-hacks audio fix
|
||||||
|
// Force the BGM sequence channels to follow the BGM sequence player mute behavior
|
||||||
|
// Make the audio completely silent if MUTE_BEHAVIOR_STOP_SCRIPT or MUTE_BEHAVIOR_STOP_NOTES is set
|
||||||
|
if (seqChannel->seqPlayer == &gSequencePlayers[0]) {
|
||||||
|
seqChannel->muteBehavior = seqChannel->seqPlayer->muteBehavior;
|
||||||
|
if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES)) != 0) {
|
||||||
|
seqChannel->seqPlayer->muteVolumeScale = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
channelVolume = seqChannel->volume * seqChannel->volumeScale *
|
channelVolume = seqChannel->volume * seqChannel->volumeScale *
|
||||||
seqChannel->seqPlayer->fadeVolume * seqChannel->seqPlayer->volumeScale;
|
seqChannel->seqPlayer->fadeVolume * seqChannel->seqPlayer->volumeScale;
|
||||||
if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) {
|
if (seqChannel->seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_SOFTEN) != 0) {
|
||||||
|
|
|
@ -2356,6 +2356,21 @@ void play_dialog_sound(u8 dialogID) {
|
||||||
|
|
||||||
void set_sequence_player_volume(s32 player, f32 volume) {
|
void set_sequence_player_volume(s32 player, f32 volume) {
|
||||||
gSequencePlayers[player].volumeScale = volume;
|
gSequencePlayers[player].volumeScale = volume;
|
||||||
|
|
||||||
|
// Rom-hacks audio fix
|
||||||
|
// Custom sequences tend to ignore volume scaling and muting...
|
||||||
|
// Force the BGM sequence player to follow the Vanilla behavior:
|
||||||
|
// - Volume can't go higher than default volume
|
||||||
|
// - Volume is reduced to 31% when the game is paused
|
||||||
|
// - Audio is stopped when the game is paused outside the Castle levels
|
||||||
|
if (player == SEQ_PLAYER_LEVEL && sCurrentBackgroundMusicSeqId != 0xff) {
|
||||||
|
struct SequencePlayer *seqPlayer = &gSequencePlayers[player];
|
||||||
|
f32 maxVolume = get_current_background_music_default_volume() / 127.f;
|
||||||
|
seqPlayer->volume = MIN(seqPlayer->volume, maxVolume);
|
||||||
|
seqPlayer->fadeVolume = MIN(seqPlayer->fadeVolume, maxVolume);
|
||||||
|
seqPlayer->muteVolumeScale = 0.31f;
|
||||||
|
seqPlayer->muteBehavior = MUTE_BEHAVIOR_SOFTEN | ((gCurrCourseNum != 0) * (MUTE_BEHAVIOR_STOP_SCRIPT | MUTE_BEHAVIOR_STOP_NOTES));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2509,6 +2524,13 @@ u16 get_current_background_music(void) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 get_current_background_music_default_volume(void) {
|
||||||
|
if (sCurrentBackgroundMusicSeqId != 0xff) {
|
||||||
|
return sBackgroundMusicDefaultVolume[sCurrentBackgroundMusicSeqId];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
u8 get_current_background_music_target_volume(void) {
|
u8 get_current_background_music_target_volume(void) {
|
||||||
return sBackgroundMusicTargetVolume;
|
return sBackgroundMusicTargetVolume;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ void stop_background_music(u16 seqId);
|
||||||
void fadeout_background_music(u16 arg0, u16 fadeOut);
|
void fadeout_background_music(u16 arg0, u16 fadeOut);
|
||||||
void drop_queued_background_music(void);
|
void drop_queued_background_music(void);
|
||||||
u16 get_current_background_music(void);
|
u16 get_current_background_music(void);
|
||||||
|
u8 get_current_background_music_default_volume(void);
|
||||||
u8 get_current_background_music_target_volume(void);
|
u8 get_current_background_music_target_volume(void);
|
||||||
u8 get_current_background_music_max_target_volume(void);
|
u8 get_current_background_music_max_target_volume(void);
|
||||||
u8 is_current_background_music_volume_lowered(void);
|
u8 is_current_background_music_volume_lowered(void);
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "pc/configfile.h"
|
#include "pc/configfile.h"
|
||||||
#include "audio/external.h"
|
#include "audio/external.h"
|
||||||
#include "engine/graph_node.h"
|
#include "engine/graph_node.h"
|
||||||
#include "types.h"
|
#include "characters_bass_sounds.h"
|
||||||
|
|
||||||
extern Gfx mario_cap_seg3_dl_03022F48[];
|
extern Gfx mario_cap_seg3_dl_03022F48[];
|
||||||
extern Gfx luigi_cap_seg3_dl_03022F48[];
|
extern Gfx luigi_cap_seg3_dl_03022F48[];
|
||||||
|
@ -87,6 +87,8 @@ struct Character gCharacters[CT_MAX] = {
|
||||||
.soundSnoring3 = SOUND_MARIO_SNORING3,
|
.soundSnoring3 = SOUND_MARIO_SNORING3,
|
||||||
.soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER,
|
.soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER,
|
||||||
.soundImaTired = SOUND_MARIO_IMA_TIRED,
|
.soundImaTired = SOUND_MARIO_IMA_TIRED,
|
||||||
|
.soundLetsAGo = CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO),
|
||||||
|
.soundOkeyDokey = CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY),
|
||||||
},
|
},
|
||||||
|
|
||||||
[CT_LUIGI] = {
|
[CT_LUIGI] = {
|
||||||
|
@ -150,6 +152,8 @@ struct Character gCharacters[CT_MAX] = {
|
||||||
.soundSnoring3 = SOUND_LUIGI_SNORING3,
|
.soundSnoring3 = SOUND_LUIGI_SNORING3,
|
||||||
.soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER,
|
.soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER,
|
||||||
.soundImaTired = SOUND_LUIGI_IMA_TIRED,
|
.soundImaTired = SOUND_LUIGI_IMA_TIRED,
|
||||||
|
.soundLetsAGo = CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO),
|
||||||
|
.soundOkeyDokey = CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY),
|
||||||
},
|
},
|
||||||
|
|
||||||
[CT_TOAD] = {
|
[CT_TOAD] = {
|
||||||
|
@ -213,6 +217,8 @@ struct Character gCharacters[CT_MAX] = {
|
||||||
.soundSnoring3 = SOUND_MARIO_SNORING3,
|
.soundSnoring3 = SOUND_MARIO_SNORING3,
|
||||||
.soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER,
|
.soundSoLongaBowser = SOUND_MARIO_SO_LONGA_BOWSER,
|
||||||
.soundImaTired = SOUND_MARIO_IMA_TIRED,
|
.soundImaTired = SOUND_MARIO_IMA_TIRED,
|
||||||
|
.soundLetsAGo = CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO),
|
||||||
|
.soundOkeyDokey = CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY),
|
||||||
},
|
},
|
||||||
|
|
||||||
[CT_WALUIGI] = {
|
[CT_WALUIGI] = {
|
||||||
|
@ -279,6 +285,8 @@ struct Character gCharacters[CT_MAX] = {
|
||||||
.soundSnoring3 = SOUND_LUIGI_SNORING3,
|
.soundSnoring3 = SOUND_LUIGI_SNORING3,
|
||||||
.soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER,
|
.soundSoLongaBowser = SOUND_LUIGI_SO_LONGA_BOWSER,
|
||||||
.soundImaTired = SOUND_LUIGI_IMA_TIRED,
|
.soundImaTired = SOUND_LUIGI_IMA_TIRED,
|
||||||
|
.soundLetsAGo = CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO),
|
||||||
|
.soundOkeyDokey = CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY),
|
||||||
},
|
},
|
||||||
|
|
||||||
[CT_WARIO] = {
|
[CT_WARIO] = {
|
||||||
|
@ -342,6 +350,8 @@ struct Character gCharacters[CT_MAX] = {
|
||||||
.soundSnoring3 = SOUND_WARIO_SNORING3,
|
.soundSnoring3 = SOUND_WARIO_SNORING3,
|
||||||
.soundSoLongaBowser = SOUND_WARIO_SO_LONGA_BOWSER,
|
.soundSoLongaBowser = SOUND_WARIO_SO_LONGA_BOWSER,
|
||||||
.soundImaTired = SOUND_WARIO_IMA_TIRED,
|
.soundImaTired = SOUND_WARIO_IMA_TIRED,
|
||||||
|
.soundLetsAGo = CHAR_BASS_SOUND(SOUND_WARIO_LETS_A_GO),
|
||||||
|
.soundOkeyDokey = CHAR_BASS_SOUND(SOUND_WARIO_OKEY_DOKEY),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -450,29 +460,41 @@ static s32 get_character_sound(struct MarioState* m, enum CharacterSound charact
|
||||||
case CHAR_SOUND_SNORING3: return character->soundSnoring3;
|
case CHAR_SOUND_SNORING3: return character->soundSnoring3;
|
||||||
case CHAR_SOUND_SO_LONGA_BOWSER: return character->soundSoLongaBowser;
|
case CHAR_SOUND_SO_LONGA_BOWSER: return character->soundSoLongaBowser;
|
||||||
case CHAR_SOUND_IMA_TIRED: return character->soundImaTired;
|
case CHAR_SOUND_IMA_TIRED: return character->soundImaTired;
|
||||||
|
case CHAR_SOUND_LETS_A_GO: return character->soundLetsAGo;
|
||||||
|
case CHAR_SOUND_OKEY_DOKEY: return character->soundOkeyDokey;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void play_character_sound_internal(struct MarioState *m, enum CharacterSound characterSound, u32 offset, u32 flags) {
|
||||||
|
if (m != NULL && (m->flags & flags) == 0) {
|
||||||
|
s32 sound = get_character_sound(m, characterSound);
|
||||||
|
if (sound != 0) {
|
||||||
|
struct Character* character = get_character(m);
|
||||||
|
f32 *pos = (m->marioObj != NULL ? m->marioObj->header.gfx.cameraToObject : gGlobalSoundSource);
|
||||||
|
if ((u32) (sound & CHAR_BASS_MAGIC) == CHAR_BASS_MAGIC) {
|
||||||
|
CharacterBassSound *cbs = get_character_bass_sound(sound);
|
||||||
|
if (cbs != NULL) {
|
||||||
|
play_character_bass_sound(cbs, pos, character->soundFreqScale);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
play_sound_with_freq_scale(sound + offset, pos, character->soundFreqScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m->flags |= flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void play_character_sound(struct MarioState* m, enum CharacterSound characterSound) {
|
void play_character_sound(struct MarioState* m, enum CharacterSound characterSound) {
|
||||||
s32 sound = get_character_sound(m, characterSound);
|
play_character_sound_internal(m, characterSound, 0, 0);
|
||||||
if (sound == 0) { return; }
|
|
||||||
struct Character* character = get_character(m);
|
|
||||||
play_sound_with_freq_scale(sound, m->marioObj->header.gfx.cameraToObject, character->soundFreqScale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void play_character_sound_offset(struct MarioState* m, enum CharacterSound characterSound, u32 offset) {
|
void play_character_sound_offset(struct MarioState* m, enum CharacterSound characterSound, u32 offset) {
|
||||||
s32 sound = get_character_sound(m, characterSound);
|
play_character_sound_internal(m, characterSound, offset, 0);
|
||||||
if (sound == 0) { return; }
|
|
||||||
struct Character* character = get_character(m);
|
|
||||||
play_sound_with_freq_scale(sound + offset, m->marioObj->header.gfx.cameraToObject, character->soundFreqScale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void play_character_sound_if_no_flag(struct MarioState* m, enum CharacterSound characterSound, u32 flags) {
|
void play_character_sound_if_no_flag(struct MarioState* m, enum CharacterSound characterSound, u32 flags) {
|
||||||
if ((m->flags & flags) == 0) {
|
play_character_sound_internal(m, characterSound, 0, flags);
|
||||||
play_character_sound(m, characterSound);
|
|
||||||
m->flags |= flags;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
f32 get_character_anim_offset(struct MarioState* m) {
|
f32 get_character_anim_offset(struct MarioState* m) {
|
||||||
|
|
|
@ -81,6 +81,8 @@ struct Character {
|
||||||
s32 soundSnoring3;
|
s32 soundSnoring3;
|
||||||
s32 soundSoLongaBowser;
|
s32 soundSoLongaBowser;
|
||||||
s32 soundImaTired;
|
s32 soundImaTired;
|
||||||
|
s32 soundLetsAGo;
|
||||||
|
s32 soundOkeyDokey;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CharacterSound {
|
enum CharacterSound {
|
||||||
|
@ -126,6 +128,8 @@ enum CharacterSound {
|
||||||
CHAR_SOUND_SNORING3,
|
CHAR_SOUND_SNORING3,
|
||||||
CHAR_SOUND_SO_LONGA_BOWSER,
|
CHAR_SOUND_SO_LONGA_BOWSER,
|
||||||
CHAR_SOUND_IMA_TIRED,
|
CHAR_SOUND_IMA_TIRED,
|
||||||
|
CHAR_SOUND_LETS_A_GO,
|
||||||
|
CHAR_SOUND_OKEY_DOKEY,
|
||||||
CHAR_SOUND_MAX // MUST BE LAST
|
CHAR_SOUND_MAX // MUST BE LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
99
src/game/characters_bass_sounds.h
Normal file
99
src/game/characters_bass_sounds.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include "types.h"
|
||||||
|
#include "bass/bass.h"
|
||||||
|
#include "game/camera.h"
|
||||||
|
#undef min // Redefined in math_util.h, undef it to avoid compiler warnings
|
||||||
|
#undef max // Redefined in math_util.h, undef it to avoid compiler warnings
|
||||||
|
#include "engine/math_util.h"
|
||||||
|
|
||||||
|
#define H01(s, i, x) (x * 65599u + (u8) s[(i) < sizeof(s) ? (i) : sizeof(s)])
|
||||||
|
#define H04(s, i, x) H01(s, i, H01(s, i + 1, H01(s, i + 2, H01(s, i + 3, x))))
|
||||||
|
#define H16(s, i, x) H04(s, i, H04(s, i + 4, H04(s, i + 8, H04(s, i + 12, x))))
|
||||||
|
#define H64(s, i, x) H16(s, i, H16(s, i + 16, H16(s, i + 32, H16(s, i + 48, x))))
|
||||||
|
#define CHAR_BASS_MAGIC 0xFF000000u
|
||||||
|
#define CHAR_BASS_SOUND_ID(name) (H64(#name "________________________________________________________________", 0, 0) & ~CHAR_BASS_MAGIC)
|
||||||
|
#define CHAR_BASS_SOUND(name) (CHAR_BASS_MAGIC | CHAR_BASS_SOUND_ID(name))
|
||||||
|
#define CHAR_BASS_SOUND_NOT_LOADED 0xFFFFFFFFu
|
||||||
|
#define DECL_CHAR_BASS_SOUND_RAW(name, ...) static const u8 sCharacterBassSoundRaw_##name[] =
|
||||||
|
#define DECL_CHAR_BASS_SOUND(name) { CHAR_BASS_SOUND(name), (s32) sizeof(sCharacterBassSoundRaw_##name), sCharacterBassSoundRaw_##name, CHAR_BASS_SOUND_NOT_LOADED, 0.f }
|
||||||
|
|
||||||
|
// Undef these to avoid naming issues
|
||||||
|
#undef SOUND_MARIO_LETS_A_GO
|
||||||
|
#undef SOUND_LUIGI_LETS_A_GO
|
||||||
|
#undef SOUND_WARIO_LETS_A_GO
|
||||||
|
#undef SOUND_MARIO_OKEY_DOKEY
|
||||||
|
#undef SOUND_LUIGI_OKEY_DOKEY
|
||||||
|
#undef SOUND_WARIO_OKEY_DOKEY
|
||||||
|
|
||||||
|
/////////////////
|
||||||
|
// Bass sounds //
|
||||||
|
/////////////////
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_MARIO_LETS_A_GO) {
|
||||||
|
#include "sound/samples/sfx_mario/1A_mario_lets_a_go.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_LUIGI_LETS_A_GO) {
|
||||||
|
#include "sound/samples/sfx_custom_luigi/1A.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_WARIO_LETS_A_GO) {
|
||||||
|
#include "sound/samples/sfx_custom_wario/1A.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_MARIO_OKEY_DOKEY) {
|
||||||
|
#include "sound/samples/sfx_mario_peach/0B_mario_okey_dokey.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_LUIGI_OKEY_DOKEY) {
|
||||||
|
#include "sound/samples/sfx_custom_luigi_peach/0B.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
DECL_CHAR_BASS_SOUND_RAW(SOUND_WARIO_OKEY_DOKEY) {
|
||||||
|
#include "sound/samples/sfx_custom_wario_peach/0B.table.inc.c"
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////
|
||||||
|
// Bass sounds table //
|
||||||
|
///////////////////////
|
||||||
|
|
||||||
|
typedef struct { s32 sound; s32 size; const u8 *raw; HSAMPLE sample; f32 freq; } CharacterBassSound;
|
||||||
|
static CharacterBassSound sCharacterBassSounds[] = {
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_MARIO_LETS_A_GO),
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_LUIGI_LETS_A_GO),
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_WARIO_LETS_A_GO),
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_MARIO_OKEY_DOKEY),
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_LUIGI_OKEY_DOKEY),
|
||||||
|
DECL_CHAR_BASS_SOUND(SOUND_WARIO_OKEY_DOKEY),
|
||||||
|
{ 0, 0, NULL, CHAR_BASS_SOUND_NOT_LOADED, 0.f },
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
// Bass sounds functions //
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
static CharacterBassSound *get_character_bass_sound(s32 sound) {
|
||||||
|
for (CharacterBassSound *cbs = sCharacterBassSounds; cbs->raw != NULL; cbs++) {
|
||||||
|
if (cbs->sound == sound) {
|
||||||
|
return cbs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void play_character_bass_sound(CharacterBassSound *cbs, f32 *pos, f32 freqScale) {
|
||||||
|
if (cbs->sample == CHAR_BASS_SOUND_NOT_LOADED) {
|
||||||
|
cbs->sample = BASS_SampleLoad(TRUE, cbs->raw, 0, cbs->size, 32, BASS_SAMPLE_OVER_POS);
|
||||||
|
BASS_SAMPLE info; BASS_SampleGetInfo(cbs->sample, &info);
|
||||||
|
cbs->freq = info.freq;
|
||||||
|
}
|
||||||
|
DWORD handle = BASS_SampleGetChannel(cbs->sample, 0);
|
||||||
|
f32 dist = vec3f_length(pos);
|
||||||
|
f32 pan = (get_sound_pan(pos[0], pos[2]) - 0.5f) * 2.f;
|
||||||
|
f32 intensity = sound_get_level_intensity(dist);
|
||||||
|
f32 masterVolume = (f32) configMasterVolume / 127.f;
|
||||||
|
f32 sfxVolume = (f32) configSfxVolume / 127.f;
|
||||||
|
BASS_ChannelSetAttribute(handle, BASS_ATTRIB_VOL, masterVolume * sfxVolume * intensity * 0.75f);
|
||||||
|
BASS_ChannelSetAttribute(handle, BASS_ATTRIB_PAN, pan);
|
||||||
|
BASS_ChannelSetAttribute(handle, BASS_ATTRIB_FREQ, cbs->freq * freqScale);
|
||||||
|
BASS_ChannelPlay(handle, TRUE);
|
||||||
|
}
|
|
@ -2237,7 +2237,7 @@ void check_death_barrier(struct MarioState *m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (level_trigger_warp(m, WARP_OP_WARP_FLOOR) == 20 && !(m->flags & MARIO_UNKNOWN_18)) {
|
if (level_trigger_warp(m, WARP_OP_WARP_FLOOR) == 20 && !(m->flags & MARIO_UNKNOWN_18)) {
|
||||||
play_sound(SOUND_MARIO_WAAAOOOW, m->marioObj->header.gfx.cameraToObject);
|
play_character_sound(m, CHAR_SOUND_WAAAOOOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,8 +319,7 @@ void play_sound_and_spawn_particles(struct MarioState *m, u32 soundBits, u32 wav
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m->flags & MARIO_METAL_CAP) || soundBits == SOUND_ACTION_UNSTUCK_FROM_GROUND
|
if ((m->flags & MARIO_METAL_CAP) || soundBits == SOUND_ACTION_UNSTUCK_FROM_GROUND) {
|
||||||
|| soundBits == SOUND_MARIO_PUNCH_HOO || soundBits == SOUND_LUIGI_PUNCH_HOO) {
|
|
||||||
play_sound(soundBits, m->marioObj->header.gfx.cameraToObject);
|
play_sound(soundBits, m->marioObj->header.gfx.cameraToObject);
|
||||||
} else {
|
} else {
|
||||||
play_sound(m->terrainSoundAddend + soundBits, m->marioObj->header.gfx.cameraToObject);
|
play_sound(m->terrainSoundAddend + soundBits, m->marioObj->header.gfx.cameraToObject);
|
||||||
|
|
|
@ -2643,7 +2643,7 @@ static void end_peach_cutscene_star_dance(struct MarioState *m) {
|
||||||
cutscene_put_cap_on(m);
|
cutscene_put_cap_on(m);
|
||||||
}
|
}
|
||||||
if (animFrame == 88 && m->playerIndex == 0) {
|
if (animFrame == 88 && m->playerIndex == 0) {
|
||||||
play_sound(SOUND_MARIO_HERE_WE_GO, m->marioObj->header.gfx.cameraToObject);
|
play_character_sound(m, CHAR_SOUND_HERE_WE_GO);
|
||||||
}
|
}
|
||||||
if (!nonMario && animFrame >= 98) {
|
if (!nonMario && animFrame >= 98) {
|
||||||
m->marioBodyState->handState = MARIO_HAND_PEACE_SIGN;
|
m->marioBodyState->handState = MARIO_HAND_PEACE_SIGN;
|
||||||
|
|
|
@ -501,7 +501,9 @@ void star_select_finish_selection(void) {
|
||||||
#if defined(VERSION_JP)
|
#if defined(VERSION_JP)
|
||||||
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
|
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
|
||||||
#else
|
#else
|
||||||
play_sound(SOUND_MENU_STAR_SOUND_LETS_A_GO, gGlobalSoundSource);
|
if (gMarioState->marioObj) vec3f_copy(gMarioState->marioObj->header.gfx.cameraToObject, gGlobalSoundSource);
|
||||||
|
play_character_sound(gMarioState, CHAR_SOUND_LETS_A_GO);
|
||||||
|
play_sound(SOUND_MENU_STAR_SOUND, gGlobalSoundSource);
|
||||||
#endif
|
#endif
|
||||||
#ifdef VERSION_SH
|
#ifdef VERSION_SH
|
||||||
queue_rumble_data(60, 70);
|
queue_rumble_data(60, 70);
|
||||||
|
|
|
@ -46,7 +46,8 @@ void djui_panel_host_message_do_host(UNUSED struct DjuiBase* caller) {
|
||||||
fake_lvl_init_from_save_file();
|
fake_lvl_init_from_save_file();
|
||||||
extern s16 gChangeLevelTransition;
|
extern s16 gChangeLevelTransition;
|
||||||
gChangeLevelTransition = gLevelValues.entryLevel;
|
gChangeLevelTransition = gLevelValues.entryLevel;
|
||||||
play_sound(SOUND_MENU_STAR_SOUND_OKEY_DOKEY, gGlobalSoundSource);
|
if (gMarioState->marioObj) vec3f_copy(gMarioState->marioObj->header.gfx.cameraToObject, gGlobalSoundSource);
|
||||||
|
play_character_sound(gMarioState, CHAR_SOUND_OKEY_DOKEY);
|
||||||
extern void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);
|
extern void play_transition(s16 transType, s16 time, u8 red, u8 green, u8 blue);
|
||||||
play_transition(0x09, 0x14, 0x00, 0x00, 0x00);
|
play_transition(0x09, 0x14, 0x00, 0x00, 0x00);
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ static struct LuaObjectField sChainSegmentFields[LUA_CHAIN_SEGMENT_FIELD_COUNT]
|
||||||
{ "yaw", LVT_S16, offsetof(struct ChainSegment, yaw), false, LOT_NONE },
|
{ "yaw", LVT_S16, offsetof(struct ChainSegment, yaw), false, LOT_NONE },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define LUA_CHARACTER_FIELD_COUNT 59
|
#define LUA_CHARACTER_FIELD_COUNT 61
|
||||||
static struct LuaObjectField sCharacterFields[LUA_CHARACTER_FIELD_COUNT] = {
|
static struct LuaObjectField sCharacterFields[LUA_CHARACTER_FIELD_COUNT] = {
|
||||||
{ "animOffsetEnabled", LVT_U8, offsetof(struct Character, animOffsetEnabled), true, LOT_NONE },
|
{ "animOffsetEnabled", LVT_U8, offsetof(struct Character, animOffsetEnabled), true, LOT_NONE },
|
||||||
{ "animOffsetFeet", LVT_F32, offsetof(struct Character, animOffsetFeet), true, LOT_NONE },
|
{ "animOffsetFeet", LVT_F32, offsetof(struct Character, animOffsetFeet), true, LOT_NONE },
|
||||||
|
@ -329,7 +329,9 @@ static struct LuaObjectField sCharacterFields[LUA_CHARACTER_FIELD_COUNT] = {
|
||||||
{ "soundHoohoo", LVT_S32, offsetof(struct Character, soundHoohoo), true, LOT_NONE },
|
{ "soundHoohoo", LVT_S32, offsetof(struct Character, soundHoohoo), true, LOT_NONE },
|
||||||
{ "soundHrmm", LVT_S32, offsetof(struct Character, soundHrmm), true, LOT_NONE },
|
{ "soundHrmm", LVT_S32, offsetof(struct Character, soundHrmm), true, LOT_NONE },
|
||||||
{ "soundImaTired", LVT_S32, offsetof(struct Character, soundImaTired), true, LOT_NONE },
|
{ "soundImaTired", LVT_S32, offsetof(struct Character, soundImaTired), true, LOT_NONE },
|
||||||
|
{ "soundLetsAGo", LVT_S32, offsetof(struct Character, soundLetsAGo), true, LOT_NONE },
|
||||||
{ "soundMamaMia", LVT_S32, offsetof(struct Character, soundMamaMia), true, LOT_NONE },
|
{ "soundMamaMia", LVT_S32, offsetof(struct Character, soundMamaMia), true, LOT_NONE },
|
||||||
|
{ "soundOkeyDokey", LVT_S32, offsetof(struct Character, soundOkeyDokey), true, LOT_NONE },
|
||||||
{ "soundOnFire", LVT_S32, offsetof(struct Character, soundOnFire), true, LOT_NONE },
|
{ "soundOnFire", LVT_S32, offsetof(struct Character, soundOnFire), true, LOT_NONE },
|
||||||
{ "soundOoof", LVT_S32, offsetof(struct Character, soundOoof), true, LOT_NONE },
|
{ "soundOoof", LVT_S32, offsetof(struct Character, soundOoof), true, LOT_NONE },
|
||||||
{ "soundOoof2", LVT_S32, offsetof(struct Character, soundOoof2), true, LOT_NONE },
|
{ "soundOoof2", LVT_S32, offsetof(struct Character, soundOoof2), true, LOT_NONE },
|
||||||
|
|
|
@ -1071,7 +1071,9 @@ char gSmluaConstants[] = ""
|
||||||
"CHAR_SOUND_SNORING3 = 39\n"
|
"CHAR_SOUND_SNORING3 = 39\n"
|
||||||
"CHAR_SOUND_SO_LONGA_BOWSER = 40\n"
|
"CHAR_SOUND_SO_LONGA_BOWSER = 40\n"
|
||||||
"CHAR_SOUND_IMA_TIRED = 41\n"
|
"CHAR_SOUND_IMA_TIRED = 41\n"
|
||||||
"CHAR_SOUND_MAX = 42\n"
|
"CHAR_SOUND_LETS_A_GO = 42\n"
|
||||||
|
"CHAR_SOUND_OKEY_DOKEY = 43\n"
|
||||||
|
"CHAR_SOUND_MAX = 44\n"
|
||||||
"DIALOG_000 = 0\n"
|
"DIALOG_000 = 0\n"
|
||||||
"DIALOG_001 = 1\n"
|
"DIALOG_001 = 1\n"
|
||||||
"DIALOG_002 = 2\n"
|
"DIALOG_002 = 2\n"
|
||||||
|
|
Loading…
Reference in a new issue