Metadata-Version: 2.5
Name: gamemlx
Version: 0.2.1
Summary: Pure MLX inference package for GAME (vocal MIDI extraction) on Apple Silicon
License: MIT
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: click
Requires-Dist: huggingface-hub
Requires-Dist: librosa
Requires-Dist: mido
Requires-Dist: mlx>=0.26
Requires-Dist: numpy<2
Requires-Dist: pyyaml
Requires-Dist: safetensors
Requires-Dist: soundfile
Description-Content-Type: text/markdown

# gamemlx

**GAME — MLX edition.** Pure [MLX](https://github.com/ml-explore/mlx) inference for
[GAME](https://github.com/openvpi/GAME) (Guided Automatic MIDI Extraction): singing vocals → MIDI,
running natively on Apple Silicon GPU.

- **Numerically aligned with the official PyTorch implementation**: on a 20-file test set,
  fp32 output matches torch CPU **exactly** — all onset/offset/pitch diffs `0.0000`
  ([docs/ALIGNMENT.md](docs/ALIGNMENT.md))
- **~9× faster than torch CPU** on M4 Air (0.172s vs 1.609s per file average), ~15–20× realtime
- Low memory: 111MB wired (fp16) / 206MB (fp32) on the medium model
- Automatic silence slicing → per-chunk inference → timeline-merged MIDI output (same behavior as upstream)
- Models auto-download from HuggingFace (ModelScope fallback)

## Install

```bash
pip install gamemlx          # or: uv tool install gamemlx
```

Requires Apple Silicon (M1–M4) and Python ≥ 3.10.

## Quick start

```bash
# alias auto-downloads weights (small | medium | large) on first use
gamemlx extract vocals.wav -m medium --language zh

# local model dir + options
gamemlx extract song/ -m ./weights/GAME-1.0-medium-mlx \
    --precision fp16 --language zh --tempo 120 \
    --seg-threshold 0.2 --seg-radius 0.02 --est-threshold 0.2 \
    --output-dir out/
```

Python API:

```python
import gamemlx

model, lang_map = gamemlx.load_model("medium")          # → GAMEModel + {"en":1,"ja":2,"yue":3,"zh":4}
gamemlx.extract(model, "vocals.wav", language="zh")      # writes .mid next to the input
```

Supported languages: `en`, `ja`, `yue`, `zh` (improves segmentation; omit for language-agnostic).

## Models

| alias | params | HF repo | also on ModelScope |
|---|---|---|---|
| `small` | 12.7M | [baicai1145/GAME-MLX-small](https://huggingface.co/baicai1145/GAME-MLX-small) | ✓ |
| `medium` | 49.9M | [baicai1145/GAME-MLX-medium](https://huggingface.co/baicai1145/GAME-MLX-medium) | ✓ |
| `large` | 99.0M | [baicai1145/GAME-MLX-large](https://huggingface.co/baicai1145/GAME-MLX-large) | ✓ |

Converted from [openvpi/GAME](https://github.com/openvpi/GAME) v1.0 checkpoints
(`scripts/convert_to_mlx.py`). Cache: `~/.cache/gamemlx` (override with `GAMEMLX_CACHE`).

## Precision & performance

| mode | notes |
|---|---|
| `fp32` (default) | bit-aligned with torch reference on the test set |
| `fp16` | same speed on Apple GPUs (no tensor cores), **half the memory** — use for `large` on 8GB machines |

Apple Silicon GPUs execute fp16 and fp32 at the same rate; fp16's benefit here is memory, not speed.
Speed optimizations (operator fusion via `mx.compile`, fused QKV, mask fast paths) are on by
default — disable with `GAMEMLX_OPT=0` for the bit-exact eager path. Details:
[docs/OPTIMIZATIONS.md](docs/OPTIMIZATIONS.md), [docs/BENCH.md](docs/BENCH.md).

## Development

```bash
uv venv && uv pip install -e . mlx numpy librosa soundfile mido pyyaml safetensors huggingface_hub click

# convert weights from a GAME torch checkpoint
python scripts/convert_to_mlx.py --input /path/to/GAME-1.0-medium/model.pt --output weights/GAME-1.0-medium-mlx

# alignment test vs torch CPU (needs GAME repo + torch installed; see script headers for env vars)
python scripts/compare.py
python scripts/bench.py
```

## Credits

- [openvpi/GAME](https://github.com/openvpi/GAME) — the original model, training code and
  pretrained checkpoints (MIT). This project is an independent MLX inference port.
- Model weights follow the upstream license; conversion script included in this repo.

## License

MIT — see [LICENSE](LICENSE).
