1# @strudel/midi 2 3This package adds midi functionality to strudel Patterns. 4 5## Install 6 7```sh 8npm i @strudel/midi --save 9``` 10 11## Available Controls 12 13The following MIDI controls are available: 14 15OUTPUT: 16 17- `midi` - opens a midi output device. 18- `note` - Sends MIDI note messages. Can accept note names (e.g. "c4") or MIDI note numbers (0-127) 19- `midichan` - Sets the MIDI channel (1-16, defaults to 1) 20- `velocity` - Sets note velocity (0-1, defaults to 0.9) 21- `gain` - Modifies velocity by multiplying with it (0-1, defaults to 1) 22- `control` - Sets MIDI control change messages 23- `ccn` - Sets MIDI CC controller number (0-127) 24- `ccv` - Sets MIDI CC value (0-1) 25- `progNum` - Sends MIDI program change messages (0-127) 26- `sysex` - Sends MIDI System Exclusive messages (id: number 0-127 or array of bytes 0-127, data: array of bytes 0-127) 27- `sysexid` - Sets MIDI System Exclusive ID (number 0-127 or array of bytes 0-127) 28- `sysexdata` - Sets MIDI System Exclusive data (array of bytes 0-127) 29- `midibend` - Sets MIDI pitch bend (-1 - 1) 30- `miditouch` - Sets MIDI key after touch (0-1) 31- `midicmd` - Sends MIDI system real-time messages to control timing and transport on MIDI devices. 32- `nrpnn` - Sets MIDI NRPN non-registered parameter number (array of bytes 0-127) 33- `nrpv` - Sets MIDI NRPN non-registered parameter value (0-127) 34 35 36INPUT: 37 38- `midin` - Opens a MIDI input port to receive MIDI control change messages. 39 40Additional controls can be mapped using the mapping object passed to `.midi()`: 41 42## Examples 43 44### midi(outputName?, options?) 45 46Either connect a midi device or use the IAC Driver (Mac) or Midi Through Port (Linux) for internal midi messages. 47If no outputName is given, it uses the first midi output it finds. 48 49```javascript 50$: chord("<C^7 A7 Dm7 G7>").voicing().midi('IAC Driver') 51``` 52 53In the console, you will see a log of the available MIDI devices as soon as you run the code, e.g. `Midi connected! Using "Midi Through Port-0".` 54 55### Options 56 57The `.midi()` function accepts an options object with the following properties: 58 59```javascript 60$: note("c a f e").midi('IAC Driver', { isController: true, midimap: 'default'}) 61``` 62 63<details> 64<summary>Available Options</summary> 65 66| Option | Type | Default | Description | 67|--------|------|---------|-------------| 68| isController | boolean | false | When true, disables sending note messages. Useful for MIDI controllers | 69| latencyMs | number | 34 | Latency in milliseconds to align MIDI with audio engine | 70| noteOffsetMs | number | 10 | Offset in milliseconds for note-off messages to prevent glitching | 71| midichannel | number | 1 | Default MIDI channel (1-16) | 72| velocity | number | 0.9 | Default note velocity (0-1) | 73| gain | number | 1 | Default gain multiplier for velocity (0-1) | 74| midimap | string | 'default' | Name of MIDI mapping to use for control changes | 75| midiport | string/number | - | MIDI device name or index | 76 77</details> 78 79 80 81 82### midiport(outputName) 83 84Selects the MIDI output device to use, pattern can be used to switch between devices. 85 86```javascript 87$: midiport('IAC Driver') 88$: note("c a f e").midiport("<0 1 2 3>").midi() 89``` 90 91### midichan(number) 92 93Selects the MIDI channel to use. If not used, `.midi` will use channel 1 by default. 94 95### control, ccn && ccv 96 97`control` sends MIDI control change messages to your MIDI device. 98 99- `ccn` sets the cc number. Depends on your synths midi mapping 100- `ccv` sets the cc value. normalized from 0 to 1. 101 102```javascript 103$: note("c a f e").control([74, sine.slow(4)]).midi() 104$: note("c a f e").ccn(74).ccv(sine.slow(4)).midi() 105``` 106 107In the above snippet, `ccn` is set to 74, which is the filter cutoff for many synths. `ccv` is controlled by a saw pattern. 108Having everything in one pattern, the `ccv` pattern will be aligned to the note pattern, because the structure comes from the left by default. 109But you can also control cc messages separately like this: 110 111```javascript 112$: note("c a f e").midi() 113$: ccv(sine.segment(16).slow(4)).ccn(74).midi() 114``` 115 116### progNum (Program Change) 117 118`progNum` control sends MIDI program change messages to switch between different presets/patches on your MIDI device. 119Program change values should be numbers between 0 and 127. 120 121```javascript 122// Play notes while changing programs 123note("c3 e3 g3").progNum("<0 1 2>").midi() 124``` 125 126Program change messages are useful for switching between different instrument sounds or presets during a performance. 127The exact sound that each program number maps to depends on your MIDI device's configuration. 128 129## sysex, sysexid && sysexdata (System Exclusive Message) 130 131`sysex`, `sysexid` and `sysexdata` control sends MIDI System Exclusive (SysEx) messages to your MIDI device. 132sysEx messages are device-specific commands that allow deeper control over synthesizer parameters. 133The value should be an array of numbers between 0-255 representing the SysEx data bytes. 134 135```javascript 136// Send a simple SysEx message 137let id = 0x43; //Yamaha 138//let id = "0x00:0x20:0x32"; //Behringer ID can be an array of numbers 139let data = "0x79:0x09:0x11:0x0A:0x00:0x00"; // Set NSX-39 voice to say "Aa" 140$: note("c d e f e d c").sysex(id, data).midi(); 141$: note("c d e f e d c").sysexid(id).sysexdata(data).midi(); 142``` 143 144The exact format of SysEx messages depends on your MIDI device's specification. 145Consult your device's MIDI implementation guide for details on supported SysEx messages. 146 147### midibend && miditouch 148 149`midibend` sets MIDI pitch bend (-1 - 1) 150`miditouch` sets MIDI key after touch (0-1) 151 152```javascript 153 154$: note("c d e f e d c").midibend(sine.slow(4).range(-0.4,0.4)).midi(); 155$: note("c d e f e d c").miditouch(sine.slow(4).range(0,1)).midi(); 156 157``` 158 159### midicmd 160 161`midicmd` sends MIDI system real-time messages to control timing and transport on MIDI devices. 162 163It supports the following commands: 164 165- `clock`/`midiClock` - Sends MIDI timing clock messages 166- `start` - Sends MIDI start message 167- `stop` - Sends MIDI stop message 168- `continue` - Sends MIDI continue message 169 170```javascript 171// You can control the clock with a pattern and ensure it starts in sync when the repl begins. 172// Note: It might act unexpectedly if MIDI isn't set up initially. 173stack( 174 midicmd("clock*48,<start stop>/2").midi('IAC Driver') 175) 176``` 177 178`midicmd` also supports sending control change, program change and sysex messages. 179 180- `cc` - sends MIDI control change messages. 181- `progNum` - sends MIDI program change messages. 182- `sysex` - sends MIDI system exclusive messages. 183 184```javascript 185stack( 186 // "cc:ccn:ccv" 187 midicmd("cc:74:1").midi('IAC Driver'), 188 // "progNum:progNum" 189 midicmd("progNum:1").midi('IAC Driver'), 190 // "sysex:[sysexid]:[sysexdata]" 191 midicmd("sysex:[0x43]:[0x79:0x09:0x11:0x0A:0x00:0x00]").midi('IAC Driver') 192) 193```