MusicPlayer¶
Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.
Description¶
MusicPlayer is a thin client for the music system. It sends commands to the AudioScheduler, which handles the actual sequencing of notes using sample-accurate timing. This ensures that background music is completely independent of the game's frame rate and render performance.
The player uses one audio channel (typically a Pulse channel) for music, leaving other channels available for sound effects.
Namespace¶
Inheritance¶
- Base class: None (standalone class)
- Used by:
Engine(manages music player instance)
Constructors¶
MusicPlayer(AudioEngine& engine)¶
Constructs the MusicPlayer.
Parameters: - engine (AudioEngine&): Reference to the AudioEngine used to play sounds
Notes: - Typically created and managed by Engine - Access via engine.getMusicPlayer()
Example:
Public Methods¶
void play(const MusicTrack& track)¶
Starts playing a track.
Parameters: - track (const MusicTrack&): The track to play
Returns: - void
Notes: - Decoupled: Sends a command to start sequencing the track in the audio thread/core. - Stops any currently playing track. - Starts from the beginning of the track. - If track has loop = true, will loop automatically. - Uses one audio channel (typically Pulse).
Example:
static const MusicNote MELODY[] = {
makeNote(INSTR_PULSE_LEAD, Note::C, 0.20f),
makeNote(INSTR_PULSE_LEAD, Note::E, 0.20f),
makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),
makeRest(0.10f),
};
static const MusicTrack GAME_MUSIC = {
MELODY,
sizeof(MELODY) / sizeof(MusicNote),
true, // loop
WaveType::PULSE,
0.5f // volume
};
void init() override {
auto& music = engine.getMusicPlayer();
music.play(GAME_MUSIC);
}
void stop()¶
Stops playback and silences the channel.
Returns: - void
Notes: - Immediately stops the current note - Resets playback to the beginning - Channel is freed for other use
Example:
void pause()¶
Pauses playback.
Returns: - void
Notes: - Current note continues until it ends, then playback pauses - Playback state is preserved (can resume from where it paused) - Use for pause menus
Example:
void resume()¶
Resumes playback.
Returns: - void
Notes: - Only works if playback was paused - Resumes from where it was paused - Use to unpause after pause menu
Example:
bool isPlaying() const¶
Checks if a track is currently playing.
Returns: - bool: true if playing, false otherwise
Notes: - Returns false if stopped or paused - Use to check playback state before operations
Example:
auto& music = engine.getMusicPlayer();
if (music.isPlaying()) {
// Music is active
} else {
// Music is stopped or paused
}
void setTempoFactor(float factor)¶
Sets the global tempo scaling factor.
Parameters: - factor (float): Tempo multiplier - 1.0f: Normal speed - 2.0f: Double speed - 0.5f: Half speed
Returns: - void
Notes: - Affects all note durations - Useful for speed-up effects or slow-motion - Applied to all tracks
Example:
auto& music = engine.getMusicPlayer();
music.setTempoFactor(1.5f); // 50% faster
music.setTempoFactor(0.5f); // 50% slower
music.setTempoFactor(1.0f); // Normal speed
float getTempoFactor() const¶
Gets the current tempo scaling factor.
Returns: - float: Current factor (default 1.0f)
Example:
MusicTrack Structure¶
A MusicTrack contains:
notes(constMusicNote*): Array of music notesnoteCount(size_t): Number of notes in the arrayloop(bool): Whether to loop the trackwaveType(WaveType): Wave type to use (typicallyPULSE)volume(float): Volume level (0.0 to 1.0)
MusicNote Structure¶
A MusicNote contains:
instrument(InstrumentPreset): Instrument preset to usenote(Note): Musical note (C, D, E, etc.)duration(float): Duration in seconds
Use helper functions: - makeNote(instrument, note, duration): Create a note - makeRest(duration): Create a rest (silence)
Usage Example¶
#include "audio/MusicPlayer.h"
#include "audio/AudioMusicTypes.h"
using namespace pixelroot32::audio;
// Define a simple melody
static const MusicNote MAIN_THEME[] = {
makeNote(INSTR_PULSE_LEAD, Note::C, 0.25f),
makeNote(INSTR_PULSE_LEAD, Note::E, 0.25f),
makeNote(INSTR_PULSE_LEAD, Note::G, 0.25f),
makeRest(0.1f),
makeNote(INSTR_PULSE_LEAD, Note::C, 0.5f),
makeRest(0.2f),
};
static const MusicTrack MAIN_THEME_TRACK = {
MAIN_THEME,
sizeof(MAIN_THEME) / sizeof(MusicNote),
true, // loop
WaveType::PULSE,
0.6f // volume
};
class GameScene : public pixelroot32::core::Scene {
public:
void init() override {
// Start background music
auto& music = engine.getMusicPlayer();
music.play(MAIN_THEME_TRACK);
}
void update(unsigned long deltaTime) override {
Scene::update(deltaTime);
// Music updates automatically
}
void onPauseMenu() {
auto& music = engine.getMusicPlayer();
music.pause();
}
void onResumeGame() {
auto& music = engine.getMusicPlayer();
music.resume();
}
void onGameOver() {
auto& music = engine.getMusicPlayer();
music.stop();
}
};
Performance Considerations¶
- One channel: Music uses one channel, leaving others for sound effects
- Update frequency:
update()must be called every frame - Track size: Larger tracks use more memory (store in flash)
- Tempo factor: Changing tempo is fast (just a multiplier)
ESP32 Considerations¶
- Memory: Store tracks in flash (const/constexpr) to save RAM
- CPU: Music playback is lightweight (simple sequencing)
- Channel conflict: Music and sound effects share channels; plan accordingly
See Also¶
- AudioEngine - Audio playback engine
- AudioTypes - Audio data structures
- AudioMusicTypes - Music data structures
- Manual - Audio
- API Overview