Skip to content

How To Custom JSON with Oopsy

takumi-ogata edited this page Jun 18, 2024 · 3 revisions

If you have custom hardware based on the Daisy Seed or Daisy Patch SM, Oopsy provides a way to describe your hardware just like any of the included boards. The interface uses the JSON format with just a few fields to tell Oopsy what's what. You can find all of Oopsy's board definitions here if you'd like more examples beyond this how to.

This is work-in-progress, so it's not yet available on the master branch (or fork) of Oopsy. For testing, you should check out the dev branch using git in your terminal:

git checkout dev

Critical Fields

There are four fields that are essential for any board description:

  • name
    • This describes the name of the board, which helps with organizing file generation.
  • som
    • This describes the System On Module (SOM) used by your hardware. The options are seed and patch_sm.
  • audio
    • This field should be structured as an object (contained by curly braces {}) with a "channels" field describing the number of audio channels.
  • components
    • This field describes the board's I/O layout, and should be structured as an object with each field corresponding to the object name you'll use in Max. Each individual component object should have a "component" field describing what type of component it is and a "pin" field describing which pin it uses. Components that use multiple pins should use an object formatted according to its description in the following section.

Here's an example of a minimally viable JSON description with these fields:

{
    "name": "my_board",
    "som": "seed",
    "audio": {"channels": 2},
    "components": {
        "knob": {
            "component": "AnalogControl",
            "pin": 21
        }
    }
}

Just wire up a potentiometer to the Seed on a breadbord and you're off to the races!

Note: You may encounter a compiler error if you have a space in your .json file name.

Additional fields

Defines

The "defines" field, structured as an object with each field representing a C-style macro, allows the use of a few additional features. Here's a list of the currently valid macros:

  • OOPSY_TARGET_HAS_MIDI_INPUT
    • With its value set to 1, this macro will provide a MIDI input stream that's accessed like an audio input (e.g. in 3 midi if the board has two audio ins). This feature uses USART 1 on pins 13 and 14 of the Daisy Seed.
  • OOPSY_TARGET_HAS_MIDI_OUTPUT
    • With its value set to 1, this macro will output a MIDI data stream (e.g. out 3 midi if the board is only using two outputs). This feature uses USART 1 on pins 13 and 14 of the Daisy Seed.

Aliases

The "aliases" field allows you to provide alternate names for a component. Structured as an object, each key represents the alias, and its corresponding item represent the original name of the component. As an example:

"aliases": {
    "pot": "knob"
}

Appended to the first JSON example in this how to, this would allow you to refer to your component in Max as either pot or knob.

Components

Here's a table of the main components:

Component Pin description Notes
Switch Single pin A momentary or toggle switch with an internal pullup
Switch3 {"a": (pin), "b": (pin)} A SP3T switch with the outer terminals connected to "a" and "b"
Encoder {"a": (pin), "b": (pin), "click": (pin)} A rotary encoder with a momentary pushbutton shaft
GateIn Single pin A GPIO serving as a gate input
AnalogControl Single pin Any analog input -- CV, potentiometer, or otherwise. Ensure the pin is a valid analog input!
Led Single pin An LED
RgbLed {"r": (pin), "g": (pin), "b": (pin)} An RGB LED
GateOut Single pin A GPIO serving as a gate output
CVOuts Single pin One of two DAC outputs on the Daisy

Note that these names are case sensitive.

Full example

Let's combine all this together an take a look at the JSON describing the Daisy Pod:

{
    "name": "pod",
    "som": "seed",
    "defines": {
        "OOPSY_TARGET_HAS_MIDI_INPUT": 1
    },
    "audio": {
        "channels": 2
    },
    "components": {
        "sw1": {
            "component": "Switch",
            "pin": 27
        },
        "sw2": {
            "component": "Switch",
            "pin": 28
        },
        "knob1": {
            "component": "AnalogControl",
            "pin": 21
        },
        "knob2": {
            "component": "AnalogControl",
            "pin": 15
        },
        "encoder": {
            "component": "Encoder",
            "pin": {
                "a": 26,
                "b": 25,
                "click": 13
            }
        },
        "led1": {
            "component": "RgbLed",
            "pin": {
                "r": 20,
                "g": 19,
                "b": 18
            }
        },
        "led2": {
            "component": "RgbLed",
            "pin": {
                "r": 17,
                "g": 24,
                "b": 23
            }
        },
        "led3": {
            "component": "Led",
            "pin": 10,
        },
        "cvout": {
            "component": "CVOuts"
        },
        "gatein": {
            "component": "GateIn",
            "pin": 12
        },
        "sw3": {
            "component": "Switch3",
            "pin": {
                "a": 1,
                "b": 2
            }
        }
	},
    "aliases": {
        "cvout1": "cvout",
        "switch": "sw1",
        "button": "sw1",
        "switch1": "sw1",
        "button1": "sw1",
        "switch2": "sw2",
        "button2": "sw2",
        "switch3": "sw3",
        "gate": "gatein",
        "gate1": "gatein",
        "encswitch": "encoder_rise",
        "enp": "encoder_press",
        "press": "encoder_press",
        "knob": "knob1",
        "ctrl": "knob1",
        "ctrl1": "knob1",
        "ctrl2": "knob2",
        "led": "led1"
    }
}