paper.mdpreviewpaper.mdsource354 lines · 9.3 KB · raw
1---
2title: 'StrudelCycles: live coding algorithmic patterns on the web'
3date: '2022-03-22'
4url2cite: all-links
5---
6
7# Introduction
8
9This paper introduces Strudel, an alternative implementation of the TidalCycles live coding system, using the JavaScript programming language.
10
11# Background
12
13TidalCycles (or *Tidal* for short) has been developed since around 2009, as a system for live coding algorithmic patterns, particularly in music [@tidalcycles]. Tidal is embedded in the pure functional *Haskell* programming language, taking advantage of its terse syntax and advanced type system. Over the past decade, Tidal has undergone a number of re-writes, developing a functional reactive representation of pattern, where patterns may be combined and transformed in a wide variety of ways [@alternate-timelines]. Over this time is has gained diverse ideas from other patterned forms, including from computer music [@spiegel], Indian classical music [@bel], textiles [@fabricating], improvised percussion [@hession], and Ancient Greek lyric [@cyclic-patterns]. 
14
15Most recently, attention has turned to transferring Tidal's ideas to other, less 'pure' languages; firstly, to the Python programming language as *TidalVortex* [@tidalvortex] (*Vortex* for short), and now to JavaScript as StrudelCycles (*Strudel* for short), the topic of the present paper. For general background on the motivations for porting Tidal to a multi-paradigm programming language, please see the TidalVortex paper [@tidalvortex]. The motivations for porting it to JavaScript are similar, with a particular slanting on accessibility - of course, a web browser based application does not require any installation. As with Vortex though, it is important to point out that this is a creative, free/open source project, and as such, an primary motivation will always be developer's curiosity, and market-driven perspectives on development choices may even be demotivational.
16
17General motivations / related work.
18Reference vortex paper and summarise its background.
19
20The reimplementation of TidalCycles in Python (cite TidalVortex) showed that it is possible to translate pure functional reactive programming ideas to a multi paradigm language. It proved to be a stepping stone to move to other multi-paradigm languages, like JavaScript. A significant part of of the Python codebase could be quickly ported to JavaScript by syntactical adjustments.
21
22# Introducing Strudel
23
24* Motivating musical example
25
26# Tidal patterns
27
28(should we explain shortly what tidal patterns do in general here?)
29
30The essence of TidalCycles are Patterns. Patterns are abstract entities that represent flows of time, supporting both continuous changes (like signals) and discrete events (like notes).
31Taking a time span as its input, a Pattern can output a set of events that happen within that time span.
32It depends on the structure of the Pattern where the events are placed.
33From now on, this process of generating events from a time span will be called **querying**.
34Example:
35
36```js
37const pattern = sequence(c3, [e3, g3]);
38const events = pattern.query(0, 1);
39console.log(events.map(e => e.show()))
40```
41
42In this example, we create a pattern using the `sequence` function and **query** it for the timespan from `0` to `1`.
43Those numbers represent units of time called **cycles**. The length of one cycle defaults to one second, but could be any number of seconds.
44The console output looks like this:
45
46```js
47(0   -> 1/2 c3)
48(1/2 -> 3/4 e3)
49(3/2 -> 1   g3)
50```
51
52In this output, each line represents one event. The two fractions represent the begin and end time of the event, followed by its value.
53In this case, the events are placed in sequential order, where c3 takes the first half, and e3 and g3 together take the second half.
54This temporal placement is the result of the `sequence` function, which divides its arguments equally over one cycle.
55If an argument is an array, the same rule applies to that part of the sequence. In our example e3 and g3 are divided equally over the second half of the whole sequence.
56
57# Mini Notation
58
59In this example, the Pattern is created using the `mini` function, which parses Tidal's Mini Notation.
60The Mini Notation is a Domain Specific Language (DSL) that allows expressing rhythms in a short mannger.
61
62* Some comparisons of -Strudel with -Vortex and -Cycles code?
63
64(the following examples are from vortex paper, with added js versions)
65
66## 1
67
68```haskell
69sound "bd ~ [sd cp]"
70```
71
72```python
73sound("bd", silence, ["sd", "cp"])
74```
75
76```javascript
77sound("bd ~ [sd cp]")
78```
79
80without mini notation:
81
82```haskell
83sound $ cat
84   [pure "bd", silence,
85    cat(pure "sd", pure "cp")]
86```
87
88```javascript
89sound('bd', silence, cat('sd', 'cp'))
90```
91
92## 2
93
94```haskell
95sound "bd ~ <sd cp>"
96```
97
98```python
99sound("bd", silence, slowcat("sd", "cp"))
100```
101
102```javascript
103sound("bd ~ <sd cp>")
104// sound('bd', silence, slowcat('sd', 'cp'))
105```
106
107## 3
108
109```haskell
110sound "bd {cp sd, lt mt ht}"
111```
112
113```python
114sound("bd", pm(["cp", "sd"], ["lt", "mt", "ht"]))
115```
116
117```js
118?
119```
120
121## 4
122
123```haskell
124sound "bd {cp sd, [lt mt,bd bd bd] ht}"
125```
126
127```python
128 sound("bd", pm(["cp", "sd"],
129 [pr(["lt", "mt"],
130 ["bd", "bd", "bd"]
131 ),
132 "ht" ]))
133```
134
135```js
136??
137```
138
139## 5
140
141```haskell
142sound "bd sd cp" # speed "1 2"
143```
144
145```python
146sound("bd", "sd", "cp") >> speed (1, 2)
147```
148
149```javascript
150sound("bd sd cp").speed("1 2")
151```
152
153(operator overloading like in vortex?)
154
155## 6
156
157```haskell
158rev $ sound "bd sd"
159```
160
161```python
162rev(sound("bd", "sd"))
163sound("bd", "sd").rev()
164```
165
166```javascript
167rev(sound("bd sd"))
168sound("bd sd").rev()
169```
170
171## 7
172
173```haskell
174jux rev $ every 3 (fast 2) $ sound "bd sd"
175```
176
177```python
178jux(rev, every(3, fast(2), sound("bd", "sd")))
179sound("bd","sd").every(3, fast(2)).jux(rev)
180```
181
182```js
183jux(rev, every(3, fast(2), sound("bd sd")))
184sound("bd sd").every(3, fast(2)).jux(rev)
185```
186
187(partial application)
188
189## 8
190
191```haskell
192n ("1 2 3" + "4 5") # sound "drum"
193```
194
195```python
196n (sequence(1,2,3) + sequence(4,5)) >> sound "drum"
197```
198
199```js
200n("1 2 3".add("4 5")).sound("drum")
201n("5 [6 7] 8").sound("drum")
202```
203
204(operator overloading?)
205
206## 9
207
208```haskell
209speed("1 2 3" + sine)
210```
211
212```python
213speed(sequence(1,2,3) + sine)
214```
215
216```js
217speed("1 2 3".add(sine))
218"c3*4".add(sine.mul(12).slow(8)).pianoroll()
219```
220
221## 10
222
223* Mininotation
224
225# Strudel/web specifics
226
227Some discussion about whether strudel is really a port of TidalCycles, or whether javascript affordances mean it's going its own way..
228
229* Recursive Scheduling: "calling itself in the future"
230* Optimizing Syntax for minimal keystrokes / readability: "AST Hacking" via shift-ast
231pseudo variables
232  * Handling mininotation - double quoted and template strings to mini calls
233  * Operator overloading
234* Fixing inconsistencies (e.g. with stut/echo)
235adding source locations
236* Dynamic HUD: Highlighting + drawing
237* Translation of Tidal concepts to Javascript - different constraints, affordances, aesthetics
238* Dynamic Harmonic Programming?
239* emulating musician thought patterns
240* microtonal features?
241webserial
242
243## User Code Transpilation
244
245(compare user input vs shifted output)
246
247### double quotes -> mini calls
248
249```javascript
250"c3 e3" // or `c3 e3`
251```
252
253```javascript
254mini("c3 e3")
255```
256
257### operator overloading
258
259```javascript
260cat(c3, e3) * 4
261```
262
263```javascript
264reify(cat("c3","e3")).fast(4)
265```
266
267(reify is redundant here, the shapeshifter could have an additional check...)
268
269(TBD: ability to multiply mini notation strings)
270
271### pseudo variables
272
273```javascript
274cat(c3, r, e3)
275```
276
277```javascript
278cat("c3",silence,"e3")
279```
280
281### locations
282
283```javascript
284cat(c3, e3)
285```
286
287```javascript
288cat(
289  reify("c3").withLocation([1,4,4],[1,6,6]),
290  reify("e3").withLocation([1,8,8],[1,10,10])
291)
292```
293
294```javascript
295mini("c3 e3")
296```
297
298with locations:
299
300```javascript
301// "c3 e3"
302mini("c3 e3").withMiniLocation([1,0,0],[1,7,7])
303```
304
305(talk about mini adding locations of mini notation parser)
306
307### top level await
308
309```javascript
310const p = (await piano()).toDestination()
311cat(c3).tone(p)
312```
313
314```javascript
315(async()=>{
316  const p = (await piano()).toDestination();
317  return cat("c3").tone(p);
318})()
319```
320
321# Musical examples
322
323...
324
325# Ongoing work/future aims
326
327* WASM Sound Backend
328* OSC -> Supercollider
329* mininotation as the 'regex' of metre
330
331That @roberts2016 are excellent, I reference their work at least twice per sentence [@roberts2016, p. 3]. 
332
333```javascript
334"1 2 3"
335```
336
337# References
338
339[@roberts2016]: https://www.tandfonline.com/doi/abs/10.1080/14794713.2016.1227602?journalCode=rpdm20
340[@alternate-timelines]: https://zenodo.org/record/5788732
341[@tidal.pegjs]: https://www.semanticscholar.org/paper/Bringing-the-TidalCycles-Mini-Notation-to-the-Roberts/74965efadd572ae3f40d14c633a5c8581c1b9f42
342[@tidalvortex]: https://zenodo.org/record/6456380
343[@ogborn17]: https://www.semanticscholar.org/paper/Estuary%3A-Browser-based-Collaborative-Projectional-Ogborn-Beverley/c6b5d34575d6230dfd8751ca4af8e5f6e44d916b
344[@tidalcycles]: https://dl.acm.org/doi/10.1145/2633638.2633647
345[@hession]: https://www.scopus.com/record/display.uri?eid=2-s2.0-84907386880&origin=inward&txGid=03307e26fba02a27bdc68bda462016f6266316467_Extending_Instruments_with_Live_Algorithms_in_a_Percussion_Code_Duo
346[@spiegel]: https://www.academia.edu/664807/Manipulations_of_musical_patterns
347[@bel]: https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.517.7129
348[@algorithmicpattern]: https://zenodo.org/record/4299661
349[@fabricating]: https://zenodo.org/record/2155745
350[@cyclic-patterns]: https://zenodo.org/record/1548969
351
352- gibber
353- krill
354- glicol