jevstrudel.git / docs / iclc2023-paper / demo-preprocessed.md
1---
2bibliography: citations.json
3date: 2022-06-24
4title: "Strudel: Algorithmic Patterns for the Web"
5---
6
7# Introduction
8
9This paper introduces Strudel (or sometimes 'StrudelCycles'), an
10alternative implementation of the Tidal (or 'TidalCycles') live coding
11system, using the JavaScript programming language. Strudel is an attempt
12to make live coding more accessible, by creating a system that runs
13entirely in the browser, while opening Tidal's approach to algorithmic
14patterns [@mcleanAlgorithmicPattern2020a] up to modern audio/visual web
15technologies. The Strudel REPL is a live code editor dedicated to
16manipulating Strudel patterns while they play, with builtin visual
17feedback. While Strudel is written in JavaScript, the API is optimized
18for simplicity and readability by applying code transformations on the
19syntax tree level, allowing language operations that would otherwise be
20impossible. The application supports multiple ways to output sound,
21including Tone.js, Web Audio nodes, OSC (Open Sound Control) messages,
22Web Serial and Web MIDI. The project is split into multiple packages,
23allowing granular reuse in other applications. Apart from TidalCycles,
24Strudel draws inspiration from many prior existing projects like
25TidalVortex [@mcleanTidalVortexZero2022], Gibber
26[@robertsGibberLiveCoding2012], Estuary
27[@ogbornEstuaryBrowserbasedCollaborative2017], Hydra [@jackHydra2022],
28Ocarina [@solomonPurescriptocarina2022] and Feedforward
29[@mcleanFeedforward2020].
30
31# Porting from Haskell
32
33The original Tidal is implemented as a domain specific language (DSL),
34embedded in the Haskell pure functional programming language, taking
35advantage of Haskell's terse syntax and advanced, 'strong' type system.
36Javascript on the other hand, is a multi-paradigm programming language,
37with a dynamic type system. Because Tidal leans heavily on many of
38Haskell's more unique features, it was not always clear that it could
39meaningfully be ported to a multi-paradigm scripting language. However,
40this already proved to be the case with an earlier port to Python
41\[TidalVortex; @mcleanTidalVortexZero2022\], and we have now
42successfully implemented Tidal's pure functional representation of
43patterns in Strudel, including partial application, and functor,
44applicative and monad structures. Over the past few months since the
45project started in January 2022, a large part of Tidal's functionality
46has already been ported, including its mini-notation for polymetric
47sequences, and a large part of its library of pattern manipulations. The
48result is a terse and highly composable system, where just about
49everything is a pattern, that may be transformed and combined with other
50patterns in a myriad of ways.
51
52# Representing Patterns
53
54Patterns are the essence of Tidal. Its patterns are abstract entities
55that represent flows of time as functions, adapting a technique called
56pure functional reactive programming. Taking a time span as its input, a
57Pattern can output a set of events that happen within that time span. It
58depends on the structure of the Pattern how the events are located in
59time. From now on, this process of generating events from a time span
60will be called **querying**. Example:
61
62<MiniRepl tune={`const pattern = sequence(c3, [e3, g3]);
63const events = pattern.query(0, 1);
64console.log(events.map(e => e.show()))`} />
65
66In this example, we create a pattern using the `sequence` function and
67**query** it for the time span from `0` to `1`. Those numbers represent
68units of time called **cycles**. The length of one cycle depends on the
69tempo, which defaults to one cycle per second. The resulting events are:
70
71<MiniRepl tune={`[{ value: 'c3', begin: 0, end: 1/2 },
72{ value: 'e3', begin: 1/2, end: 3/4 },
73{ value: 'g3', begin: 3/4, end: 1 }]`} />
74
75Each event has a value, a begin time and an end time, where time is
76represented as a fraction. In the above case, the events are placed in
77sequential order, where c3 takes the first half, and e3 and g3 together
78take the second half. This temporal placement is the result of the
79`sequence` function, which divides its arguments equally over one cycle.
80If an argument is an array, the same rule applies to that part of the
81cycle. In the example, e3 and g3 are divided equally over the second
82half of the whole cycle.
83
84In the REPL, the user only has to type in the pattern itself, the
85querying will be handled by the scheduler. The scheduler will repeatedly
86query the pattern for events, which then will be used for playback.
87
88![Screenshot of the Strudel editor, including piano-roll
89visualisation.](images/strudel-screenshot.png){width="43%"}
90
91# Making Patterns
92
93In practice, the end-user live coder will not deal with constructing
94patterns directly, but will rather build patterns using Strudel's
95extensive combinator library to create, combine and transform patterns.
96
97The live coder may use the `sequence` function as already seen above, or
98more often the mini-notation for even terser notation of rhythmic
99sequences. Such sequences are often treated only a starting point for
100manipulation, where they then are undergo pattern transformations such
101as repetition, symmetry, interference/combination or randomisation,
102potentially at multiple timescales. Because Strudel patterns are
103represented as pure functions of time rather than as data structures,
104very long and complex generative results can be represented and
105manipulated without having to store the resulting sequences in memory.
106
107# Pattern Example
108
109The following example showcases how patterns can be utilized to create
110musical complexity from simple parts, using repetition and interference:
111
112<MiniRepl tune={`"<0 2 [4 6](3,4,1) 3*2>".scale('D minor')
113.off(1/4, scaleTranspose(2))
114.off(1/2, scaleTranspose(6))
115.legato(.5)
116.echo(4, 1/8, .5)
117.tone((await piano()).chain(out()))
118.pianoroll()`} />
119
120The pattern starts with a rhythm of numbers in mini notation, which are
121interpreted inside the scale of D minor. Without the scale function, the
122first line can be expressed as:
123
124<MiniRepl tune={`"<d3 f3 [a3 c3](3, 4, 1) g3*2>"`} />
125
126This line could also be expressed without mini notation:
127
128<MiniRepl tune={`slowcat(d3, f3, [a3, c3].euclid(3, 4, 1), g3.fast(2))`} />
129
130Here is a short description of all the functions used:
131
132-   `slowcat`: play elements sequentially, where each lasts one cycle
133-   `brackets`: elements inside brackets are divided equally over the
134    time of their parent
135-   `euclid(p, s, o)`: place p pulses evenly over s steps, with offset o
136    [@toussaintEuclideanAlgorithmGenerates2005]
137-   `fast(n)`: speed up by n. `g3.fast(2)` will play g3 two times.
138-   `off(n, f)`: copy each event, offset it by n cycles and apply
139    function f
140-   `legato(n)`: multiply duration of event with n
141-   `echo(t, n, v)`: copy each event t times, with n cycles in between
142    each copy, decreasing velocity by v
143-   `tone(instrument)`: play back each event with the given Tone.js
144    instrument
145-   `pianoroll()`: visualize events as midi notes in a pianoroll
146
147# Ways to make Sound
148
149To generate sound, Strudel supports different outputs:
150
151-   Tone.js
152-   Web Audio API
153-   WebDirt, a js recreation of Tidal's *Dirt* sample engine
154-   OSC via osc-js
155-   MIDI via WebMIDI
156
157Tone.js proved to be limited for the use case of Strudel, where each
158individual event could potentially have a completely different audio
159graph. While the Web Audio API takes a *fire-and-forget* approach,
160creating a lot of Tone.js instruments and effects causes performance
161issues quickly. For that reason, we chose to search for alternatives.
162
163Strudel's Web Audio API output creates a new audio graph for each event.
164It currently supports basic oscillators, sample playback, envelopes,
165filters and an experimental support for soundfonts.
166
167WebDirt [@ogbornDktr0WebDirt2022] was created as part of the Estuary
168Live Coding System [@ogbornEstuaryBrowserbasedCollaborative2017], and
169proved to be a solid choice for handling samples in Strudel as well.
170
171Using OSC, it is possible to send messages to SuperDirt
172[@SuperDirt2022], which is what Tidal does to generate sound. The
173downside of using OSC is that it requires the user to install
174SuperCollider and its sc3plugins library, which can be difficult.
175
176The MIDI output can be used to send MIDI messages to either external
177instruments or to other programs on the same device. Web MIDI is
178currently only supported on Chromium-based browsers.
179
180# Future Outlook
181
182The project is still young, with many features on the horizon. As
183general guiding principles, Strudel aims to be
184
1851.  accessible
1862.  consistent with Tidal's approach to pattern
1873.  modular and extensible
188
189For the future, it is planned to integrate alternative sound engines
190such as Glicol [@lanChaosprintGlicol2022] and Faust
191[@FaustProgrammingLanguage2022]. To improve compatibility with Tidal,
192more Tidal functions are planned to be ported, as well as full
193compatibility with SuperDirt. Besides sound, other ways to render events
194are being explored, such as graphical, and choreographic output. We are
195also looking into alternative ways of editing patterns, including
196multi-user editing for network music, parsing a novel syntax to escape
197the constraints of javascript, and developing hardware/e-textile
198interfaces.
199
200# Links
201
202The Strudel REPL is available at <https://strudel.cc>,
203including an interactive tutorial. The repository is at
204<https://codeberg.org/uzu/strudel/releases>, all the code is open source
205under the GPL-3.0 License.
206
207# Acknowledgments
208
209Thanks to the Strudel and wider Tidal, live coding, webaudio and
210free/open source software communities for inspiration and support. Alex
211McLean's work on this project is supported by a UKRI Future Leaders
212Fellowship \[grant number MR/V025260/1\].
213
214# References {#references .unnumbered}