MIDI Type 1 → Type 0 Converter (Frontend)
Convert MIDI Type 1 files to Type 0 with a lightweight WordPress plugin featuring frontend uploads, asynchronous processing, and batch download support.
by Alexander Peppe · github.com/diskchord/midi-type0-converter
★ 0stars
0forks
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/diskchord/midi-type0-converter/archive/refs/heads/main.zipMIDI Type 1 -> Type 0 Converter (WordPress Plugin)
Frontend WordPress plugin that lets users upload .mid/.midi files, converts MIDI Type 1 to Type 0 asynchronously, and provides per-file or batch ZIP downloads.
Features
- Frontend upload UI via shortcode:
[midi_type0_converter] - Multi-file upload with per-job status polling
- Asynchronous conversion pipeline (
queued -> processing -> done/error) - Optional routing of all channel events to MIDI Channel 1
- Optional removal of General MIDI percussion on Channel 10 while routing parts to Channel 1
- Optional removal of descriptive metadata while preserving the first title
- Per-file signed download links
- Batch ZIP download link (when
ZipArchiveis available) - Private storage under
wp-content/uploads/mtc-private - Rate limits for upload/status/download endpoints
- Optional ClamAV scan before storing uploads (disabled by default)
Requirements
- WordPress (plugin architecture + AJAX + cron APIs)
- PHP 8.0+ recommended (uses modern PHP features like
match) ZipArchiveextension for "Download All (ZIP)"- Optional:
clamdscanfor antivirus scanning when enabled by filter
Installation
- Copy this project folder into
wp-content/plugins/. - Activate the plugin in WordPress admin.
- Add shortcode
[midi_type0_converter]to a page/post. - Open that page and upload MIDI files.
Usage
- Select one or more
.mid/.midifiles. - Choose any settings under Options:
Play all parts on the piano (MIDI Channel 1)routes every part to the piano itself instead of playing some parts through a Disklavier's speakers.Exclude percussion (MIDI Channel 10)becomes available with that option and prevents General MIDI drum events from playing as piano notes.
Strip extra metadatacan help files that will not load, start, or play correctly on some Disklaviers and older MIDI players. It removes unnecessary descriptive text while keeping the first title and playback data.
- Click
Upload & Convert. - Polling starts automatically and status updates appear in the table.
- Download files individually as they complete, or use
Download All (ZIP)when available.
How It Works
- Upload endpoint:
mtc_upload(wp_ajax_*)- Validates nonce, extension, MIDI header (
MThd), size limits, and optional ClamAV scan when enabled. - Persists job row in DB table with initial
queuedstatus. - Schedules background job via
wp_schedule_single_event.
- Validates nonce, extension, MIDI header (
- Status endpoint:
mtc_status(wp_ajax_*)- Returns jobs for a
batch_id, statuses, and signed download URLs. - Nudges stale queued jobs (cron spawn + fallback inline processing for very stale items).
- Returns jobs for a
- Conversion worker:
mtc_process_job- Claims queued jobs atomically and runs pure-PHP conversion (
includes/class-mtc-midi-converter.php).
- Claims queued jobs atomically and runs pure-PHP conversion (
- Download handlers:
?mtc_download=1...for a single converted MIDI?mtc_zip=1...for batch ZIP- Links are HMAC-signed and time-limited.
Data Model
Table: {wp_prefix}mtc_jobs
idbatch_idoriginal_nameoriginal_pathconverted_pathstatus(queued,processing,done,error)error_msgforce_channel_zero(0or1; routes to user-facing MIDI Channel 1)exclude_percussion(0or1; only effective withforce_channel_zero)strip_extra_metadata(0or1)created_atupdated_at
Configuration (Filters)
Add filters in a must-use plugin or theme functions.php.
add_filter('mtc_max_upload_bytes', fn() => 10 * 1024 * 1024);
add_filter('mtc_max_files_per_batch', fn() => 200);
add_filter('mtc_download_ttl_seconds', fn() => DAY_IN_SECONDS);
add_filter('mtc_max_queued_ui_ms', fn() => 6000);
add_filter('mtc_poll_interval_ms', fn() => 2000);
add_filter('mtc_poll_max_backoff_ms', fn() => 15000);
add_filter('mtc_rate_limit_window_seconds', fn() => 10 * MINUTE_IN_SECONDS);
add_filter('mtc_rate_limit_max_uploads_per_window', fn() => 80);
add_filter('mtc_status_rate_limit_per_batch_window_seconds', fn() => 60);
add_filter('mtc_status_rate_limit_per_batch_per_window', fn() => 240);
add_filter('mtc_status_rate_limit_ip_window_seconds', fn() => 600);
add_filter('mtc_status_rate_limit_ip_per_window', fn() => 1000);
add_filter('mtc_queue_nudge_after_seconds', fn() => 3);
add_filter('mtc_inline_process_after_seconds', fn() => 12);
// ClamAV is disabled by default. Enable it only on hosts with a working clamdscan setup.
add_filter('mtc_clamav_enabled', fn() => true);
add_filter('mtc_clamav_fail_open', fn() => false);
add_filter('mtc_clamdscan_path', fn() => '/usr/bin/clamdscan');
add_filter('mtc_clamav_cmd_timeout_seconds', fn() => 6);
add_filter('mtc_timeout_bin', fn() => '/usr/bin/timeout');
add_filter('mtc_zip_cache_ttl', fn() => 900);
add_filter('mtc_cleanup_days', fn() => 2);
Security Notes
- Nonce-protected AJAX requests (
mtc_nonce) - Signed, expiring download URLs (HMAC with
wp_salt('auth')) - Uploaded files stored in a non-public uploads subdirectory
- Direct-access blocks for Apache/IIS (
.htaccess,web.config) - MIME/header checks plus binary MIDI magic check (
MThd) - Optional AV scanning through
clamdscanwhen enabled
Operational Notes
- This plugin relies on WP-Cron for background processing.
- If your site has low traffic, cron events may fire late.
- Recent changes include queue nudging and inline fallback to reduce long
queuedwaits.
Development
Project layout:
.
├── midi-type0-converter.php # Main plugin bootstrap + AJAX/cron handlers
├── includes/
│ └── class-mtc-midi-converter.php # Pure PHP MIDI parser/merger
└── assets/
├── mtc.js # Frontend upload + polling UI
└── mtc.css # Frontend styles
Syntax checks:
php -l midi-type0-converter.php
php -l includes/class-mtc-midi-converter.php
php tests/midi-converter-test.php
License
GPLv2 or later.