kobimusic

workspace

← learn

the flow format

an automation as a JSON document: nodes, and the edges between them

An automation is a small JSON document. The builder edits one, a .flow.json file is one, and the API takes one as its request. Nodes do things; edges carry files from one node's output port to another's input port. The kinds of node are on the nodes page.

{
  "kobi": "flow/1",
  "name": "scans to sheet music",
  "nodes": [
    { "id": "in",  "type": "input" },
    { "id": "omr", "type": "sheet-to-score", "params": { "model": "copista-mini" } },
    { "id": "out", "type": "returns" }
  ],
  "edges": [
    { "from": "in.files", "to": "omr.sheets" },
    { "from": "omr.score", "to": "out.value" }
  ]
}

the rules

  • kobi is "flow/1", exactly. New kinds of node and new optional parameters will never change it.
  • A node's id is lower-case letters, digits and hyphens, starting with a letter. An edge names ports as node.port.
  • At most 64 nodes, 256 edges and 64 KB.
  • No loops. A tool whose output goes nowhere is refused, since it would spend credits on a result nobody keeps.
  • Files a port does not take are passed over, not failed: a stray text file in a folder of scans does not spoil the run.
  • A parameter left out takes its default. The builder writes every parameter out, so that a default changing later cannot change what a saved flow does.
  • Fields this version does not know are kept when a flow is opened and saved. A node of a kind it does not know is an error on that node: the flow opens, and will not run.

inputs make a flow a tool

An input node has no file of its own: it is given one when the flow is run. That is what makes a flow reusable. In the workspace, a saved flow with an input appears on the tools menu of every file that input could take, and a folder given to an input stands for every file in it.

asking before it runs

A node may list some of its parameters under ask: "ask": ["partBook"]. When the flow is run from a file's tools menu, those are put to the person first, starting from what the flow says, because they are questions about the file in hand. Whether a document is a part-book is something only whoever is holding it knows. A parameter about some kinds of file only is asked only when one of those is chosen. A run from the builder, the API or an agent asks nothing: it is given every parameter already.

from a MIDI file to sheet music

A MIDI file played in is timed in seconds, at a tempo made up to hold the notes, so engraved as it is its bars line up with nothing. So before a MIDI is engraved it is put on its beats: beat-align finds them from its own notes, and fit-to-beats takes them from a beat map. Then dehumanize cleans up its rhythm, writing the notes as a person would: runs even, chords together, grace notes kept. The built-in “midi to sheet music” does all of it.

fit-to-beats has two inputs and pairs what reaches them by name: take-3.mid goes with take-3.beats.json, from the same folder. It leaves the notes where they were played unless told to straighten them, because dehumanizing after is the better reading.

doing things in order

File operations have a gate input called after and an output called done. Join save.saved to delete.after and the originals are deleted only once their results are saved. If any conversion failed, the delete refuses to run at all.