Built-In Melodies System
Overview
The built-in melodies system allows you to bake melodies directly into the firmware, eliminating the need for SD card downloads. Melodies are stored in PROGMEM (Flash memory), so they don't consume precious RAM.
How It Works
- Check: When a melody is requested, the Player first checks if the UID starts with
builtin_ - Load: If it's built-in, the melody is loaded from Flash memory (PROGMEM)
- Fallback: If not built-in, it loads from SD card as usual
Adding New Melodies
Step 1: Create Your Melody Data
Each melody step is a 2-byte (uint16_t) bitmask representing which bells to activate:
// Example: Simple pattern
const uint16_t PROGMEM melody_my_tune[] = {
0x0001, // Bell 0
0x0002, // Bell 1
0x0004, // Bell 2
0x0008, // Bell 3
0x0003, // Bells 0+1 together
0x000F // Bells 0+1+2+3 together
};
Bitmask Reference:
0x0001= Bell 0 (bit 0)0x0002= Bell 1 (bit 1)0x0004= Bell 2 (bit 2)0x0008= Bell 3 (bit 3)0x0010= Bell 4 (bit 4)0x0020= Bell 5 (bit 5)0x0040= Bell 6 (bit 6)0x0080= Bell 7 (bit 7)0x0100= Bell 8 (bit 8)- ... up to
0x8000= Bell 15 (bit 15) 0x0000= Silence/rest
Combining Bells:
0x0003= Bells 0+1 (0x0001 | 0x0002)0x0005= Bells 0+2 (0x0001 | 0x0004)0x000F= Bells 0+1+2+30xFFFF= All 16 bells
Step 2: Add to BuiltInMelodies.hpp
Open src/BuiltInMelodies/BuiltInMelodies.hpp and:
- Add your melody array:
// Your new melody
const uint16_t PROGMEM melody_my_awesome_tune[] = {
0x0001, 0x0002, 0x0004, 0x0008,
0x0010, 0x0020, 0x0040, 0x0080,
// ... up to 200 steps
};
- Add to MELODY_LIBRARY array:
const MelodyInfo MELODY_LIBRARY[] = {
// ... existing melodies ...
// Your new melody
{
"My Awesome Tune", // Display name
"builtin_my_awesome_tune", // UID (must start with "builtin_")
melody_my_awesome_tune, // Data array
sizeof(melody_my_awesome_tune) / sizeof(uint16_t), // Step count
200 // Default speed in milliseconds per beat
}
};
Step 3: Use Your Melody
Send a play command with the built-in melody UID:
MQTT:
{
"group": "playback",
"action": "play",
"uid": "builtin_my_awesome_tune",
"name": "My Awesome Tune",
"speed": 200
}
WebSocket/HTTP:
{
"group": "playback",
"action": "play",
"uid": "builtin_my_awesome_tune",
"name": "My Awesome Tune",
"speed": 200
}
Pre-Loaded Melodies
The following melodies are already built-in:
| UID | Name | Steps | Default Speed |
|---|---|---|---|
builtin_scale |
Simple Scale | 8 | 200ms |
builtin_happy_birthday |
Happy Birthday | 23 | 250ms |
builtin_jingle_bells |
Jingle Bells | 32 | 180ms |
builtin_westminster |
Westminster Chimes | 16 | 400ms |
builtin_alarm |
Alarm | 16 | 150ms |
builtin_doorbell |
Doorbell | 4 | 300ms |
builtin_single_bell |
Single Bell Test | 1 | 100ms |
Memory Usage
Flash Memory (PROGMEM)
- Small melody (~30 steps): 60 bytes
- Large melody (~200 steps): 400 bytes
- 40 melodies average: ~6-10KB (stored in Flash, not RAM!)
RAM Usage
Only the currently playing melody is loaded into RAM. Built-in melodies are copied from Flash when needed.
Tips
- Always use
builtin_prefix for UIDs to identify them as built-in - Test with small melodies first before adding large ones
- Use hex calculator for complex bell combinations:
0x0001 | 0x0004 = 0x0005 - Add rests with
0x0000for silence between notes - Keep it simple - most melodies work great with 30-50 steps
Converting Binary Files to Code
If you have existing binary melody files and want to convert them to built-in format:
# Python script to convert binary file to C++ array
with open('melody.bin', 'rb') as f:
data = f.read()
print("const uint16_t PROGMEM melody_name[] = {")
for i in range(0, len(data), 2):
if i % 16 == 0:
print(" ", end="")
high = data[i]
low = data[i+1]
value = (high << 8) | low
print(f"0x{value:04X}", end="")
if i < len(data) - 2:
print(", ", end="")
if (i + 2) % 16 == 0:
print()
print("\n};")
Example: Creating a Custom Melody
Let's create "Mary Had a Little Lamb":
// Mary Had a Little Lamb
// Notes: E D C D E E E, D D D, E G G
// Mapping: E=0, D=1, C=2, G=3
const uint16_t PROGMEM melody_mary_lamb[] = {
0x0001, 0x0002, 0x0004, 0x0002, // E D C D
0x0001, 0x0001, 0x0001, 0x0000, // E E E (rest)
0x0002, 0x0002, 0x0002, 0x0000, // D D D (rest)
0x0001, 0x0008, 0x0008 // E G G
};
// Add to MELODY_LIBRARY:
{
"Mary Had a Little Lamb",
"builtin_mary_lamb",
melody_mary_lamb,
sizeof(melody_mary_lamb) / sizeof(uint16_t),
300 // 300ms per beat
}
Now you can play it with UID builtin_mary_lamb!