1--- 2title: MIDI, OSC & MQTT 3layout: ../../layouts/MainLayout.astro 4--- 5 6import { MiniRepl } from '../../docs/MiniRepl'; 7import { JsDoc } from '../../docs/JsDoc'; 8 9# MIDI, OSC and MQTT 10 11Normally, Strudel is used to pattern sound, using its own '[web audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)'-based synthesiser called [SuperDough](https://codeberg.org/uzu/strudel/src/branch/main/packages/superdough). 12 13It is also possible to pattern other things with Strudel, such as software and hardware synthesisers with MIDI, other software using Open Sound Control/OSC (including the [SuperDirt](https://github.com/musikinformatik/SuperDirt/) synthesiser commonly used with Strudel's sibling [TidalCycles](https://tidalcycles.org/)), or the MQTT 'internet of things' protocol. 14 15# MIDI 16 17Strudel supports MIDI without any additional software (thanks to [webmidi](https://npmjs.com/package/webmidi)), just by adding methods to your pattern: 18 19## midin(inputName?) 20 21<JsDoc client:idle name="midin" h={0} /> 22 23## midikeys(inputName?) 24 25<JsDoc client:idle name="midikeys" h={0} /> 26 27## midi(outputName?,options?) 28 29Either connect a midi device or use the IAC Driver (Mac) or Midi Through Port (Linux) for internal midi messages. 30If no outputName is given, it uses the first midi output it finds. 31 32<MiniRepl 33 client:idle 34 tune={` 35$: chord("<C^7 A7 Dm7 G7>").voicing().midi('IAC Driver') 36`} 37/> 38 39In the console, you will see a log of the available MIDI devices as soon as you run the code, 40e.g. 41 42``` 43 `Midi connected! Using "Midi Through Port-0".` 44``` 45 46The `.midi()` function accepts an options object with the following properties: 47 48<MiniRepl 49 client:idle 50 tune={`$: note("d e c a f").midi('IAC Driver', { isController: true, midimap: 'default'}) 51`} 52/> 53 54<details> 55<summary>Available Options</summary> 56 57| Option | Type | Default | Description | 58| ------------ | ------------- | --------- | ---------------------------------------------------------------------- | 59| isController | boolean | false | When true, disables sending note messages. Useful for MIDI controllers | 60| latencyMs | number | 34 | Latency in milliseconds to align MIDI with audio engine | 61| noteOffsetMs | number | 10 | Offset in milliseconds for note-off messages to prevent glitching | 62| midichannel | number | 1 | Default MIDI channel (1-16) | 63| velocity | number | 0.9 | Default note velocity (0-1) | 64| gain | number | 1 | Default gain multiplier for velocity (0-1) | 65| midimap | string | 'default' | Name of MIDI mapping to use for control changes | 66| midiport | string/number | - | MIDI device name or index | 67 68</details> 69 70### midiport(outputName) 71 72Selects the MIDI output device to use, pattern can be used to switch between devices. 73 74```javascript 75$: midiport('IAC Driver'); 76$: note('c a f e').midiport('<0 1 2 3>').midi(); 77``` 78 79<JsDoc client:idle name="midiport" h={0} /> 80 81## midichan(number) 82 83Selects the MIDI channel to use. If not used, `.midi` will use channel 1 by default. 84 85## midicmd(command) 86 87`midicmd` sends MIDI system real-time messages to control timing and transport on MIDI devices. 88 89It supports the following commands: 90 91- `clock`/`midiClock` - Sends MIDI timing clock messages 92- `start` - Sends MIDI start message 93- `stop` - Sends MIDI stop message 94- `continue` - Sends MIDI continue message 95 96// You can control the clock with a pattern and ensure it starts in sync when the repl begins. 97// Note: It might act unexpectedly if MIDI isn't set up initially. 98 99<MiniRepl 100 client:idle 101 tune={`$:stack( 102 midicmd("clock*48,<start stop>/2").midi('IAC Driver') 103)`} 104/> 105 106## control, ccn && ccv 107 108- `control` sends MIDI control change messages to your MIDI device. 109- `ccn` sets the cc number. Depends on your synths midi mapping 110- `ccv` sets the cc value. normalized from 0 to 1. 111 112<MiniRepl client:idle tune={`note("c a f e").control([74, sine.slow(4)]).midi()`} /> 113 114<MiniRepl client:idle tune={`note("c a f e").ccn(74).ccv(sine.slow(4)).midi()`} /> 115 116In the above snippet, `ccn` is set to 74, which is the filter cutoff for many synths. `ccv` is controlled by a saw pattern. 117Having everything in one pattern, the `ccv` pattern will be aligned to the note pattern, because the structure comes from the left by default. 118But you can also control cc messages separately like this: 119 120<MiniRepl 121 client:idle 122 tune={`$: note("c a f e").midi() 123$: ccv(sine.segment(16).slow(4)).ccn(74).midi()`} 124/> 125 126Instead of setting `ccn` and `ccv` directly, you can also create mappings with `midimaps`: 127 128## midimaps 129 130<JsDoc client:idle name="midimaps" h={0} /> 131 132## defaultmidimap 133 134<JsDoc client:idle name="defaultmidimap" h={0} /> 135 136## progNum (Program Change) 137 138`progNum` sends MIDI program change messages to switch between different presets/patches on your MIDI device. 139Program change values should be numbers between 0 and 127. 140 141<MiniRepl client:idle tune={`// Switch between programs 0 and 1 every cycle 142progNum("<0 1>").midi() 143 144// Play notes while changing programs 145note("c3 e3 g3").progNum("<0 1 2>").midi()`} /> 146 147Program change messages are useful for switching between different instrument sounds or presets during a performance. 148The exact sound that each program number maps to depends on your MIDI device's configuration. 149 150## sysex, sysexid && sysexdata (System Exclusive Message) 151 152`sysex` sends MIDI System Exclusive (SysEx) messages to your MIDI device. 153ysEx messages are device-specific commands that allow deeper control over synthesizer parameters. 154The value should be an array of numbers between 0-255 representing the SysEx data bytes. 155 156<MiniRepl 157 client:idle 158 tune={`// Send a simple SysEx message 159let id = 0x43; //Yamaha 160//let id = "0x00:0x20:0x32"; //Behringer ID can be an array of numbers 161let data = "0x79:0x09:0x11:0x0A:0x00:0x00"; // Set NSX-39 voice to say "Aa" 162$: note("c a f e").sysex(id, data).midi(); 163$: note("c a f e").sysexid(id).sysexdata(data).midi();`} 164/> 165 166The exact format of SysEx messages depends on your MIDI device's specification. 167Consult your device's MIDI implementation guide for details on supported SysEx messages. 168 169## midibend && miditouch 170 171`midibend` sets MIDI pitch bend (-1 - 1) 172`miditouch` sets MIDI key after touch (0-1) 173 174<MiniRepl client:idle tune={`note("c a f e").midibend(sine.slow(4).range(-0.4,0.4)).midi()`} /> 175 176<MiniRepl client:idle tune={`note("c a f e").miditouch(sine.slow(4).range(0,1)).midi()`} /> 177 178# OSC/SuperDirt/StrudelDirt 179 180In TidalCycles, sound is usually generated using [SuperDirt](https://github.com/musikinformatik/SuperDirt/), which runs inside SuperCollider. Strudel also supports using SuperDirt, although it requires installing some additional software. 181 182There is also [StrudelDirt](https://github.com/daslyfe/StrudelDirt) which is SuperDirt with some optimisations for working with Strudel. (A longer term aim is to merge these optimisations back into mainline SuperDirt) 183 184## Prequisites 185 186To get SuperDirt to work with Strudel, you need to 187 1881. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info. 1892. install SuperDirt, or the [StrudelDirt](https://github.com/daslyfe/StrudelDirt) fork which is optimised for use with Strudel 1903. install [node.js](https://nodejs.org/en/) 1914. download [Strudel Repo](https://codeberg.org/uzu/strudel/) (or git clone, if you have git installed) 1925. run `pnpm i` in the strudel directory 1936. run `pnpm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider 194 195Now you're all set! 196 197## Usage 198 1991. Start SuperCollider, either using SuperCollider IDE or by running `sclang` in a terminal 2002. Open the [Strudel REPL](https://strudel.cc/#cygiYmQgc2QiKS5vc2MoKQ%3D%3D) 201 202...or test it here: 203 204<MiniRepl client:only="react" tune={`s("bd sd").osc()`} /> 205 206If you now hear sound, congratulations! If not, you can get help on the [#strudel channel in the TidalCycles discord](https://discord.com/invite/HGEdXmRkzT). 207 208Note: if you have the 'Audio Engine Target' in settings set to 'OSC', you do not need to add .osc() to the end of your pattern. 209 210### Pattern.osc 211 212<JsDoc client:idle name="Pattern.osc" h={0} /> 213 214## SuperDirt Params 215 216Please refer to [Tidal Docs](https://tidalcycles.org/) for more info. 217 218<br /> 219 220But can we use Strudel [offline](/learn/pwa)? 221 222# MQTT 223 224MQTT is a lightweight network protocol, designed for 'internet of things' devices. For use with strudel, you will 225need access to an MQTT server known as a 'broker' configured to accept secure 'websocket' connections. You could 226run one yourself (e.g. by running [mosquitto](https://mosquitto.org/)), although getting an SSL certificate that 227your web browser will trust might be a bit tricky for those without systems administration experience. 228Alternatively, you can use [a public broker](https://www.hivemq.com/mqtt/public-mqtt-broker/). 229 230Strudel does not yet support receiving messages over MQTT, only sending them. 231 232## Usage 233 234The following example shows how to send a pattern to an MQTT broker: 235 236<MiniRepl 237 client:only="react" 238 tune={`"hello world" 239 .mqtt(undefined, // username (undefined for open/public servers) 240 undefined, // password 241 '/strudel-pattern', // mqtt 'topic' 242 'wss://mqtt.eclipseprojects.io:443/mqtt', // MQTT server address 243 'mystrudel', // MQTT client id - randomly generated if not supplied 244 0 // latency / delay before sending messages (0 = no delay) 245 )`} 246 247/> 248 249Other software can then receive the messages. For example using the [mosquitto](https://mosquitto.org/) commandline client tools: 250 251``` 252 253> mosquitto_sub -h mqtt.eclipseprojects.io -p 1883 -t "/strudel-pattern" 254> hello 255> world 256> hello 257> world 258> ... 259 260``` 261 262Control patterns will be encoded as JSON, for example: 263 264<MiniRepl 265 client:only="react" 266 tune={`sound("sax(3,8)").speed("2 3") 267 .mqtt(undefined, // username (undefined for open/public servers) 268 undefined, // password 269 '/strudel-pattern', // mqtt 'topic' 270 'wss://mqtt.eclipseprojects.io:443/mqtt', // MQTT server address 271 'mystrudel', // MQTT client id - randomly generated if not supplied 272 0 // latency / delay before sending messages (0 = no delay) 273 )`} 274/> 275 276Will send messages like the following: 277 278``` 279 280{"s":"sax","speed":2} 281{"s":"sax","speed":2} 282{"s":"sax","speed":3} 283{"s":"sax","speed":2} 284... 285 286``` 287 288Libraries for receiving MQTT are available for many programming languages. 289 290``` 291 292```