Train three open piano models, then deploy one Cog anywhere
A reproducible CC0 symbolic training pipeline, listening previews, one inference image for Cog and RunPod Serverless, and one-click scale-to-zero deployment on app.nz.
Listen to this article
On-device voiceUses the voice built into your browser; no article text leaves this page.
Audio narration is not supported by this browser.
Open model hosting is much more convincing when the repository contains the training input, reproducible artifact, inference code, listening preview, and deployment contract—not just a card pointing at somebody else's weights.
We built that complete path for three deliberately small piano models:
| Model | Learned character | Listen |
|---|---|---|
open-piano-baroque | broken triads and contrapuntal answers | Opus preview |
open-piano-jazz | ii–V–I-flavoured movement and seventh chords | Opus preview |
open-piano-minimal | repeating cells and slow harmonic movement | Opus preview |
You can deploy the Piano Generator on app.nz in one click, inspect the open Cog project, or reproduce every artifact locally.
The honest training claim
These are tiny symbolic demonstrations, not replacements for a large performance model. Each preset learns an order-3 note transition table from four original 32-event sequences. The corpus is CC0-1.0; the trainer and runtime are MIT. No audio recording or pretrained model weight is downloaded.
That limitation is useful. The complete build finishes in seconds, its artifacts are under 1 KiB each after gzip, and every corpus, model, and preview has a SHA-256 in models/manifest.json. Anyone can audit exactly what “trained” means here.
bun run generate:open-piano
cd replicatecog/appnz-piano-generator
python3 -m unittest -v test_predict.pyThe generator emits deterministic stereo Opus previews with three small additive piano voices: felt, studio, and bright. The synthesis is intentionally dependency-light and CPU-friendly, so testing does not quietly rent a GPU.
One predictor, two hosting contracts
predict.py owns model loading, bounded generation, synthesis, and Opus encoding. Both serving routes call that same predictor:
CC0 symbolic corpus
→ train_piano.py
→ gzip model + provenance manifest
→ Predictor.predict()
├─ Cog HTTP: /health-check · /openapi.json · /predictions
└─ RunPod: runpod_handler(job.input)
→ stereo OpusThe standard cog.yaml makes the source project usable with Cog:
cd replicatecog/appnz-piano-generator
cog predict \
-i model=open-piano-jazz -i sound=bright \
-i bars=8 -i tempo=118 -i key=F -i seed=29The repository Dockerfile exposes the normal typed Cog HTTP contract on port
- app.nz reads the same schema to build the controls in its Cog Studio,
tracks prediction state and cost, and returns the worker to zero after its idle window. A checksum-pinned static ffmpeg layer avoids Debian's large desktop media dependency tree; the tested Linux AMD64 image is 413 MB uncompressed and has no cold-start weight download.
Deploy the same image on RunPod
The image also includes the current RunPod Python SDK and a small handler. Build and push it as Linux AMD64, create a RunPod Serverless template from the image, then use this container start command:
python -u /app/runpod_handler.pyKeep minimum workers at zero when cold starts are acceptable, and pin production templates to an immutable image version or SHA rather than latest. A request has RunPod's normal shape:
{
"input": {
"model": "open-piano-minimal",
"sound": "felt",
"bars": 8,
"tempo": 92,
"key": "D",
"seed": 43
}
}The handler returns a bounded inline audio/ogg data URI plus byte count and model metadata. For much longer audio models, upload output to object storage and return a URL; do not force multi-megabyte media through an inline response.
RunPod's Pod HTTP proxy has a fixed request timeout, so long inference should use Serverless asynchronous submit/status APIs. This piano model is short enough for either path, but the boundary matters when swapping it for diffusion.
What app.nz adds around an open Cog
The model stays portable: source, standard Cog config, Docker image, and RunPod handler all work without app.nz. The platform supplies the surrounding product surface:
- one-click deployment from a reviewed template;
- typed controls generated from the published schema;
- authenticated REST, CLI, MCP, and Go desktop access to the same deployment;
- prediction history, searchable artifacts, cost records, and scale-to-zero;
- a route from lightweight serverless demand to a warm worker when traffic is
sustained.
From the CLI:
app music pipelines
app cogs run piano-generator \
--input '{"model":"open-piano-baroque","sound":"studio","bars":8,"tempo":104,"key":"C","seed":17}'MCP clients can discover it with list_music_pipelines and list_cog_templates, then invoke run_cog_template. The desktop app exposes the same generic Cog lifecycle, so adding a model does not require a separate desktop inference implementation.
Growing beyond the demo
The next useful iteration is not to hide a larger licensed dataset inside the image. Use the repository's license-aware indexer and bounded Opus sharder, separate research-only material, train against remote shards, and publish the result as a versioned artifact. policy_url already lets the Piano Cog load a compatible n-gram or RL policy up to 64 MiB.
For full audio generation, the sibling ACE-Step 1.5 Cog provides 10–600 second diffusion, lyrics and LoRA support on a GPU. The small piano project remains the fast, inspectable reference for the entire train → package → deploy → listen loop.
Useful primary references: