MIDI converter: stereo routing experiment Tested: 2026-09-27 00:11 Asia/Shanghai = 2026-09-26 16:11 UTC. Source: new, original synthetic sine tones; no human performance or third-party samples. You may use, modify and redistribute these generated fixtures, scripts and MIDI outputs to reproduce this experiment. QUESTION Does this site's audio-to-MIDI conversion preserve the original left/right routing? Eight isolated notes alternate between the left and right audio channels. A second WAV is the exact arithmetic average of those channels. This is not a new MIDI-to-audio engine or a real-music accuracy benchmark. ENVIRONMENT USED Python 3.12.14; mido 1.3.3; ego-browser CLI 0.5.1.13; Chromium 152.0.7977.54; browser user-agent reports Chrome/152.0.0.0; Ego Node v24.18.1. Desktop macOS, not a physical phone. Python generator uses only standard-library modules. mido is needed only for measurements. REPRODUCE INPUTS AND RECHECK THE SAVED OUTPUTS Unzip this bundle and run from that directory: python3 -m venv .venv .venv/bin/python -m pip install -r requirements.txt .venv/bin/python generate.py --out run To remeasure the saved outputs, copy alternating-stereo.mid and downmix-mono.mid from this bundle into run/, then run: .venv/bin/python measure.py --dir run This rechecks existing outputs; it does not constitute a fresh browser conversion. REPEAT A FRESH CONVERSION MANUALLY 1. Open https://getmp3tomidi.com/ in a compatible desktop browser. 2. Choose run/alternating-stereo.wav. Wait for automatic conversion. 3. Under Shape the notes, use quiet-note filter -40 dB, minimum note length 40 ms, transpose 0. 4. Download MIDI and save it as run/alternating-stereo.mid. 5. Repeat for run/downmix-mono.wav, saving run/downmix-mono.mid. 6. Run .venv/bin/python measure.py --dir run. Do not change the MIDI or shift its time axis before measuring. AUTOMATE THE SAME BROWSER CONVERSION This requires the installed Ego browser and ego-browser CLI, which are not Python dependencies. The browser-test.mjs script exports run({spaceId,pageLabel,outputDirectory}). Use absolute paths, and use your own active task space. Example: ego-browser nodejs <<'JS' const task = await taskSpace('Reproduce MIDI converter stereo experiment'); console.log({spaceId:task.spaceId}); const {run} = await import('file:///ABSOLUTE/PATH/browser-test.mjs'); await run({spaceId:task.spaceId,pageLabel:'p1',outputDirectory:'/ABSOLUTE/PATH/run'}); await task.finish({keep:[]}); JS Replace both ABSOLUTE/PATH placeholders with the folder where you extracted the bundle. The generator must have already produced both WAVs in run/. ACTUAL EXECUTION FOR THIS RECORD Within the project, Python commands used benchmark/.venv/bin/python instead of .venv/bin/python: benchmark/.venv/bin/python dist/examples/midi-converter/generate.py --out dist/examples/midi-converter benchmark/.venv/bin/python dist/examples/midi-converter/measure.py --dir dist/examples/midi-converter The browser command imported browser-test.mjs from that same directory and invoked run with active spaceId 42, pageLabel p2 and that directory as outputDirectory. The first Blob-fetch attempt was blocked by the site's Content Security Policy. The completed script uses the actual Download MIDI link and browser download event; it does not reconstruct or re-encode the MIDI. Both successful downloads were parsed after saving. SETTINGS AND VERSION IDENTITY browser-results.json records time, browser user-agent, settings and observed note events. Its versions object maps exact SHA-256 hashes to live app.js, pitch-engine.js, midi-file.js and audio-limits.js. Those files were fetched before and after the test and hashes matched. Their byte-for-byte snapshots are saved as engine-*.js. These are archived engine source files for inspection, not a complete standalone website. The script reruns the public site: future engine/browser changes can change results; check the hashes rather than assuming identical behavior. MEASUREMENT measure.py reads WAV headers and sample integers, verifies mono = (left + right)/2 exactly, parses actual MIDI using file tempo, compares full output bytes, and counts note-ons, tracks, MIDI channels and control messages. Pan is controller 10 (CC10). Maximum onset error compares each matching-pitch event with the programmed onset without a global shift. Full event lists and formulas are in measurements.json and the script. Observed: both outputs contain pitches 60,64,67,72,69,65,62,60; Type 0, one track, 960 ticks/beat, channel 0 (zero-based), no control-change events. Output bytes match exactly. Maximum absolute onset error is about 2.6042 ms in both; not a universal accuracy claim. SCOPE The fixture contains isolated tones with silence, not simultaneous left/right instruments. No claim about chords, room recordings, real songs, DAW import or a physical phone. MIDI-to-audio was not run in this test: the site has no WAV/MP3 export. The existing /midi-to-wav article separately documents an older external-renderer test, which is not counted as this experiment.