Skip to content

Repository files navigation

maestroMIDIplayer

A web app for browsing and playing the MAESTRO v3.0.0 piano MIDI dataset on a real piano. Built for home server deployment — designed to drive a Roland FP digital piano via the Web MIDI API over Bluetooth.

1,276 piano performances from the International Piano-e-Competition, spanning 60 composers and 10 competition years (2004–2018).

Warning

This application is vibecoded. Do not use it as a reference for best practices in Python, FastAPI, SvelteKit, or any other technology. It is a personal project built for fun and learning, not production-quality code. For more information about this please see the about page.

Features

  • Browse by composer — portrait cards with images from Wikipedia, sortable track lists
  • Browse by competition — year/round/session hierarchy parsed from MIDI filenames
  • Client-side MIDI playback — streams MIDI events to any connected output via the Web MIDI API
  • Live piano visualization — 88-key display in the player bar lights up with active notes in real time
  • Search — full-text search across composers and piece titles
  • Transport controls — play, pause, stop, seek, tempo adjustment (0.25x–2.0x), auto-advance queue
  • Dark/light theme — dark by default, persisted in localStorage
  • All-outputs mode — sends MIDI to every available output simultaneously (no manual device selection needed)
  • Single-container Docker deployment — multi-stage build, one image serves everything

Tech Stack

Layer Technology
Backend Python 3.12+ / FastAPI, managed with uv
Frontend SvelteKit 2 (Svelte 5) + Tailwind CSS 4
Client MIDI Web MIDI API + @tonejs/midi
Composer images Wikipedia PageImages API, disk-cached
Database None — CSV loaded into memory at startup
Deployment Docker (multi-stage build)

Prerequisites

  • Python 3.12+ and uv
  • Node.js 22+
  • A Chromium-based browser (Chrome, Edge) for Web MIDI API support

Getting Started

Development

Start the backend and frontend dev servers:

# Backend
cd backend
uv sync
uv run uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# Frontend (in a second terminal)
cd frontend
npm install
npm run dev

The frontend dev server proxies API requests to localhost:8000. Open http://localhost:5173 in your browser.

Production (Docker)

docker compose up --build

This builds a single image that serves both the API and the compiled frontend on port 8000. If no dataset is found at startup, the backend downloads and extracts MAESTRO v3.0.0 automatically.

Production (RHEL / OpenShift)

The image is built to comply with OpenShift's restricted / restricted-v2 SCC:

  • All files are owned by UID 1000 / GID 0 (root group) with chmod g=u so any arbitrary UID injected by the namespace can read and write through group 0.
  • The USER directive uses the numeric UID 1000 — named users are not resolvable when OpenShift assigns a high UID at runtime.
  • Port 8000 is unprivileged, no special port capabilities are required.
  • allowPrivilegeEscalation: false and capabilities.drop: [ALL] are set in the container securityContext.

Deploy with the provided manifests

# Create the dataset PVC first
oc apply -f openshift/pvc.yaml

# Deploy the application (edit image: field first)
oc apply -f openshift/deployment.yaml
oc apply -f openshift/service.yaml
oc apply -f openshift/route.yaml

The openshift/ directory also contains a route.yaml with TLS edge termination. Set the host: field or remove it to let OpenShift auto-generate a hostname.

Dataset auto-download: the first startup downloads MAESTRO v3.0.0 (~1.4 GB) into the PVC. The PVC request is 3 Gi to leave headroom. If your cluster lacks egress access to Google Cloud Storage, pre-populate the PVC and set MAESTRO_AUTO_DOWNLOAD_DATASET=false.

Production (without Docker)

# Build the frontend
cd frontend
npm ci && npm run build

# Run the backend (serves the built frontend automatically)
cd ../backend
uv sync
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000

Configuration

All settings use the MAESTRO_ prefix and can be set as environment variables:

Variable Default Description
MAESTRO_DATASET_PATH ../MaestroDataset Path to the MAESTRO dataset directory
MAESTRO_AUTO_DOWNLOAD_DATASET true Download and extract dataset automatically when CSV is missing
MAESTRO_DATASET_DOWNLOAD_URL https://storage.googleapis.com/magentadata/datasets/maestro/v3.0.0/maestro-v3.0.0-midi.zip Dataset ZIP URL used for auto-download
MAESTRO_DATASET_DOWNLOAD_TIMEOUT_SECONDS 1800 Timeout for dataset ZIP download
MAESTRO_IMAGE_CACHE_DIR .cache/composer_images Cache directory for composer portraits
MAESTRO_HOST 0.0.0.0 Server bind address
MAESTRO_PORT 8000 Server port
MAESTRO_ENV development Set to production to disable the API docs UI
MAESTRO_CORS_ORIGINS ["http://localhost:5173","http://localhost:8000"] JSON list of allowed origins

API

Method Endpoint Description
GET /api/health Health check with track/composer/year counts
GET /api/tracks List tracks (query: ?q=, ?composer=, ?year=, ?sort=, ?order=)
GET /api/tracks/{id} Single track by ID
GET /api/composers List composers with piece counts and durations
GET /api/composers/{slug}/image Composer portrait (Wikipedia or SVG placeholder)
GET /api/composers/{slug}/tracks Tracks by composer
GET /api/competitions Competition years with round/session summaries
GET /api/competitions/{year} Full year data with rounds, sessions, tracks
GET /api/midi/tracks/{id}/file Raw MIDI file download
GET /api/midi/ports Available server-side MIDI output ports
WS /api/playback Server-side playback control (play, pause, stop, seek, tempo)

Project Structure

MaestroMIDIPlayer/
├── MaestroDataset/              # Bind-mount point for MAESTRO v3.0.0 dataset
├── backend/
│   ├── pyproject.toml
│   ├── app/
│   │   ├── main.py              # FastAPI app, middleware, static file serving
│   │   ├── core/
│   │   │   ├── config.py        # Settings via pydantic-settings
│   │   │   └── limiter.py       # Rate limiter instance
│   │   ├── data/
│   │   │   ├── models.py        # Pydantic models
│   │   │   ├── dataset.py       # CSV loader, in-memory store, search
│   │   │   └── filename_parser.py  # Extract round/session from filenames
│   │   ├── services/
│   │   │   └── composer_images.py  # Wikipedia image fetcher + cache
│   │   └── routers/             # API route handlers
│   └── tests/
├── frontend/
│   ├── package.json
│   ├── src/
│   │   ├── lib/
│   │   │   ├── api.ts           # Backend API client
│   │   │   ├── midi-player.ts   # Web MIDI playback engine
│   │   │   ├── stores.ts        # Svelte stores + TypeScript interfaces
│   │   │   └── utils.ts         # Duration formatting, etc.
│   │   ├── components/          # PlayerBar, SearchBar, ComposerCard, etc.
│   │   └── routes/              # SvelteKit pages
│   └── static/
├── Dockerfile                   # Multi-stage build
└── docker-compose.yml

Dataset

The MAESTRO dataset is not included in this repository. If maestro-v3.0.0.csv is missing in MAESTRO_DATASET_PATH, the backend auto-downloads and extracts MAESTRO v3.0.0 at startup.

The dataset is provided under CC BY-NC-SA 4.0.

License

This project is for personal/educational use. The MAESTRO dataset has its own license (CC BY-NC-SA 4.0).

About

A vibecoded web app for browsing and playing piano performances from the MAESTRO dataset

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages