Skip to content

CLI Reference

MIDI Sketch Bach includes a command-line tool for generating Bach-style MIDI files directly from the terminal.

Reading musical options

CLI options such as --form, --key, --character, --scale, and --bars are music-structure choices. If the terminology is unfamiliar, start with the Music Primer for Engineers.

Build

bash
git clone https://github.com/libraz/midi-sketch-bach.git
cd midi-sketch-bach
make build

The npm package is unpublished and does not expose a CLI executable. Run the native binary from the source tree.

Usage

./build/bin/bach_cli [options]

Options

OptionAliasTypeDefaultDescription
--form <value>stringfugueMusical form name
--key <value>stringc_majorKey name such as c_major, g_minor, F_major
--character <value>stringsevereSubject character (severe, playful, noble, restless)
--instrument <value>stringForm defaultInstrument the form accepts (organ, harpsichord, piano, violin, cello, guitar)
--bpm <value>number100Starting tempo in BPM (40--200)
--seed <value>number0Random seed (0 = random; resolved seed is reported)
--scale <value>stringshortLength multiplier (short, medium, long, full)
--bars <value>number--Target bar count (overrides --scale)
--free-counterpointbooleanfalseExperimental: generate the Passacaglia secondary counterline by scored search. Other forms exit with an unavailable diagnostic
-o <path>stringoutput.midOutput file path
--jsonbooleanfalseWrite event data beside the MIDI file as .json
--generated-jsonbooleanfalseEmit generated.v1 + provenance.v1 JSON for scoring (developer)
--composer-phase <value>string--Developer harness mode for pinned composer phases. Cannot be combined with the options above
--help-hboolean--Show usage

Removed flags

--voices, --minor, --analyze, --strict, and --toccata-style no longer exist. The voice count is decided by the form, and mode is encoded in --key (c_major, d_minor, etc.). Invalid --form/--key/--character/--instrument/--scale values, an option with a missing value, and out-of-range --bpm exit with an error instead of falling back to a default.

The form picks the instrument

Each form is written for one instrument — organ for forms 0--6, cello for the Cello Prelude, violin for the Chaconne, harpsichord or piano for the Goldberg Variations. --instrument selects among what the form accepts; anything else exits with an incompatible-instrument error.

Form Names

Use these names with the --form option:

Name
fugue
prelude_and_fugue
trio_sonata
chorale_prelude
toccata_and_fugue
passacaglia
fantasia_and_fugue
cello_prelude
chaconne
goldberg_variations

Character Names

Name
severe
playful
noble
restless

Instrument Names

Name
organ
harpsichord
piano
violin
cello
guitar

Examples

Basic Generation

Generate the default piece (Fugue in C major):

bash
./build/bin/bach_cli -o fugue.mid

Fugue in D Minor

bash
./build/bin/bach_cli --form fugue --key d_minor --character severe --bpm 76 -o fugue-dm.mid

Prelude and Fugue in C Major

bash
./build/bin/bach_cli --form prelude_and_fugue --key c_major -o prelude-fugue.mid

Trio Sonata in F Major

bash
./build/bin/bach_cli --form trio_sonata --key f_major --bpm 90 -o trio-sonata.mid

Chorale Prelude in A Major

bash
./build/bin/bach_cli --form chorale_prelude --key a_major --character noble --bpm 66 -o chorale.mid

Toccata and Fugue in D Minor

bash
./build/bin/bach_cli --form toccata_and_fugue --key d_minor --character restless -o toccata-fugue.mid

Passacaglia in C Minor

bash
./build/bin/bach_cli --form passacaglia --key c_minor --scale long -o passacaglia.mid

Fantasia and Fugue in G Minor

bash
./build/bin/bach_cli --form fantasia_and_fugue --key g_minor -o fantasia-fugue.mid

Cello Prelude in G Major

bash
./build/bin/bach_cli --form cello_prelude --key g_major --instrument cello -o cello-prelude.mid

Chaconne in D Minor

bash
./build/bin/bach_cli --form chaconne --key d_minor --instrument violin -o chaconne.mid

Goldberg Variations in G Major

bash
./build/bin/bach_cli --form goldberg_variations --key g_major --instrument harpsichord -o goldberg.mid

Deterministic Output with Seed

bash
./build/bin/bach_cli --form fugue --key g_minor --seed 42 -o fugue-seed42.mid

Full-Scale Passacaglia

bash
./build/bin/bach_cli --form passacaglia --key d_minor --scale full -o passacaglia-full.mid

Target a Specific Bar Count

bash
./build/bin/bach_cli --form fugue --key c_major --bars 24 -o fugue-24bars.mid

Output JSON Event Data

bash
./build/bin/bach_cli --form fugue --key d_minor --json -o fugue.mid

This writes fugue.mid and fugue.json. --generated-json adds fugue.generated.json and fugue.provenance.json. When -o already ends in .json, the sidecars are appended to that name rather than replacing its extension, so the output file is never overwritten by its own sidecar.

JSON Output Format

When using --json, the sidecar JSON follows the EventData structure:

The events JSON reports the same output-key pitches as the .mid file, including any octave shift needed for the instrument's range. The generated.v1 sidecar keeps the engine's internal C pitches. Every event note also carries a source provenance tag ("material", "compose", or "ornament").

json
{
  "form": "fugue",
  "key": "D_minor",
  "bpm": 80,
  "seed": 12345,
  "total_ticks": 84480,
  "total_bars": 44,
  "description": "Fugue in D_minor",
  "tempos": [
    { "tick": 0, "bpm": 80 },
    { "tick": 80640, "bpm": 78 },
    { "tick": 81600, "bpm": 76 },
    { "tick": 82560, "bpm": 74 },
    { "tick": 83520, "bpm": 72 }
  ],
  "time_signatures": [
    { "tick": 0, "numerator": 4, "denominator": 4 }
  ],
  "tracks": [
    {
      "name": "Soprano",
      "channel": 0,
      "program": 19,
      "note_count": 128,
      "control_changes": [
        { "tick": 0, "controller": 7, "value": 75 }
      ],
      "notes": [
        {
          "pitch": 74,
          "velocity": 80,
          "start_tick": 0,
          "duration": 240,
          "voice": 0,
          "source": "material"
        }
      ]
    }
  ]
}

bpm is only the starting tempo — see Converting Ticks to Seconds for placing these ticks on the clock.

Exit Codes

CodeMeaning
0Success
2Parse/configuration error — unknown or invalid option, missing or out-of-range value, or incompatible option combination
3Generation error — incompatible character/instrument, unavailable free counterpoint, or composer validation failure
4Output error — the MIDI file or a JSON sidecar could not be written

When --generated-json is set and composer validation fails, a .diagnostic.json sidecar is written alongside the intended output before the run exits with code 3.

Dual-licensed: AGPL-3.0 · commercial licensing available. Generated MIDI is yours to use freely.