1This document introduces you to Strudel in a technical sense. 2 3It is rather out of date, but there might still be useful info below. 4 5If you just want to *use* Strudel, have a look at the [Tutorial](https://strudel.tidalcycles.org/tutorial/). 6 7## Strudel Packages 8 9There are different packages for different purposes. They.. 10 11- split up the code into smaller chunks 12- can be selectively used to implement some sort of time based system 13 14Please refer to the individual README files in the [packages folder](https://codeberg.org/uzu/strudel/src/branch/main/packages) 15 16## REPL 17 18The [REPL](https://strudel.tidalcycles.org/) is the place where all packages come together to form a live coding system. It can also be seen as a reference implementation for users of the library. 19 20More info in the [REPL README](https://codeberg.org/uzu/strudel/src/branch/main/packages/repl/README.md) 21 22# High Level Overview 23 24<img src="strudelflow.png" width="600" /> 25 26## 1. End User Code 27 28The End User Code is written in JavaScript with added syntax sugar. The [eval package](https://github.com/tidalcycles/strudel/tree/main/packages/eval#strudelcycleseval) evaluates the user code 29after a transpilation step, which resolves the syntax sugar. If you don't want the syntax sugar, you can omit the eval package and call the native javascript `eval` instead. 30 31### 🍭 Syntax Sugar 32 33JavaScript Transpilation = converting valid JavaScript to valid JavaScript: 34 35```js 36"c3 [e3 g3]".fast(2) 37``` 38 39becomes 40 41```js 42mini('c3 [e3 g3]') 43 .withMiniLocation([1, 0, 0], [1, 11, 11]) // source location 44 .fast(2); 45``` 46 47- double quoted strings and backtick strings are turned into `mini` calls (single quoted strings are left as is) 48- The source location is added by chaining `withMiniLocation`, which enables the real time highlighting later 49- (psuedo) variable names that look like notes (like `c4`, `bb2` or `fs3`) are turned into strings 50- support for top level await 51- operator overloading could be implemented in the future 52 53This is how it works: 54 55<img src="https://github.com/tidalcycles/strudel/blob/talk/talk/public/shiftflow.png?raw=true" width="800" /> 56 57- The user code is parsed with a [shift parser](https://github.com/shapesecurity/shift-parser-js), generating an AST 58- The AST is transformed to resolve the syntax sugar 59- The AST is used to generate code again (shift-codegen) 60 61Shift will most likely be replaced with acorn in the future, see https://github.com/tidalcycles/strudel/issues/174 62 63### Mini Notation 64 65Another important part of the user code is the mini notation, which allows to express rhythms in a short manner. 66 67- the mini notation is [implemented as a PEG grammar](https://github.com/tidalcycles/strudel/blob/main/packages/mini/krill.pegjs), living in the [mini package](https://github.com/tidalcycles/strudel/tree/main/packages/mini) 68- it is based on [krill](https://github.com/Mdashdotdashn/krill) by Mdashdotdashn 69- the peg grammar is used to generate a parser with [peggyjs](https://peggyjs.org/) 70- the generated parser takes a mini notation string and outputs an AST 71- the AST can then be used to construct a pattern using the regular Strudel API 72 73Here's an example AST: 74 75```json 76{ 77 "type_": "pattern", 78 "arguments_": { "alignment": "h" }, 79 "source_": [ 80 { 81 "type_": "element", "source_": "c3", 82 "location_": { "start": { "offset": 1, "line": 1, "column": 2 }, "end": { "offset": 4, "line": 1, "column": 5 } } 83 }, 84 { 85 "type_": "element", 86 "location_": { "start": { "offset": 4, "line": 1, "column": 5 }, "end": { "offset": 11, "line": 1, "column": 12 } } 87 "source_": { 88 "type_": "pattern", "arguments_": { "alignment": "h" }, 89 "source_": [ 90 { 91 "type_": "element", "source_": "e3", 92 "location_": { "start": { "offset": 5, "line": 1, "column": 6 }, "end": { "offset": 8, "line": 1, "column": 9 } } 93 }, 94 { 95 "type_": "element", "source_": "g3", 96 "location_": { "start": { "offset": 8, "line": 1, "column": 9 }, "end": { "offset": 10, "line": 1, "column": 11 } } 97 } 98 ] 99 }, 100 } 101 ] 102} 103``` 104 105which translates to `seq(c3, seq(e3, g3))` 106 107## 2. Querying & Scheduling 108 109When the user code has been evaluated, we hopefully get a Pattern instance, which we can use to query events from. 110These events can then be used to trigger side effects in the real world. On that note, Events are mostly called Hap(s) in the codebase, because JS already has a built in `Event` class. 111 112### Querying 113 114> Querying = Asking a Pattern for Events within a certain time span 115 116```js 117seq('c3', ['e3', 'g3']) // <--- Pattern 118 .queryArc(0, 2) // query events within 0 and 2 cycles 119 .map((hap) => hap.showWhole()); // make readable 120``` 121 122yields 123 124```js 125[ 126 '0/1 -> 1/2: c3', // cycle 0 127 '1/2 -> 3/4: e3', 128 '3/4 -> 1/1: g3', 129 '1/1 -> 3/2: c3', // cycle 1 130 '3/2 -> 7/4: e3', 131 '7/4 -> 2/1: g3', 132]; 133``` 134 135### 🗓️ Scheduling 136 137The scheduler will query events repeatedly, creating a possibly endless loop of time slices. 138Here is a simplified example of how it works 139 140```js 141let step = 0.5; // query interval in seconds 142let tick = 0; // how many intervals have passed 143let pattern = seq('c3', ['e3', 'g3']); // pattern from user 144setInterval(() => { 145 const events = pattern.queryArc(tick * step, ++tick * step); 146 events.forEach((event) => { 147 console.log(event.showWhole()); 148 const o = getAudioContext().createOscillator(); 149 o.frequency.value = getFreq(event.value); 150 o.start(event.whole.begin); 151 o.stop(event.whole.begin + event.duration); 152 o.connect(getAudioContext().destination); 153 }); 154}, step * 1000); // query each "step" seconds 155``` 156 157## 3. Sound Output 158 159The third and last step is to use the scheduled events to make sound. 160Patterns are wrapped with param functions to compose different properties of the sound. 161 162```js 163note("[c2(3,8) [<eb2 g1> bb1]]") // sets frequency 164 .s("<sawtooth square>") // sound source 165 .gain(.5) // turn down volume 166 .cutoff(sine.range(200,1000).slow(4)) // modulated cutoff 167 .slow(2) 168 .out().logValues()`, 169 ]} 170/> 171``` 172 173Here is an example Hap value with different properties: 174 175```js 176{ note: 'a4', s: 'sawtooth', gain: 0.5, cutoff: 267 } 177``` 178<img src="waa-nodes.png" width="600" /> 179 180<div className="text-left"> 181 182- Patterns represent just values in time! 183- Suitable for any time based output (music, visuals, movement, .. ?) 184 185### Supported Outputs 186 187At the time of writing this doc, the following outputs are supported: 188 189- Web Audio API `.out()` see [/webaudio](https://github.com/tidalcycles/strudel/tree/main/packages/webaudio) 190- MIDI `.midi()` see [/midi](https://github.com/tidalcycles/strudel/tree/main/packages/midi) 191- OSC `.osc()` see [/osc](https://github.com/tidalcycles/strudel/tree/main/packages/osc) 192- Serial `.serial()` see [/serial](https://github.com/tidalcycles/strudel/tree/main/packages/serial) 193- Tone.js `.tone()` (deprecated?) [/tone](https://github.com/tidalcycles/strudel/tree/main/packages/tone) 194- WebDirt `.webdirt()` (deprecated?) [/webdirt](https://github.com/tidalcycles/strudel/tree/main/packages/webdirt) 195- Speech `.speak()` (experimental) part of [/core](https://github.com/tidalcycles/strudel/tree/main/packages/core) 196 197These could change, so make sure to check the [packages folder](https://github.com/tidalcycles/strudel/tree/main/packages).