A hardware-based 10-track MIDI looper pedal built with Raspberry Pi 3B+ and designed for use with Casio keyboards. Record, layer, and loop MIDI performances with physical button controls and LED feedback.
- 10 Independent Tracks - Layer multiple MIDI recordings
- Super Looper Mode - Perfect synchronization with fixed loop duration
- Backing Track Recording - Hear previous tracks while recording new ones
- Auto-Looping Playback - Tracks loop seamlessly based on longest recording
- Full MIDI Capture - Records velocity, sustain pedal, and all MIDI CC data
- Multitrack Tone Isolation - Each track can use a different instrument/tone
- Persistent Storage - Auto-saves session, survives power cycles
- MIDI Export - Export as merged or separate MIDI files
- MIDI Import - Load existing MIDI files into tracks
- Visual Feedback - LED indicators for mode, tracks, and recording status
- Tone-Independent - Recordings play in any sound you select on your keyboard
Here is a quick video https://github.com/user-attachments/assets/2e4bd62a-28d7-422f-b661-94d50daeed41
- Raspberry Pi 3B+ (1GB RAM)
- Casio CTX870IN Keyboard (or compatible USB-MIDI keyboard)
- 4× Tactile Push Buttons
- 1× Touch Sensor (TTP223 or similar)
- 10× Green LEDs (Track indicators)
- 1× Red LED (Recording mode)
- 1× Yellow LED (Playing mode)
- 1× Blue LED (Pause indicator)
- 1× White LED (Clear track indicator)
- 1× Red LED (Delete all indicator)
- Breadboard & Jumper Wires
- USB Cable (USB-A to USB-B for Casio keyboard)
- Power Supply (5V 2.5A+ Micro USB)
- Resistors (220Ω) for LEDs (code uses PWM at 20% duty cycle as workaround)
| Component | GPIO Pin | Physical Pin |
|---|---|---|
| Button 1 (Mode Toggle) | GPIO 5 | Pin 29 |
| Button 2 (Start/Stop) | GPIO 6 | Pin 31 |
| Button 3 (Left/Pause) | GPIO 13 | Pin 33 |
| Button 4 (Right/Clear) | GPIO 19 | Pin 35 |
| Component | GPIO Pin | Physical Pin |
|---|---|---|
| Touch Sensor OUT | GPIO 26 | Pin 37 |
| Touch Sensor VCC | 3.3V | Pin 1 or 17 |
| Touch Sensor GND | GND | Any GND pin |
| LED Color/Function | GPIO Pin | Physical Pin |
|---|---|---|
| RED (Recording Mode) | GPIO 20 | Pin 38 |
| YELLOW (Playing Mode) | GPIO 21 | Pin 40 |
| BLUE (Pause) | GPIO 22 | Pin 15 |
| WHITE (Clear Track) | GPIO 23 | Pin 16 |
| RED (Delete All) | GPIO 24 | Pin 18 |
| Track | GPIO Pin | Physical Pin |
|---|---|---|
| Track 1 | GPIO 4 | Pin 7 |
| Track 2 | GPIO 17 | Pin 11 |
| Track 3 | GPIO 27 | Pin 13 |
| Track 4 | GPIO 25 | Pin 22 |
| Track 5 | GPIO 12 | Pin 32 |
| Track 6 | GPIO 16 | Pin 36 |
| Track 7 | GPIO 2 | Pin 3 |
| Track 8 | GPIO 3 | Pin 5 |
| Track 9 | GPIO 8 | Pin 24 |
| Track 10 | GPIO 7 | Pin 26 |
Connect all LED cathodes and button grounds to GND pins:
- Pin 6, 9, 14, 20, 25, 30, 34, 39 (all are GND)
Recording Mode ↔ Playing Mode
- Only works when STOPPED (not during recording/playback)
- Visual indicator: RED LED (REC) / YELLOW LED (PLAY)
Master transport control
- Starts recording on currently selected track
- Overwrites previous recording on that track
- Backing tracks (other recorded tracks) loop in background
- RED LED and selected track LED blink during recording
- Plays all recorded tracks together
- Tracks loop automatically based on longest track duration
- All tracks with recordings light up
- Stops recording/playback
- Sends MIDI panic (stops stuck notes)
- Auto-saves session (in REC mode)
Context-sensitive dual function
- Navigate LEFT through tracks (10 → 9 → 8 → ... → 1 → 10)
- Selected track LED lights up
- Use to choose which track to record on
- PAUSE/RESUME playback
- BLUE LED lights when paused
- Sends MIDI panic when pausing
Context-sensitive dual function
- Navigate RIGHT through tracks (1 → 2 → 3 → ... → 10 → 1)
- Selected track LED lights up
- Use to choose which track to record on
- CLEAR currently selected track
- WHITE LED flashes briefly
- Track immediately goes silent
- Session auto-saves
Emergency reset
- Deletes ALL 10 tracks permanently
- Stops playback/recording if running
- Sends MIDI panic
- RED "Delete All" LED flashes for 1 second
⚠️ No undo!
- Auto-saves after each recording in REC mode
- Auto-saves when tracks are cleared
- Auto-loads last session on startup
- Dual session files:
- Normal mode:
~/looper_autosave/session.json - Super Looper mode:
~/looper_autosave/supersession.json
- Normal mode:
- Survives power cycles!
Access via SSH to control advanced features:
# Super Looper Mode
SL ON # Enable Super Looper with fixed duration
SL OFF # Return to Normal mode
# Track Status
status # Show all tracks, durations, and mode
# MIDI Export
save # Export tracks (merged or separate)
# MIDI Import
load <track> <file.mid> # Load MIDI file into trackExport your compositions via SSH:
save
# Choose option:
# 1 - Merge all tracks into one MIDI file
# 2 - Export each track as separate MIDI files
# Files saved to: ~/looper_exports/Merged export: merged_output.mid (all tracks combined)
Separate exports: track_1.mid, track_2.mid, etc.
Load existing MIDI files into tracks:
# Syntax: load <track_number> <filepath>
load 1 ~/my_melody.mid
load 5 /home/pi/Downloads/bass_line.midCheck which tracks have recordings:
status
# Normal mode output:
# Mode: Normal
# Track 1: 245 events, 8.32s
# Track 2: Empty
# Track 3: 189 events, 5.47s
# Longest track: 8.32s
# Super Looper mode output:
# Mode: 🔒 SUPER LOOPER (Fixed Duration: 8.50s)
# Track 1: 245 events, 8.50s (forced to SL duration)
# Track 2: 189 events, 8.50s (forced to SL duration)
# All tracks loop to: 8.50s- Use Raspberry Pi OS Lite (64-bit)
- Enable SSH in imager settings
- Configure WiFi credentials
- Set hostname:
raspberrypi - Username:
pi
# SSH into Pi
ssh pi@raspberrypi.local
# Update system
sudo apt update
sudo apt upgrade -y
# Install required packages
sudo apt install -y python3-pip python3-rpi.gpio python3-mido python3-rtmidi
# Or if apt doesn't have them:
pip3 install --break-system-packages mido python-rtmidi# On your Mac, copy the script to Pi:
scp looper.py pi@raspberrypi.local:~/
# Or create it directly on Pi:
ssh pi@raspberrypi.local
nano looper.py
# Paste the code, save with Ctrl+X, Y, Enter# Make sure Casio is plugged in via USB
python3 looper.py
# You should see:
# Found Inputs: ['Casio USB-MIDI...']
# System Ready.
# Press Ctrl+C to stopsudo nano /etc/systemd/system/looper.servicePaste this:
[Unit]
Description=MIDI Looper
After=network.target
[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/python3 /home/pi/looper.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetEnable it:
sudo systemctl enable looper.service
sudo systemctl start looper.service
# Check status:
sudo systemctl status looper.service# Copy file to Pi's home directory:
scp /path/to/file.mid pi@raspberrypi.local:~/
# Copy to specific location:
scp melody.mid pi@raspberrypi.local:~/looper_exports/# Copy file from Pi to current directory:
scp pi@raspberrypi.local:~/looper_exports/merged_output.mid .
# Copy multiple files:
scp pi@raspberrypi.local:~/looper_exports/*.mid ~/Desktop/# Connect with SFTP:
sftp pi@raspberrypi.local
# SFTP commands:
get looper_exports/merged_output.mid # Download
put my_track.mid # Upload
ls # List files
cd looper_exports # Change directory
exit # QuitSuper Looper Mode ensures perfect synchronization across all tracks by enforcing a fixed loop duration. Unlike normal mode where tracks loop at different lengths, Super Looper guarantees all tracks align to the same timeline.
- Fixed Duration Enforcement - All tracks loop to the exact same duration
- Perfect Synchronization - No drift or timing misalignment between tracks
- Separate Session Management - Independent save files for Super Looper and Normal modes
- Auto-Stop Recording - Recordings automatically stop at the set duration limit
- Two Setup Methods:
- Manual Declaration: Set a specific duration before recording (e.g., 8 seconds)
- First Track Duration: Use the first recorded track's length as the fixed duration
Via the CLI (SSH into your Pi):
# Enable Super Looper
SL ON
# You'll be prompted to choose setup method:
# 1. Declare time manually - Enter duration in seconds
# 2. Get time from first recorded track - Duration set automaticallyExample session:
SL ON
=== Super Looper Duration Setup ===
1. Declare time manually
2. Get time from first recorded track
Choose option (1/2): 1
Enter duration in seconds: 8.5
✓ Super Looper enabled with 8.50s fixed duration-
Manual Duration Setup:
- Type
SL ON - Choose option
1 - Enter duration (e.g.,
8for 8 seconds) - All tracks will now loop to exactly 8 seconds
- Recordings auto-stop at 8 seconds
- Type
-
First Track Duration:
- Type
SL ON - Choose option
2 - Record your first track normally
- When you press Stop, that duration becomes the fixed length
- All subsequent tracks loop to this duration
- Type
Shorter than Fixed Duration:
Fixed duration: 8.00s
Recorded: 5.50s
Result: Track loops twice (2.5 loops per cycle) to fill 8.00s
Exceeds Fixed Duration:
Fixed duration: 8.00s
Recorded: 9.20s
Result: Track cut at 8.00s, ⚠️ warning displayed
# Return to Normal mode
SL OFF
# Your Super Looper session is saved
# Normal mode session is restoredSuper Looper uses separate session files:
- Super Looper:
~/looper_autosave/supersession.json - Normal Mode:
~/looper_autosave/session.json
Switching modes:
- Current session is auto-saved
- Mode switches to new mode
- Previous session in that mode is loaded
- All tracks and settings are preserved independently
status
# Output in Super Looper mode:
# Mode: 🔒 SUPER LOOPER (Fixed Duration: 8.50s)
# Track 1: 245 events, 8.50s (forced to SL duration)
# Track 2: 189 events, 8.50s (forced to SL duration)
# All tracks loop to: 8.50s✅ Best for:
- Drum patterns and rhythmic loops
- EDM/electronic music production
- Perfectly timed backing tracks
- Songs requiring strict timekeeping
❌ Not ideal for:
- Free-form improvisation
- Varying phrase lengths
- Classical/jazz with rubato
Each track uses its own dedicated MIDI channel (0-9) for tone isolation:
- Track 1 → Channel 0
- Track 2 → Channel 1
- ...
- Track 10 → Channel 9
This means every track can have a different tone/instrument simultaneously!
Workflow:
- Select tone on your Casio keyboard before recording
- Press Button 2 to start recording
- The tone is automatically captured and saved with the track
- Navigate to next track (Button 4)
- Change tone on keyboard
- Record next track with new tone
Example:
Track 1: Select "Grand Piano" → Record melody
Track 2: Select "Strings" → Record harmony
Track 3: Select "Bass" → Record bass line
Track 4: Select "Drums" → Record percussion
When recording a new track, all previously recorded tracks play in the background:
- Hear the complete mix while adding new parts
- Perfect for layering complementary melodies
- No need for external metronome if you have a rhythm track
Example:
1. Record drums on Track 1
2. Select Track 2 → drums play as backing track
3. Record bass while hearing drums
4. Select Track 3 → drums + bass play as backing tracks
5. Record melody with full rhythm section
Normal Mode:
- Each track loops at its own recorded duration
- Shorter tracks loop multiple times per cycle
- Example: 4s track + 8s track → 4s track plays twice
Super Looper Mode:
- All tracks loop to the same fixed duration
- Ensures perfect synchronization
- Example: All tracks loop to exactly 8.00s
Your recordings store MIDI data only, not audio:
- Change tone on keyboard anytime during playback
- All tracks respond to new tone selection
- Example: Record in Piano, play back as Strings
Per-Track Tones (Advanced): The system remembers each track's original tone:
- Track 1: Piano (Program 0)
- Track 2: Strings (Program 48)
- Each plays with its recorded tone during multitrack playback
Clearing Individual Tracks:
1. Switch to PLAY mode (Button 1)
2. Start playback (Button 2)
3. Navigate to track to clear (Button 3/4)
4. Press Button 4 (Clear) - WHITE LED flashes
5. Track immediately goes silent
Clearing All Tracks:
Touch the touch sensor
→ RED LED flashes for 1 second
→ All 10 tracks deleted
→ ⚠️ No undo!
Merged Export (Single file):
save
Choose: 1
# Creates: merged_output.mid (all tracks combined)
# Use in: DAW software, MIDI playersSeparate Export (Individual files):
save
Choose: 2
# Creates: track_1.mid, track_2.mid, ..., track_10.mid
# Use in: DAW for individual editing/mixing- Start with rhythm: Record drums/percussion on Track 1 first
- Layer bass next: Track 2 provides harmonic foundation
- Add harmonies: Tracks 3-6 for chords and melodies
- Use Track 10 for leads: Easy to clear/re-record solos
- Name your tracks (in DAW after export for reference)
- Power on (default: REC mode, Track 1 selected)
- Press Button 2 (Start recording)
- RED LED and Track 1 LED blink
- Play your melody on Casio keyboard
- Press Button 2 (Stop recording)
- LEDs stop blinking
- Track auto-saves
- Press Button 4 (Right) to select Track 2
- Press Button 2 (Start recording)
- Track 1 loops in background as you record Track 2
- Play complementary part
- Press Button 2 (Stop)
- Press Button 1 to switch to PLAY mode
- YELLOW LED lights up
- All recorded tracks' LEDs light up
- Press Button 2 (Start playback)
- All tracks play together, looping continuously
- Press Button 3 (Pause) to pause/resume
- Press Button 2 (Stop) when done
- SSH into Pi:
ssh pi@raspberrypi.local - Type:
save - Choose:
1(merged) or2(separate tracks) - Transfer file to Mac:
scp pi@raspberrypi.local:~/looper_exports/merged_output.mid ~/Desktop/
- Transfer MIDI file to Pi:
scp bass_line.mid pi@raspberrypi.local:~/ - SSH into Pi and load it:
load 3 ~/bass_line.mid - Track 3 now contains that MIDI data
- Captures all MIDI messages: note on/off, velocity, sustain, mod wheel, etc.
- Records timing with microsecond precision
- No quantization - records exactly what you play
- Tracks loop based on longest track duration
- Example: Track 1 (5s) + Track 2 (10s) → Track 1 loops twice per cycle
- Seamless loop transitions
- Each MIDI event: ~50 bytes
- 1GB RAM can store ~20 million events
- Practical limit: hours of recording before RAM fills
- Records MIDI data only, not audio
- Your keyboard interprets the MIDI
- Change sound on Casio anytime - recording adapts
- Example: Record in Grand Piano, play back as Strings
- Pi + LEDs: ~500mA @ 5V (2.5W)
- Recommended: 5V 2.5A+ power supply
- Compatible: Phone chargers (22.5W+), official Pi adapter, quality power banks
vcgencmd get_throttled
# Output should be: throttled=0x0# Check connected MIDI devices:
python3 -c "import mido; print(mido.get_input_names())"
# Replug USB cable, wait 10 seconds, try again- Check GPIO connections match pinout
- Verify GND connections
- Test individual LED:
gpio -g mode 20 out; gpio -g write 20 1
- Use better power supply (5V 2.5A minimum)
- Avoid long/thin USB cables
- Don't use USB hub power
# Check logs:
sudo journalctl -u looper.service -n 50
# Stop service for manual testing:
sudo systemctl stop looper.service
python3 looper.py# Check autosave file exists:
ls -lh ~/looper_autosave/session.json
# If corrupted, delete and start fresh:
rm ~/looper_autosave/session.json| LED | Steady On | Blinking | Flashing |
|---|---|---|---|
| RED (Rec) | Recording mode active | Currently recording | - |
| YELLOW (Play) | Playing mode active | - | - |
| BLUE (Pause) | Playback paused | - | - |
| WHITE (Clear) | - | - | Track cleared |
| RED (Delete) | - | - | All tracks deleted |
| Green (Track) | Track selected OR has data | Recording on this track | - |
- Recording is overwrite mode - Re-recording a track erases previous version
- Touch sensor deletes everything - Use carefully!
- No resistors = LED risk - PWM helps, but don't run 24/7
- Auto-save is automatic - Manual save only for MIDI export
- Backing tracks loop during recording - Hear context while recording new parts
- Overdub mode (layer recordings on same track)
- Metronome with tempo control
- Undo last recording
- Volume control per track
- OLED display for visual feedback
- Foot pedal support
- Quantization options
- MIDI clock sync
Feel free to submit issues, fork the repository, and create pull requests for any improvements.
MIT License - Feel free to use and modify for your projects!
Built with:
For questions or suggestions, open an issue on GitHub!
Happy Looping! 🎹🎵