Convert Mscz To Midi Verified May 2026

.mscz is MuseScore’s compressed project file. You can convert it to standard MIDI (.mid) using MuseScore (recommended), other score editors that import MuseScore files, or by extracting the contained MusicXML and converting that. Below are verified, step-by-step methods for Windows, macOS, and Linux.

To verify that the conversion was successful:

Even with verified methods, things go wrong. Here is how to fix corrupted MSCZ to MIDI exports.

Many free online converters produce corrupt or "flattened" MIDI files. A verified conversion must preserve the following elements from your original MSCZ: convert mscz to midi verified

If your converter loses track separation (i.e., everything merges into one piano track), the conversion is not verified.


Date: [Current Date]
Subject: Verifying the accurate conversion of MuseScore Studio files (.mscz) to Standard MIDI Files (.mid)
Purpose: To establish a reliable method for converting .mscz (MuseScore native format) to .mid (MIDI) and to verify the integrity and accuracy of the conversion.

This implementation provides robust conversion with comprehensive verification to ensure the output MIDI files accurately represent the original MuseScore files. If your converter loses track separation (i

Choose the version that fits your needs.

# mscz_to_midi_converter.py

import os import zipfile import json import tempfile import subprocess import hashlib from pathlib import Path from typing import Dict, Any, Optional, Tuple import music21 import mido from midiutil import MIDIFile import xml.etree.ElementTree as ET

class MSCZtoMIDIConverter: """Convert MuseScore (.mscz) files to MIDI (.mid) format with verification.""" "C:/Program Files/MuseScore 3/bin/MuseScore3.exe"

def __init__(self, musescore_path: Optional[str] = None):
    """
    Initialize converter.
Args:
        musescore_path: Path to MuseScore executable (auto-detected if None)
    """
    self.musescore_path = musescore_path or self._find_musescore()
def _find_musescore(self) -> Optional[str]:
    """Auto-detect MuseScore installation."""
    possible_paths = [
        # Windows
        "C:/Program Files/MuseScore 4/bin/MuseScore4.exe",
        "C:/Program Files/MuseScore 3/bin/MuseScore3.exe",
        # macOS
        "/Applications/MuseScore 4.app/Contents/MacOS/mscore",
        "/Applications/MuseScore 3.app/Contents/MacOS/mscore",
        # Linux
        "/usr/bin/musescore",
        "/usr/local/bin/musescore",
    ]
for path in possible_paths:
        if os.path.exists(path):
            return path
    return None
def convert(self, input_path: str, output_path: Optional[str] = None, 
            verify: bool = True) -> Dict[str, Any]:
    """
    Convert MSCZ file to MIDI.
Args:
        input_path: Path to .mscz file
        output_path: Desired output path (auto-generated if None)
        verify: Whether to verify conversion quality
Returns:
        Dictionary with conversion results and verification data
    """
    input_path = Path(input_path)
if not input_path.exists():
        raise FileNotFoundError(f"Input file not found: input_path")
if input_path.suffix.lower() != '.mscz':
        raise ValueError(f"File must have .mscz extension: input_path")
# Generate output path if not provided
    if output_path is None:
        output_path = input_path.with_suffix('.mid')
    else:
        output_path = Path(output_path)
# Method 1: Direct MuseScore conversion (most reliable)
    result = self._convert_via_musescore(input_path, output_path)
# Method 2: Fallback using music21 if MuseScore unavailable
    if result['success'] is False:
        result = self._convert_via_music21(input_path, output_path)
# Verify conversion quality
    if verify and result['success']:
        verification = self._verify_conversion(input_path, output_path)
        result['verification'] = verification
        result['verified'] = verification['passed']
return result
def _convert_via_musescore(self, input_path: Path, output_path: Path) -> Dict[str, Any]:
    """Convert using MuseScore CLI."""
    if not self.musescore_path:
        return 
            'success': False,
            'method': 'musescore',
            'error': 'MuseScore not found'
try:
        # MuseScore conversion command
        cmd = [
            self.musescore_path,
            str(input_path),
            '-o', str(output_path),
            '-T', '0'  # No time limit for conversion
        ]
result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=60
        )
if result.returncode == 0 and output_path.exists():
            return 
                'success': True,
                'method': 'musescore',
                'output_path': str(output_path),
                'file_size': output_path.stat().st_size
else:
            return 
                'success': False,
                'method': 'musescore',
                'error': result.stderr or 'Unknown error'
except subprocess.TimeoutExpired:
        return 
            'success': False,
            'method': 'musescore',
            'error': 'Conversion timeout (60 seconds)'
