A real-time Python tool that converts MIDI note input into PPM (Pulse Position Modulation) audio signals to control an original Teddy Ruxpin toy's servos. Input can come from a live MIDI device or a MIDI file.
The PPM signal is output on the right stereo channel, matching the 8-channel RC-style format used by the original Teddy Ruxpin cassette tapes.
Inspired by https://github.com/pjdoland/jf-sebastian and https://github.com/GabeKnuth/t-rux
- Python 3.10+
- A Teddy Ruxpin with its cassette mechanism wired to accept line-level audio input
- An audio interface with stereo output (right channel carries the PPM signal)
- For live mode: a MIDI controller or virtual MIDI port
python -m venv venv
source venv/bin/activate
pip install -r requirements.txtConnect a MIDI controller and run:
python ruxppm.pyThe tool will list available MIDI input ports and prompt you to select one. If only one port is found, it is selected automatically.
Pass a .mid file as an argument:
python ruxppm.py song.midThe file plays back in real time, driving the servos with proper timing. The program exits automatically when playback finishes.
Both modes can be stopped at any time with Ctrl+C.
| Note | Name | Servo | PPM Channel | Behavior |
|---|---|---|---|---|
| 60 | C3 | EYES | CH4 | Velocity-scaled open; release closes |
| 62 | D3 | UPPER jaw | CH2 | Velocity-scaled close; release opens |
| 64 | E3 | LOWER jaw | CH3 | Toggle on/off (not velocity-scaled) |
Edit the constants at the top of ruxppm.py to adjust:
| Constant | Default | Description |
|---|---|---|
SAMPLE_RATE |
44100 | Audio sample rate. Higher rates (96000, 192000) give finer servo resolution. |
NOTE_EYES |
60 | MIDI note number for eyes |
NOTE_NOSE |
62 | MIDI note number for upper jaw |
NOTE_MOUTH |
64 | MIDI note number for lower jaw |
SERVO_SCALE |
0.90 | Servo travel multiplier (0.0–1.0) |
NOSE_OPEN |
80 | Upper jaw open position (0–100 scale) |
MIT