Sound
The 93 sound channels of Content/sounds/, played with the original's volume, pitch and conflict rules, heard from Blupi's place.
| Header | src/GalaxyEggbert/Game/Sound.hpp |
|---|---|
| Source | src/GalaxyEggbert/Game/Sound.cpp |
| Namespace | GalaxyEggbert::Game |
| Channel enum | GalaxyEggbert::Def::SoundChannel in include/GalaxyEggbert/Def/SoundChannel.hpp |
Purpose
Sound owns one CNA SoundEffect and at most one SoundEffectInstance per channel. Channel n is
Content/sounds/soundNNN.wav; a missing file makes that channel a silent no-op. Every play takes the channel's
volume and pitch from kVolumePitch, ported with approval from Mobile Eggbert's tableVolumePitch, times the
player's effects volume. A channel already playing is not restarted, except channel 10, as in the original. Music is not part of this
class: the host plays it with CNA's MediaPlayer (Audio & Music).
Collaborators
Def::SoundChannel: the original's channel numbers 0-92 (0 reserved, never renumber).- CNA's
Microsoft::Xna::Framework::Audio:SoundEffect,SoundEffectInstance,SoundState. - InteractionSystem receives a
Sound&and plays the world's sounds (doors, pickups, enemies, voyages). - GalaxyEggbertGame owns
sound_: loads it, sets the listener and the hidden flag every frame, plays Blupi's and the vehicles' sounds, applies the Setup's switch and volume. - BlupiController supplies the ground icon for
PlayLand()and the motor state for the vehicle loops. - SaveData: sound on/off and
effectsVolume=(0-100).
Public API
| Member | What it does |
|---|---|
static constexpr int kNumChannels = 93 | Channels 0-92. |
void LoadContent() | Loads every Content/sounds/soundNNN.wav that exists (path relative to the working directory). |
int LoadedCount() const | How many channels have a file. |
void Play(SoundChannel channel, bool loop = false) | Plays a channel with its table volume and pitch; left out while Blupi is hidden if it is one of his sounds. |
void PlayDirect(SoundChannel channel, bool loop = false) | As Play() but past the hidden-Blupi filter (sounds the original played directly). |
void PlayAt(SoundChannel channel, float x, float y, float z, bool loop = false) | A sound of the world at a place; played only if Audible() from the listener. |
void SetListener(float x, float y, float z) | Where sounds are heard from: Blupi, set every frame of play. |
static bool Audible(float dx, float dy, float dz), kAudibleAcross = 15, kAudibleUpDown = 11.25 | Within 15 cells along X and Z and 11.25 up or down: the original's one screen beyond the view (BD-0076). |
void SetBlupiHidden(bool), static bool MutedWhileHidden(SoundChannel) | While Blupi is hidden (Hide power) his own channels are not played (BD-0075). |
void Stop(SoundChannel), void StopAll() | Stop one channel (a crate push, a motor loop) or all. |
void SetReplayMuted(bool) | Silence everything during a resume replay or demo verification. |
void SetEnabled(bool), bool IsEnabled() const | The Setup's sound switch; disabling stops all. |
void SetEffectsVolume(float), float GetEffectsVolume() const | 0 silent to 1 the original's loudness, clamped; applies from the next play. |
void PlayJump(), void PlayLand(std::uint16_t groundIcon) | Channel 1; the landing, channel 3 or its material variant. |
static SoundChannel FootstepChannelFor(std::uint16_t icon) | The landing channel for a ground tile: 78, 80, ... 90 in seven icon ranges, else 3. |
static SoundChannel CeilingChannelFor(std::uint16_t icon) | The same ranges' second sound (79, 81, ... 91) for a ceiling met rising, else 4. |
How it is used
Each frame of play, in src/GalaxyEggbertCNA/GalaxyEggbertGameUpdate.cpp:
sound_.SetBlupiHidden(phase_ == GalaxyEggbert::Def::GamePhase::Play && blupi_.IsHidden());
...
sound_.SetListener(blupi_.GetX(), blupi_.GetY(), blupi_.GetZ());
A world sound at a cell, here the lightning's zap:
sound_.PlayAt(GalaxyEggbert::Def::SoundChannel::SoundChannel69, cell.X, cell.Y, cell.Z);
- A looped channel (a vehicle motor) is started with
Play(channel, true)and ended withStop(channel); the host'sUpdateVehicleMotorSound()andStopVehicleMotorSound()do this for channels 15-18 and 28-31. - Inside the audible box a sound plays at full table volume; there is no distance fade and no stereo balance (GP-0412).
- The pitch is applied as the original applies it (XNA octaves, clamped at 0 below); before 2026-11-02 it was missing (BD-0031).
- An instance's looping flag is set only when the instance is created: XNA forbids changing it after the first play.
Tests
VerifyInteractionSystem(tools/VerifyInteractionSystem.cpp):MutedWhileHidden()for all 93 channels against the original's list,Audible()inside and at the edges, every range ofFootstepChannelFor()andCeilingChannelFor(). The test linksSoundwithoutLoadContent(), so no audio device is used.VerifyGESaveData: the effects and music volumes stored insavedata.txt.
Related pages
- Audio & Music — channels, vehicle motors, music and the backend.
- InteractionSystem, GalaxyEggbertGame, SaveData.