-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5d8c4ac
commit 882af85
Showing
31 changed files
with
5,937 additions
and
5,826 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,49 @@ | ||
#ifndef GUARD_BARD_MUSIC_H | ||
#define GUARD_BARD_MUSIC_H | ||
|
||
#define BARD_SOUND_MAX_LENGTH 6 | ||
// The maximum number of BardSoundTemplates/BardSounds there can be for each easy chat word. | ||
#define MAX_BARD_SOUNDS_PER_WORD 6 | ||
|
||
struct BardSound | ||
// The number of pitch tables there are for each pitch table size (see sPitchTables). | ||
#define NUM_BARD_PITCH_TABLES_PER_SIZE 5 | ||
|
||
// This struct describes which phoneme song to play for the sound, and whether to | ||
// make any adjustments to its length or volume. Very few sounds make any adjustments. | ||
struct BardSoundTemplate | ||
{ | ||
/*0x00*/ u8 songLengthId; | ||
/*0x01*/ s8 songLengthOffset; | ||
/*0x02*/ u16 unused; | ||
/*0x04*/ s16 volume; | ||
/*0x06*/ u16 unused2; | ||
u8 songId; | ||
s8 lengthAdjustment; | ||
u16 unused; // Only set on EC_WORD_WAAAH, and never read. | ||
s16 volume; | ||
}; | ||
|
||
struct BardPhoneme | ||
// This is the length and pitch to play the phoneme song at. | ||
// These will be calculated in 'CalcWordSounds'. | ||
struct BardSound | ||
{ | ||
/*0x00*/ u16 length; | ||
/*0x02*/ u16 pitch; | ||
u16 length; | ||
u16 pitch; | ||
}; | ||
|
||
struct BardSong | ||
{ | ||
/*0x00*/ u8 currWord; | ||
/*0x01*/ u8 currPhoneme; | ||
/*0x02*/ u8 phonemeTimer; | ||
/*0x03*/ u8 state; | ||
/*0x04*/ s16 length; | ||
/*0x06*/ u16 volume; | ||
/*0x08*/ s16 pitch; | ||
/*0x0A*/ s16 voiceInflection; | ||
/*0x0C*/ u16 lyrics[NUM_BARD_SONG_WORDS]; | ||
/*0x18*/ struct BardPhoneme phonemes[BARD_SOUND_MAX_LENGTH]; | ||
/*0x30*/ const struct BardSound *sound; | ||
u8 lyricsIndex; | ||
u8 soundIndex; | ||
u8 timer; | ||
u8 state; | ||
s16 length; // Length of the sound for the word currently being sung (i.e. the sum of 'length' in all the current word's phonemes). | ||
u16 volume; | ||
s16 pitch; | ||
s16 voiceInflection; | ||
u16 lyrics[NUM_BARD_SONG_WORDS]; | ||
struct BardSound sounds[MAX_BARD_SOUNDS_PER_WORD]; | ||
const struct BardSoundTemplate *soundTemplates; | ||
}; | ||
|
||
extern const u16 gNumBardWords_Species; | ||
extern const u16 gNumBardWords_Moves; | ||
const struct BardSound *GetWordSounds(u16 word); | ||
void GetWordPhonemes(struct BardSong *song, u16 word); | ||
|
||
const struct BardSoundTemplate *GetWordSoundTemplates(u16 easyChatWord); | ||
void CalcWordSounds(struct BardSong *song, u16 pitchTableIndex); | ||
|
||
#endif //GUARD_BARD_MUSIC_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,63 +1,247 @@ | ||
#include "global.h" | ||
#include "bard_music.h" | ||
#include "easy_chat.h" | ||
#include "constants/songs.h" | ||
|
||
#include "data/bard_music/bard_sounds.h" | ||
#include "data/bard_music/word_pitch.h" | ||
#include "data/bard_music/default_sound.h" | ||
#include "data/bard_music/length_table.h" | ||
// Indicates that the previous sound should be held. | ||
#define PREV_BARD_SOUND { .songId = NUM_PHONEME_SONGS } | ||
|
||
static s16 CalcWordPitch(int pitchIdx, int songPos) | ||
// Invalid sound, indicates the end of the sounds for the word. | ||
#define NULL_BARD_SOUND { .songId = PHONEME_ID_NONE } | ||
|
||
#include "data/bard_music/pokemon.h" | ||
#include "data/bard_music/moves.h" | ||
#include "data/bard_music/trainer.h" | ||
#include "data/bard_music/status.h" | ||
#include "data/bard_music/battle.h" | ||
#include "data/bard_music/greetings.h" | ||
#include "data/bard_music/people.h" | ||
#include "data/bard_music/voices.h" | ||
#include "data/bard_music/speech.h" | ||
#include "data/bard_music/endings.h" | ||
#include "data/bard_music/feelings.h" | ||
#include "data/bard_music/conditions.h" | ||
#include "data/bard_music/actions.h" | ||
#include "data/bard_music/lifestyle.h" | ||
#include "data/bard_music/hobbies.h" | ||
#include "data/bard_music/time.h" | ||
#include "data/bard_music/misc.h" | ||
#include "data/bard_music/adjectives.h" | ||
#include "data/bard_music/events.h" | ||
#include "data/bard_music/trendysaying.h" | ||
|
||
static const struct BardSoundTemplate (*const sBardSoundTemplatesTable[EC_NUM_GROUPS])[MAX_BARD_SOUNDS_PER_WORD] = { | ||
[EC_GROUP_POKEMON] = NULL, // Handled by sBardSoundTemplates_Pokemon | ||
[EC_GROUP_TRAINER] = sBardSoundTemplates_Trainer, | ||
[EC_GROUP_STATUS] = sBardSoundTemplates_Status, | ||
[EC_GROUP_BATTLE] = sBardSoundTemplates_Battle, | ||
[EC_GROUP_GREETINGS] = sBardSoundTemplates_Greetings, | ||
[EC_GROUP_PEOPLE] = sBardSoundTemplates_People, | ||
[EC_GROUP_VOICES] = sBardSoundTemplates_Voices, | ||
[EC_GROUP_SPEECH] = sBardSoundTemplates_Speech, | ||
[EC_GROUP_ENDINGS] = sBardSoundTemplates_Endings, | ||
[EC_GROUP_FEELINGS] = sBardSoundTemplates_Feelings, | ||
[EC_GROUP_CONDITIONS] = sBardSoundTemplates_Conditions, | ||
[EC_GROUP_ACTIONS] = sBardSoundTemplates_Actions, | ||
[EC_GROUP_LIFESTYLE] = sBardSoundTemplates_Lifestyle, | ||
[EC_GROUP_HOBBIES] = sBardSoundTemplates_Hobbies, | ||
[EC_GROUP_TIME] = sBardSoundTemplates_Time, | ||
[EC_GROUP_MISC] = sBardSoundTemplates_Misc, | ||
[EC_GROUP_ADJECTIVES] = sBardSoundTemplates_Adjectives, | ||
[EC_GROUP_EVENTS] = sBardSoundTemplates_Events, | ||
[EC_GROUP_MOVE_1] = NULL, // Handled by sBardSoundTemplates_Moves | ||
[EC_GROUP_MOVE_2] = NULL, // Handled by sBardSoundTemplates_Moves | ||
[EC_GROUP_TRENDY_SAYING] = sBardSoundTemplates_TrendySaying, | ||
[EC_GROUP_POKEMON_NATIONAL] = NULL, // Handled by sBardSoundTemplates_Pokemon | ||
}; | ||
|
||
// The pitch tables below will be indexed using the number of BardSoundTemplates per word, so a table is selected | ||
// that has at least MAX_BARD_SOUNDS_PER_WORD pitch values. Curiously they select pitch tables whose size is +1 | ||
// of the maximum number of sounds per word, so the final pitch value (before PITCH_END) isn't used. | ||
// (i.e., 'NUM_BARD_PITCH_TABLES_PER_SIZE * (MAX_BARD_SOUNDS_PER_WORD-1)' would select a sufficiently large table). | ||
#define BASE_PITCH_TABLE_INDEX (NUM_BARD_PITCH_TABLES_PER_SIZE * MAX_BARD_SOUNDS_PER_WORD) | ||
|
||
#define PITCH_END 0x1800 | ||
|
||
static const s16 sPitch1_0[] = { -0x300, PITCH_END }; | ||
static const s16 sPitch1_1[] = { 0x0900, PITCH_END }; | ||
static const s16 sPitch1_2[] = { 0x0100, PITCH_END }; | ||
static const s16 sPitch1_3[] = { 0x0400, PITCH_END }; | ||
static const s16 sPitch1_4[] = { 0x0b00, PITCH_END }; | ||
|
||
static const s16 sPitch2_0[] = { -0x300, -0x100, PITCH_END }; | ||
static const s16 sPitch2_1[] = { -0x300, 0x0200, PITCH_END }; | ||
static const s16 sPitch2_2[] = { 0x0200, 0x0400, PITCH_END }; | ||
static const s16 sPitch2_3[] = { 0x0600, 0x0800, PITCH_END }; | ||
static const s16 sPitch2_4[] = { 0x0900, 0x0800, PITCH_END }; | ||
|
||
static const s16 sPitch3_0[] = { -0x300, -0x100, -0x300, PITCH_END }; | ||
static const s16 sPitch3_1[] = { 0x0400, -0x300, 0x0400, PITCH_END }; | ||
static const s16 sPitch3_2[] = { 0x0900, 0x0800, 0x0600, PITCH_END }; | ||
static const s16 sPitch3_3[] = { 0x0100, 0x0200, 0x0400, PITCH_END }; | ||
static const s16 sPitch3_4[] = { 0x0600, 0x1000, 0x0d00, PITCH_END }; | ||
|
||
static const s16 sPitch4_0[] = { 0x0400, 0x0900, 0x0400, 0x0900, PITCH_END }; | ||
static const s16 sPitch4_1[] = { 0x0900, 0x0400, 0x0d00, 0x0400, PITCH_END }; | ||
static const s16 sPitch4_2[] = { 0x0100, 0x0200, 0x0400, 0x0600, PITCH_END }; | ||
static const s16 sPitch4_3[] = { 0x0800, 0x0600, 0x0400, 0x0200, PITCH_END }; | ||
static const s16 sPitch4_4[] = { 0x0f00, 0x0d00, 0x0b00, 0x0a00, PITCH_END }; | ||
|
||
static const s16 sPitch5_0[] = { -0x300, -0x100, 0x0100, 0x0200, 0x0400, PITCH_END }; | ||
static const s16 sPitch5_1[] = { 0x0900, 0x0800, 0x0600, 0x0400, 0x0200, PITCH_END }; | ||
static const s16 sPitch5_2[] = { 0x0100, 0x0400, 0x0900, 0x0400, 0x0100, PITCH_END }; | ||
static const s16 sPitch5_3[] = { 0x0900, 0x0400, 0x0900, 0x0400, -0x300, PITCH_END }; | ||
static const s16 sPitch5_4[] = { 0x0b00, 0x0800, 0x0400, 0x0400, 0x0600, PITCH_END }; | ||
|
||
static const s16 sPitch6_0[] = { -0x300, -0x100, 0x0100, 0x0200, 0x0400, 0x0600, PITCH_END }; | ||
static const s16 sPitch6_1[] = { 0x0800, 0x0600, 0x0400, 0x0200, 0x0100, -0x100, PITCH_END }; | ||
static const s16 sPitch6_2[] = { 0x0100, 0x0200, 0x0400, 0x0100, 0x0200, 0x1000, PITCH_END }; | ||
static const s16 sPitch6_3[] = { 0x0400, -0x300, 0x0900, 0x0400, 0x0900, 0x0400, PITCH_END }; | ||
static const s16 sPitch6_4[] = { 0x0800, 0x0900, 0x0800, 0x0900, 0x0800, 0x0900, PITCH_END }; | ||
|
||
static const s16 sPitch7_0[] = { 0x0200, 0x0100, 0x0200, 0x0100, 0x0200, 0x0400, 0x0200, PITCH_END }; | ||
static const s16 sPitch7_1[] = { 0x0100, 0x0100, -0x100, -0x100, -0x300, 0x0400, -0x300, PITCH_END }; | ||
static const s16 sPitch7_2[] = { 0x0800, 0x0900, 0x0b00, 0x0d00, 0x0e00, 0x0d00, 0x0b00, PITCH_END }; | ||
static const s16 sPitch7_3[] = { 0x0800, 0x0600, 0x0400, 0x0200, 0x0d00, 0x0b00, 0x0900, PITCH_END }; | ||
static const s16 sPitch7_4[] = { 0x0300, 0x0400, 0x0600, 0x0800, 0x0700, 0x0800, 0x0400, PITCH_END }; | ||
|
||
// In practice only sPitch7_# below are used below. | ||
// BASE_PITCH_TABLE_INDEX is 30 by default, and this table is always indexed with (x + 30), where x is some value 0 - 4 | ||
static const s16 *const sPitchTables[NUM_BARD_PITCH_TABLES_PER_SIZE * 7] = { | ||
sPitch1_0, sPitch1_1, sPitch1_2, sPitch1_3, sPitch1_4, | ||
sPitch2_0, sPitch2_1, sPitch2_2, sPitch2_3, sPitch2_4, | ||
sPitch3_0, sPitch3_1, sPitch3_2, sPitch3_3, sPitch3_4, | ||
sPitch4_0, sPitch4_1, sPitch4_2, sPitch4_3, sPitch4_4, | ||
sPitch5_0, sPitch5_1, sPitch5_2, sPitch5_3, sPitch5_4, | ||
sPitch6_0, sPitch6_1, sPitch6_2, sPitch6_3, sPitch6_4, | ||
sPitch7_0, sPitch7_1, sPitch7_2, sPitch7_3, sPitch7_4 | ||
}; | ||
|
||
// If this fails, CalcWordSounds will likely read out of bounds for sPitchTables. | ||
STATIC_ASSERT(BASE_PITCH_TABLE_INDEX + (NUM_BARD_PITCH_TABLES_PER_SIZE-1) < ARRAY_COUNT(sPitchTables), NotEnoughPitchTablesForBardSounds) | ||
|
||
static const struct BardSoundTemplate sEmptyPhonemeTemplate[] = { | ||
NULL_BARD_SOUND, | ||
NULL_BARD_SOUND, | ||
NULL_BARD_SOUND, | ||
NULL_BARD_SOUND, | ||
NULL_BARD_SOUND, | ||
NULL_BARD_SOUND | ||
}; | ||
|
||
static const int sPhonemeLengths[NUM_PHONEME_SONGS + 1] = { | ||
[PHONEME_ID(PH_TRAP_BLEND)] = 9, | ||
[PHONEME_ID(PH_TRAP_HELD)] = 22, | ||
[PHONEME_ID(PH_TRAP_SOLO)] = 15, | ||
[PHONEME_ID(PH_FACE_BLEND)] = 16, | ||
[PHONEME_ID(PH_FACE_HELD)] = 39, | ||
[PHONEME_ID(PH_FACE_SOLO)] = 21, | ||
[PHONEME_ID(PH_CLOTH_BLEND)] = 9, | ||
[PHONEME_ID(PH_CLOTH_HELD)] = 30, | ||
[PHONEME_ID(PH_CLOTH_SOLO)] = 24, | ||
[PHONEME_ID(PH_DRESS_BLEND)] = 15, | ||
[PHONEME_ID(PH_DRESS_HELD)] = 25, | ||
[PHONEME_ID(PH_DRESS_SOLO)] = 12, | ||
[PHONEME_ID(PH_FLEECE_BLEND)] = 22, | ||
[PHONEME_ID(PH_FLEECE_HELD)] = 45, | ||
[PHONEME_ID(PH_FLEECE_SOLO)] = 24, | ||
[PHONEME_ID(PH_KIT_BLEND)] = 15, | ||
[PHONEME_ID(PH_KIT_HELD)] = 40, | ||
[PHONEME_ID(PH_KIT_SOLO)] = 9, | ||
[PHONEME_ID(PH_PRICE_BLEND)] = 21, | ||
[PHONEME_ID(PH_PRICE_HELD)] = 42, | ||
[PHONEME_ID(PH_PRICE_SOLO)] = 18, | ||
[PHONEME_ID(PH_LOT_BLEND)] = 9, | ||
[PHONEME_ID(PH_LOT_HELD)] = 22, | ||
[PHONEME_ID(PH_LOT_SOLO)] = 15, | ||
[PHONEME_ID(PH_GOAT_BLEND)] = 27, | ||
[PHONEME_ID(PH_GOAT_HELD)] = 48, | ||
[PHONEME_ID(PH_GOAT_SOLO)] = 18, | ||
[PHONEME_ID(PH_THOUGHT_BLEND)] = 27, | ||
[PHONEME_ID(PH_THOUGHT_HELD)] = 33, | ||
[PHONEME_ID(PH_THOUGHT_SOLO)] = 24, | ||
[PHONEME_ID(PH_CHOICE_BLEND)] = 25, | ||
[PHONEME_ID(PH_CHOICE_HELD)] = 39, | ||
[PHONEME_ID(PH_CHOICE_SOLO)] = 19, | ||
[PHONEME_ID(PH_MOUTH_BLEND)] = 16, | ||
[PHONEME_ID(PH_MOUTH_HELD)] = 54, | ||
[PHONEME_ID(PH_MOUTH_SOLO)] = 18, | ||
[PHONEME_ID(PH_FOOT_BLEND)] = 9, | ||
[PHONEME_ID(PH_FOOT_HELD)] = 45, | ||
[PHONEME_ID(PH_FOOT_SOLO)] = 15, | ||
[PHONEME_ID(PH_GOOSE_BLEND)] = 12, | ||
[PHONEME_ID(PH_GOOSE_HELD)] = 39, | ||
[PHONEME_ID(PH_GOOSE_SOLO)] = 23, | ||
[PHONEME_ID(PH_STRUT_BLEND)] = 5, | ||
[PHONEME_ID(PH_STRUT_HELD)] = 45, | ||
[PHONEME_ID(PH_STRUT_SOLO)] = 12, | ||
[PHONEME_ID(PH_CURE_BLEND)] = 21, | ||
[PHONEME_ID(PH_CURE_HELD)] = 48, | ||
[PHONEME_ID(PH_CURE_SOLO)] = 12, | ||
[PHONEME_ID(PH_NURSE_BLEND)] = 21, | ||
[PHONEME_ID(PH_NURSE_HELD)] = 69, | ||
[PHONEME_ID(PH_NURSE_SOLO)] = 18, | ||
[NUM_PHONEME_SONGS] = 15, // This is the length that will be used by PREV_BARD_SOUND to hold the previous phoneme sound. | ||
}; | ||
|
||
static s16 GetWordPitch(int tableIndex, int pitchIndex) | ||
{ | ||
return sBardSoundPitchTables[pitchIdx][songPos]; | ||
return sPitchTables[tableIndex][pitchIndex]; | ||
} | ||
|
||
const struct BardSound *GetWordSounds(u16 word) | ||
const struct BardSoundTemplate *GetWordSoundTemplates(u16 easyChatWord) | ||
{ | ||
u32 category; | ||
u32 subword; | ||
const struct BardSound (*ptr)[BARD_SOUND_MAX_LENGTH]; | ||
const struct BardSoundTemplate (*ptr)[MAX_BARD_SOUNDS_PER_WORD]; | ||
|
||
if (IsBardWordInvalid(word)) | ||
{ | ||
return gBardSound_InvalidWord; | ||
} | ||
category = EC_GROUP(word); | ||
subword = EC_INDEX(word); | ||
if (IsBardWordInvalid(easyChatWord)) | ||
return sEmptyPhonemeTemplate; | ||
|
||
category = EC_GROUP(easyChatWord); | ||
subword = EC_INDEX(easyChatWord); | ||
switch (category) | ||
{ | ||
case EC_GROUP_POKEMON: | ||
case EC_GROUP_POKEMON_NATIONAL: | ||
ptr = gBardSounds_Pokemon; | ||
ptr = sBardSoundTemplates_Pokemon; | ||
break; | ||
case EC_GROUP_MOVE_1: | ||
case EC_GROUP_MOVE_2: | ||
ptr = gBardSounds_Moves; | ||
ptr = sBardSoundTemplates_Moves; | ||
break; | ||
default: | ||
ptr = gBardSoundsTable[category]; | ||
ptr = sBardSoundTemplatesTable[category]; | ||
break; | ||
} | ||
ptr += subword; | ||
return *ptr; | ||
} | ||
|
||
void GetWordPhonemes(struct BardSong *song, u16 word) | ||
// Assumes that 'soundTemplates' has already been loaded with the BardSoundTemplates for the easy chat word to calculate sounds for. | ||
// 'pitchTableIndex' is chosen depending on the easy chat word, but is essentially an arbitrary value 0-4. | ||
void CalcWordSounds(struct BardSong *song, u16 pitchTableIndex) | ||
{ | ||
int i; | ||
const struct BardSound *sound; | ||
const struct BardSoundTemplate *template; | ||
|
||
song->length = 0; | ||
for (i = 0; i < BARD_SOUND_MAX_LENGTH; i ++) | ||
|
||
for (i = 0; i < MAX_BARD_SOUNDS_PER_WORD; i ++) | ||
{ | ||
sound = &song->sound[i]; | ||
if (sound->songLengthId != 0xFF) | ||
template = &song->soundTemplates[i]; | ||
if (template->songId != PHONEME_ID_NONE) | ||
{ | ||
song->phonemes[i].length = sound->songLengthOffset + gBardSoundLengthTable[sound->songLengthId]; | ||
song->phonemes[i].pitch = CalcWordPitch(word + 30, i); | ||
song->length += song->phonemes[i].length; | ||
// Calculate the length and pitch of each phoneme in this word. | ||
// A phoneme's length is always the same, and depends on the phoneme song and any adjustments in the template. | ||
// Its pitch changes depending on the easy chat word and where in the list of templates the phoneme appears. | ||
song->sounds[i].length = template->lengthAdjustment + sPhonemeLengths[template->songId]; | ||
song->sounds[i].pitch = GetWordPitch(pitchTableIndex + BASE_PITCH_TABLE_INDEX, i); | ||
|
||
// Add this phoneme's length to the total sound length for this word. | ||
song->length += song->sounds[i].length; | ||
} | ||
} | ||
song->currPhoneme = 0; | ||
song->soundIndex = 0; | ||
song->voiceInflection = 0; | ||
} |
Oops, something went wrong.