{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://open-music-project.org/schema/1.3/project.schema.json",
  "title": "OMP project.json",
  "type": "object",
  "required": ["format", "formatVersion", "timebase", "arrangement"],
  "properties": {
    "format": { "const": "omp" },
    "formatVersion": { "type": "string", "pattern": "^\\d+\\.\\d+\\.\\d+$" },
    "generator": {
      "type": "object",
      "properties": {
        "name": { "type": "string" },
        "version": { "type": "string" }
      }
    },
    "meta": {
      "type": "object",
      "properties": {
        "title": { "type": "string" },
        "artist": { "type": "string" },
        "license": { "type": "string" },
        "created": { "type": "string" },
        "modified": { "type": "string" }
      }
    },
    "timebase": {
      "type": "object",
      "required": ["ppq"],
      "properties": {
        "ppq": { "type": "integer", "minimum": 24 },
        "key": {
          "type": "string",
          "enum": [
            "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B",
            "Cm", "C#m", "Dm", "D#m", "Em", "Fm", "F#m", "Gm", "G#m", "Am", "A#m", "Bm"
          ],
          "default": "C"
        },
        "tempoMap": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["tick", "bpm"],
            "properties": {
              "tick": { "type": "integer", "minimum": 0 },
              "bpm": { "type": "number", "exclusiveMinimum": 0 }
            }
          }
        },
        "timeSignatures": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["tick", "num", "den"],
            "properties": {
              "tick": { "type": "integer", "minimum": 0 },
              "num": { "type": "integer", "minimum": 1 },
              "den": { "type": "integer", "minimum": 1 }
            }
          }
        }
      }
    },
    "channels": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": { "type": "string" },
          "color": { "type": "string" },
          "mixer": { "type": "string" },
          "instrument": {
            "type": "object",
            "properties": {
              "kind": { "enum": ["sampler", "plugin", "external", "none"] },
              "uid": { "type": "string" },
              "asset": { "type": "string" },
              "state": { "type": "string" },
              "params": { "type": "object" },
              "rootNote": { "type": "integer", "minimum": 0, "maximum": 127 },
              "stretchMode": { "enum": ["off", "repitch", "stretch"] }
            }
          }
        }
      }
    },
    "patterns": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "required": ["name", "length", "parts"],
        "properties": {
          "name": { "type": "string" },
          "length": { "type": "integer", "minimum": 0 },
          "color": { "type": "string" },
          "swing": { "type": "number", "minimum": 50, "maximum": 75 },
          "parts": {
            "type": "array",
            "minItems": 1,
            "items": { "$ref": "#/$defs/part" }
          }
        }
      }
    },
    "arrangement": {
      "type": "object",
      "required": ["tracks"],
      "properties": {
        "tracks": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["name", "items"],
            "properties": {
              "name": { "type": "string" },
              "mute": { "type": "boolean" },
              "mixer": { "type": "string" },
              "color": { "type": "string" },
              "items": {
                "type": "array",
                "items": {
                  "oneOf": [
                    { "$ref": "#/$defs/patternItem" },
                    { "$ref": "#/$defs/audioItem" }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "mixer": {
      "type": "object",
      "properties": {
        "tracks": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["id", "name"],
            "properties": {
              "id": { "type": "string" },
              "name": { "type": "string" },
              "role": { "enum": ["bus", "track", "master"] },
              "gain": { "type": "number" },
              "pan": { "type": "number" },
              "mute": { "type": "boolean" },
              "inserts": { "type": "array", "items": { "$ref": "#/$defs/insert" } },
              "sendTo": { "type": "string" },
              "sends": { "type": "array", "items": { "$ref": "#/$defs/send" } }
            }
          }
        }
      }
    },
    "automation": {
      "type": "object",
      "required": ["rel"],
      "properties": {
        "rel": {
          "type": "string",
          "pattern": "^automation/.+\\.json$"
        }
      }
    },
    "extensions": { "type": "object" }
  },
  "$defs": {
    "part": {
      "type": "object",
      "required": ["channel", "source"],
      "properties": {
        "channel": { "type": "string" },
        "source": {
          "type": "object",
          "required": ["kind"],
          "oneOf": [
            {
              "properties": {
                "kind": { "const": "inline" },
                "notes": {
                  "type": "array",
                  "items": { "$ref": "#/$defs/note" }
                },
                "cc": { "type": "array", "items": { "$ref": "#/$defs/cc" } }
              },
              "required": ["kind", "notes"]
            },
            {
              "properties": {
                "kind": { "const": "smf" },
                "rel": { "type": "string" }
              },
              "required": ["kind", "rel"]
            }
          ]
        }
      }
    },
    "insert": {
      "type": "object",
      "required": ["uid"],
      "properties": {
        "uid": { "type": "string" },
        "state": { "type": "string" },
        "params": { "type": "object" },
        "bypassed": { "type": "boolean" },
        "wet": { "type": "number", "minimum": 0, "maximum": 1 }
      }
    },
    "send": {
      "type": "object",
      "required": ["target"],
      "properties": {
        "target": { "type": "string" },
        "gainDb": { "type": "number" }
      }
    },
    "note": {
      "type": "object",
      "required": ["t", "d", "n"],
      "properties": {
        "t": { "type": "integer", "minimum": 0 },
        "d": { "type": "integer", "minimum": 0 },
        "n": { "type": "integer", "minimum": 0, "maximum": 127 },
        "v": { "type": "integer", "minimum": 0, "maximum": 127 },
        "ch": { "type": "integer", "minimum": 0, "maximum": 15 }
      }
    },
    "cc": {
      "type": "object",
      "required": ["t", "num", "val"],
      "properties": {
        "t": { "type": "integer", "minimum": 0 },
        "num": { "type": "integer", "minimum": 0, "maximum": 127 },
        "val": { "type": "integer", "minimum": 0, "maximum": 127 },
        "ch": { "type": "integer", "minimum": 0, "maximum": 15 }
      }
    },
    "patternItem": {
      "type": "object",
      "required": ["type", "ref", "start", "length"],
      "properties": {
        "type": { "const": "pattern" },
        "ref": { "type": "string" },
        "start": { "type": "integer", "minimum": 0 },
        "clipStart": { "type": "integer", "minimum": 0 },
        "length": { "type": "integer", "minimum": 0 },
        "loop": { "type": "boolean" },
        "mute": { "type": "boolean" },
        "color": { "type": "string" }
      }
    },
    "audioItem": {
      "type": "object",
      "required": ["type", "ref", "start"],
      "properties": {
        "type": { "const": "audio" },
        "ref": { "type": "string" },
        "start": { "type": "integer", "minimum": 0 },
        "clipStart": { "type": "integer", "minimum": 0 },
        "clipLength": { "type": "integer", "minimum": 0 },
        "gain": { "type": "number" },
        "fadeIn": { "type": "integer", "minimum": 0 },
        "fadeOut": { "type": "integer", "minimum": 0 },
        "pitch": { "type": "number" },
        "mute": { "type": "boolean" },
        "color": { "type": "string" }
      }
    }
  }
}
