# Generate MIDI with algorithms and models

> Choose algorithmic composition, a locally loaded model or remote inference, then turn the result into editable, playable MIDI.

Canonical: https://maru.audio/docs/midi-generation
Documentation index: https://maru.audio/llms.txt

MIDI generation produces musical events: pitches, start times, durations,
velocities and tracks. Choose an algorithm when you want explicit musical
rules, a model when you want learned patterns, or combine them. Local and
remote execution describe where a model runs, not a different kind of music.

The result still needs an instrument to make sound. Keep generation separate
from playback so you can audition the same phrase with different instruments,
edit it, save it and export it as MIDI.

## Choose an approach

| Approach | Useful when | What you supply | Main tradeoff |
| --- | --- | --- | --- |
| Algorithmic composition | You need clear harmony, rhythm, range or repeatability | Rules, musical context and a seed when randomness is used | Variation follows the rules you chose |
| Local model inference | You want learned continuation or variation on the user's device | A compatible checkpoint, tokenizer, runtime and musical prompt | Initial download, loading time and device memory |
| Remote model inference | You want a model to run on your own server or an external service | An inference service and its supported request format | Network latency, service capacity and handling uploaded musical material |
| Hybrid | You want model variation within a deliberate musical structure | An algorithmic scaffold, model output and validation rules | Each stage needs an explicit musical-data contract |

**Downloading weights is not remote inference.** A browser can download model
files from a server and then generate locally. Remote inference sends a request
to another process that executes the model and returns the notes.

## Start with an algorithm

Useful strategies include step sequences, arpeggios, Euclidean rhythms,
weighted note choices, Markov transitions, chord-tone selection and voice-leading
rules. Start with the smallest strategy that expresses your idea. A bassline
that follows roots and fifths may need no model at all.

Maru's [Symbolic library](https://maru.audio/docs/symbolic-library.md) provides musical
values and transformations. [Symbolic Cycle](https://maru.audio/docs/symbolic-cycle.md)
composes them into patterns in the [Code Sequencer](https://maru.audio/modules/code-sequencer).
Its generators can draft a progression, melody and bassline without loading
model weights. Paste this into Code Sequencer's Symbolic interpreter:

```js
const chords = generateProgression({
  scale: "F:major",
  chords: 4,
  seed: 7,
})

export const keys = chords.voicing("open").velocity(0.45)
export const lead = generateMelody({
  over: chords,
  rhythm: "x ~ x x@2 x x@2",
  range: "f4:a5",
  seed: 11,
})
export const bass = generateBassline({
  over: chords,
  rhythm: "x ~ ~ x ~ ~ x ~",
  style: "root-fifth",
})
```

Keep the seeds fixed while changing the range, rhythm or harmony. This lets
you hear what each choice does. Change a seed to explore another take. These
functions belong to the Symbolic Cycle environment; this snippet is not a
standalone JavaScript file or a model-loading API.

## Load a model locally

A note model predicts musical tokens from a context, such as an existing phrase
and constraints. Its tokens must be decoded into notes before playback. MIDI
pitch numbers are not interchangeable with model token IDs.

Prepare a compatible set of assets: checkpoint, tokenizer, vocabulary, generation
configuration and any grammar constraints. An ONNX file alone does not establish
that the model's input shapes, token format and decoding behavior are supported.

For a local integration:

1. Load the runtime and model outside the realtime audio callback. Show loading,
   failure and cancellation states, and reuse a loaded session across takes.
2. Encode the musical context using that model's tokenizer. Bound the context
   and requested output length to what the model supports.
3. Generate in a worker or another suitable execution boundary, then decode
   and validate the notes before handing them to playback.
4. Keep accepted takes independently of the loaded model. Release sessions and
   their memory when they are no longer needed.

Maru's experimental browser MIDI-GPT implementation uses ONNX graphs with
matching tokenization and grammar. The portable `midi-gpt-core` and
`midi-gpt-runtime` packages are private workspace components; they are not a
published general-purpose MIDI model loader. Raw token inference alone does
not provide a complete MIDI generator. Check the exact implementation and
target before promising browser, native or offline support.

## Run inference remotely

Use a server when its hardware, shared model lifetime or service integration
fits your product better. The server loads the model; the client sends musical
context and generation settings, follows progress or waits for completion,
and receives a score or MIDI file.

Keep service credentials on your backend. Support cancellation, bounded request
sizes and recovery from an unavailable service. Preserve the source phrase
and accepted takes when a request fails. If you offer a local alternative,
make the change of execution location explicit before sending material remotely.

Maru has a development MIDI-GPT HTTP bridge configured through the server-side
`MIDI_GPT_SERVER_URL`. It checks the service's `/info` endpoint and sends score
and request data to `/generate`. The website bridge is development-only; it
does not establish a public hosted MIDI generation API or a service available
to every account.

For your own remote integration, use the chosen model service's actual contract.
Maru's [audio generation API](https://maru.audio/docs/generative-features.md)
returns audio; a `generate_audio` job is not a MIDI composition request.
[Audio to MIDI](https://maru.audio/docs/audio-to-midi-in-a-module.md) transcribes a recording
and is another distinct task.

## Combine rules and learned variation

One useful pipeline is to generate chords algorithmically, ask a compatible
model to continue a short melody, then inspect the result with Symbolic.
Check pitch range, timing, note density and how the melody relates to the
harmony. Preserve the raw take alongside any edits, quantization or transposition.

Choose one time representation at each boundary: ticks with a resolution,
beats with a tempo map, or seconds. Preserve tempo, time signatures, tracks,
channels and note durations when converting to a Standard MIDI File. The host
owns scheduling and device access; generated notes reach a module through its
declared MIDI ports and existing playback path.

## Compare useful musical results

Audition algorithms and models through the same instrument at the same tempo.
Judge phrase shape, repetition, harmonic fit, useful variation and the edits
needed to make a take work. Measure model loading separately from generation
time. Retain checkpoint and tokenizer identities, prompt, seed and sampling
settings with each model take; for algorithmic takes, retain the rules and
their parameters. A seed alone does not guarantee identical results across
different runtimes.

Check the selected model's code, weight and output terms for your intended
use. For tokenizer round trips, training comparisons and experiment records,
continue with [audio and MIDI model experiments](https://maru.audio/docs/audio-model-experiments.md).
For the musical ideas behind token prediction, see
[Generating notes](https://maru.audio/learn/generating-notes.md).
