jevstrudel.git / docs / iclc2023-paper / iclc2023.html
iclc2023.html954 lines · 65.3 KB · raw
1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2<html xmlns="http://www.w3.org/1999/xhtml">
3  <head>
4    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5    <meta http-equiv="Content-Style-Type" content="text/css" />
6    <meta name="generator" content="pandoc" />
7    <meta name="date" content="2022-12-14" />
8    <title>Strudel: live coding patterns on the Web</title>
9    <style type="text/css">
10      code {
11        white-space: pre;
12      }
13    </style>
14    <style type="text/css">
15      pre > code.sourceCode {
16        white-space: pre;
17        position: relative;
18      }
19      pre > code.sourceCode > span {
20        display: inline-block;
21        line-height: 1.25;
22      }
23      pre > code.sourceCode > span:empty {
24        height: 1.2em;
25      }
26      .sourceCode {
27        overflow: visible;
28      }
29      code.sourceCode > span {
30        color: inherit;
31        text-decoration: inherit;
32      }
33      div.sourceCode {
34        margin: 1em 0;
35      }
36      pre.sourceCode {
37        margin: 0;
38      }
39      @media screen {
40        div.sourceCode {
41          overflow: auto;
42        }
43      }
44      @media print {
45        pre > code.sourceCode {
46          white-space: pre-wrap;
47        }
48        pre > code.sourceCode > span {
49          text-indent: -5em;
50          padding-left: 5em;
51        }
52      }
53      pre.numberSource code {
54        counter-reset: source-line 0;
55      }
56      pre.numberSource code > span {
57        position: relative;
58        left: -4em;
59        counter-increment: source-line;
60      }
61      pre.numberSource code > span > a:first-child::before {
62        content: counter(source-line);
63        position: relative;
64        left: -1em;
65        text-align: right;
66        vertical-align: baseline;
67        border: none;
68        display: inline-block;
69        -webkit-touch-callout: none;
70        -webkit-user-select: none;
71        -khtml-user-select: none;
72        -moz-user-select: none;
73        -ms-user-select: none;
74        user-select: none;
75        padding: 0 4px;
76        width: 4em;
77        color: #aaaaaa;
78      }
79      pre.numberSource {
80        margin-left: 3em;
81        border-left: 1px solid #aaaaaa;
82        padding-left: 4px;
83      }
84      div.sourceCode {
85      }
86      @media screen {
87        pre > code.sourceCode > span > a:first-child::before {
88          text-decoration: underline;
89        }
90      }
91      code span.al {
92        color: #ff0000;
93        font-weight: bold;
94      } /* Alert */
95      code span.an {
96        color: #60a0b0;
97        font-weight: bold;
98        font-style: italic;
99      } /* Annotation */
100      code span.at {
101        color: #7d9029;
102      } /* Attribute */
103      code span.bn {
104        color: #40a070;
105      } /* BaseN */
106      code span.bu {
107        color: #008000;
108      } /* BuiltIn */
109      code span.cf {
110        color: #007020;
111        font-weight: bold;
112      } /* ControlFlow */
113      code span.ch {
114        color: #4070a0;
115      } /* Char */
116      code span.cn {
117        color: #880000;
118      } /* Constant */
119      code span.co {
120        color: #60a0b0;
121        font-style: italic;
122      } /* Comment */
123      code span.cv {
124        color: #60a0b0;
125        font-weight: bold;
126        font-style: italic;
127      } /* CommentVar */
128      code span.do {
129        color: #ba2121;
130        font-style: italic;
131      } /* Documentation */
132      code span.dt {
133        color: #902000;
134      } /* DataType */
135      code span.dv {
136        color: #40a070;
137      } /* DecVal */
138      code span.er {
139        color: #ff0000;
140        font-weight: bold;
141      } /* Error */
142      code span.ex {
143      } /* Extension */
144      code span.fl {
145        color: #40a070;
146      } /* Float */
147      code span.fu {
148        color: #06287e;
149      } /* Function */
150      code span.im {
151        color: #008000;
152        font-weight: bold;
153      } /* Import */
154      code span.in {
155        color: #60a0b0;
156        font-weight: bold;
157        font-style: italic;
158      } /* Information */
159      code span.kw {
160        color: #007020;
161        font-weight: bold;
162      } /* Keyword */
163      code span.op {
164        color: #666666;
165      } /* Operator */
166      code span.ot {
167        color: #007020;
168      } /* Other */
169      code span.pp {
170        color: #bc7a00;
171      } /* Preprocessor */
172      code span.sc {
173        color: #4070a0;
174      } /* SpecialChar */
175      code span.ss {
176        color: #bb6688;
177      } /* SpecialString */
178      code span.st {
179        color: #4070a0;
180      } /* String */
181      code span.va {
182        color: #19177c;
183      } /* Variable */
184      code span.vs {
185        color: #4070a0;
186      } /* VerbatimString */
187      code span.wa {
188        color: #60a0b0;
189        font-weight: bold;
190        font-style: italic;
191      } /* Warning */
192    </style>
193    <link rel="stylesheet" href="css/iclc.css" />
194  </head>
195  <body>
196    <div id="header">
197      <h1 class="title">Strudel: live coding patterns on the Web</h1>
198      <ul id="authorlist">
199        <li>true</li>
200        <li>true</li>
201      </ul>
202      <h3 class="date">2022-12-14</h3>
203    </div>
204
205    <h2 class="abstract">Abstract</h2>
206    <div id="abstract">
207      <p>
208        This paper introduces Strudel, which brings the TidalCycles approach to live coding algorithmic patterns to
209        native JavaScript and the web. We begin by giving a little background of the first year of development, before
210        sharing some detail about its implementation and examples of use. We go on to outline the wide range of
211        synthesis and other outputs available in Strudel, including WebAudio, MIDI, OSC (for SuperDirt), WebSerial and
212        CSound, and introduce Strudel’s REPL live editor, including its built-in visualisations. We then compare Strudel
213        with Tidal, the trade-offs involved between JavaScript and Haskell, and the unique capabilities offered by
214        Strudel for aligning patterns.
215      </p>
216    </div>
217
218    <h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction</h1>
219    <p>
220      In the following paper, we introduce <em>Strudel</em>, an alternative implementation of the TidalCycles (or
221      ‘Tidal’ for short) live coding system, using the JavaScript programming language. Strudel is an attempt to make
222      live coding more accessible, by creating a system that runs entirely in the browser, while opening Tidal’s
223      approach to algorithmic patterns
224      <span class="citation" data-cites="mcleanAlgorithmicPattern2020a">(Mclean 2020)</span> up to modern audio/visual
225      web technologies. The Strudel REPL is a live code editor dedicated to manipulating patterns while they play, with
226      builtin visual feedback. While Strudel is written in JavaScript, the API is optimized for simplicity and
227      readability by applying code transformations on the syntax tree level, allowing language operations that would
228      otherwise be impossible. The application supports multiple ways to output sound, including Tone.js, Web Audio
229      Nodes, OSC (Open Sound Control) messages, Web Serial, Web MIDI and Csound. The project is split into multiple
230      packages, allowing granular reuse in other applications. Apart from TidalCycles, Strudel draws inspiration from
231      many prior existing projects like TidalVortex
232      <span class="citation" data-cites="mcleanTidalVortexZero2022">(McLean et al. 2022)</span>, Gibber
233      <span class="citation" data-cites="robertsGibberLiveCoding2012">(Roberts and Kuchera-morin 2012)</span>, Estuary
234      <span class="citation" data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al. 2017)</span>, Hydra
235      <span class="citation" data-cites="jackHydra2022">(Jack [2022] 2022)</span>, Ocarina
236      <span class="citation" data-cites="solomonPurescriptocarina2022">(Solomon [2021] 2022)</span> and Feedforward
237      <span class="citation" data-cites="mcleanFeedforward2020">(McLean 2020)</span>. This paper expands the Strudel
238      Demo paper for the Web Audio Conference 2022
239      <span class="citation" data-cites="StrudelWAC2022">(Roos and McLean 2022)</span>.
240    </p>
241    <p>
242      The first tentative commit to the Strudel project was on 22nd January 2022 by Alex McLean, with the core
243      representation implemented over the following few days. Although this was his first attempt at a JavaScript-based
244      application, by 27th January, Alex had managed to upload the initial version to the ‘npm’ javascript package
245      database, sharing with the wider community for comment. By 4th February, Felix Roos had discovered Strudel and
246      contributed a ‘REPL’ user interface to it, and then contributed a scheduler the next day, so that Strudel could
247      already make sound. At this point, Alex and Felix shared ownership to the repository, and the project has since
248      proved to be a productive confluence of Felix’s own work into music representation and visualisation, with Alex’s
249      experience with making Tidal. Felix has since become the primary contributor to Strudel, with Alex continuing to
250      jump between developing both Strudel and Tidal. Aspects of Strudel’s development have therefore fed back into
251      TidalCycles, and both systems have maintained a shared conceptual underpinning. We plan to continue working
252      towards feature parity between these systems, although within the syntactical trade-offs and library ecosystems of
253      JavaScript and Haskell, some divergence is inevitable and healthy.
254    </p>
255    <p>
256      Over the first year of its life, Strudel is now a fully-fledged live coding environment, porting Tidal’s core
257      represention of patterns, pattern transformations, and mininotation for polymetric sequences, combined with a
258      wealth of features for synthesising and visualising those patterns.
259    </p>
260    <h1 data-number="2" id="from-tidal-to-strudel-and-back">
261      <span class="header-section-number">2</span> From Tidal to Strudel and back
262    </h1>
263    <p>
264      As mentioned above, the original Tidal is implemented as a domain specific language (DSL) embedded in the Haskell
265      pure functional programming language, and takes advantage of Haskell’s terse syntax and advanced, ‘strong’ type
266      system. JavaScript on the other hand, is a multi-paradigm programming language, with a dynamic type system.
267      Because Tidal leans heavily on many of Haskell’s more unique features, it was not always clear that it could
268      meaningfully be ported to a multi-paradigm scripting language. However, this possibility was already demonstrated
269      with an earlier port to Python [TidalVortex;
270      <span class="citation" data-cites="mcleanTidalVortexZero2022">McLean et al. (2022)</span>], and we have now
271      successfully implemented Tidal’s pure functional representation of patterns in Strudel, including partial
272      application, currying, and the functor, applicative and monadic structures that underlie Tidal’s expressive
273      pattern transformations. The result is a terse and highly composable system, where everything is either a pattern,
274      or a function for combining and manipulating patterns, offering a rich creative ground for exploration.
275    </p>
276    <p>
277      This development process has been far from a one-way port, however. The process of porting Tidal’s concepts has
278      also opened up new possibilities, some just from revisiting every design decision, and some from the particular
279      affordances and constraints offered by JavaScript. This has lead to new features (and indeed bugfixes) that have
280      found their way back to Tidal where appropriate, and ongoing work that we will return to in the conclusion of this
281      paper.
282    </p>
283    <h1 data-number="3" id="representing-patterns">
284      <span class="header-section-number">3</span> Representing Patterns
285    </h1>
286    <p>
287      Patterns are the essence of Tidal. Its patterns are abstract entities that represent flows of time as functions,
288      adapting a technique called pure functional reactive programming. Taking a time span as its input, a Pattern can
289      output a set of events that happen within that time span. It depends on the structure of the Pattern how the
290      events are located in time. From now on, this process of generating events from a time span will be called
291      <strong>querying</strong>. Example:
292    </p>
293    <div class="sourceCode" id="cb1">
294      <pre
295        class="sourceCode js"
296      ><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> pattern <span class="op">=</span> <span class="fu">sequence</span>(c3<span class="op">,</span> [e3<span class="op">,</span> g3])</span>
297<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> events <span class="op">=</span> pattern<span class="op">.</span><span class="fu">queryArc</span>(<span class="dv">0</span><span class="op">,</span> <span class="dv">1</span>)</span>
298<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="bu">console</span><span class="op">.</span><span class="fu">log</span>(events<span class="op">.</span><span class="fu">map</span>(e <span class="kw">=&gt;</span> e<span class="op">.</span><span class="fu">show</span>()))</span></code></pre>
299    </div>
300    <p>
301      In this example, we create a pattern using the <code>sequence</code> function and <strong>query</strong> it for
302      the time span from <code>0</code> to <code>1</code>. Those numbers represent units of time called
303      <strong>cycles</strong>. The length of one cycle depends on the tempo, which defaults to one cycle per second. The
304      resulting events are:
305    </p>
306    <div class="sourceCode" id="cb2">
307      <pre
308        class="sourceCode js"
309      ><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>[{ <span class="dt">value</span><span class="op">:</span> <span class="st">&#39;c3&#39;</span><span class="op">,</span> <span class="dt">begin</span><span class="op">:</span> <span class="dv">0</span><span class="op">,</span> <span class="dt">end</span><span class="op">:</span> <span class="dv">1</span><span class="op">/</span><span class="dv">2</span> }<span class="op">,</span></span>
310<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>{ <span class="dt">value</span><span class="op">:</span> <span class="st">&#39;e3&#39;</span><span class="op">,</span> <span class="dt">begin</span><span class="op">:</span> <span class="dv">1</span><span class="op">/</span><span class="dv">2</span><span class="op">,</span> <span class="dt">end</span><span class="op">:</span> <span class="dv">3</span><span class="op">/</span><span class="dv">4</span> }<span class="op">,</span></span>
311<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>{ <span class="dt">value</span><span class="op">:</span> <span class="st">&#39;g3&#39;</span><span class="op">,</span> <span class="dt">begin</span><span class="op">:</span> <span class="dv">3</span><span class="op">/</span><span class="dv">4</span><span class="op">,</span> <span class="dt">end</span><span class="op">:</span> <span class="dv">1</span> }]</span></code></pre>
312    </div>
313    <p>
314      Each event has a value, a begin time and an end time, where time is represented as a fraction. In the above case,
315      the events are placed in sequential order, where c3 takes the first half, and e3 and g3 together take the second
316      half. This temporal placement is the result of the <code>sequence</code> function, which divides its arguments
317      equally over one cycle. If an argument is an array, the same rule applies to that part of the cycle. In the
318      example, e3 and g3 are divided equally over the second half of the whole cycle.
319    </p>
320    <p>
321      The above examples do not represent how Strudel is used in practice. In the live coding editor, the user only has
322      to type in the pattern itself, the querying will be handled by the scheduler. The scheduler will repeatedly query
323      the pattern for events, which are then scheduled as sound synthesis or other event triggers. Also, the above event
324      data structure has been simplified for readability.
325    </p>
326    <figure>
327      <img
328        src="images/strudel-screenshot2.png"
329        style="width: 60%"
330        alt="Screenshot of the Strudel ‘REPL’ live coding editor, including piano-roll visualisation."
331      />
332      <figcaption aria-hidden="true">
333        Screenshot of the Strudel ‘REPL’ live coding editor, including piano-roll visualisation.
334      </figcaption>
335    </figure>
336    <h1 data-number="4" id="making-patterns"><span class="header-section-number">4</span> Making Patterns</h1>
337    <p>
338      In practice, the end-user live coder will not deal with constructing patterns directly, but will rather build
339      patterns using Strudel’s extensive combinator library to create, combine and transform patterns.
340    </p>
341    <p>
342      The live coder will rarely use the <code>sequence</code> function as seen above, as sequencing is implicit in many
343      functions. For example in the following, the <code>note</code> function constructs a pattern of notes, sequencing
344      its arguments in the same manner as the previous example.
345    </p>
346    <div class="sourceCode" id="cb3">
347      <pre
348        class="sourceCode js"
349      ><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">note</span>(c3<span class="op">,</span> [e3<span class="op">,</span> g3])</span></code></pre>
350    </div>
351    <p>
352      Perhaps more often, they will use the mini-notation for even terser notation of rhythmic sequences: [^This last
353      example is also valid Tidal code, albeit the parenthesis is not required in its Haskell syntax in this case. Tidal
354      does not support passing sequences as lists directly to the <code>note</code> function, however.].
355    </p>
356    <div class="sourceCode" id="cb4">
357      <pre
358        class="sourceCode js"
359      ><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">note</span>(<span class="st">&quot;c3 [e3 g3]&quot;</span>)</span></code></pre>
360    </div>
361    <p>
362      Such sequences are often treated only a starting point for manipulation, where they then undergo pattern
363      transformations such as repetition, symmetry, interference/combination or randomisation, potentially at multiple
364      timescales. Because Strudel patterns are represented as pure functions of time rather than as data structures,
365      very long and complex generative results can be represented and manipulated without having to store the resulting
366      sequences in memory.
367    </p>
368    <h1 data-number="5" id="pattern-example"><span class="header-section-number">5</span> Pattern Example</h1>
369    <p>
370      The following example showcases how patterns can be utilized to create musical complexity from simple parts, using
371      repetition and interference:
372    </p>
373    <div class="sourceCode" id="cb5">
374      <pre
375        class="sourceCode js"
376      ><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;&lt;0 2 [4 6](3,4,1) 3&gt;&quot;</span></span>
377<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">off</span>(<span class="dv">1</span><span class="op">/</span><span class="dv">4</span><span class="op">,</span> <span class="fu">add</span>(<span class="dv">2</span>))</span>
378<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">off</span>(<span class="dv">1</span><span class="op">/</span><span class="dv">2</span><span class="op">,</span> <span class="fu">add</span>(<span class="dv">6</span>))</span>
379<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">scale</span>(<span class="st">&#39;D minor&#39;</span>)</span>
380<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">legato</span>(<span class="op">.</span><span class="dv">25</span>)</span>
381<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">note</span>()<span class="op">.</span><span class="fu">s</span>(<span class="st">&quot;sawtooth square&quot;</span>)</span>
382<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="op">.</span><span class="fu">delay</span>(<span class="op">.</span><span class="dv">8</span>)<span class="op">.</span><span class="fu">delaytime</span>(<span class="op">.</span><span class="dv">125</span>)</span></code></pre>
383    </div>
384    <p>
385      The pattern starts with a rhythm of numbers in mini notation, which are later interpreted inside the scale of D
386      minor. The first line could also be expressed without mini notation:
387    </p>
388    <div class="sourceCode" id="cb6">
389      <pre
390        class="sourceCode js"
391      ><code class="sourceCode javascript"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">cat</span>(<span class="dv">0</span><span class="op">,</span> <span class="dv">2</span><span class="op">,</span> [<span class="dv">4</span><span class="op">,</span> <span class="dv">6</span>]<span class="op">.</span><span class="fu">euclid</span>(<span class="dv">3</span><span class="op">,</span> <span class="dv">4</span><span class="op">,</span> <span class="dv">1</span>)<span class="op">,</span> <span class="dv">3</span>)</span></code></pre>
392    </div>
393    <p>
394      These numbers then undergo various pattern transformations. Here is a short description of all the functions used:
395    </p>
396    <ul>
397      <li><code>cat</code>: play elements sequentially, where each lasts one cycle</li>
398      <li><code>brackets</code>: elements inside brackets are divided equally over the time of their parent</li>
399      <li>
400        <code>.euclid(p, s, o)</code>: place p pulses evenly over s steps, with offset o
401        <span class="citation" data-cites="toussaintEuclideanAlgorithmGenerates2005">(Toussaint 2005)</span>
402      </li>
403      <li>
404        <code>.off(n, f)</code>: layers a pattern on top of itself, with the new layer offset by n cycles, and with
405        function f applied
406      </li>
407      <li><code>.legato(n)</code>: multiply the duration of all events in a pattern by a factor of n</li>
408      <li>
409        <code>.echo(t, n, v)</code>: copy each event t times, with n cycles in between each copy, decreasing velocity by
410        v
411      </li>
412      <li><code>.note()</code>: interpretes values as notes</li>
413      <li><code>.s(name)</code>: play back each event with the given sound</li>
414      <li><code>.delay(wet)</code>: add delay</li>
415      <li><code>.delaytime(t)</code>: set delay time</li>
416    </ul>
417    <p>Much of the above will be familiar to Tidal users.</p>
418    <!-- This example shows some of Strudel's unique support for chords and transposition familiar to students of Western music theory. This differs a little from Tidal's approach and thanks to the integration of the javascript library XXX (*TODO* ? or is this all your work Felix?), Strudel's support for tonal transformations such as voice leading is perhaps respects more advanced than Tidal. -->
419    <h1 data-number="6" id="ways-to-make-sound-and-other-events">
420      <span class="header-section-number">6</span> Ways to make Sound (and other events)
421    </h1>
422    <p>To generate sound, Strudel supports bindings for different outputs:</p>
423    <ul>
424      <li>Tone.js (deprecated)</li>
425      <li>Web Audio API</li>
426      <li>WebDirt, a js recreation of Tidal’s <em>Dirt</em> sample engine (deprecated)</li>
427      <li>OSC via osc-js, compatible with superdirt</li>
428      <li>Csound via the Csound WebAssembly build</li>
429      <li>MIDI via WebMIDI</li>
430      <li>Serial via WebSerial</li>
431    </ul>
432    <p>
433      At first, we used Tone.js as sound output, but it proved to be limited for the use case of Strudel, where each
434      individual event could potentially have a completely different audio graph. While the Web Audio API takes a
435      <em>fire-and-forget</em> approach, creating a lot of Tone.js instruments and effects causes performance issues
436      quickly. For that reason, we chose to search for alternatives.
437    </p>
438    <p>
439      Strudel’s new default output uses the Web Audio API to create a new audio graph for each event. It currently
440      supports basic oscillators, sample playback, various effects and an experimental support for soundfonts.
441    </p>
442    <p>
443      WebDirt <span class="citation" data-cites="ogbornDktr0WebDirt2022">(Ogborn [2016] 2022)</span> was created as part
444      of the Estuary Live Coding System
445      <span class="citation" data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al. 2017)</span>, and
446      proved to be a solid choice for handling samples in Strudel as well. We are however focused on working more
447      directly with the Web Audio API to be able to integrate new features more tightly.
448    </p>
449    <p>
450      Using the OSC protocol via Strudel’s provided Node.js-based OSC proxy server, it is possible to send network
451      messages to trigger events. This is mainly used to render sound using SuperDirt
452      <span class="citation" data-cites="SuperDirt2022">(<em>SuperDirt</em> [2015] 2022)</span>, which is the
453      well-developed Supercollider-based synthesis framework that Tidal live coders generally use as standard.
454    </p>
455    <p>
456      Recently, the experimental integration of Csound proved to bring a new dimension of sound design capabilities to
457      Strudel. Thanks to the WebAssembly distribution of this classic system
458      <span class="citation" data-cites="CsoundWebAssembly">(Yi, Lazzarini, and Costello 2018)</span>, Csound
459      ‘orchestra’ synthesisers can be embedded in and then patterned with Strudel code.
460    </p>
461    <p>
462      MIDI output can also be used to send MIDI messages to either external instruments or to other programs on the same
463      device. Unlike OSC, Strudel is able to send MIDI directly without requiring additional proxy software, but only
464      from web browsers that support it (at the time of writing, this means Chromium-based browsers).
465    </p>
466    <p>
467      Finally, Strudel supports Serial output, for example to trigger events via microcontrollers. This has already been
468      explored for robot choreography by Kate Sicchio and Alex McLean, via a performance presented at the International
469      Conference on Live Interfaces 2022.
470    </p>
471    <h1 data-number="7" id="the-strudel-repl"><span class="header-section-number">7</span> The Strudel REPL</h1>
472    <p>
473      While Strudel can be used as a library in any JavaScript codebase, its main, reference user interface is the
474      Strudel REPL[^REPL stands for read, evaluate, print/play, loop. It is friendly jargon for an interactive
475      programming interface from computing heritage, usually for a commandline interface but also applied to live coding
476      editors.], which is a browser-based live coding environment. This live code editor is dedicated to manipulating
477      Strudel patterns while they play. The REPL features built-in visual feedback, which highlights which elements in
478      the patterned (mini-notation) sequences are influencing the event that is currently being played. This feedback is
479      designed to support both learning and live use of Strudel.
480    </p>
481    <p>
482      Besides a UI for playback control and meta information, the main part of the REPL interface is the code editor
483      powered by CodeMirror. In it, the user can edit and evaluate pattern code live, using one of the available
484      synthesis outputs to create music and/or sound art. The control flow of the REPL follows 3 basic steps:
485    </p>
486    <ol type="1">
487      <li>
488        The user writes and updates code. Each update transpiles and evaluates it to create a
489        <code>Pattern</code> instance
490      </li>
491      <li>
492        While the REPL is running, the <code>Scheduler</code> queries the active <code>Pattern</code> by a regular
493        interval, generating <code>Events</code> (also known as <code>Haps</code> in Strudel) for the next time span.
494      </li>
495      <li>
496        For each scheduling tick, all generated <code>Events</code> are triggered by calling their
497        <code>onTrigger</code> method, which is set by the output.
498      </li>
499    </ol>
500    <figure>
501      <img
502        src="https://github.com/tidalcycles/strudel/raw/talk/talk/public/strudelflow.png?raw=true"
503        style="width: 43%"
504        alt="REPL control flow"
505      />
506      <figcaption aria-hidden="true">REPL control flow</figcaption>
507    </figure>
508    <h2 data-number="7.1" id="user-code"><span class="header-section-number">7.1</span> User Code</h2>
509    <p>To create a <code>Pattern</code> from the user code, two steps are needed:</p>
510    <ol type="1">
511      <li>Transpile the JS input code to make it functional</li>
512      <li>Evaluate the transpiled code</li>
513    </ol>
514    <h3 data-number="7.1.1" id="transpilation-evaluation">
515      <span class="header-section-number">7.1.1</span> Transpilation &amp; Evaluation
516    </h3>
517    <p>
518      In the JavaScript world, using transpilation is a common practise to be able to use language features that are not
519      supported by the base language. Tools like <code>babel</code> will transpile code that contains unsupported
520      language features into a version of the code without those features.
521    </p>
522    <p>
523      In the same tradition, Strudel can add a transpilation step to simplify the user code in the context of live
524      coding. For example, the Strudel REPL lets the user create mini notation patterns using just double quoted
525      strings, while single quoted strings remain what they are:
526    </p>
527    <div class="sourceCode" id="cb7">
528      <pre
529        class="sourceCode js"
530      ><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;c3 [e3 g3]*2&quot;</span></span></code></pre>
531    </div>
532    <p>is transpiled to:</p>
533    <div class="sourceCode" id="cb8">
534      <pre
535        class="sourceCode js"
536      ><code class="sourceCode javascript"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mini</span>(<span class="st">&quot;c3 [e3 g3]*2&quot;</span>)<span class="op">.</span><span class="fu">withMiniLocation</span>([<span class="dv">1</span><span class="op">,</span><span class="dv">0</span><span class="op">,</span><span class="dv">0</span>]<span class="op">,</span>[<span class="dv">1</span><span class="op">,</span><span class="dv">14</span><span class="op">,</span><span class="dv">14</span>])</span></code></pre>
537    </div>
538    <p>
539      Here, the string is wrapped in <code>mini</code>, which will create a pattern from a mini notation string.
540      Additionally, the <code>withMiniLocation</code> method passes the original source code location of the string to
541      the pattern, which enables highlighting active events.
542    </p>
543    <p>
544      Other convenient features like pseudo variables, operator overloading and top level await are possible with
545      transpilation.
546    </p>
547    <p>After the transpilation, the code is ready to be evaluated into a <code>Pattern</code>.</p>
548    <p>
549      Behind the scenes, the user code string is parsed with <code>acorn</code>, turning it into an Abstract Syntax Tree
550      (AST). The AST allows changing the structure of the code before generating the transpiled version using
551      <code>escodegen</code>.
552    </p>
553    <h3 data-number="7.1.2" id="mini-notation"><span class="header-section-number">7.1.2</span> Mini Notation</h3>
554    <p>
555      While the transpilation allows JavaScript to express Patterns in a less verbose way, it is still preferable to use
556      the Mini Notation as a more compact way to express rhythm. Strudel aims to provide the same Mini Notation features
557      and syntax as used in Tidal.
558    </p>
559    <p>
560      The Mini Notation parser is implemented using <code>peggy</code>, which allows generating performant parsers for
561      Domain Specific Languages (DSLs) using a concise grammar notation. The generated parser turns the Mini Notation
562      string into an AST which is used to call the respective Strudel functions with the given structure. For example,
563      <code>"c3 [e3 g3]*2"</code> will result in the following calls:
564    </p>
565    <div class="sourceCode" id="cb9">
566      <pre
567        class="sourceCode js"
568      ><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">seq</span>(</span>
569<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="fu">reify</span>(<span class="st">&#39;c3&#39;</span>)<span class="op">.</span><span class="fu">withLocation</span>([<span class="dv">1</span><span class="op">,</span><span class="dv">1</span><span class="op">,</span><span class="dv">1</span>]<span class="op">,</span> [<span class="dv">1</span><span class="op">,</span><span class="dv">4</span><span class="op">,</span><span class="dv">4</span>])<span class="op">,</span></span>
570<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>  <span class="fu">seq</span>(</span>
571<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>    <span class="fu">reify</span>(<span class="st">&#39;e3&#39;</span>)<span class="op">.</span><span class="fu">withLocation</span>([<span class="dv">1</span><span class="op">,</span><span class="dv">5</span><span class="op">,</span><span class="dv">5</span>]<span class="op">,</span> [<span class="dv">1</span><span class="op">,</span><span class="dv">8</span><span class="op">,</span><span class="dv">8</span>])<span class="op">,</span></span>
572<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>    <span class="fu">reify</span>(<span class="st">&#39;g3&#39;</span>)<span class="op">.</span><span class="fu">withLocation</span>([<span class="dv">1</span><span class="op">,</span><span class="dv">8</span><span class="op">,</span><span class="dv">8</span>]<span class="op">,</span> [<span class="dv">1</span><span class="op">,</span><span class="dv">10</span><span class="op">,</span><span class="dv">10</span>])<span class="op">,</span></span>
573<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a>  )<span class="op">.</span><span class="fu">fast</span>(<span class="dv">2</span>)</span>
574<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>)</span></code></pre>
575    </div>
576    <h3 data-number="7.1.3" id="highlighting-locations">
577      <span class="header-section-number">7.1.3</span> Highlighting Locations
578    </h3>
579    <p>
580      As seen in the examples above, both the JS and the Mini Notation parser add source code locations using
581      <code>withMiniLocation</code> and <code>withLocation</code> methods. While the JS parser adds locations relative
582      to the user code as a whole, the Mini Notation adds locations relative to the position of the mini notation
583      string. The absolute location of elements within Mini Notation can be calculated by simply adding both locations
584      together. This absolute location can be used to highlight active events in real time.
585    </p>
586    <h2 data-number="7.2" id="scheduling-events"><span class="header-section-number">7.2</span> Scheduling Events</h2>
587    <p>
588      After an instance of <code>Pattern</code> is obtained from the user code, it is used by the scheduler to get
589      queried for events. Once started, the scheduler runs at a fixed interval to query active pattern for events
590      withing the current interval’s time span. A simplified implementation looks like this:
591    </p>
592    <div class="sourceCode" id="cb10">
593      <pre
594        class="sourceCode js"
595      ><code class="sourceCode javascript"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> pattern <span class="op">=</span> <span class="fu">seq</span>(<span class="st">&#39;c3&#39;</span><span class="op">,</span> [<span class="st">&#39;e3&#39;</span><span class="op">,</span> <span class="st">&#39;g3&#39;</span>])<span class="op">;</span> <span class="co">// pattern from user</span></span>
596<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> interval <span class="op">=</span> <span class="fl">0.5</span><span class="op">;</span> <span class="co">// query interval in seconds</span></span>
597<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> time <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> <span class="co">// beginning of current time span</span></span>
598<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> minLatency <span class="op">=</span> <span class="op">.</span><span class="dv">1</span><span class="op">;</span> <span class="co">// min time before a hap should trigger</span></span>
599<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="pp">setInterval</span>(() <span class="kw">=&gt;</span> {</span>
600<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> haps <span class="op">=</span> pattern<span class="op">.</span><span class="fu">queryArc</span>(time<span class="op">,</span> time <span class="op">+</span> interval)<span class="op">;</span></span>
601<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  time <span class="op">+=</span> interval<span class="op">;</span> <span class="co">// increment time</span></span>
602<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>  haps<span class="op">.</span><span class="fu">forEach</span>((hap) <span class="kw">=&gt;</span> {</span>
603<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> deadline <span class="op">=</span> hap<span class="op">.</span><span class="at">whole</span><span class="op">.</span><span class="at">begin</span> <span class="op">-</span> time <span class="op">+</span> minLatency<span class="op">;</span></span>
604<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a>    <span class="fu">onTrigger</span>(hap<span class="op">,</span> deadline<span class="op">,</span> duration)<span class="op">;</span></span>
605<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>  })<span class="op">;</span></span>
606<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>}<span class="op">,</span> interval <span class="op">*</span> <span class="dv">1000</span>)<span class="op">;</span> <span class="co">// query each &quot;interval&quot; seconds</span></span></code></pre>
607    </div>
608    <p>
609      Note that the above code is simplified for illustrative purposes. The actual implementation has to work around
610      imprecise callbacks of <code>setInterval</code>. More about the implementation details can be read in
611      <a href="https://loophole-letters.vercel.app/web-audio-scheduling">this blog post</a>.
612    </p>
613    <p>
614      The fact that <code>Pattern.queryArc</code> is a pure function that maps a time span to a set of events allows us
615      to choose any interval we like without changing the resulting output. It also means that when the pattern is
616      changed from outside, the next scheduling callback will work with the new pattern, keeping its clock running.
617    </p>
618    <p>
619      The latency between the time the pattern is evaluated and the change is heard is between
620      <code>minLatency</code> and <code>interval + minLatency</code>, in our example between 100ms and 600ms. In
621      Strudel, the current query interval is 50ms with a minLatency of 100ms, meaning the latency is between 50ms and
622      150ms.
623    </p>
624    <h2 data-number="7.3" id="output"><span class="header-section-number">7.3</span> Output</h2>
625    <p>
626      The last step is to trigger each event in the chosen output. This is where the given time and value of each event
627      is used to generate audio or any other form of time based output. The default output of the Strudel REPL is the
628      WebAudio output. To understand what an output does, we first have to understand what control parameters are.
629    </p>
630    <h3 data-number="7.3.1" id="control-parameters">
631      <span class="header-section-number">7.3.1</span> Control Parameters
632    </h3>
633    <p>
634      To be able to manipulate multiple aspects of sound in parallel, so called control parameters are used to shape the
635      value of each event. Example:
636    </p>
637    <div class="sourceCode" id="cb11">
638      <pre
639        class="sourceCode js"
640      ><code class="sourceCode javascript"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">note</span>(<span class="st">&quot;c3 e3&quot;</span>)<span class="op">.</span><span class="fu">cutoff</span>(<span class="dv">1000</span>)<span class="op">.</span><span class="fu">s</span>(<span class="st">&#39;sawtooth&#39;</span>)</span>
641<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">.</span><span class="fu">queryArc</span>(<span class="dv">0</span><span class="op">,</span> <span class="dv">1</span>)<span class="op">.</span><span class="fu">map</span>(hap <span class="kw">=&gt;</span> hap<span class="op">.</span><span class="at">value</span>)</span>
642<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co">/* [</span></span>
643<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co">  { note: &#39;c3&#39;, cutoff: 1000, s: &#39;sawtooth&#39; }</span></span>
644<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co">  { note: &#39;e3&#39;, cutoff: 1000, s: &#39;sawtooth&#39; }</span></span>
645<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">] */</span></span></code></pre>
646    </div>
647    <p>
648      Here, the control parameter functions <code>note</code>, <code>cutoff</code> and <code>s</code> are used, where
649      each controls a different property in the value object. Each control parameter function accepts a primitive value,
650      a list of values to be sequenced into a <code>Pattern</code>, or a <code>Pattern</code>. In the example,
651      <code>note</code> gets a <code>Pattern</code> from a Mini Notation expression (double quoted), while
652      <code>cutoff</code> and <code>s</code> are given a <code>Number</code> and a (single quoted)
653      <code>String</code> respectively.
654    </p>
655    <p>
656      Strudel comes with a large default set of control parameter functions that are based on the ones used by Tidal and
657      SuperDirt, focusing on music and audio terminology. It is however possible to create custom control paramters for
658      any purpose:
659    </p>
660    <div class="sourceCode" id="cb12">
661      <pre
662        class="sourceCode js"
663      ><code class="sourceCode javascript"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> { x<span class="op">,</span> y } <span class="op">=</span> <span class="fu">createParams</span>(<span class="st">&#39;x&#39;</span><span class="op">,</span> <span class="st">&#39;y&#39;</span>)</span>
664<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="fu">x</span>(sine<span class="op">.</span><span class="fu">range</span>(<span class="dv">0</span><span class="op">,</span> <span class="dv">200</span>))<span class="op">.</span><span class="fu">y</span>(cosine<span class="op">.</span><span class="fu">range</span>(<span class="dv">0</span><span class="op">,</span><span class="dv">200</span>))</span></code></pre>
665    </div>
666    <p>
667      This example creates the custom control parameters <code>x</code> and <code>y</code> which are then used to form a
668      pattern that descibes the coordinates of a circle.
669    </p>
670    <h3 data-number="7.3.2" id="outputs"><span class="header-section-number">7.3.2</span> Outputs</h3>
671    <p>
672      Now that we know how the value of an event is manipulated using control parameters, we can look at how outputs can
673      use that value to generate anything. The scheduler above was calling the <code>onTrigger</code> function which is
674      used to implement the output. A very simple version of the web audio output could look like this:
675    </p>
676    <div class="sourceCode" id="cb13">
677      <pre
678        class="sourceCode js"
679      ><code class="sourceCode javascript"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> <span class="fu">onTrigger</span>(hap<span class="op">,</span> deadline<span class="op">,</span> duration) {</span>
680<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> { note } <span class="op">=</span> hap<span class="op">.</span><span class="at">value</span><span class="op">;</span></span>
681<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> time <span class="op">=</span> <span class="fu">getAudioContext</span>()<span class="op">.</span><span class="at">currentTime</span> <span class="op">+</span> deadline<span class="op">;</span></span>
682<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> o <span class="op">=</span> <span class="fu">getAudioContext</span>()<span class="op">.</span><span class="fu">createOscillator</span>()<span class="op">;</span></span>
683<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>  o<span class="op">.</span><span class="at">frequency</span><span class="op">.</span><span class="at">value</span> <span class="op">=</span> <span class="fu">getFreq</span>(note)<span class="op">;</span></span>
684<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  o<span class="op">.</span><span class="fu">start</span>(time)<span class="op">;</span></span>
685<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>  o<span class="op">.</span><span class="fu">stop</span>(time <span class="op">+</span> <span class="bu">event</span><span class="op">.</span><span class="at">duration</span>)<span class="op">;</span></span>
686<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>  o<span class="op">.</span><span class="fu">connect</span>(<span class="fu">getAudioContext</span>()<span class="op">.</span><span class="at">destination</span>)<span class="op">;</span></span>
687<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre>
688    </div>
689    <p>
690      The above example will create an <code>OscillatorNode</code> for each event, where the frequency is controlled by
691      the <code>note</code> param. In essence, this is how the WebAudio API output of Strudel works, only with many more
692      parameters to control synths, samples and effects.
693    </p>
694    <h1 data-number="8" id="pattern-alignment-and-combination">
695      <span class="header-section-number">8</span> Pattern alignment and combination
696    </h1>
697    <p>
698      One core aspect of Strudel, inherited from Tidal, is the flexible way that patterns can be combined, irrespective
699      of their structure. Its declarative approach means a live coder does not have to think about the details of
700      <em>how</em> this is done, only <em>what</em> is to be done.
701    </p>
702    <p>
703      As a simple example, consider two number patterns <code>"0 [1 2] 3"</code>, and <code>"10 20"</code>. The first
704      has three contiguous steps of equal lengths, with the second step broken down into two substeps, giving four
705      events in total. There are a very large number of ways in which the structure of these two patterns could be
706      combined, but the default method in both Strudel and Tidal is to line up the cycles of the two patterns, and then
707      take events from the first pattern and match them with those in the second pattern. Therefore, the following two
708      lines are equivalent:
709    </p>
710    <div class="sourceCode" id="cb14">
711      <pre
712        class="sourceCode js"
713      ><code class="sourceCode javascript"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;0 [1 2] 3&quot;</span><span class="op">.</span><span class="fu">add</span>(<span class="st">&quot;10 20&quot;</span>)</span>
714<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;10 [11 22] 23&quot;</span></span></code></pre>
715    </div>
716    <p>
717      Where the events only partially overlap, they are treated as fragments of the event in the first pattern. This is
718      a little difficult to conceptualise, but lets start by comparing the two patterns in the following example:
719    </p>
720    <div class="sourceCode" id="cb15">
721      <pre
722        class="sourceCode js"
723      ><code class="sourceCode javascript"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;0 1 2&quot;</span><span class="op">.</span><span class="fu">add</span>(<span class="st">&quot;10 20&quot;</span>)</span>
724<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;10 [11 21] 20&quot;</span></span></code></pre>
725    </div>
726    <p>
727      They are similar to the previous example in that the number <code>1</code> is split in two, with its two halves
728      added to <code>10</code> and <code>20</code> respectively. However, the <code>11</code> ‘remembers’ that it is a
729      fragment of that original <code>1</code> event, and so is treated as having a duration of a third of a cycle,
730      despite only being active for a sixth of a cycle. Likewise, the <code>21</code> is also a fragment of that
731      original <code>1</code> event, but a fragment of its second half. Because the start of its event is missing, it
732      wouldn’t actually trigger a sound (unless it underwent further pattern transformations/combinations).
733    </p>
734    <p>
735      In practice, the effect of this default, implicit method for combining two patterns is that the second pattern is
736      added <em>in</em> to the first one, and indeed this can be made explicit:
737    </p>
738    <div class="sourceCode" id="cb16">
739      <pre
740        class="sourceCode js"
741      ><code class="sourceCode javascript"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="st">&quot;0 1 2&quot;</span><span class="op">.</span><span class="at">add</span><span class="op">.</span><span class="fu">in</span>(<span class="st">&quot;10 20&quot;</span>)</span></code></pre>
742    </div>
743    <p>This makes way for other ways to align the pattern, and several are already defined, in particular:</p>
744    <ul>
745      <li>
746        <code>in</code> - as explained above, aligns cycles, and applies values from the pattern on the right
747        <em>in</em> to the pattern on the left.
748      </li>
749      <li>
750        <code>out</code> - as with <code>in</code>, but values are applied <em>out</em> of the pattern on the left
751        (i.e. <em>in</em> to the one on the right).
752      </li>
753      <li>
754        <code>mix</code> - structures from both patterns are combined, so that the new events are not fragments but are
755        created at intersections of events from both sides.
756      </li>
757      <li>
758        <code>squeeze</code> - cycles from the pattern on the right are squeezed into events on the left. So that
759        e.g. <code>"0 1 2".add.squeeze("10 20")</code> is equivalent to <code>"[10 20] [11 21] [12 22]"</code>.
760      </li>
761      <li>
762        <code>squeezeout</code> - as with <code>squeeze</code>, but cycles from the left are squeezed into events on the
763        right. So, <code>"0 1 2".add.squeezeout("10 20")</code> is equivalent to <code>[10 11 12] [20 21 22]</code>.
764      </li>
765      <li>
766        <code>trig</code> is similar to <code>squeezeout</code> in that cycles from the right are aligned with events on
767        the left. However those cycles are not ‘squeezed’, rather they are truncated to fit the event. So
768        <code>"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")</code> would be equivalent to
769        <code>10 11 12 13 20 21 30 31</code>. In effect, events on the right ‘trigger’ cycles on the left.
770      </li>
771      <li>
772        <code>trigzero</code> is similar to <code>trig</code>, but the pattern is ‘triggered’ from its very first cycle,
773        rather than from the current cycle. <code>trig</code> and <code>trigzero</code> therefore only give different
774        results where the leftmost pattern differs from one cycle to the next.
775      </li>
776    </ul>
777    <p>
778      We will save going deeper into the background, design and practicalities of these alignment functions for future
779      publications. However in the next section, we take them as a case study for looking at the different design
780      affordances offered by Haskell to Tidal, and JavaScript to Strudel.
781    </p>
782    <h1 data-number="9" id="comparing-strudel-and-haskell-in-use">
783      <span class="header-section-number">9</span> Comparing Strudel and Haskell in use
784    </h1>
785    <p>
786      Unlike Haskell, JavaScript lacks the ability to define custom infix operators, or change the meaning of existing
787      ones. So the above Strudel example of <code>"0 1 2".add.out("10 20")</code> is equivalent to the Tidal expression
788      <code>"0 1 2" +| "10 20"</code>, where the vertical bar in the operator <code>+|</code> stands for
789      <code>out</code> (where <code>a |+ b</code> would be equivalent of <code>a.add.in(b)</code>).
790    </p>
791    <p>
792      From this we can already see that Tidal tends towards brevity through mixing infix operators with functions, and
793      Strudel tends towards spelling out operations which are joined together with the <code>.</code> operator. This
794      then is the design trade-off of Tidal’s tersity, versus Strudel’s simplicity.
795    </p>
796    <p>To demonstrate this, consider the following Tidal pattern:</p>
797    <pre
798      class="tidal"
799    ><code>iter 4 $ every 3 (||+ n &quot;10 20&quot;) $ (n &quot;0 1 3&quot;) # s &quot;triangle&quot; # crush 4</code></pre>
800    <p>This can be directly translated to the Strudel equivalent:</p>
801    <div class="sourceCode" id="cb18">
802      <pre
803        class="sourceCode js"
804      ><code class="sourceCode javascript"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="fu">iter</span>(<span class="dv">4</span><span class="op">,</span> <span class="fu">every</span>(<span class="dv">3</span><span class="op">,</span> add<span class="op">.</span><span class="fu">squeeze</span>(<span class="st">&quot;10 20&quot;</span>)<span class="op">,</span> <span class="fu">n</span>(<span class="st">&quot;0 1 3&quot;</span>)<span class="op">.</span><span class="fu">s</span>(<span class="st">&quot;triangle&quot;</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)))</span></code></pre>
805    </div>
806    <p>Although for a more canonical Strudel expression, we would reorder it as:</p>
807    <div class="sourceCode" id="cb19">
808      <pre
809        class="sourceCode js"
810      ><code class="sourceCode javascript"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="fu">n</span>(<span class="st">&quot;0 1 3&quot;</span>)<span class="op">.</span><span class="fu">every</span>(<span class="dv">3</span><span class="op">,</span> add<span class="op">.</span><span class="fu">squeeze</span>(<span class="st">&quot;10 20&quot;</span>))<span class="op">.</span><span class="fu">iter</span>(<span class="dv">4</span>)<span class="op">.</span><span class="fu">s</span>(<span class="st">&quot;triangle&quot;</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)</span></code></pre>
811    </div>
812    <p>
813      The Strudel example uses the <code>.</code> method call operator for all operations and combinations, whereas the
814      Tidal example has <code>#</code> for the default method for combining patterns and uses infix operators for other
815      methods. The lack of parenthesis in the Tidal example is partly due to the way that arguments are applied to
816      Haskell’s functions, and partly due to the use of the <code>$</code> operator as an alternative way to establish
817      precedence and control the order of evaluation.
818    </p>
819    <p>
820      Considering the above, we argue that the Haskell syntax is a little cleaner, but that the Strudel syntax is easier
821      to learn. Our informal observation is that while Haskell’s dollar <code>$</code> operator is very useful in making
822      code easier to work with, it is one of the most difficult aspects of Tidal use for beginners to learn. On the
823      other hand, the deeper levels of parenthesis in Strudel code can be difficult to keep track of, especially while
824      coding under pressure of live musical performance. However this difficulty can be largely be mitigated by
825      reordering expressions, and further mitigated by supporting editor features.
826    </p>
827    <p>
828      With Strudel, we have little choice but to embrace the affordances and constraints offered by JavaScript, and
829      while designing a domain-specific language entirely based on method calls is a challenge, through creative
830      adoption of functional programming techniques like partial application, we are so far very happy with the results.
831      Tidal’s functional reactive approach to pattern-making has in general translated well to JavaScript, and
832      opportunities and constraints have overall traded off to create a very approachable and useable live coding
833      environment.
834    </p>
835    <h2 data-number="9.1" id="the-trade-off-of-flexible-typing">
836      <span class="header-section-number">9.1</span> The trade-off of flexible typing
837    </h2>
838    <p>
839      We have identified one problem with porting Tidal to JavaScript where we have missed Haskell’s strict typing and
840      type inference. In both Tidal and Strudel, time is rational, where any point in time is represented as the ratio
841      of two integers. This allows representation of musical ratios such that are impossible to represent accurately
842      using the more common floating point numbers. However while libraries are available that support rational numbers
843      in JavaScript, the lack of strict typing means that it is easy to implement pattern methods where computationally
844      expensive conversion from floating point to rational numbers are performed late, and therefore often enough to
845      overload the CPUs, due to the large number of iterative calculations required to estimate a ratio for a given
846      floating point number. To mitigate this problem, we might consider moving to TypeScript in the future.
847    </p>
848    <h1 data-number="10" id="future-outlook"><span class="header-section-number">10</span> Future Outlook</h1>
849    <p>
850      The project is still young, with many features on the horizon. As general guiding principles, Strudel aims to be
851    </p>
852    <ol type="1">
853      <li>accessible</li>
854      <li>consistent with Tidal’s approach to pattern</li>
855      <li>modular and extensible</li>
856    </ol>
857    <p>
858      While Haskell’s type system makes it a great language for the ongoing development of Tidal’s inner representation
859      of pattern, JavaScript’s vibrant ecosystem, flexibility and accessibility makes it a great host for more ad-hoc
860      experiments, including interface design. For the future, it is planned to integrate additional alternative sound
861      engines such as Glicol <span class="citation" data-cites="lanChaosprintGlicol2022">(Lan [2020] 2022)</span> and
862      Faust
863      <span class="citation" data-cites="FaustProgrammingLanguage2022"
864        >(<em>Faust - Programming Language for Audio Applications and Plugins</em> [2016] 2022)</span
865      >. Strudel is already approaching feature parity with Tidal, but there are more Tidal functions to be ported, and
866      work to be done to improve compatibility with Tidal’s mininotation. Tidal version 2.0 is under development, which
867      brings a new representation for sequences to its patterns, which will then be brought to Strudel. Besides sound,
868      other ways to render events are being explored, such as graphical, and choreographic output. We are also looking
869      into alternative ways of editing patterns, including multi-user editing for network music, parsing a novel syntax
870      to escape the constraints of javascript, and developing hardware/e-textile interfaces. In summary, there is a lot
871      of fun ahead.
872    </p>
873    <h1 data-number="11" id="links"><span class="header-section-number">11</span> Links</h1>
874    <p>
875      The Strudel REPL is available at <a href="https://strudel.cc" class="uri">https://strudel.cc</a>, including an
876      interactive tutorial. The repository is at
877      <a href="https://github.com/tidalcycles/strudel" class="uri">https://github.com/tidalcycles/strudel</a>, all the
878      code is open source under the AGPL-3.0 License.
879    </p>
880    <h1 data-number="12" id="acknowledgments"><span class="header-section-number">12</span> Acknowledgments</h1>
881    <p>
882      Thanks to the Strudel and wider Tidal, live coding, WebAudio and free/open source software communities for
883      inspiration and support. Alex McLean’s work on this project is supported by a UKRI Future Leaders Fellowship
884      [grant number MR/V025260/1].
885    </p>
886    <h1 class="unnumbered" id="references">References</h1>
887    <div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
888      <div id="ref-FaustProgrammingLanguage2022" class="csl-entry" role="doc-biblioentry">
889        <em>Faust - Programming Language for Audio Applications and Plugins</em>. (2016) 2022. C++. GRAME.
890        <a href="https://github.com/grame-cncm/faust">https://github.com/grame-cncm/faust</a>.
891      </div>
892      <div id="ref-jackHydra2022" class="csl-entry" role="doc-biblioentry">
893        Jack, Olivia. (2022) 2022. <em>Hydra</em>.
894        <a href="https://github.com/ojack/hydra">https://github.com/ojack/hydra</a>.
895      </div>
896      <div id="ref-lanChaosprintGlicol2022" class="csl-entry" role="doc-biblioentry">
897        Lan, Qichao. (2020) 2022. <em>Chaosprint/Glicol</em>. Rust.
898        <a href="https://github.com/chaosprint/glicol">https://github.com/chaosprint/glicol</a>.
899      </div>
900      <div id="ref-mcleanAlgorithmicPattern2020a" class="csl-entry" role="doc-biblioentry">
901        Mclean, Alex. 2020. <span>“Algorithmic Pattern.”</span> In
902        <em>Proceedings of the International Conference on New Interfaces for Musical Expression</em>, 265--270.
903        Birmingham, UK. <a href="https://zenodo.org/record/4813352">https://zenodo.org/record/4813352</a>.
904      </div>
905      <div id="ref-mcleanFeedforward2020" class="csl-entry" role="doc-biblioentry">
906        McLean, Alex. 2020. <span>“Feedforward.”</span> In
907        <em>Proceedings of New Interfaces for Musical Expression</em>. Birmingham.
908        <a href="https://zenodo.org/record/6353969">https://zenodo.org/record/6353969</a>.
909      </div>
910      <div id="ref-mcleanTidalVortexZero2022" class="csl-entry" role="doc-biblioentry">
911        McLean, Alex, Raphaël Forment, Sylvain Le Beux, and Damián Silvani. 2022. <span>“TidalVortex Zero.”</span> In
912        <em>Proceedings of the 7th International Conference on Live Coding</em>. Limerick, Ireland: Zenodo.
913        <a href="https://doi.org/10.5281/zenodo.6456380">https://doi.org/10.5281/zenodo.6456380</a>.
914      </div>
915      <div id="ref-ogbornDktr0WebDirt2022" class="csl-entry" role="doc-biblioentry">
916        Ogborn, David. (2016) 2022. <em>Dktr0/WebDirt</em>. JavaScript.
917        <a href="https://github.com/dktr0/WebDirt">https://github.com/dktr0/WebDirt</a>.
918      </div>
919      <div id="ref-ogbornEstuaryBrowserbasedCollaborative2017" class="csl-entry" role="doc-biblioentry">
920        Ogborn, David, Jamie Beverley, Luis Navarro del Angel, Eldad Tsabary, and Alex McLean. 2017.
921        <span>“Estuary: Browser-Based Collaborative Projectional Live Coding of Musical Patterns.”</span> In
922        <em>Proceedings of the International Conference on Live Coding</em>, 11. Morelia.
923      </div>
924      <div id="ref-robertsGibberLiveCoding2012" class="csl-entry" role="doc-biblioentry">
925        Roberts, Charles, and Joann Kuchera-morin. 2012. <span>“Gibber: Live Coding Audio in the Browser.”</span> In
926        <em>In Proceedings of the 2012 International Computer Music Conference</em>.
927      </div>
928      <div id="ref-StrudelWAC2022" class="csl-entry" role="doc-biblioentry">
929        Roos, Felix, and Alex McLean. 2022. <span>“Strudel: Algorithmic Patterns for the Web.”</span> In. Zenodo.
930        <a href="https://doi.org/10.5281/zenodo.6768844">https://doi.org/10.5281/zenodo.6768844</a>.
931      </div>
932      <div id="ref-solomonPurescriptocarina2022" class="csl-entry" role="doc-biblioentry">
933        Solomon, Mike. (2021) 2022. <em>Purescript-Ocarina</em>. PureScript.
934        <a href="https://github.com/mikesol/purescript-ocarina">https://github.com/mikesol/purescript-ocarina</a>.
935      </div>
936      <div id="ref-SuperDirt2022" class="csl-entry" role="doc-biblioentry">
937        <em>SuperDirt</em>. (2015) 2022. SuperCollider. musikinformatik.
938        <a href="https://github.com/musikinformatik/SuperDirt">https://github.com/musikinformatik/SuperDirt</a>.
939      </div>
940      <div id="ref-toussaintEuclideanAlgorithmGenerates2005" class="csl-entry" role="doc-biblioentry">
941        Toussaint, Godfried. 2005. <span>“The Euclidean Algorithm Generates Traditional Musical Rhythms.”</span> In
942        <em>In Proceedings of BRIDGES: Mathematical Connections in Art, Music and Science</em>, 47–56.
943        <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231"
944          >http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231</a
945        >.
946      </div>
947      <div id="ref-CsoundWebAssembly" class="csl-entry" role="doc-biblioentry">
948        Yi, Steven, Victor Lazzarini, and Edward Costello. 2018.
949        <span>“WebAssembly AudioWorklet Csound.”</span> In. Berlin, Germany.
950        <a href="https://mural.maynoothuniversity.ie/16018/">https://mural.maynoothuniversity.ie/16018/</a>.
951      </div>
952    </div>
953  </body>
954</html>