MusicPlayer¶
Lightweight sequencer built on top of AudioEngine to play background melodies as tracks.
Description¶
MusicPlayer is a simple sequencer that plays MusicTrack structures. It advances notes based on game time, converts MusicNote entries to AudioEvent calls, and manages playback state (play, stop, pause, resume).
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: - 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:
void update(unsigned long deltaTime)¶
Updates the player state. Should be called every frame.
Parameters: - deltaTime (unsigned long): Time elapsed since last frame in milliseconds
Returns: - void
Notes: - Must be called every frame for proper timing - Advances note playback based on elapsed time - Automatically plays next notes in sequence - Typically called automatically by Engine
Example:
// Called automatically by Engine, but can be called manually:
void update(unsigned long deltaTime) override {
Scene::update(deltaTime);
// Music player is updated automatically by Engine
// No need to call manually
}
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