# clef.im clef.im renders public-domain scores as notation, plays them back, and synthesizes them to 16-bit PCM WAV on the server. It also generates random rhythm snippets and renders any score you POST to it. This file describes the whole API. `GET /api` returns the same thing as JSON. ## Note notation - A melody is a space-separated list of tokens. Each token is Pitch/beats, or r/beats for a rest. - `beats` is measured in quarter notes: 1 = quarter, 0.5 = eighth, 0.25 = sixteenth, 1.5 = dotted quarter, 2 = half. Omit `/beats` for a default quarter note. - Pitches are scientific notation with # or b: C4 is middle C, so Bb3 and F#5 are valid. - Pitches joined with + sound simultaneously as a chord, sharing one duration and cursor step: C4+E4+G4/1 is a quarter-note C major triad. - Tuplets / triplets are written as decimal beats: 0.333333 for an eighth-note triplet (1/3 beat), 0.166667 for a sixteenth-note sextuplet (1/6 beat). - `|` is ignored, so bar lines can be written for readability. - Max 512 sounding notes and 256 total beats per phrase. BPM is clamped to 40-240 (default 100). - Example: `C5/1 D5/0.75 C5/0.25 | C4+E4+G4/1 A4/1 r/0.5 Bb4/0.5` ## Endpoints ### GET /api/tunes The public-domain catalogue: every tune with its key, tempo, bar count and provenance. Returns: application/json Example: ```sh curl https://clef.im/api/tunes ``` ### GET /api/tunes/:id One catalogue tune, with its notes and the source its transcription was checked against. Returns: application/json Example: ```sh curl https://clef.im/api/tunes/ode ``` ### GET /api/tunes/:id/score.svg One catalogue tune as a standalone SVG score. Returns: image/svg+xml Example: ```sh curl https://clef.im/api/tunes/ode/score.svg ``` ### GET /api/tunes/:id/audio.wav One catalogue tune, synthesized server-side with the accompaniment. Returns: audio/wav Query parameters: - `drums` (e.g. `0`) — Set to 0 to drop the drum kit. - `bass` (e.g. `0`) — Set to 0 to drop the bass line. - `pad` (e.g. `0`) — Set to 0 to drop the pad. Example: ```sh curl https://clef.im/api/tunes/ode/audio.wav -o ode.wav ``` ### POST /api/render Render a score you supply. Echoes the canonical phrase back, so this is the cheapest way to check that your notes parsed the way you meant. Returns: application/json Body (JSON): ``` { "notes": "C5/1 D5/0.75 C5/0.25 | C4+E4+G4/1 A4/1", "bpm": 108, "key": "F", "timeSig": [4, 4], "pickup": 0 } Only `notes` is required. It is either a token string (see notation below) or an array of note objects. Optional fields: `id` (string), `title` (string), `bpm` (40-240, default 100), `timeSig` (array [beatsPerBar, beatUnit], default [4,4]), `key` (standard key string, default "C"), `pickup` (beats of anacrusis, default 0). Array shape for `notes`: [{ "pitch": "C5", "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "dur": 0.75 }] In an object, only `pitch` is required (`midi` is derived, `at` falls back to the running cursor, `dur` to 1, `vel` to 0.85). Canonical Response (`application/json`): { "id": "render", "title": "render", "bpm": 108, "timeSig": [4, 4], "key": "F", "pickup": 0, "notes": [ { "pitch": "C5", "midi": 72, "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "midi": 74, "dur": 0.75, "at": 1, "vel": 0.85 } ] } ``` Example: ```sh curl -X POST https://clef.im/api/render -H "content-type: application/json" -d '{"notes":"C5/1 D5/0.75 C5/0.25 A4/1 A4/1","bpm":108,"key":"F"}' ``` ### POST /api/render.wav Synthesize a score you supply to 16-bit PCM WAV, with the accompaniment. Returns: audio/wav Query parameters: - `drums` (e.g. `0`) — Set to 0 to drop the drum kit. - `bass` (e.g. `0`) — Set to 0 to drop the bass line. - `pad` (e.g. `0`) — Set to 0 to drop the pad. Body (JSON): ``` { "notes": "C5/1 D5/0.75 C5/0.25 | C4+E4+G4/1 A4/1", "bpm": 108, "key": "F", "timeSig": [4, 4], "pickup": 0 } Only `notes` is required. It is either a token string (see notation below) or an array of note objects. Optional fields: `id` (string), `title` (string), `bpm` (40-240, default 100), `timeSig` (array [beatsPerBar, beatUnit], default [4,4]), `key` (standard key string, default "C"), `pickup` (beats of anacrusis, default 0). Array shape for `notes`: [{ "pitch": "C5", "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "dur": 0.75 }] In an object, only `pitch` is required (`midi` is derived, `at` falls back to the running cursor, `dur` to 1, `vel` to 0.85). Canonical Response (`application/json`): { "id": "render", "title": "render", "bpm": 108, "timeSig": [4, 4], "key": "F", "pickup": 0, "notes": [ { "pitch": "C5", "midi": 72, "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "midi": 74, "dur": 0.75, "at": 1, "vel": 0.85 } ] } ``` Example: ```sh curl -X POST "https://clef.im/api/render.wav?drums=0" -H "content-type: application/json" -d '{"notes":"C5/1 D5/0.75 C5/0.25 A4/1 A4/1","bpm":108,"key":"F"}' -o tune.wav ``` ### POST /api/render.svg A score you supply, engraved as a standalone SVG. Returns: image/svg+xml Body (JSON): ``` { "notes": "C5/1 D5/0.75 C5/0.25 | C4+E4+G4/1 A4/1", "bpm": 108, "key": "F", "timeSig": [4, 4], "pickup": 0 } Only `notes` is required. It is either a token string (see notation below) or an array of note objects. Optional fields: `id` (string), `title` (string), `bpm` (40-240, default 100), `timeSig` (array [beatsPerBar, beatUnit], default [4,4]), `key` (standard key string, default "C"), `pickup` (beats of anacrusis, default 0). Array shape for `notes`: [{ "pitch": "C5", "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "dur": 0.75 }] In an object, only `pitch` is required (`midi` is derived, `at` falls back to the running cursor, `dur` to 1, `vel` to 0.85). Canonical Response (`application/json`): { "id": "render", "title": "render", "bpm": 108, "timeSig": [4, 4], "key": "F", "pickup": 0, "notes": [ { "pitch": "C5", "midi": 72, "dur": 1, "at": 0, "vel": 0.85 }, { "pitch": "D5", "midi": 74, "dur": 0.75, "at": 1, "vel": 0.85 } ] } ``` Example: ```sh curl -X POST https://clef.im/api/render.svg -H "content-type: application/json" -d '{"notes":"C5/1 D5/0.75 C5/0.25 A4/1 A4/1"}' ``` ### GET /api/rhythm A random but deterministic melody, for callers with no score of their own. Same seed always returns the same phrase. Returns: application/json Query parameters: - `seed` (e.g. `42`) — Integer. Reproduces a previous phrase. - `bars` (e.g. `4`) — Length in bars, 1-16 (default 8). - `key` (e.g. `G`) — Key root, e.g. C, G, Bb, Eb (default C). - `bpm` (e.g. `120`) — Tempo, 40-240 (default 96). Example: ```sh curl 'https://clef.im/api/rhythm?seed=42&bars=4&key=G&bpm=120' ``` ### GET /api/rhythm.wav The same generated phrase, synthesized server-side. Returns: audio/wav Query parameters: - `seed` (e.g. `42`) — Integer. Reproduces a previous phrase. - `bars` (e.g. `4`) — Length in bars, 1-16 (default 8). - `key` (e.g. `G`) — Key root, e.g. C, G, Bb, Eb (default C). - `bpm` (e.g. `120`) — Tempo, 40-240 (default 96). - `drums` (e.g. `0`) — Set to 0 to drop the drum kit. - `bass` (e.g. `0`) — Set to 0 to drop the bass line. - `pad` (e.g. `0`) — Set to 0 to drop the pad. Example: ```sh curl 'https://clef.im/api/rhythm.wav?seed=42&bars=8' -o rhythm.wav ``` ### GET /api/rhythm.svg The same generated phrase, engraved as a standalone SVG. Returns: image/svg+xml Query parameters: - `seed` (e.g. `42`) — Integer. Reproduces a previous phrase. - `bars` (e.g. `4`) — Length in bars, 1-16 (default 8). - `key` (e.g. `G`) — Key root, e.g. C, G, Bb, Eb (default C). - `bpm` (e.g. `120`) — Tempo, 40-240 (default 96). Example: ```sh curl 'https://clef.im/api/rhythm.svg?seed=42&bars=4' ```