except Exception as e:
        return 
            'success': False,
            'method': 'musescore',
            'error': str(e)
def _convert_via_music21(self, input_path: Path, output_path: Path) -> Dict[str, Any]:
    """Convert using music21 as fallback."""
    try:
        # Extract MSCZ (it's a ZIP file)
        with tempfile.TemporaryDirectory() as tmpdir:
            tmp_path = Path(tmpdir)
# Extract MSCZ
            with zipfile.ZipFile(input_path, 'r') as zip_ref:
                zip_ref.extractall(tmp_path)
# Find the MSCX file (XML format)
            mscx_file = None
            for file in tmp_path.glob('*.mscx'):
                mscx_file = file
                break
if not mscx_file:
                return 
                    'success': False,
                    'method': 'music21',
                    'error': 'No .mscx file found in archive'
# Parse with music21
            score = music21.converter.parse(str(mscx_file))
# Write as MIDI
            score.write('midi', fp=str(output_path))
if output_path.exists():
                return 
                    'success': True,
                    'method': 'music21',
                    'output_path': str(output_path),
                    'file_size': output_path.stat().st_size
else:
                return 
                    'success': False,
                    'method': 'music21',
                    'error': 'Failed to write MIDI file'
except Exception as e:
        return 
            'success': False,
            'method': 'music21',
            'error': str(e)
def _verify_conversion(self, input_path: Path, output_path: Path) -> Dict[str, Any]:
    """Verify the quality of the conversion."""
    verification = {
        'passed': False,
        'checks': {},
        'metadata': {}
    }
try:
        # Check 1: File existence and size
        if not output_path.exists():
            verification['checks']['file_exists'] = False
            return verification
        verification['checks']['file_exists'] = True
        verification['checks']['file_size_bytes'] = output_path.stat().st_size
# Check 2: Basic MIDI structure
        try:
            mid = mido.MidiFile(str(output_path))
            verification['checks']['valid_midi'] = True
            verification['checks']['num_tracks'] = len(mid.tracks)
            verification['checks']['total_ticks'] = max(
                sum(len(track) for track in mid.tracks), 0
            )
# Check for note events
            note_events = 0
            for track in mid.tracks:
                for msg in track:
                    if msg.type in ['note_on', 'note_off']:
                        note_events += 1
            verification['checks']['note_events'] = note_events
            verification['checks']['has_notes'] = note_events > 0
except Exception as e:
            verification['checks']['valid_midi'] = False
            verification['checks']['midi_error'] = str(e)
            return verification
# Check 3: Extract metadata from original MSCZ
        try:
            with zipfile.ZipFile(input_path, 'r') as zip_ref:
                if 'META-INF/container.xml' in zip_ref.namelist():
                    # Parse container.xml for metadata
                    container_data = zip_ref.read('META-INF/container.xml')
                    root = ET.fromstring(container_data)
                    verification['metadata']['has_container'] = True
        except:
            verification['metadata']['has_container'] = False
# Overall verification passed if basic checks succeed
        verification['passed'] = (
            verification['checks']['file_exists'] and
            verification['checks']['valid_midi'] and
            verification['checks']['has_notes']
        )
# Quality rating
        if verification['passed']:
            if verification['checks']['note_events'] > 100:
                verification['quality'] = 'excellent'
            elif verification['checks']['note_events'] > 10:
                verification['quality'] = 'good'
            else:
                verification['quality'] = 'basic'
except Exception as e:
        verification['error'] = str(e)
        verification['passed'] = False
return verification
def batch_convert(self, input_dir: str, output_dir: str, 
                  pattern: str = "*.mscz") -> Dict[str, Any]:
    """Convert multiple MSCZ files."""
    input_dir = Path(input_dir)
    output_dir = Path(output_dir)
    output_dir.mkdir(parents=True, exist_ok=True)
results = 
        'total': 0,
        'successful': 0,
        'failed': 0,
        'conversions': []
for mscz_file in input_dir.glob(pattern):
        results['total'] += 1
        output_file = output_dir / mscz_file.with_suffix('.mid').name
try:
            result = self.convert(str(mscz_file), str(output_file), verify=True)
            results['conversions'].append(
                'input': str(mscz_file),
                'output': str(output_file),
                'success': result['success'],
                'verified': result.get('verified', False)
            )
if result['success']:
                results['successful'] += 1
            else:
                results['failed'] += 1
except Exception as e:
            results['failed'] += 1
            results['conversions'].append(
                'input': str(mscz_file),
                'output': str(output_file),
                'success': False,
                'error': str(e)
            )
return results