{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://map.audio/schemas/pam/dj-set.schema.json",
  "title": "DJ set",
  "description": "What dj_set (the plugin bridge's djSet and the MCP server tool) and `pam dj set` load. One of set and presets. The native reader is pam::dj::parseRequest (modules/engine/dj/DjSet.h), the TS one parseDjSetRequest (interface/src/components/Dj/djSetInput.ts); shared/dj/set-fixtures.json pins both. Each surface adds its own fields: dj_set takes op and play, pam dj set its render options.",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "set": {
      "$ref": "#/$defs/DjSetDocument"
    },
    "presets": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/presetPath"
      },
      "minItems": 1,
      "maxItems": 65,
      "description": "Shorthand: the queue is these presets in order, each at its first populated variation, every other field at its default."
    }
  },
  "$defs": {
    "presetPath": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    },
    "gridBars": {
      "enum": [
        1,
        2,
        4,
        8,
        16
      ]
    },
    "DjSetDocument": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "queue"
      ],
      "description": "queue[0] is NOW. A key named deck or decks is refused: the set is one timeline.",
      "properties": {
        "queue": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/DjSetItem"
          },
          "minItems": 1,
          "maxItems": 65
        },
        "stepBars": {
          "$ref": "#/$defs/gridBars",
          "default": 4,
          "description": "Bars each item plays unless it gives its own."
        },
        "launchBars": {
          "$ref": "#/$defs/gridBars",
          "default": 1,
          "description": "The grid a boundary lands on."
        },
        "auto": {
          "type": "boolean",
          "default": true,
          "description": "Step to the next item every stepBars; off holds NOW until Go."
        },
        "defaultTransition": {
          "$ref": "#/$defs/DjTransition",
          "description": "The boundary every item without its own plays. Default: {mode:'auto', window:{bars:1, paramCurve:'ease', mixCurve:'ease'}}."
        },
        "tempo": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "source": {
              "enum": [
                "master",
                "followNext",
                "followAudio"
              ],
              "default": "master",
              "description": "master holds one tempo; followNext glides to each NEXT preset's tempo across its window; followAudio lets deck B lead, each GO B gliding to its track's tempo, live only. A set with no deck B (every pam dj set, and dj_set until a track plays) holds like master, starting at bpm."
            },
            "glideBars": {
              "enum": [
                0,
                1,
                2,
                4,
                8
              ],
              "default": 4
            },
            "bpm": {
              "type": "number",
              "minimum": 20,
              "maximum": 400,
              "description": "The master tempo the set runs at. Live, refused while deck B leads under followAudio."
            }
          }
        }
      }
    },
    "DjSetItem": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "presetPath"
      ],
      "properties": {
        "presetPath": {
          "$ref": "#/$defs/presetPath"
        },
        "variationIndex": {
          "type": "integer",
          "minimum": 0,
          "maximum": 7,
          "description": "Default: the preset's first populated slot."
        },
        "bars": {
          "type": "integer",
          "minimum": 1,
          "maximum": 64,
          "description": "Default: stepBars."
        },
        "transition": {
          "$ref": "#/$defs/DjTransition",
          "description": "The boundary into this item; ignored on queue[0]."
        }
      }
    },
    "DjTransition": {
      "type": "object",
      "additionalProperties": false,
      "description": "Resolved in order: the preset's spec, spec merged over it one level deep per section, then bars, mode and curve as the DJ view's Length, Mode and Curve rows apply them.",
      "properties": {
        "preset": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64,
          "description": "A transition preset id: drop, rise, break, blend, sweep, fill, or one the user saved."
        },
        "spec": {
          "$ref": "#/$defs/TransitionSpec"
        },
        "bars": {
          "type": "number",
          "minimum": 0,
          "maximum": 32
        },
        "mode": {
          "enum": [
            "auto",
            "param",
            "mix",
            "seq",
            "all",
            "swap",
            "chop"
          ]
        },
        "curve": {
          "enum": [
            "linear",
            "ease",
            "exp",
            "log"
          ]
        }
      }
    },
    "TransitionSpec": {
      "type": "object",
      "additionalProperties": false,
      "description": "shared/morph/transitionSpec.ts TransitionSpec; the song_mode tool's transitionSpecSchema, whose bars run to 8 where a set's run to 32.",
      "properties": {
        "mode": {
          "enum": [
            "auto",
            "param",
            "mix",
            "seq",
            "all",
            "swap",
            "chop"
          ]
        },
        "window": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "bars": {
              "type": "number",
              "minimum": 0,
              "maximum": 32
            },
            "paramCurve": {
              "enum": [
                "linear",
                "ease",
                "exp",
                "log"
              ]
            },
            "patternCurve": {
              "enum": [
                "linear",
                "ease",
                "exp",
                "log"
              ]
            },
            "mixCurve": {
              "enum": [
                "linear",
                "ease",
                "exp",
                "log"
              ]
            },
            "staggerBy": {
              "enum": [
                "off",
                "cell",
                "category"
              ]
            },
            "staggerSpread": {
              "type": "number",
              "minimum": 0,
              "maximum": 0.9
            },
            "staggerOrder": {
              "enum": [
                "forward",
                "reverse"
              ]
            },
            "relations": {
              "enum": [
                "off",
                "stepped"
              ]
            }
          }
        },
        "pattern": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "policy": {
              "enum": [
                "dissolve",
                "wipe",
                "cells"
              ]
            }
          }
        },
        "audio": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "mixLaw": {
              "enum": [
                "equalPower",
                "equalGain",
                "correlation"
              ]
            },
            "tail": {
              "enum": [
                "cut",
                "fade",
                "ring"
              ]
            },
            "tailMaxBars": {
              "type": "number",
              "minimum": 0.25,
              "maximum": 32
            }
          }
        },
        "phase": {
          "enum": [
            "inherit",
            "reset",
            "continue"
          ]
        },
        "swap": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "order": {
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1,
                "maximum": 16
              },
              "maxItems": 16,
              "uniqueItems": true
            },
            "timing": {
              "enum": [
                "immediate",
                "step",
                "bar"
              ]
            }
          }
        },
        "chop": {
          "type": "object",
          "additionalProperties": false,
          "description": "CHOP's NOW/NEXT sequence: bit i of pattern set = step i plays NEXT.",
          "properties": {
            "pattern": {
              "type": "integer",
              "minimum": 0,
              "maximum": 4294967295
            },
            "steps": {
              "type": "integer",
              "minimum": 4,
              "maximum": 32
            },
            "repeats": {
              "enum": [
                1,
                2,
                4
              ]
            },
            "smooth": {
              "type": "number",
              "minimum": 0,
              "maximum": 1
            }
          }
        }
      }
    }
  }
}
