Skip to content

Custom Seed Targets

Graham Wakefield edited this page Jul 26, 2021 · 11 revisions

For a custom seed-based target (i.e. not Patch/Field/Petal/Pod/Versio etc.):

You will need to create a JSON file specific to the hardware target. It could be a good idea to store this JSON file in the same folder as your patcher.

The path to this JSON file can be configured in the [oopsy] patcher using either the "browse" button, by sending the "target " message to it, or including it in the [oopsy] patcher arguments.

JSON configuration files

Here are some examples:

Minimal example

A minimal breadboard-ready configuration, with buttons attached to pins 18 & 28, knobs attached to pins 21 & 25:

{
	"components": {
		"sw1": {
			"component": "Switch",
			"pin": 18,
			"automap": true
		},
		"knob1": {
			"component": "AnalogControl",
			"pin": 21,
			"automap": true
		},
		"knob2": {
			"component": "AnalogControl",
			"pin": 25,
			"automap": true
		},
		"sw2": {
			"component": "Switch",
			"pin": 28,
			"automap": true
		}
	}
}

Daisy Pod

This is fully equivalent to the default Daisy Pod target:

{
	"name":"pod",
	"defines": {
		"OOPSY_TARGET_HAS_MIDI_INPUT": 1
	},
	"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 }
		}
	},
	"aliases": {
		"switch": "sw1",
		"button": "sw1",
		"switch1": "sw1",
		"button1": "sw1",
		"switch2": "sw2",
		"button2": "sw2",
		"enp": "encoder_press",
		"switch3": "encoder_press",
		"press": "encoder_press",
		"knob": "knob1",
		"ctrl": "knob1",
		"ctrl1": "knob1",
		"ctrl2": "knob2",
		"led": "led1"
	}
}

Noise Engineering Versio

This is fully equivalent to the default Versio target:

{
	"name":"pod",
	"defines": {
		"OOPSY_TARGET_HAS_MIDI_INPUT": 1
	},
	"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 }
		}
	},
	"aliases": {
		"switch": "sw1",
		"button": "sw1",
		"switch1": "sw1",
		"button1": "sw1",
		"switch2": "sw2",
		"button2": "sw2",
		"enp": "encoder_press",
		"switch3": "encoder_press",
		"press": "encoder_press",
		"knob": "knob1",
		"ctrl": "knob1",
		"ctrl1": "knob1",
		"ctrl2": "knob2",
		"led": "led1"
	}
}

Options

components (required): A set of named component mappings. Currently available components are:

  • "AnalogControl" (for CV inputs, knobs, sliders, etc.)
    • requires: "pin": <number>
    • provides inputs: <name>, <name>_trig
  • "GateIn"
    • requires: "pin": <number>
    • provides inputs: <name>, <name>_trig
  • "Switch"
    • requires: "pin": <number>,
    • provides inputs: <name>, <name>_rise, <name>_fall, <name>_seconds
  • "Switch3"
    • requires: "pin": { "a":<number>, "b":<number> }
    • provides inputs: <name>
  • "Encoder"
    • requires: "pin": { "a":<number>, "b":<number>, "click":<number> }
    • provides inputs: <name>, <name>_press, <name>_rise, <name>_fall, <name>_seconds
  • "Led"
    • requires: "pin": <number>,
    • provides outputs: <name>
  • "RgbLed"
    • requires: "pin": { "r":<number>, "g":<number>, "b":<number> },
    • provides outputs: <name>, <name>_red, <name>_green, <name>_blue, <name>_white
  • "GateOut"
    • requires: "pin": <number>,
    • provides outputs: <name>
  • "CVOuts" (a general purpose two-channel DAC)
    • no pins required,
    • provides outputs: <name>1, <name>2

More types will be added in the future.

name (optional): An optional name for the target. (Defaults to "custom")

defines (optional): Any C preprocessor #define values. For example, add "OOPSY_TARGET_HAS_MIDI_INPUT": 1 to ensure MIDI input handling code is included in the binary.

