jevstrudel.git / website / src / pages / learn / input-output.mdx
input-output.mdx292 lines · 10.5 KB · raw
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```