MuseScore 4.7+ plugin: dockable audio player with waveform, precise seeking, A-B looping, speed, pitch, and a 10-band equalizer, for ear-training and transcription without leaving MuseScore.
Download the latest release for your operating system:
- macOS (Apple Silicon):
MUTranscriber-x.x.x-macOS-arm64.zip - macOS (Intel):
MUTranscriber-x.x.x-macOS-intel.zip - Windows:
MUTranscriber-x.x.x-Windows.zip - Linux:
MUTranscriber-x.x.x-Linux.zip
Not sure which Mac you have? Apple menu → About This Mac → "Chip" tells you Apple Silicon (M1/M2/M3/...) vs Intel.
Extract the downloaded .zip file to access the installation files.
- Locate the extracted file
MUTranscriber-x.x.x.pkg(from whichever of the arm64/intel archives matches your Mac) - Double-click the
.pkgfile to launch the installer - Follow the on-screen instructions to complete the installation
- The plugin will be automatically installed to
~/Documents/MuseScore4/Plugins/MUTranscriber/
- Locate the extracted file
MUTranscriber-x.x.x-Setup.exe - Double-click the
.exefile to launch the installer - Follow the on-screen instructions to complete the installation
- The plugin will be automatically installed to
Documents\MuseScore4\Plugins\MUTranscriber\
- Extract the
MUTranscriber-x.x.x-Linux.ziparchive - Copy the
MUTranscriberfolder to your MuseScore plugins directory:cp -r MUTranscriber ~/Documents/MuseScore4/Plugins/ - Ensure the binary has execution permissions:
chmod +x ~/Documents/MuseScore4/Plugins/MUTranscriber/dist/MUTranscriber
- Launch MuseScore 4
- Navigate to Plugins → Manage Plugins
- In the plugin manager, locate MUTranscriber in the list
- Click Enable to enable it
- Open a score in MuseScore
- Navigate to Plugins → MUTranscriber to launch the plugin: a dockable panel appears at the bottom of the window
- Click "Load..." (or pick from the recent-files list) to choose an audio file
- Play/Pause, click on the waveform to move the cursor, use the A/B buttons or the handles on the waveform to define a loop that repeats automatically, and adjust speed, pitch, and the 10-band equalizer from the toolbar
Nothing loads automatically when the plugin opens: every session starts
empty, loading is always an explicit action. The recent-files list is
persisted in recent_files.json next to the plugin (not in the score), so
it survives across different projects.
- MuseScore 4.7 or later
- macOS: macOS 10.13 or later (separate installers for Apple Silicon and Intel - see the Download section above)
- Windows: Windows 10 or later
- Linux: Ubuntu 22.04+ / Debian 11+ or a compatible distribution
- ffmpeg on the system
PATH(or discoverable via MuseScore's own preferences) is required to load formats other than WAV/FLAC/OGG/AIFF, MP3 in particular - the backend transcodes those on the fly to a temporary WAV file when loading
For issues or questions, please use the Issues section of this repository.
If you’d like to support my work, you can make a donation via PayPal:
The MuseScore 4 plugin API doesn't expose QtMultimedia. This plugin works
around that limitation with a small Python backend (sounddevice) running
in the background, driven by the QML side over a local HTTP API.
The steps above are for the prebuilt releases. To build the backend yourself instead:
cd python
./build.shProduces dist/MUTranscriber (or dist/MUTranscriber.exe on Windows),
launched automatically by the plugin via QProcess. Without a prior
build, the plugin won't be able to start the backend. This requires
Python 3 plus the packages listed in python/requirements.txt (only
needed to build the executable, not to run it afterward).
To develop/iterate without a PyInstaller rebuild on every change, the server can be run directly instead:
cd python
pip install -r requirements.txt
python server.py(in that case, the plugin will detect the already-running backend and reuse that process instead of starting a new one).
The GitHub Actions workflow at .github/workflows/build.yml builds and
packages all four installers (macOS .pkg for Apple Silicon and Intel
separately via create_pkg.sh, Windows .exe via installer.iss/Inno
Setup, and the Linux archive) on every v* tag push. The two macOS builds
are fully independent of each other rather than fused into one universal2
binary, so a slow/congested runner queue for one architecture never
delays shipping the other.
Both the backend and the QML plugin independently try the same ordered
list of ports (8001 through 8005) on every launch, and agree on
whichever one responds first - no fixed port, no configuration stored
anywhere: if 8001 is already taken by something else on the machine,
the backend automatically falls back to the next port, and the plugin
finds it by probing and checking the actual shape of the /status
response (not just an HTTP 200, to avoid mistaking some unrelated service
for ours).
- Speed (0.25x-1.25x) and pitch (±12 semitones, one octave) are
independent transforms applied to the whole track
(
librosa.effects.time_stretch/pitch_shift) - changing either one recomputes the buffer with both current values, never just the one that changed. This recompute takes time proportional to the track's length (shown via a spinner + ETA in the UI). - The equalizer (10 ISO bands, 31Hz-16kHz) is applied in real time
inside the audio callback (peaking IIR filters via
scipy.signal.sosfilt), so without the same delay as speed/pitch.
| Endpoint | Method | Description |
|---|---|---|
/status |
GET | Current state (position, duration, loop, speed, pitch, recompute in progress, etc.) |
/load |
POST | {file_path} - loads an audio file |
/waveform |
GET | Min/max envelope (optional start_s/end_s for a high-resolution slice) |
/play |
POST | {position_s?} - starts/resumes playback |
/pause |
POST | Pauses playback |
/seek |
POST | {position_s} |
/loop |
POST | {a_s?, b_s?} (null clears a marker, omit to leave it untouched) |
/volume |
POST | {volume} (0-200) |
/speed |
POST | {rate} (0.25-1.25) |
/pitch |
POST | {semitones} (-12 to +12) |
/eq |
GET/POST | Equalizer state ({enabled, gains}) |
/eq-presets |
GET | Predefined EQ presets |
/recent-files |
GET/POST/DELETE | Recent-files list (persisted as JSON) |
/heartbeat |
GET | Keeps the process alive (auto-stops otherwise) |
The process automatically stops if it stops receiving a heartbeat for 10 seconds (avoids an orphaned process if MuseScore exits abnormally).