aliases (optional): To provide multiple alternate names that can map to the same component


DEPRECATED INFORMATION BELOW

(Currently the JSON format below will continue to work, but once the format above achieves generality, this will be removed.

JSON configuration file

Minimal starting point:

{
	"defines": {
		"OOPSY_TARGET_SEED": 1
	},
	"labels": {
		"params": {},
		"outs": {},
		"datas": {}
	},
	"inputs": {},
	"outputs": {},
	"datahandlers": {},
	"inserts": [],
	"max_apps": 1
}

defines: Any C preprocessor #define values. For example, add "OOPSY_TARGET_HAS_MIDI_INPUT": 1 to ensure MIDI input handling code is included in the binary; "OOPSY_IO_COUNT": 4 if the device has 4x4 audio rather than the default 2x2 audio IO.

labels: These are the "magic" names that [param]s etc. will recognize, and should map to a string that exists as a key in the "inputs", "outputs" etc. sections of the JSON. More than one label can map to the same key.

inputs: These define how code is generated for control-rate inputs (knobs, cvs, gates, switches, etc.). Any feature marked "automap": true will be mapped to any otherwise unmapped [param] in the gen~ patch. The "code" section is a C/C++ statement to derive the control value from the Seed hardware.

outputs: These define how code is generated for non-audio [out] objects. The "code" section is a C/C++ statement to set the value on the Seed hardware; use $<name> to insert the gen~ variable value into the expression. The "where" key can define where this code should be inserted; use "audio" to place in the audio callback (e.g. gates, some LEDs) or "main" to place this in the main while loop (most other outputs).

datahandlers: These define how custom [data] objects can be used to map to hardware features. This is pretty experimental at the moment and is likely to change.

inserts: A way to insert arbitrary "code" into different sections of the template (according to the "where" tag). "where" can be

  • "header", (e.g. #include files)
  • "init", (for any code that needs to run at startup)
  • "main", (for any code that runs continuously in the main loop)
  • "display", (like "main", but only runs every 10ms)
  • "audio", (in audio interrupt, before audio processing)
  • "post_audio" (in audio interrupt, after audio processing)

max_apps: Assumes 1 if not defined. If greater than 1 this will enable multi-app binaries, but limits how many can be included.

Here is an example custom seed JSON config that has been used by a forum poster (note careful escaping of quotes):

{
  "defines": {
    "OOPSY_TARGET_SEED": 1
  },
  "labels": {
    "params": {
      "knob1": "kn1",
      "knob2": "kn2",
      "knob3": "kn3"
    },
    "outs": {},
    "datas": {}
  },
  "inputs": {
    "kn1": {
      "automap": true,
      "code": "hardware.seed.adc.GetFloat(0);"
    },
    "kn2": {
      "automap": true,
      "code": "hardware.seed.adc.GetFloat(1);"
    },
    "kn3": {
      "automap": true,
      "code": "hardware.seed.adc.GetFloat(2);"
    }
  },
  "outputs": {},
  "datahandlers": {},
  "inserts": [
    {
      "where": "init",
      "code": "AdcChannelConfig cfg[3];"
    },
    {
      "where": "init",
      "code": "cfg[0].InitSingle(oopsy::daisy.hardware.seed.GetPin(21));"
    },
    {
      "where": "init",
      "code": "cfg[1].InitSingle(oopsy::daisy.hardware.seed.GetPin(22));"
    },
    {
      "where": "init",
      "code": "cfg[2].InitSingle(oopsy::daisy.hardware.seed.GetPin(23));"
    },
    {
      "where": "init",
      "code": "oopsy::daisy.hardware.seed.adc.Init(cfg, 3);"
    },
    {
      "where": "header",
      "code": "#include \"daisy_seed.h\""
    },
    {
      "where": "header",
      "code": "using namespace daisy;"
    }
  ],
  "max_apps": 1
}
Clone this wiki locally