Alchemy
Loading...
Searching...
No Matches

audio.c

Go to the documentation of this file.
1#include "types.h"
2#include "audio_engine.h"
3#include "ram_buffer.h"
5
9
10/// Interpolates adjacent key frequencies and scales them by the wave sample
11/// frequency. Called by the song player for each PCM note.
12s32 Pcm_KeyToFrequency(void *wave, u8 key, u8 pitch) {
13 u32 keyIndex;
14 u32 pitchScale;
15 u32 lowerFrequency;
16 u32 upperFrequency;
17
18 keyIndex = key;
19 pitchScale = (u32)pitch << 24;
20 if (keyIndex > 178) {
21 keyIndex = 178;
22 pitchScale = 255U << 24;
23 }
24
25 lowerFrequency = gSound_PcmPitchCodes[keyIndex];
26 lowerFrequency =
27 gSound_PcmFrequencySteps[lowerFrequency & 15] >> (lowerFrequency >> 4);
28 upperFrequency = gSound_PcmPitchCodes[keyIndex + 1];
29 upperFrequency =
30 gSound_PcmFrequencySteps[upperFrequency & 15] >> (upperFrequency >> 4);
31
32 return Audio_UmulHigh32(
33 *(s32 *)((u8 *)wave + 4),
34 lowerFrequency +
35 Audio_UmulHigh32(upperFrequency - lowerFrequency, pitchScale));
36}
37
38/// Provides the empty callback retained by the sound driver.
39void Audio_NoopStub(void) {}
40
41// The sound data's symbols supply the player count and maximum track count.
42extern char Sound_PlayerCount[];
43extern char Sound_MaxLines[];
44#define SOUND_PLAYER_COUNT ((u16)(u32)Sound_PlayerCount)
45#define SOUND_MAX_LINES ((u32)Sound_MaxLines)
46
47void Sound_Mixer(void);
48void AudioEngine_Initialize(struct SoundWork *work);
49void AudioEngine_SetMode(u32 mode);
51void MusicPlayer_Initialize(struct SoundPlayer *player,
52 struct SoundTrack *tracks, u8 count);
53void MusicPlayer_StartSong(struct SoundPlayer *player,
54 const struct SequenceHeader *header);
55void MusicPlayer_Stop(struct SoundPlayer *player);
56void MusicPlayer_BeginFadeOut(struct SoundPlayer *player, u16 speed);
57void Audio_ResumePlayer(struct SoundPlayer *player);
58extern struct SoundWork gSound_Work;
59extern struct CgbNote gSound_CgbNotes[4];
60extern u8 gSound_WorkBytes[];
61extern const struct PlayerSlot gSound_PlayerSlots[];
62extern const struct SongEntry gSound_SongTable[];
63
64void MusicTrack_OperateWorkByte(struct SoundPlayer *player,
65 struct SoundTrack *track);
67 struct SoundTrack *track);
69 struct SoundTrack *track);
71 struct SoundTrack *track);
73void MusicTrack_Stop(struct SoundPlayer *player, struct SoundTrack *track);
74void MusicPlayer_StepFade(struct SoundPlayer *player);
75void MusicTrack_CalcOutput(struct SoundPlayer *player,
76 struct SoundTrack *track);
77void Cgb_UpdateChannels(void);
78void CgbChannel_Mute(u8 channel);
79s32 Cgb_KeyToFrequency(u8 kind, u8 key, u8 fine);
81
82/// Clears the player's paused flag while holding the player lock. Called by
83/// the resume and play-or-resume commands.
84void Audio_ResumePlayer(struct SoundPlayer *player) {
85 if (player->lock == SOUND_LOCK) {
86 player->lock++;
88 player->lock = SOUND_LOCK;
89 }
90}
91
92/// Starts a fade under the player lock, resuming the player for fade-ins.
93static __inline__ void MusicPlayer_SetFadeParameters(struct SoundPlayer *player,
94 u16 period, u16 volume) {
95 if (player->lock == SOUND_LOCK) {
96 player->lock++;
97 player->fadeCounter = period;
98 player->fadePeriod = period;
99 player->fadeVolume = volume;
100 if (volume & SOUND_FADE_IN)
101 player->status &= ~SOUND_PLAYER_PAUSED;
102 player->lock = SOUND_LOCK;
103 }
104}
105
106/// Begins a fade that stops and clears tracks when its volume reaches zero.
107/// Called by MusicPlayer_FadeOut.
108void MusicPlayer_BeginFadeOut(struct SoundPlayer *player, u16 speed) {
110}
111
112/// The bytes of mixer code Audio_Initialize copies to IWRAM.
113#define SOUND_MIXER_CODE_SIZE 0x400
114
115/// Copies the RAM mixer to IWRAM, initializes the PCM and CGB paths and
116/// configures every player from gSound_PlayerSlots. Called by
117/// Audio_InitializeRuntimeDefaults at power-on.
119 s32 playerIndex;
120
121 // Sound_Mixer is a Thumb symbol: its address has bit 0 set
122 Bios_CpuSet((void *)((u32)Sound_Mixer & ~1), Ram_SoundMixer,
127 // Each configured player owns its tracks but shares the work-byte area.
128 for (playerIndex = 0; playerIndex < SOUND_PLAYER_COUNT; playerIndex++) {
129 struct SoundPlayer *player = gSound_PlayerSlots[playerIndex].player;
130
132 gSound_PlayerSlots[playerIndex].trackCount);
133 player->checkPriority = gSound_PlayerSlots[playerIndex].checkPriority;
134 player->workBytes = gSound_WorkBytes;
135 }
136}
137
139
140/// Starts the song on the player selected by its song-table entry. Called by
141/// AudioCommand_Play.
142void Audio_PlaySound(u16 songId) {
143 const struct PlayerSlot *slots = gSound_PlayerSlots;
144 const struct SongEntry *songs = gSound_SongTable;
145 const struct SongEntry *song = &songs[songId];
146
147 MusicPlayer_StartSong(slots[song->slot].player, song->header);
148}
149
150/// Starts the song unless its selected player is already playing it. Nothing
151/// in ☀️ calls it.
153 const struct PlayerSlot *slots = gSound_PlayerSlots;
154 const struct SongEntry *songs = gSound_SongTable;
155 const struct SongEntry *song = &songs[songId];
156 struct SoundPlayer *player = slots[song->slot].player;
157
158 if (player->header != song->header)
159 MusicPlayer_StartSong(player, song->header);
160 else if ((player->status & 0xFFFF) == 0 ||
161 (player->status & SOUND_PLAYER_PAUSED))
162 MusicPlayer_StartSong(player, song->header);
163}
164
165/// Starts a different or finished song, or resumes the same paused song.
166/// Nothing in ☀️ calls it.
168 const struct PlayerSlot *slots = gSound_PlayerSlots;
169 const struct SongEntry *songs = gSound_SongTable;
170 const struct SongEntry *song = &songs[songId];
171 struct SoundPlayer *player = slots[song->slot].player;
172
173 if (player->header != song->header)
174 MusicPlayer_StartSong(player, song->header);
175 else if ((player->status & 0xFFFF) == 0)
176 MusicPlayer_StartSong(player, song->header);
177 else if (player->status & SOUND_PLAYER_PAUSED)
178 Audio_ResumePlayer(player);
179}
180
181/// Stops the selected player only when it holds this song. Nothing in ☀️
182/// calls it.
184 const struct PlayerSlot *slots = gSound_PlayerSlots;
185 const struct SongEntry *songs = gSound_SongTable;
186 const struct SongEntry *song = &songs[songId];
187 struct SoundPlayer *player = slots[song->slot].player;
188
189 if (player->header == song->header)
190 MusicPlayer_Stop(player);
191}
192
193/// Resumes the selected player only when it holds this song. Nothing in ☀️
194/// calls it.
196 const struct PlayerSlot *slots = gSound_PlayerSlots;
197 const struct SongEntry *songs = gSound_SongTable;
198 const struct SongEntry *song = &songs[songId];
199 struct SoundPlayer *player = slots[song->slot].player;
200
201 if (player->header == song->header)
202 Audio_ResumePlayer(player);
203}
204
205/// Stops every player. Nothing in ☀️ calls it.
207 s32 playerIndex;
208
209 for (playerIndex = 0; playerIndex < SOUND_PLAYER_COUNT; playerIndex++)
210 MusicPlayer_Stop(gSound_PlayerSlots[playerIndex].player);
211}
212
213/// Resumes `player`. Nothing in ☀️ calls it.
215 Audio_ResumePlayer(player);
216}
217
218/// Resumes every player. Nothing in ☀️ calls it.
220 s32 playerIndex;
221
222 for (playerIndex = 0; playerIndex < SOUND_PLAYER_COUNT; playerIndex++)
223 Audio_ResumePlayer(gSound_PlayerSlots[playerIndex].player);
224}
225
226/// Begins the standard stop-and-clear fade. Called by AudioCommand_Play's fade
227/// cues.
228void MusicPlayer_FadeOut(struct SoundPlayer *player, u16 speed) {
229 MusicPlayer_BeginFadeOut(player, speed);
230}
231
232/// Begins a fade that pauses the player at zero volume, keeping its tracks'
233/// state for a later resume. Nothing in ☀️ calls it.
234UNUSED void MusicPlayer_FadeOutPause(struct SoundPlayer *player, u16 speed) {
235 MusicPlayer_SetFadeParameters(player, speed,
237}
238
239/// Starts a fade from zero volume and resumes the player. Nothing in ☀️ calls
240/// it.
241UNUSED void MusicPlayer_FadeIn(struct SoundPlayer *player, u16 speed) {
243}
244
245/// Initializes active tracks still carrying their reset flag: clears their
246/// settings and gives them the default bend range, volume and LFO speed.
247/// Nothing in ☀️ calls it.
249 s32 count = player->trackCount;
250 struct SoundTrack *track = player->tracks;
251
252 while (count > 0) {
253 if (track->flags & SOUND_TRACK_ACTIVE) {
254 if (track->flags & SOUND_TRACK_RESET) {
255 // Clear the 64-byte settings prefix, retaining the sequence cursor.
257 track->flags = SOUND_TRACK_ACTIVE;
258 track->bendRange = 2;
259 track->volumeScale = 0x40;
260 track->lfoSpeed = 22;
261 track->voice.kind = 1;
262 }
263 }
264 count--;
265 track++;
266 }
267}
268
269/// Resets the CGB sound hardware, installs the CGB-aware command handlers and
270/// callbacks in the sound work, and clears the four channel records `notes`.
271/// Called by Audio_Initialize.
273 struct SoundWork *work;
274 u32 lock;
275
277 REG_SOUNDCNT_L = 0;
278 // Channels 1, 2 and 4 silent with a rising envelope, restarted; channel 3
279 // off; the master volume full on both sides
280 REG_NR12 = 8;
281 REG_NR22 = 8;
282 REG_NR42 = 8;
283 REG_NR14 = 0x80;
284 REG_NR24 = 0x80;
285 REG_NR44 = 0x80;
286 REG_NR30 = 0;
287 REG_NR50 = 0x77;
288
289 work = SOUND_WORK;
290 lock = work->lock;
291 if (lock != SOUND_LOCK)
292 return;
293 work->lock = lock + 1;
294
295 // Replace generic commands with the CGB-capable handlers.
310
311 work->cgbNotes = notes;
313 work->cgbMute = CgbChannel_Mute;
316
317 // Clear note state, then assign the four hardware routing masks.
318 {
319 u32 zero = 0;
320
321 Bios_CpuSet((void *)&zero, notes,
323 (sizeof(struct CgbNote) * 4 / 4));
324 }
325 notes[0].kind = 1;
326 notes[0].channelBits = 0x11;
327 notes[1].kind = 2;
328 notes[1].channelBits = 0x22;
329 notes[2].kind = 3;
330 notes[2].channelBits = 0x44;
331 notes[3].kind = 4;
332 notes[3].channelBits = 0x88;
333
334 work->lock = lock;
335}
static __inline__ void MusicPlayer_SetFadeParameters(struct SoundPlayer *player, u16 period, u16 volume)
Starts a fade under the player lock, resuming the player for fade-ins.
Definition audio.c:93
UNUSED void MusicPlayer_FadeIn(struct SoundPlayer *player, u16 speed)
Starts a fade from zero volume and resumes the player.
Definition audio.c:241
void MusicPlayer_Initialize(struct SoundPlayer *player, struct SoundTrack *tracks, u8 count)
Deactivates up to sixteen tracks and links the player into the mixer tick chain.
Definition engine.c:246
#define SOUND_PLAYER_COUNT
Definition audio.c:44
void MusicTrack_SetLfoSpeedFromCommand(struct SoundPlayer *player, struct SoundTrack *track)
struct SoundWork gSound_Work
UNUSED void MusicPlayer_FadeOutPause(struct SoundPlayer *player, u16 speed)
Begins a fade that pauses the player at zero volume, keeping its tracks' state for a later resume.
Definition audio.c:234
void AudioEngine_Initialize(struct SoundWork *work)
Resets the sound hardware, clears the whole sound work block and installs the default PCM driver: sto...
Definition engine.c:64
#define SOUND_MIXER_CODE_SIZE
The bytes of mixer code Audio_Initialize copies to IWRAM.
Definition audio.c:113
void CgbAudio_Initialize(struct CgbNote *notes)
Resets the CGB sound hardware, installs the CGB-aware command handlers and callbacks in the sound wor...
Definition audio.c:272
void MusicTrack_ReleaseKey(struct SoundPlayer *player, struct SoundTrack *track)
void MusicTrack_OperateWorkByte(struct SoundPlayer *player, struct SoundTrack *track)
Executes a work-byte operation and consumes a branch address for comparisons.
Definition engine.c:957
UNUSED void Audio_ResumeAllPlayers(void)
Resumes every player. Nothing in ☀️ calls it.
Definition audio.c:219
void Audio_PlaySound(u16 songId)
Starts the song on the player selected by its song-table entry.
Definition audio.c:142
void AudioEngine_SetPcmRate(u32 mode)
Sets the PCM frame length (mode bits 16 to 19 pick a gSound_FrameLengths entry) and the rates derived...
Definition engine.c:105
void Cgb_UpdateChannels(void)
Steps CGB note envelopes and writes changed pitch, volume and trigger registers, once a frame.
Definition engine.c:537
void Audio_Initialize(void)
Copies the RAM mixer to IWRAM, initializes the PCM and CGB paths and configures every player from gSo...
Definition audio.c:118
UNUSED void MusicPlayer_Resume(struct SoundPlayer *player)
Resumes player. Nothing in ☀️ calls it.
Definition audio.c:214
void MusicTrack_CalcOutput(struct SoundPlayer *player, struct SoundTrack *track)
Recalculates dirty stereo volumes and pitch from track settings and modulation.
Definition engine.c:411
const struct PlayerSlot gSound_PlayerSlots[]
void AudioEngine_RunMixer(void)
Definition audio.c:138
u32 Audio_UmulHigh32(u32 left, u32 right)
void Sound_Mixer(void)
void CgbChannel_Mute(u8 channel)
Disables one CGB channel using its envelope or wave-control register.
Definition engine.c:485
void AudioEngine_RunMixerTick(void)
void MusicPlayer_StartSong(struct SoundPlayer *player, const struct SequenceHeader *header)
Starts a song when its priority permits, resetting its tracks and tempo.
Definition engine.c:282
s32 Pcm_KeyToFrequency(void *wave, u8 key, u8 pitch)
Interpolates adjacent key frequencies and scales them by the wave sample frequency.
Definition audio.c:12
UNUSED void Audio_StopSound(u16 songId)
Stops the selected player only when it holds this song.
Definition audio.c:183
void MusicPlayer_Stop(struct SoundPlayer *player)
Pauses this player and stops all of its tracks, under the player's lock.
Definition engine.c:339
void MusicPlayer_StepFade(struct SoundPlayer *player)
Advances a due fade step, updating active track volumes, or at the end of a fade out stops (or pauses...
Definition engine.c:360
UNUSED void MusicPlayer_ResetActiveTracks(struct SoundPlayer *player)
Initializes active tracks still carrying their reset flag: clears their settings and gives them the d...
Definition audio.c:248
UNUSED void Audio_ResumeSound(u16 songId)
Resumes the selected player only when it holds this song.
Definition audio.c:195
struct CgbNote gSound_CgbNotes[4]
s32 Cgb_KeyToFrequency(u8 kind, u8 key, u8 fine)
Converts a key and fractional pitch to a CGB tone or noise-register value.
Definition engine.c:448
UNUSED void Audio_StopAllPlayers(void)
Stops every player. Nothing in ☀️ calls it.
Definition audio.c:206
void MusicTrack_Stop(struct SoundPlayer *player, struct SoundTrack *track)
void MusicPlayer_FadeOut(struct SoundPlayer *player, u16 speed)
Begins the standard stop-and-clear fade.
Definition audio.c:228
u32 gSound_PcmFrequencySteps[]
Frequencies by note at octave zero, in 32-bit fixed point.
Definition tables.c:124
UNUSED void Audio_PlaySoundIfInactive(u16 songId)
Starts the song unless its selected player is already playing it.
Definition audio.c:152
SoundCommand gSound_CommandTable[36]
void AudioEngine_SetMode(u32 mode)
Applies the reverb, channel-count, volume, bias and sample-rate fields of mode to the sound work,...
Definition engine.c:136
char Sound_PlayerCount[]
void MusicPlayer_BeginFadeOut(struct SoundPlayer *player, u16 speed)
Begins a fade that stops and clears tracks when its volume reaches zero.
Definition audio.c:108
void MusicTrack_SetModulationFromCommand(struct SoundPlayer *player, struct SoundTrack *track)
#define SOUND_MAX_LINES
Definition audio.c:45
u8 gSound_PcmPitchCodes[]
PCM pitches: the high four bits hold the octave, the low four the note.
Definition tables.c:105
UNUSED void Audio_PlayOrResumeSound(u16 songId)
Starts a different or finished song, or resumes the same paused song.
Definition audio.c:167
char Sound_MaxLines[]
void Audio_ResumePlayer(struct SoundPlayer *player)
Clears the player's paused flag while holding the player lock.
Definition audio.c:84
const struct SongEntry gSound_SongTable[]
u8 gSound_WorkBytes[]
void Audio_NoopStub(void)
Provides the empty callback retained by the sound driver.
Definition audio.c:39
Declares nothing of its own: it only includes audio_engine_symbols.h and sound/audio_engine_types....
void Bios_CpuSet(const void *source, void *destination, u32 control)
#define AUDIO_INITIAL_MODE
#define SOUNDCNT_X_ALL_TONES_ON
#define SOUND_COMMAND_FADE
MusicPlayer_StepFade: a frame of a fade.
#define REG_NR12
#define SOUND_COMMAND_RELEASE_KEY
Byte 0xCE: releases the track's sounding note of the key given (or of its last key when no key byte f...
#define REG_SOUNDCNT_X
#define SOUND_FADE_FULL_VOLUME
#define REG_NR22
@ SOUND_PLAYER_PAUSED
#define REG_SOUNDCNT_L
#define SOUND_WORK
#define SOUND_COMMAND_CALCULATE_OUTPUT
MusicTrack_CalcOutput.
#define REG_NR50
#define REG_NR44
#define REG_NR42
#define SOUNDCNT_X_ENABLE
@ SOUND_FADE_PAUSE
@ SOUND_FADE_IN
#define SOUND_COMMAND_STOP_TRACK
MusicTrack_Stop: silences the track's notes and empties its list.
@ SOUND_TRACK_RESET
@ SOUND_TRACK_ACTIVE
#define SOUND_COMMAND_LFO_SPEED
Byte 0xC2: sets lfoSpeed from the next byte; 0 clears the modulation.
#define SOUND_COMMAND_PCM_RATE
AudioEngine_SetPcmRate.
#define SOUND_COMMAND_EXTENDED
Byte 0xCD, installed by CgbAudio_Initialize: runs the entry of gSound_ExtendedCommandTable the next b...
#define SOUND_COMMAND_WORK_BYTE
Byte 0xB9, installed by CgbAudio_Initialize: an operation, a work byte and an operand; sets,...
#define SOUND_COMMAND_CAST(type, routine)
Converts between SoundCommand and a table entry that takes other parameters, through the generic func...
#define SOUND_COMMAND_MODULATION
Byte 0xC4: sets modDepth from the next byte; 0 clears the modulation.
#define REG_NR24
#define REG_NR14
#define REG_NR30
#define SOUND_LOCK
void MusicTrack_DispatchStreamCommand(struct SoundPlayer *player, struct SoundTrack *track)
Reads an extended-command index and invokes its handler.
Definition engine.c:1049
void AudioCommand_InvokeSlot35(void *block)
Clears a 64-byte player or track prefix through the driver command table.
Definition engine.c:19
The hardware's I/O registers and their bits, as pret names them.
#define CPU_SET_SRC_FIXED
BIOS CpuSet control flags, above its count.
Definition io_reg.h:236
#define CPU_SET_32BIT
Definition io_reg.h:237
The work pointers in the gWorkSlot table, by name.
#define Ram_SoundMixer
Definition ram_buffer.h:19
A note on one of the four CGB channels of the hardware: its state and envelope, its levels and pan,...
u8 channelBits
This channel's NR51 bits: 0x11, 0x22, 0x44, 0x88.
u8 kind
Channel number 1 to 4 at setup, then the voice's kind; bit 3 rounds the frequency to the sound bias's...
An entry of the player table: a player, its tracks and track count, and its priority check.
struct SoundPlayer * player
u16 checkPriority
Copied to the player's checkPriority; 0 everywhere.
A song's header: its track count, priority and mode, its voices, and where each track's commands star...
An entry of the song table: a song's header and the player table entry that plays it.
u16 slot
Index into gSound_PlayerSlots; AudioCommand_Play gives slot 7's songs the first player from 7 down to...
const struct SequenceHeader * header
A player, which plays one song: its header and status, its tracks, its tempo and fade.
const struct SequenceHeader * header
The song playing or last played.
u8 checkPriority
Nonzero: a song of lower priority does not replace a playing one.
u16 fadeCounter
Frames left until the next fade step.
u16 fadeVolume
bits: 8..4 level, 0 to 0x100 in steps of 16 | 1 fade in | 0 pause at the end (SoundFadeFlag).
u32 status
bits: 31 paused | 15..0 tracks active after the last tick.
u8 trackCount
Tracks this player owns, at most 16.
u8 * workBytes
gSound_WorkBytes, which the work-byte command uses.
u32 lock
SOUND_LOCK when free; raised while the player is changed or ticked.
struct SoundTrack * tracks
trackCount tracks.
u16 fadePeriod
Frames between fade steps; 0 when not fading.
A track of a playing song: the song commands it runs, its voice and notes, and the pitch,...
u8 bendRange
Semitones a full bend reaches; 2 at reset.
u8 lfoSpeed
LFO phase step a tick, 22 at reset; 0 stops the LFO and clears modAmount.
struct SoundNote * notes
The notes this track started, newest first, linked through SoundNote.next; PCM notes from SoundWork....
struct SoundVoice voice
Copied from the player's voice table by the voice command, or set a field at a time by extended comma...
u8 flags
SoundTrackFlag.
u8 volumeScale
0 to 64 (full, the reset value): a player volume or fade level of 0 to 0x100 divided by 4.
u8 kind
bits: 7 rhythm | 6 key split | 3 fixed rate for PCM, bias rounding for CGB | 2..0 CGB channel (0 PCM)...
The sound driver's work: its lock, the mixer's rate and buffers, the PCM and CGB notes,...
s32(*) cgbFrequency(u8 kind, u8 key, u8 fine)
Cgb_KeyToFrequency.
u32 lock
SOUND_LOCK when free; raised while the driver changes it.
struct CgbNote * cgbNotes
gSound_CgbNotes; NULL before CGB setup.
u8 maxLines
Nonzero: the mixer stops taking notes once the scanline passes this many lines after its start.
void(*) cgbUpdate(void)
Run each mixer frame: Cgb_UpdateChannels.
void(*) cgbMute(u8 channel)
CgbChannel_Mute, channel 1 to 4.
void(*) SoundCommand(struct SoundPlayer *player, struct SoundTrack *track)
A command table entry: the driver calls it with the player and the track.
Definition tables.c:11
The integer types, TRUE, UNUSED and the fixed-address macros.
signed int s32
Definition types.h:14
unsigned int u32
Definition types.h:15
unsigned short u16
Definition types.h:13
#define UNUSED
Definition types.h:22
unsigned char u8
Definition types.h:11