How motor music works

Every modern brushless ESC running BLHeli-style firmware can chirp tones through its motor before arming. It is a fun side-effect of how brushless motor commutation works and a clever piece of firmware engineering. This page explains what is going on at three different levels: the physics of turning a motor into a speaker, the RTTTL byte format the firmware actually stores, and the polyphony scheduling beepmyquad does to spread a complex MIDI score across multiple motors.

1. A brushless motor is a (terrible) loudspeaker

A brushless DC motor has three stator phases (U, V, W) wound around a soft-iron stator core. To make the rotor spin the ESC switches each phase between +V and ground in a precise six-step or sinusoidal commutation pattern, usually at PWM frequencies between 24 kHz and 48 kHz. The magnetic field these switches create rotates and drags the permanent-magnet rotor with it.

A loudspeaker works on the same physics in reverse: a coil of wire in a magnetic field, driven by a varying current, exerts a force on a diaphragm and pushes air. So if you drive the motor's coils with an audio-frequency signal instead of a commutation signal, the stator laminations vibrate at the same frequency. The motor frame radiates that vibration as a faint but clearly audible tone — typically somewhere between 200 Hz and 4 kHz, which conveniently is the heart of the human speech range.

The trick that makes ESC music possible is that the firmware can produce these audio-frequency switching patterns without actually energising the motor enough to rotate. The PWM duty cycle is low and the switching pattern is symmetric, so the average torque is zero, the rotor stays still, and you hear a tone instead of seeing a spin-up.

Some quick consequences of this physics:

2. RTTTL: a 1990s ringtone format that found a second life

RTTTL stands for Ring Tone Text Transfer Language. Nokia introduced it in 1996 so users could share monophonic ringtones over SMS without needing a binary file format. A complete tune fits on one line and looks like this:

tetris:d=4,o=5,b=140:e6,8b,8c6,8d6,16e6,16d6,8c6,8b,a,8a,8c6,e6,8d6,8c6,b,8b,8c6,d6,e6,c6,a,a,8p

It has three colon-separated parts:

  1. Name — up to ten ASCII characters. Used by the firmware (and configurators) to display which tune is loaded.
  2. Defaults — comma-separated key=value pairs. d is the default note duration (1, 2, 4, 8, 16, 32 — same convention as music notation), o is the default octave (4–7), b is the tempo in beats per minute.
  3. Notes — comma-separated tokens. Each token is [duration]note[#][.][octave]: an optional duration override, the note letter (ag or p for pause), an optional sharp, an optional dot for dotted note, and an optional octave override.

Bluejay (and most BLHeli-style firmwares) accept RTTTL via the configurator's "Melody Editor". Internally the firmware parses the string into a packed byte array:

byte 0–3   : RTTTL defaults (duration, octave, tempo, flags)
byte 4–127 : up to 62 (frequency, duration) pairs

The frequency byte is an index into a lookup table that covers roughly four octaves at semitone resolution. The duration byte counts firmware timer ticks. Together they pack one note into two bytes, which is why beepmyquad caps each output at 62 notes by default — that's exactly what fits in Bluejay's 128-byte slot after the header.

3. From polyphonic MIDI to multi-motor RTTTL

MIDI files are inherently polyphonic. A single track can contain ten notes playing at the same time; a typical Western pop song has 4–8 tracks each with their own simultaneous notes. Each ESC, however, plays only one note at a time. beepmyquad's job is to take a polyphonic score and squeeze it onto N monophonic motor lanes.

The algorithm runs in two phases.

Phase 1: pinned notes

If you have manually pinned any notes to a specific motor via the editor, those notes are placed first. They always win their slot — if two pinned notes overlap on the same motor, the most recently pinned one keeps the slot and the other is deactivated. This is sorted by a per-note pin sequence number so "newest pin wins" is consistent.

Phase 2: greedy interval scheduling

Remaining notes are walked through in time order (ties broken by descending pitch). For each note we look at which motor lanes currently have no overlapping note at this time and pitch:

The result is up to N parallel monophonic streams, each emitted as its own RTTTL string via a quantisation pass: each note's duration is snapped to the nearest valid RTTTL duration (whole, half, quarter, eighth, sixteenth, thirty-second), optionally with a dot for dotted notes; each pitch is mapped to its octave; rests bridge the gaps. The 24-bit header (default duration + octave + tempo + name) is shared across all motors.

4. Why songs sound the way they do

Three predictable artefacts you'll hear once you start running this in real life:

5. The 128-byte budget in practice

62 notes is more than you'd think — most recognisable hooks fit comfortably. Some examples we've measured from the curated song library:

Practical tip: keep your dotted notes for the bass line. The header's d=4 default duration matches most quarter-note hooks, which means quarter notes encode as a single character instead of three (just c instead of 4c5). Each saved character is a saved byte.

6. Going further

If you found this interesting, useful jumping-off points:

Ready to try it? Open the converter, drop in a MIDI, hit Convert, and see your motors sing.