53#define SOUND_PCM_BUFFER_SIZE 0x630
56#define SOUND_FRAME_RATE_E4 597275
58#define SOUND_CYCLES_PER_FRAME (228 * 1232)
111 mode = (mode & 0xF0000) >> 16;
146 modeField = mode & 0xFF;
148 work->
reverb = modeField & 0x7F;
149 modeField = mode & 0xF00;
150 if (modeField != 0) {
158 }
while (modeField != 0);
160 modeField = mode & 0xF000;
162 work->
volume = modeField >> 12;
163 modeField = mode & 0xB00000;
164 if (modeField != 0) {
165 modeField = (modeField & 0x300000) >> 14;
168 modeField = mode & 0xF0000;
169 if (modeField != 0) {
191 while (channelCounter > 0) {
194 channel = (
void *)((
s32)channel +
sizeof(
struct SoundNote));
198 if (channel !=
NULL) {
204 channel = (
void *)((
s32)channel +
sizeof(
struct CgbNote));
264 while (trackCount != 0) {
294 if ((player->
status & 0xFFFF) == 0 ||
317 while (trackIndex < header->trackCount && trackIndex < player->trackCount) {
326 while (trackIndex < player->trackCount) {
332 if (header->
mode & 0x80)
349 while (tracksRemaining > 0) {
380 while (tracksRemaining > 0) {
399 while (tracksRemaining > 0) {
479 return lowerFrequency + ((
fine * (upperFrequency - lowerFrequency)) >> 8) +
513 if ((
u8)right >= (
u8)left) {
514 if ((
u8)right / 2 >= (
u8)left) {
518 }
else if ((
u8)left / 2 >= (
u8)right) {
539 s32 extraEnvelopeTick;
542 volatile u8 *sweepOrWaveControl;
543 volatile u8 *lengthDutyRegister;
544 volatile u8 *volumeEnvelopeRegister;
545 volatile u8 *frequencyOrNoiseRegister;
546 volatile u8 *triggerRegister;
567 frequencyOrNoiseRegister = &
REG_NR13;
574 frequencyOrNoiseRegister = &
REG_NR23;
581 frequencyOrNoiseRegister = &
REG_NR33;
588 frequencyOrNoiseRegister = &
REG_NR43;
593 extraEnvelopeTick = work->
cgbTick;
594 envelopeControl = *volumeEnvelopeRegister;
604 *sweepOrWaveControl = note->
sweep;
613 *sweepOrWaveControl = 0x40;
620 *sweepOrWaveControl = 0;
621 *lengthDutyRegister = note->
length;
630 *lengthDutyRegister = note->
length;
631 *frequencyOrNoiseRegister = (
u32)note->
wave << 3;
634 envelopeControl = note->
attack + 8;
665 envelopeControl = note->
release;
678 if ((
s8)(note->
level & byteMask) <= 0) {
717 goto sustain_or_release;
721 envelopeControl = note->
decay;
729 if (extraEnvelopeTick == 0) {
738 if (channel < 4 && (note->
kind & 8)) {
746 else if (bias < 0x80)
750 *frequencyOrNoiseRegister = note->
frequency;
752 *frequencyOrNoiseRegister =
753 (*frequencyOrNoiseRegister & 8) | note->
frequency;
756 *triggerRegister = (
s8)(note->
trigger & byteMask);
766 *sweepOrWaveControl = 0x80;
767 *triggerRegister = note->
trigger;
772 envelopeControl &= 0xf;
773 *volumeEnvelopeRegister = (note->
level << 4) + envelopeControl;
774 *triggerRegister = note->
trigger | 0x80;
775 if (channel == 1 && !(*sweepOrWaveControl & 8))
776 *triggerRegister = note->
trigger | 0x80;
811 while (tracksRemaining > 0) {
812 if (mask & trackBit) {
839 while (tracksRemaining > 0) {
840 if (mask & trackBit) {
867 while (tracksRemaining > 0) {
868 if (mask & trackBit) {
895 s32 selectedTracks,
s32 depthArgument) {
896 u16 mask = selectedTracks;
897 u8 depth = depthArgument;
909 while (tracksRemaining > 0) {
910 if (mask & trackBit) {
927 u16 mask = selectedTracks;
928 u8 speed = speedArgument;
940 while (tracksRemaining > 0) {
941 if (mask & trackBit) {
963 operation = *track->
cursor;
975 *workByte += operand;
978 *workByte -= operand;
990 if (*workByte == operand)
994 if (*workByte != operand)
998 if (*workByte > operand)
1002 if (*workByte >= operand)
1006 if (*workByte <= operand)
1010 if (*workByte < operand)
1014 if (*workByte == player->
workBytes[operand])
1018 if (*workByte != player->
workBytes[operand])
1022 if (*workByte > player->
workBytes[operand])
1026 if (*workByte >= player->
workBytes[operand])
1030 if (*workByte <= player->workBytes[operand])
1034 if (*workByte < player->workBytes[operand])
1053 command = *track->
cursor;
1074 finishSequence(player, track);
1083 targetAddress.
part.byte0 = source[0];
1084 targetAddress.
part.byte1 = source[1];
1085 targetAddress.
part.byte2 = source[2];
1086 targetAddress.
part.byte3 = source[3];
1088 track->
cursor = source + 4;
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.
void AudioEngine_Initialize(struct SoundWork *work)
Resets the sound hardware, clears the whole sound work block and installs the default PCM driver: sto...
void MusicTrack_OperateWorkByte(struct SoundPlayer *player, struct SoundTrack *track)
Executes a work-byte operation and consumes a branch address for comparisons.
void AudioEngine_SetPcmRate(u32 mode)
Sets the PCM frame length (mode bits 16 to 19 pick a gSound_FrameLengths entry) and the rates derived...
void Cgb_UpdateChannels(void)
Steps CGB note envelopes and writes changed pitch, volume and trigger registers, once a frame.
void MusicTrack_CalcOutput(struct SoundPlayer *player, struct SoundTrack *track)
Recalculates dirty stereo volumes and pitch from track settings and modulation.
void CgbChannel_Mute(u8 channel)
Disables one CGB channel using its envelope or wave-control register.
void MusicPlayer_StartSong(struct SoundPlayer *player, const struct SequenceHeader *header)
Starts a song when its priority permits, resetting its tracks and tempo.
void MusicPlayer_Stop(struct SoundPlayer *player)
Pauses this player and stops all of its tracks, under the player's lock.
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...
s32 Cgb_KeyToFrequency(u8 kind, u8 key, u8 fine)
Converts a key and fractional pitch to a CGB tone or noise-register value.
void MusicTrack_Stop(struct SoundPlayer *player, struct SoundTrack *track)
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,...
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 SOUNDCNT_X_ALL_TONES_ON
#define SOUND_COMMAND_FINISH
Entries of gSound_CommandTable, in gSound_CommandTableTemplate's order.
#define SOUND_FADE_FULL_VOLUME
#define SOUND_COMMAND_GOTO
Byte 0xB2: jumps to the address after it.
@ SOUND_WORK_GREATER_BYTE
@ SOUND_WORK_NOT_EQUAL_BYTE
@ SOUND_WORK_LESS_EQUAL_BYTE
@ SOUND_WORK_SUBTRACT_BYTE
@ SOUND_WORK_GREATER_EQUAL
@ SOUND_WORK_GREATER_EQUAL_BYTE
#define SOUND_COMMAND_DETACH_NOTE
SoundNote_Detach: unlinks a note from its track's list (AudioCommand_InvokeSlot34).
#define SOUND_COMMAND_CLEAR_WORK
SoundDriver_ClearBuffer: zeroes the first 64 bytes of a player or track (AudioCommand_InvokeSlot35).
#define SOUNDCNT_X_ENABLE
@ SOUND_TRACK_PITCH_DIRTY
@ SOUND_TRACK_UPDATE_VOLUME
@ SOUND_TRACK_UPDATE_PITCH
@ SOUND_TRACK_VOLUME_DIRTY
@ SOUND_PLAYER_TRACK_LIMIT
Most tracks a player takes; MusicPlayer_Initialize caps its count here, and the track masks of the Mu...
@ SOUND_CGB_CHANNEL_COUNT
CGB channels, numbered 1 to 4.
@ SOUND_PCM_NOTE_CAPACITY
The PCM notes in SoundWork.pcmNotes; mode changes and AudioEngine_StopAllChannels clear all 12,...
@ SOUND_MODULATION_VOLUME
#define SOUND_COMMAND_CAST(type, routine)
Converts between SoundCommand and a table entry that takes other parameters, through the generic func...
void Audio_EmptyCallback(void)
Provides the default empty callback before the sound driver installs its handlers.
void MusicPlayer_SetPitch(struct SoundPlayer *player, u16 mask, s16 pitch)
Sets the semitone and fractional pitch offsets of selected active tracks and marks their pitch for re...
void MusicPlayer_SetLfoSpeed(struct SoundPlayer *player, u32 selectedTracks, u32 speedArgument)
Sets LFO speed on selected active tracks, resetting modulation when stopped.
void MusicPlayer_SetModulationDepth(struct SoundPlayer *player, s32 selectedTracks, s32 depthArgument)
Sets modulation depth on selected active tracks, resetting zero-depth modulation.
const u16 gSound_FrameLengths[]
Samples per frame for each playback frequency setting.
void MusicTrack_SetVoiceAttack(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice attack rate from the sequence.
#define SOUND_CYCLES_PER_FRAME
CPU cycles in a frame: 228 lines of 1232 cycles.
void Sound_LoadCommandTable(SoundCommand *table)
void MusicTrack_SetVoiceRelease(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice release rate from the sequence.
void MusicTrack_SetVoiceDecay(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice decay rate from the sequence.
void CgbNote_UpdatePanEnvelope(struct CgbNote *note)
Chooses stereo routing and derives peak and sustain levels for a CGB note, writing them into note.
const u8 gSound_CgbPitchCodes[]
CGB channel pitches.
void AudioCommand_InvokeSlot34(struct SoundNote *note)
Detaches a note through the command table entry installed by the driver.
void MusicTrack_SetVoiceLength(struct SoundPlayer *player, struct SoundTrack *track)
Reads the hardware note length from the sequence.
const u8 gSound_Cgb3LevelCodes[]
CGB channel 3 waveform volumes.
void MusicTrack_DispatchStreamCommand(struct SoundPlayer *player, struct SoundTrack *track)
Reads an extended-command index and invokes its handler.
void MusicTrack_SetTailLength(struct SoundPlayer *player, struct SoundTrack *track)
Reads the note tail duration from the sequence.
void MusicTrack_SetVoiceSustain(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice sustain level from the sequence.
void MusicPlayer_SetPitchAndUpdateFrequency(struct SoundPlayer *player, u16 scale)
Sets the tempo multiplier and updates the number of ticks advanced per frame.
void MusicTrack_SetVoiceKind(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice kind from the sequence.
void MusicTrack_HandleNote(u32 command, struct SoundPlayer *player, struct SoundTrack *track)
#define SOUND_FRAME_RATE_E4
The display's frame rate in ten-thousandths of a hertz: 59.7275 frames a second.
const s16 gSound_CgbFrequencySteps[]
Frequencies by note for CGB channels.
const u8 gSound_NoisePitchCodes[]
Noise channel pitches.
void AudioEngine_SuspendDirectSound(void)
Stops both FIFO transfers and clears their sample buffers, raising the work's lock until AudioEngine_...
UNUSED void MusicPlayer_SetPan(struct SoundPlayer *player, u16 mask, s8 pan)
Sets the stereo pan offset of selected active tracks.
void MusicTrack_SetVoicePanOrSweep(struct SoundPlayer *player, struct SoundTrack *track)
Reads the voice pan or CGB sweep setting from the sequence.
void MusicPlayer_Tick(struct SoundPlayer *player)
void AudioCommand_InvokeSlot35(void *block)
Clears a 64-byte player or track prefix through the driver command table.
void AudioEngine_ResumeDirectSound(void)
Restarts both FIFO transfers and releases the suspended-work lock.
#define SOUND_PCM_BUFFER_SIZE
The PCM buffer's size in samples, a multiple of every frame length: the DMA plays it round and round.
UNUSED void AudioEngine_StopAllChannels(void)
Silences every PCM and CGB note while holding the sound work lock.
void MusicTrack_ClearModulation(struct SoundTrack *track)
Resets the LFO phase and amount, marking the affected output for recalculation.
void MusicTrack_SetTailLevel(struct SoundPlayer *player, struct SoundTrack *track)
Reads the note tail volume from the sequence.
void MusicTrack_ReadVoiceTarget(struct SoundPlayer *player, struct SoundTrack *track)
Reads an unaligned little-endian voice target address from the sequence.
void Runtime_CallWorkEntryWithArgs(struct SoundPlayer *player, struct SoundTrack *track)
Finishes a track through the base command table entry.
void MusicPlayer_SetVolume(struct SoundPlayer *player, u16 mask, u16 volume)
Sets the volume scale of active tracks selected by the bit mask and marks their output for recalculat...
The hardware's I/O registers and their bits, as pret names them.
#define SOUND_A_RIGHT_OUTPUT
#define DMA_START_SPECIAL
#define CPU_SET_SRC_FIXED
BIOS CpuSet control flags, above its count.
#define SOUND_ALL_MIX_FULL
#define SOUND_B_FIFO_RESET
#define SOUND_A_FIFO_RESET
#define SOUND_B_LEFT_OUTPUT
A note on one of the four CGB channels of the hardware: its state and envelope, its levels and pan,...
u8 attack
Frames per attack step.
u8 channelBits
This channel's NR51 bits: 0x11, 0x22, 0x44, 0x88.
u32 frequency
Tone frequency from Cgb_KeyToFrequency (2048 added), or channel 4's NR43 value.
u8 echoLevel
After release, the level held is peak * echoLevel / 256.
u8 outLeft
Velocity and track volume to the left, 0 to 255.
u8 release
Frames per release step.
u8 trigger
Value for NRx4: 7 restart, 6 length on, 2..0 frequency.
u8 echoLength
Frames the echo lasts.
u8 sweep
Channel 1's NR10 sweep; 8 when none.
u8 length
The voice's length.
u8 level
Envelope level 0 to 15 written to the channel.
u8 counter
Frames left in the current envelope step.
u8 peak
Top of the envelope: (outRight + outLeft) / 16, at most 15 when one side plays.
u8 modified
CgbNoteModified: what to write to the channel.
u8 panBits
NR51 bits this note sets: one side or both.
u32 * loadedWave
Channel 3: the pattern last copied into wave RAM.
u8 state
CgbNoteState and CgbNotePhase; 0 when the channel is free.
u8 sustain
Sustain level 0 to 15, scaled by peak.
u8 decay
Frames per decay step.
u8 sustainLevel
(peak * sustain + 15) / 16.
u8 outRight
Velocity and track volume to the right, 0 to 255.
u8 kind
Channel number 1 to 4 at setup, then the voice's kind; bit 3 rounds the frequency to the sound bias's...
u32 * wave
Channel 3: the 16-byte wave pattern.
A PCM note, one of 12 the mixer renders: its state and envelope, its output levels,...
struct SoundTrack * track
The track whose list holds this note; NULL once detached.
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 tempoStep
tempo * tempoScale / 256, added to tempoCount each frame.
u16 fadeCounter
Frames left until the next fade step.
u32 ticks
Song ticks played since the song started.
u16 tempoCount
Each 150 in it runs one tick, so a tempoStep of 150 is a tick a frame.
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.
void(*) nextTick(struct SoundPlayer *player)
The tick routine and player that were first in the chain before this player was added; this player's ...
u8 priority
The song's priority.
u8 trackCount
Tracks this player owns, at most 16.
u16 tempoScale
256 plays at the song's tempo.
u8 * workBytes
gSound_WorkBytes, which the work-byte command uses.
u16 tempo
Twice the tempo command's byte; 150 at start.
const struct SoundVoice * voices
The song's voice table.
u32 lock
SOUND_LOCK when free; raised while the player is changed or ticked.
struct SoundPlayer * nextTickPlayer
Passed to nextTick.
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.
s8 bend
The bend command's byte - 64: full bend is bendRange.
s8 modAmount
The LFO's output, modDepth * wave / 64: added to the pitch in 1/16 semitone, to the pan,...
u8 pitchHi
Whole semitones of the track's pitch, read as signed and added to each note's key (a sum below 0 play...
u8 pitchLo
The pitch's fraction, 0 to 255 in 1/256 semitone, passed as the fine pitch to the key-to-frequency st...
u8 tailLevel
Each new note's echo level.
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....
u8 outVolumeB
Left volume: (127 - pan) * scaled volume / 256.
u8 outVolumeA
Right volume: (pan + 128) * scaled volume / 256.
struct SoundVoice voice
Copied from the player's voice table by the voice command, or set a field at a time by extended comma...
s8 pan
The pan command's byte - 64, -64 to 63; doubled for output.
u8 fine
1/256 semitone, from MusicPlayer_SetPitch.
s8 tune
The tune command's byte - 64: 1/64 semitone.
const u8 * cursor
The next command byte in the song's data, from the header's track pointer; a track's commands end at ...
u8 volume
The song's volume command, scaled by volumeScale / 32.
u8 modDepth
0 to 255, from the modulation command or MusicPlayer_SetModulationDepth; 0 stops the LFO and clears m...
u8 modTarget
SoundModulationTarget.
u8 tailLength
Each new note's echo length in frames.
u8 lfoPhase
0 to 255, wrapping; the wave is phase over 0 to 63, 128 - phase over 64 to 191 and phase - 256 over 1...
s8 panOffset
Added to the doubled pan, from MusicPlayer_SetPan.
s8 keyOffsetB
Semitones, from MusicPlayer_SetPitch.
u8 volumeScale
0 to 64 (full, the reset value): a player volume or fade level of 0 to 0x100 divided by 4.
s8 keyOffsetA
Semitones, from the song's key-shift command.
const void * target
The PCM sample, the CGB wave pattern, duty or noise width, or for a rhythm or split voice its voice t...
u8 attack
PCM: added to the envelope each frame until 255.
u8 decay
PCM: envelope * decay / 256 a frame. CGB: frames a step.
u8 panOrSweep
CGB channel 1's sweep (NR10) when bit 7 is clear and bits 6..4 are not; else no sweep.
u8 release
PCM: envelope * release / 256 a frame. CGB: frames a step.
u8 kind
bits: 7 rhythm | 6 key split | 3 fixed rate for PCM, bias rounding for CGB | 2..0 CGB channel (0 PCM)...
u8 length
CGB sound length (NRx1); 0 plays until released.
u8 sustain
Level decay stops at: 0 to 255 for PCM, 0 to 15 for CGB.
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.
u8 pcmNoteCount
PCM notes in use, 8 at start (mode bits 11..8).
void(*) unk3c(void)
Set to Audio_EmptyCallback by AudioEngine_Initialize; no TBS code reads it by name.
u8 reverb
0 to 127 (mode bits 6..0); 0 skips the reverb pass.
u8 volume
PCM volume 0 to 15, 15 at start (mode bits 15..12).
s8 buffers[2][0x630]
Right (0, DMA 1 to FIFO A) and left (1, DMA 2 to FIFO B) samples, transferPeriod frames of frameSampl...
struct SoundPlayer * tickPlayer
Passed to tick.
u32 lock
SOUND_LOCK when free; raised while the driver changes it.
u8 rate
1 to 12, indexes gSound_FrameLengths (mode bits 19..16).
u32 frameSamples
Samples mixed a frame, from gSound_FrameLengths.
struct SoundNote pcmNotes[12]
pcmNoteCount of them play.
u32 rateStep
2^23 / outputRate, rounded; a note's frequency times it is its step a sample.
struct CgbNote * cgbNotes
gSound_CgbNotes; NULL before CGB setup.
void(*) noteOn(u32 command, struct SoundPlayer *player, struct SoundTrack *track)
MusicTrack_HandleNote, run for song bytes from 0xCF up with the byte.
void(*) cgbUpdate(void)
Run each mixer frame: Cgb_UpdateChannels.
void(*) cgbMute(u8 channel)
CgbChannel_Mute, channel 1 to 4.
SoundCommand * commands
gSound_CommandTable.
u32 outputRate
Samples a second: frameSamples * 59.7275, rounded.
volatile u8 transferCountdown
Frames until the VBlank DMA restart, which reloads it from transferPeriod; also picks the frame of th...
void(*) tick(struct SoundPlayer *player)
First of the chain of player ticks run each mixer frame; NULL for none.
u8 transferPeriod
Frames the buffers hold: 0x630 / frameSamples.
u8 cgbTick
Counts 14 down to 0 once a CGB update; at 0 the envelopes take an extra step.
void(*) SoundCommand(struct SoundPlayer *player, struct SoundTrack *track)
A command table entry: the driver calls it with the player and the track.
const SoundCommand gSound_ExtendedCommandTable[]
Extended commands; entries zero and three do nothing.
The integer types, TRUE, UNUSED and the fixed-address macros.
A word put together from its four bytes, lowest first.
struct PackedWord::@144047150331112312137023105363302267347230057174 part