1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
|
#ifndef OCARINA_H
#define OCARINA_H
#include "ultra64.h"
typedef enum OcarinaSongId {
/* 0 */ OCARINA_SONG_MINUET,
/* 1 */ OCARINA_SONG_BOLERO,
/* 2 */ OCARINA_SONG_SERENADE,
/* 3 */ OCARINA_SONG_REQUIEM,
/* 4 */ OCARINA_SONG_NOCTURNE,
/* 5 */ OCARINA_SONG_PRELUDE,
/* 6 */ OCARINA_SONG_SARIAS,
/* 7 */ OCARINA_SONG_EPONAS,
/* 8 */ OCARINA_SONG_LULLABY,
/* 9 */ OCARINA_SONG_SUNS,
/* 10 */ OCARINA_SONG_TIME,
/* 11 */ OCARINA_SONG_STORMS,
/* 12 */ OCARINA_SONG_SCARECROW_SPAWN,
/* 13 */ OCARINA_SONG_MEMORY_GAME,
/* 14 */ OCARINA_SONG_MAX,
/* 14 */ OCARINA_SONG_SCARECROW_LONG = OCARINA_SONG_MAX // anything larger than 13 is considered the long scarecrow's song
} OcarinaSongId;
typedef enum OcarinaSongActionId {
/* 0x00 */ OCARINA_ACTION_UNK_0, // acts like free play but never set
/* 0x01 */ OCARINA_ACTION_FREE_PLAY,
/* 0x02 */ OCARINA_ACTION_TEACH_MINUET, // Song demonstrations by teachers
/* 0x03 */ OCARINA_ACTION_TEACH_BOLERO,
/* 0x04 */ OCARINA_ACTION_TEACH_SERENADE,
/* 0x05 */ OCARINA_ACTION_TEACH_REQUIEM,
/* 0x06 */ OCARINA_ACTION_TEACH_NOCTURNE,
/* 0x07 */ OCARINA_ACTION_TEACH_PRELUDE,
/* 0x08 */ OCARINA_ACTION_TEACH_SARIA,
/* 0x09 */ OCARINA_ACTION_TEACH_EPONA,
/* 0x0A */ OCARINA_ACTION_TEACH_LULLABY,
/* 0x0B */ OCARINA_ACTION_TEACH_SUNS,
/* 0x0C */ OCARINA_ACTION_TEACH_TIME,
/* 0x0D */ OCARINA_ACTION_TEACH_STORMS,
/* 0x0E */ OCARINA_ACTION_UNK_E,
/* 0x0F */ OCARINA_ACTION_PLAYBACK_MINUET, // Playing back a particular song
/* 0x10 */ OCARINA_ACTION_PLAYBACK_BOLERO,
/* 0x11 */ OCARINA_ACTION_PLAYBACK_SERENADE,
/* 0x12 */ OCARINA_ACTION_PLAYBACK_REQUIEM,
/* 0x13 */ OCARINA_ACTION_PLAYBACK_NOCTURNE,
/* 0x14 */ OCARINA_ACTION_PLAYBACK_PRELUDE,
/* 0x15 */ OCARINA_ACTION_PLAYBACK_SARIA,
/* 0x16 */ OCARINA_ACTION_PLAYBACK_EPONA,
/* 0x17 */ OCARINA_ACTION_PLAYBACK_LULLABY,
/* 0x18 */ OCARINA_ACTION_PLAYBACK_SUNS,
/* 0x19 */ OCARINA_ACTION_PLAYBACK_TIME,
/* 0x1A */ OCARINA_ACTION_PLAYBACK_STORMS,
/* 0x1B */ OCARINA_ACTION_UNK_1B,
/* 0x1C */ OCARINA_ACTION_CHECK_MINUET, // Playing songs for check spots
/* 0x1D */ OCARINA_ACTION_CHECK_BOLERO,
/* 0x1E */ OCARINA_ACTION_CHECK_SERENADE,
/* 0x1F */ OCARINA_ACTION_CHECK_REQUIEM,
/* 0x20 */ OCARINA_ACTION_CHECK_NOCTURNE,
/* 0x21 */ OCARINA_ACTION_CHECK_PRELUDE,
/* 0x22 */ OCARINA_ACTION_CHECK_SARIA,
/* 0x23 */ OCARINA_ACTION_CHECK_EPONA,
/* 0x24 */ OCARINA_ACTION_CHECK_LULLABY,
/* 0x25 */ OCARINA_ACTION_CHECK_SUNS,
/* 0x26 */ OCARINA_ACTION_CHECK_TIME,
/* 0x27 */ OCARINA_ACTION_CHECK_STORMS,
/* 0x28 */ OCARINA_ACTION_CHECK_SCARECROW_SPAWN, // Playing back the song as adult that was set as child
/* 0x29 */ OCARINA_ACTION_FREE_PLAY_DONE,
/* 0x2A */ OCARINA_ACTION_SCARECROW_LONG_RECORDING,
/* 0x2B */ OCARINA_ACTION_SCARECROW_LONG_PLAYBACK,
/* 0x2C */ OCARINA_ACTION_SCARECROW_SPAWN_RECORDING,
/* 0x2D */ OCARINA_ACTION_SCARECROW_SPAWN_PLAYBACK,
/* 0x2E */ OCARINA_ACTION_MEMORY_GAME,
/* 0x2F */ OCARINA_ACTION_FROGS,
/* 0x30 */ OCARINA_ACTION_CHECK_NOWARP, // Check for any of sarias - storms
/* 0x31 */ OCARINA_ACTION_CHECK_NOWARP_DONE
} OcarinaSongActionId;
typedef enum OcarinaMode {
/* 0x00 */ OCARINA_MODE_00,
/* 0x01 */ OCARINA_MODE_01,
/* 0x02 */ OCARINA_MODE_02,
/* 0x03 */ OCARINA_MODE_03,
/* 0x04 */ OCARINA_MODE_04,
/* 0x05 */ OCARINA_MODE_05,
/* 0x06 */ OCARINA_MODE_06,
/* 0x07 */ OCARINA_MODE_07,
/* 0x08 */ OCARINA_MODE_08,
/* 0x09 */ OCARINA_MODE_09,
/* 0x0A */ OCARINA_MODE_0A,
/* 0x0B */ OCARINA_MODE_0B,
/* 0x0C */ OCARINA_MODE_0C,
/* 0x0D */ OCARINA_MODE_0D,
/* 0x0E */ OCARINA_MODE_0E,
/* 0x0F */ OCARINA_MODE_0F
} OcarinaMode;
typedef enum OcarinaButtonIndex {
/* 0 */ OCARINA_BTN_A,
/* 1 */ OCARINA_BTN_C_DOWN,
/* 2 */ OCARINA_BTN_C_RIGHT,
/* 3 */ OCARINA_BTN_C_LEFT,
/* 4 */ OCARINA_BTN_C_UP,
/* 5 */ OCARINA_BTN_C_RIGHT_OR_C_LEFT, // Special case for bFlat4: Interface/Overlap between C_RIGHT and C_LEFT
/* 0xFF */ OCARINA_BTN_INVALID = 0xFF
} OcarinaButtonIndex;
// Uses scientific pitch notation relative to middle C
// https://en.wikipedia.org/wiki/Scientific_pitch_notation
typedef enum OcarinaPitch {
/* 0x0 */ OCARINA_PITCH_C4,
/* 0x1 */ OCARINA_PITCH_DFLAT4,
/* 0x2 */ OCARINA_PITCH_D4,
/* 0x3 */ OCARINA_PITCH_EFLAT4,
/* 0x4 */ OCARINA_PITCH_E4,
/* 0x5 */ OCARINA_PITCH_F4,
/* 0x6 */ OCARINA_PITCH_GFLAT4,
/* 0x7 */ OCARINA_PITCH_G4,
/* 0x8 */ OCARINA_PITCH_AFLAT4,
/* 0x9 */ OCARINA_PITCH_A4,
/* 0xA */ OCARINA_PITCH_BFLAT4,
/* 0xB */ OCARINA_PITCH_B4,
/* 0xC */ OCARINA_PITCH_C5,
/* 0xD */ OCARINA_PITCH_DFLAT5,
/* 0xE */ OCARINA_PITCH_D5,
/* 0xF */ OCARINA_PITCH_EFLAT5,
/* 0xFF */ OCARINA_PITCH_NONE = 0xFF
} OcarinaPitch;
typedef enum OcarinaInstrumentId {
/* 0 */ OCARINA_INSTRUMENT_OFF,
/* 1 */ OCARINA_INSTRUMENT_DEFAULT,
/* 2 */ OCARINA_INSTRUMENT_MALON,
/* 3 */ OCARINA_INSTRUMENT_WHISTLE,
/* 4 */ OCARINA_INSTRUMENT_HARP,
/* 5 */ OCARINA_INSTRUMENT_GRIND_ORGAN,
/* 6 */ OCARINA_INSTRUMENT_FLUTE,
/* 7 */ OCARINA_INSTRUMENT_MAX,
/* 7 */ OCARINA_INSTRUMENT_DEFAULT_COPY1 = OCARINA_INSTRUMENT_MAX, // Unused but present in Sequence 0 table
/* 8 */ OCARINA_INSTRUMENT_DEFAULT_COPY2 = OCARINA_INSTRUMENT_MAX + 1 // Unused but present in Sequence 0 table
} OcarinaInstrumentId;
typedef enum OcarinaRecordingState {
/* 0 */ OCARINA_RECORD_OFF,
/* 1 */ OCARINA_RECORD_SCARECROW_LONG,
/* 2 */ OCARINA_RECORD_SCARECROW_SPAWN,
/* 0xFF */ OCARINA_RECORD_REJECTED = 0xFF
} OcarinaRecordingState;
/**
* bFlat4Flag Note:
* Flag for resolving whether (pitch = OCARINA_PITCH_BFLAT4)
* gets mapped to either C_RIGHT and C_LEFT
*
* This is required as C_RIGHT and C_LEFT are the only notes
* that map to two semitones apart (OCARINA_PITCH_A4 and OCARINA_PITCH_B4)
* 0x40 - BTN_Z is pressed to lower note by a semitone
* 0x80 - BTN_R is pressed to raise note by a semitone
*/
typedef struct OcarinaNote {
/* 0x0 */ u8 pitch; // number of semitones above middle C
/* 0x2 */ u16 length; // number of frames the note is sustained
/* 0x4 */ u8 volume;
/* 0x5 */ u8 vibrato;
/* 0x6 */ s8 bend; // frequency multiplicative offset from the pitch
/* 0x7 */ u8 bFlat4Flag; // See note above
} OcarinaNote; // size = 0x8
typedef struct OcarinaSongButtons {
/* 0x0 */ u8 numButtons;
/* 0x1 */ u8 buttonsIndex[8];
} OcarinaSongButtons; // size = 0x9
typedef struct OcarinaStaff {
/* 0x0 */ u8 buttonIndex;
/* 0x1 */ u8 state; // multi-use. Playing: used as songIndex. Playback: used as repeat count of song. Recording: used as OcarinaRecordingState. "status"
/* 0x2 */ u8 pos; // "locate"
} OcarinaStaff; // size = 0x3
void AudioOcarina_Start(u16 ocarinaFlags);
void AudioOcarina_SetInstrument(u8 ocarinaInstrumentId);
void AudioOcarina_SetPlaybackSong(s8 songIndexPlusOne, s8 playbackState);
void AudioOcarina_SetRecordingState(u8 recordingState);
OcarinaStaff* AudioOcarina_GetRecordingStaff(void);
OcarinaStaff* AudioOcarina_GetPlayingStaff(void);
OcarinaStaff* AudioOcarina_GetPlaybackStaff(void);
void AudioOcarina_MemoryGameInit(u8 minigameRound);
s32 AudioOcarina_MemoryGameNextNote(void);
void AudioOcarina_PlayLongScarecrowSong(void);
extern u8* gFrogsSongPtr;
extern OcarinaNote* gScarecrowLongSongPtr;
extern u8* gScarecrowSpawnSongPtr;
extern OcarinaSongButtons gOcarinaSongButtons[];
#endif
|