[
  {
    "id": "bpmosc0000tab001",
    "type": "tab",
    "label": "Send BPM via OSC",
    "disabled": false,
    "info": "Send the live BPM to any OSC receiver, every time it changes.\n\nHOW IT WORKS\n1) OSC basics: click the inject button to send one test message. Two function\n   nodes show the pattern: the first sets the OSC address (msg.topic), the\n   second sets the message (msg.payload). The OSC output node sends whatever\n   arrives.\n2) Live BPM: the Beat node emits once per beat while a deck is playing.\n   'Keep only BPM changes' remembers the last BPM and only lets a message\n   through when the value changed. 'Set the address' sends it to\n   /time-line/bpm.\n3) Test buttons: no deck playing? Click these to push a fake BPM through the\n   same chain.\n\nSETUP - YOUR OSC RECEIVER\nDouble-click an OSC output node, then click the pencil icon next to 'Server'\nto set host and port. This example points at 127.0.0.1:8000, which is where\nProtokol (a free OSC monitor by Hexler) listens - handy to see what arrives.\nPoint it at your lighting console / Resolume / TouchDesigner instead, and\nchange the address in 'Set the address' to whatever your show system expects.\n\nNOTES\n- The OSC output node uses its Address field first; when that is empty it\n  falls back to msg.topic. This flow sets msg.topic in a function node so you\n  can see the pattern.\n- BPM follows the pitch fader, so it can change often. Uncomment the rounding\n  line in 'Keep only BPM changes' to send at most 1 decimal.\n",
    "env": []
  },
  {
    "id": "bpmosc0000grp001",
    "type": "group",
    "z": "bpmosc0000tab001",
    "name": "1) OSC basics - click the inject button",
    "style": {
      "label": true
    },
    "nodes": [
      "bpmosc0000inj001",
      "bpmosc0000fna001",
      "bpmosc0000fnm001",
      "bpmosc0000out001",
      "bpmosc0000dbg001"
    ],
    "x": 54,
    "y": 59,
    "w": 852,
    "h": 142
  },
  {
    "id": "bpmosc0000grp002",
    "type": "group",
    "z": "bpmosc0000tab001",
    "name": "2) Live BPM - sends every time the BPM changes",
    "style": {
      "label": true
    },
    "nodes": [
      "bpmosc0000beat01",
      "bpmosc0000fnc001",
      "bpmosc0000fna002",
      "bpmosc0000out002",
      "bpmosc0000dbg002"
    ],
    "x": 54,
    "y": 239,
    "w": 852,
    "h": 142
  },
  {
    "id": "bpmosc0000grp003",
    "type": "group",
    "z": "bpmosc0000tab001",
    "name": "3) No deck playing? Test with these",
    "style": {
      "label": true
    },
    "nodes": [
      "bpmosc0000injt01",
      "bpmosc0000injt02"
    ],
    "x": 54,
    "y": 419,
    "w": 252,
    "h": 142
  },
  {
    "id": "bpmosc0000inj001",
    "type": "inject",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp001",
    "name": "click me",
    "props": [
      {
        "p": "payload"
      },
      {
        "p": "topic",
        "vt": "str"
      }
    ],
    "repeat": "",
    "crontab": "",
    "once": false,
    "onceDelay": 0.1,
    "topic": "",
    "payload": "",
    "payloadType": "date",
    "x": 160,
    "y": 160,
    "wires": [
      [
        "bpmosc0000fna001"
      ]
    ]
  },
  {
    "id": "bpmosc0000fna001",
    "type": "function",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp001",
    "name": "Set the address",
    "func": "// The OSC address the receiver listens on.\n// (The OSC output node uses msg.topic when its Address field is empty.)\nmsg.topic = '/time-line/test';\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 360,
    "y": 160,
    "wires": [
      [
        "bpmosc0000fnm001"
      ]
    ]
  },
  {
    "id": "bpmosc0000fnm001",
    "type": "function",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp001",
    "name": "Set the message",
    "func": "// Whatever is in msg.payload gets sent as the OSC message.\nmsg.payload = 'hello from Time-Line';\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 570,
    "y": 160,
    "wires": [
      [
        "bpmosc0000out001",
        "bpmosc0000dbg001"
      ]
    ]
  },
  {
    "id": "bpmosc0000out001",
    "type": "tl-output",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp001",
    "name": "Example OSC",
    "protocol": "osc",
    "server": "bpmosc0000srv001",
    "address": "",
    "message": "",
    "vizType": "led",
    "textSuffix": "",
    "progressMin": 0,
    "progressMax": 1,
    "progressStartLabel": "",
    "progressEndLabel": "",
    "x": 780,
    "y": 160,
    "wires": []
  },
  {
    "id": "bpmosc0000dbg001",
    "type": "debug",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp001",
    "name": "what was sent",
    "active": true,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "true",
    "targetType": "full",
    "statusVal": "",
    "statusType": "auto",
    "x": 780,
    "y": 100,
    "wires": []
  },
  {
    "id": "bpmosc0000beat01",
    "type": "tl-beat",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp002",
    "name": "",
    "x": 150,
    "y": 340,
    "wires": [
      [
        "bpmosc0000fnc001"
      ]
    ]
  },
  {
    "id": "bpmosc0000fnc001",
    "type": "function",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp002",
    "name": "Keep only BPM changes",
    "func": "// The Beat node emits once per beat. Only pass the message on\n// when the BPM value is different from the previous one.\nconst bpm = msg.payload && msg.payload.bpm;\nif (typeof bpm !== 'number') { return null; }\n\n// Optional: round to 1 decimal so tiny pitch-fader moves\n// don't spam your show system. Uncomment to use:\n// const value = Math.round(bpm * 10) / 10;\nconst value = bpm;\n\nif (value === context.get('lastBpm')) { return null; }\ncontext.set('lastBpm', value);\n\nmsg.payload = value;\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 390,
    "y": 340,
    "wires": [
      [
        "bpmosc0000fna002"
      ]
    ]
  },
  {
    "id": "bpmosc0000fna002",
    "type": "function",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp002",
    "name": "Set the address",
    "func": "msg.topic = '/time-line/bpm';\nreturn msg;",
    "outputs": 1,
    "timeout": 0,
    "noerr": 0,
    "initialize": "",
    "finalize": "",
    "libs": [],
    "x": 600,
    "y": 340,
    "wires": [
      [
        "bpmosc0000out002",
        "bpmosc0000dbg002"
      ]
    ]
  },
  {
    "id": "bpmosc0000out002",
    "type": "tl-output",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp002",
    "name": "BPM via OSC",
    "protocol": "osc",
    "server": "bpmosc0000srv001",
    "address": "",
    "message": "",
    "vizType": "text",
    "textSuffix": " BPM",
    "progressMin": 0,
    "progressMax": 1,
    "progressStartLabel": "",
    "progressEndLabel": "",
    "x": 780,
    "y": 340,
    "wires": []
  },
  {
    "id": "bpmosc0000dbg002",
    "type": "debug",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp002",
    "name": "BPM sent",
    "active": true,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "true",
    "targetType": "full",
    "statusVal": "",
    "statusType": "auto",
    "x": 780,
    "y": 280,
    "wires": []
  },
  {
    "id": "bpmosc0000injt01",
    "type": "inject",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp003",
    "name": "test: BPM 120",
    "props": [
      {
        "p": "payload"
      }
    ],
    "repeat": "",
    "crontab": "",
    "once": false,
    "onceDelay": 0.1,
    "topic": "",
    "payload": "{\"bpm\":120}",
    "payloadType": "json",
    "x": 170,
    "y": 460,
    "wires": [
      [
        "bpmosc0000fnc001"
      ]
    ]
  },
  {
    "id": "bpmosc0000injt02",
    "type": "inject",
    "z": "bpmosc0000tab001",
    "g": "bpmosc0000grp003",
    "name": "test: BPM 128.5",
    "props": [
      {
        "p": "payload"
      }
    ],
    "repeat": "",
    "crontab": "",
    "once": false,
    "onceDelay": 0.1,
    "topic": "",
    "payload": "{\"bpm\":128.5}",
    "payloadType": "json",
    "x": 170,
    "y": 520,
    "wires": [
      [
        "bpmosc0000fnc001"
      ]
    ]
  },
  {
    "id": "bpmosc0000srv001",
    "type": "tl-output-server",
    "name": "Protokol",
    "protocol": "osc",
    "host": "127.0.0.1",
    "port": 8000,
    "udpFamily": "udp4"
  }
]
