Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 376db2f7c2 | |||
| 294581f824 | |||
| 351314ccdf | |||
| e52017c0d8 | |||
| b253d437d3 | |||
| bebbe30b50 | |||
| 489d3f8d4d | |||
| cc4cad05b2 | |||
| 2cb22e94b5 | |||
| ee7d783099 | |||
| 9becd0a3f0 | |||
| 9738c90b82 | |||
| f7b58f2e3e | |||
| d856e567c1 | |||
| a7f044e1aa | |||
| 1f7d78c6ce | |||
| 4137f39495 | |||
| 0163c8ba25 | |||
| 912b3270aa | |||
| 2bc3d69fb0 | |||
| aa20526963 | |||
| 47de9e45ff | |||
| 0c193238c5 | |||
| 3428e18e7d | |||
| 8fba92f447 | |||
| 38e7fe606c | |||
| 59e7584bf7 | |||
| 7f50bcebd2 | |||
| d7b83e200c | |||
| db33707e52 | |||
| 84efa664ca | |||
| 94746b5fae |
@@ -0,0 +1,37 @@
|
||||
name: Build and Deploy
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: docker
|
||||
env:
|
||||
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9.12.2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
# cache: "pnpm"
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Deploy
|
||||
run: |
|
||||
eval $(ssh-agent -s)
|
||||
echo "$SSH_PRIVATE_KEY" | ssh-add -
|
||||
apt update && apt install -y rsync
|
||||
mkdir ~/.ssh
|
||||
ssh-keyscan matrix.toplap.org > ~/.ssh/known_hosts
|
||||
rsync -atv --delete --delete-after --progress ./website/dist/ strudel@matrix.toplap.org:/home/strudel/deploy
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'pnpm'
|
||||
# cache: 'pnpm'
|
||||
- run: pnpm install
|
||||
- run: pnpm run format-check
|
||||
- run: pnpm run lint
|
||||
@@ -1,49 +0,0 @@
|
||||
name: Build and Deploy
|
||||
|
||||
on: [workflow_dispatch]
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
deployments: write
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9.12.2
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
- name: Install Dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build
|
||||
run: pnpm build
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload entire repository
|
||||
path: "./website/dist"
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
@@ -130,3 +130,4 @@ fabric.properties
|
||||
|
||||
samples/*
|
||||
!samples/README.md
|
||||
.idea/
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
# strudel
|
||||
|
||||
[](https://github.com/tidalcycles/strudel/actions) [](https://doi.org/10.5281/zenodo.6659278)
|
||||
Live coding patterns on the web
|
||||
https://strudel.cc/
|
||||
|
||||
An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is a bit more stable now, but please continue to tread carefully.
|
||||
Development is moving to https://codeberg.org/uzu/strudel
|
||||
|
||||
- Try it here: <https://strudel.cc>
|
||||
- Docs: <https://strudel.cc/learn>
|
||||
|
||||
@@ -201,7 +201,7 @@ interfaces.
|
||||
|
||||
The Strudel REPL is available at <https://strudel.cc>,
|
||||
including an interactive tutorial. The repository is at
|
||||
<https://github.com/tidalcycles/strudel>, all the code is open source
|
||||
<https://codeberg.org/uzu/strudel/releases>, all the code is open source
|
||||
under the GPL-3.0 License.
|
||||
|
||||
# Acknowledgments
|
||||
@@ -128,7 +128,7 @@ For the future, it is planned to integrate alternative sound engines such as Gli
|
||||
# Links
|
||||
|
||||
The Strudel REPL is available at <https://strudel.cc>, including an interactive tutorial.
|
||||
The repository is at <https://github.com/tidalcycles/strudel>, all the code is open source under the GPL-3.0 License.
|
||||
The repository is at <https://codeberg.org/uzu/strudel/releases>, all the code is open source under the GPL-3.0 License.
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
@@ -0,0 +1,954 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="date" content="2022-12-14" />
|
||||
<title>Strudel: live coding patterns on the Web</title>
|
||||
<style type="text/css">
|
||||
code {
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
pre > code.sourceCode {
|
||||
white-space: pre;
|
||||
position: relative;
|
||||
}
|
||||
pre > code.sourceCode > span {
|
||||
display: inline-block;
|
||||
line-height: 1.25;
|
||||
}
|
||||
pre > code.sourceCode > span:empty {
|
||||
height: 1.2em;
|
||||
}
|
||||
.sourceCode {
|
||||
overflow: visible;
|
||||
}
|
||||
code.sourceCode > span {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
div.sourceCode {
|
||||
margin: 1em 0;
|
||||
}
|
||||
pre.sourceCode {
|
||||
margin: 0;
|
||||
}
|
||||
@media screen {
|
||||
div.sourceCode {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
pre > code.sourceCode > span {
|
||||
text-indent: -5em;
|
||||
padding-left: 5em;
|
||||
}
|
||||
}
|
||||
pre.numberSource code {
|
||||
counter-reset: source-line 0;
|
||||
}
|
||||
pre.numberSource code > span {
|
||||
position: relative;
|
||||
left: -4em;
|
||||
counter-increment: source-line;
|
||||
}
|
||||
pre.numberSource code > span > a:first-child::before {
|
||||
content: counter(source-line);
|
||||
position: relative;
|
||||
left: -1em;
|
||||
text-align: right;
|
||||
vertical-align: baseline;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
padding: 0 4px;
|
||||
width: 4em;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
pre.numberSource {
|
||||
margin-left: 3em;
|
||||
border-left: 1px solid #aaaaaa;
|
||||
padding-left: 4px;
|
||||
}
|
||||
div.sourceCode {
|
||||
}
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
code span.al {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
} /* Alert */
|
||||
code span.an {
|
||||
color: #60a0b0;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
} /* Annotation */
|
||||
code span.at {
|
||||
color: #7d9029;
|
||||
} /* Attribute */
|
||||
code span.bn {
|
||||
color: #40a070;
|
||||
} /* BaseN */
|
||||
code span.bu {
|
||||
color: #008000;
|
||||
} /* BuiltIn */
|
||||
code span.cf {
|
||||
color: #007020;
|
||||
font-weight: bold;
|
||||
} /* ControlFlow */
|
||||
code span.ch {
|
||||
color: #4070a0;
|
||||
} /* Char */
|
||||
code span.cn {
|
||||
color: #880000;
|
||||
} /* Constant */
|
||||
code span.co {
|
||||
color: #60a0b0;
|
||||
font-style: italic;
|
||||
} /* Comment */
|
||||
code span.cv {
|
||||
color: #60a0b0;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
} /* CommentVar */
|
||||
code span.do {
|
||||
color: #ba2121;
|
||||
font-style: italic;
|
||||
} /* Documentation */
|
||||
code span.dt {
|
||||
color: #902000;
|
||||
} /* DataType */
|
||||
code span.dv {
|
||||
color: #40a070;
|
||||
} /* DecVal */
|
||||
code span.er {
|
||||
color: #ff0000;
|
||||
font-weight: bold;
|
||||
} /* Error */
|
||||
code span.ex {
|
||||
} /* Extension */
|
||||
code span.fl {
|
||||
color: #40a070;
|
||||
} /* Float */
|
||||
code span.fu {
|
||||
color: #06287e;
|
||||
} /* Function */
|
||||
code span.im {
|
||||
color: #008000;
|
||||
font-weight: bold;
|
||||
} /* Import */
|
||||
code span.in {
|
||||
color: #60a0b0;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
} /* Information */
|
||||
code span.kw {
|
||||
color: #007020;
|
||||
font-weight: bold;
|
||||
} /* Keyword */
|
||||
code span.op {
|
||||
color: #666666;
|
||||
} /* Operator */
|
||||
code span.ot {
|
||||
color: #007020;
|
||||
} /* Other */
|
||||
code span.pp {
|
||||
color: #bc7a00;
|
||||
} /* Preprocessor */
|
||||
code span.sc {
|
||||
color: #4070a0;
|
||||
} /* SpecialChar */
|
||||
code span.ss {
|
||||
color: #bb6688;
|
||||
} /* SpecialString */
|
||||
code span.st {
|
||||
color: #4070a0;
|
||||
} /* String */
|
||||
code span.va {
|
||||
color: #19177c;
|
||||
} /* Variable */
|
||||
code span.vs {
|
||||
color: #4070a0;
|
||||
} /* VerbatimString */
|
||||
code span.wa {
|
||||
color: #60a0b0;
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
} /* Warning */
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/iclc.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1 class="title">Strudel: live coding patterns on the Web</h1>
|
||||
<ul id="authorlist">
|
||||
<li>true</li>
|
||||
<li>true</li>
|
||||
</ul>
|
||||
<h3 class="date">2022-12-14</h3>
|
||||
</div>
|
||||
|
||||
<h2 class="abstract">Abstract</h2>
|
||||
<div id="abstract">
|
||||
<p>
|
||||
This paper introduces Strudel, which brings the TidalCycles approach to live coding algorithmic patterns to
|
||||
native JavaScript and the web. We begin by giving a little background of the first year of development, before
|
||||
sharing some detail about its implementation and examples of use. We go on to outline the wide range of
|
||||
synthesis and other outputs available in Strudel, including WebAudio, MIDI, OSC (for SuperDirt), WebSerial and
|
||||
CSound, and introduce Strudel’s REPL live editor, including its built-in visualisations. We then compare Strudel
|
||||
with Tidal, the trade-offs involved between JavaScript and Haskell, and the unique capabilities offered by
|
||||
Strudel for aligning patterns.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction</h1>
|
||||
<p>
|
||||
In the following paper, we introduce <em>Strudel</em>, an alternative implementation of the TidalCycles (or
|
||||
‘Tidal’ for short) live coding system, using the JavaScript programming language. Strudel is an attempt to make
|
||||
live coding more accessible, by creating a system that runs entirely in the browser, while opening Tidal’s
|
||||
approach to algorithmic patterns
|
||||
<span class="citation" data-cites="mcleanAlgorithmicPattern2020a">(Mclean 2020)</span> up to modern audio/visual
|
||||
web technologies. The Strudel REPL is a live code editor dedicated to manipulating patterns while they play, with
|
||||
builtin visual feedback. While Strudel is written in JavaScript, the API is optimized for simplicity and
|
||||
readability by applying code transformations on the syntax tree level, allowing language operations that would
|
||||
otherwise be impossible. The application supports multiple ways to output sound, including Tone.js, Web Audio
|
||||
Nodes, OSC (Open Sound Control) messages, Web Serial, Web MIDI and Csound. The project is split into multiple
|
||||
packages, allowing granular reuse in other applications. Apart from TidalCycles, Strudel draws inspiration from
|
||||
many prior existing projects like TidalVortex
|
||||
<span class="citation" data-cites="mcleanTidalVortexZero2022">(McLean et al. 2022)</span>, Gibber
|
||||
<span class="citation" data-cites="robertsGibberLiveCoding2012">(Roberts and Kuchera-morin 2012)</span>, Estuary
|
||||
<span class="citation" data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al. 2017)</span>, Hydra
|
||||
<span class="citation" data-cites="jackHydra2022">(Jack [2022] 2022)</span>, Ocarina
|
||||
<span class="citation" data-cites="solomonPurescriptocarina2022">(Solomon [2021] 2022)</span> and Feedforward
|
||||
<span class="citation" data-cites="mcleanFeedforward2020">(McLean 2020)</span>. This paper expands the Strudel
|
||||
Demo paper for the Web Audio Conference 2022
|
||||
<span class="citation" data-cites="StrudelWAC2022">(Roos and McLean 2022)</span>.
|
||||
</p>
|
||||
<p>
|
||||
The first tentative commit to the Strudel project was on 22nd January 2022 by Alex McLean, with the core
|
||||
representation implemented over the following few days. Although this was his first attempt at a JavaScript-based
|
||||
application, by 27th January, Alex had managed to upload the initial version to the ‘npm’ javascript package
|
||||
database, sharing with the wider community for comment. By 4th February, Felix Roos had discovered Strudel and
|
||||
contributed a ‘REPL’ user interface to it, and then contributed a scheduler the next day, so that Strudel could
|
||||
already make sound. At this point, Alex and Felix shared ownership to the repository, and the project has since
|
||||
proved to be a productive confluence of Felix’s own work into music representation and visualisation, with Alex’s
|
||||
experience with making Tidal. Felix has since become the primary contributor to Strudel, with Alex continuing to
|
||||
jump between developing both Strudel and Tidal. Aspects of Strudel’s development have therefore fed back into
|
||||
TidalCycles, and both systems have maintained a shared conceptual underpinning. We plan to continue working
|
||||
towards feature parity between these systems, although within the syntactical trade-offs and library ecosystems of
|
||||
JavaScript and Haskell, some divergence is inevitable and healthy.
|
||||
</p>
|
||||
<p>
|
||||
Over the first year of its life, Strudel is now a fully-fledged live coding environment, porting Tidal’s core
|
||||
represention of patterns, pattern transformations, and mininotation for polymetric sequences, combined with a
|
||||
wealth of features for synthesising and visualising those patterns.
|
||||
</p>
|
||||
<h1 data-number="2" id="from-tidal-to-strudel-and-back">
|
||||
<span class="header-section-number">2</span> From Tidal to Strudel and back
|
||||
</h1>
|
||||
<p>
|
||||
As mentioned above, the original Tidal is implemented as a domain specific language (DSL) embedded in the Haskell
|
||||
pure functional programming language, and takes advantage of Haskell’s terse syntax and advanced, ‘strong’ type
|
||||
system. JavaScript on the other hand, is a multi-paradigm programming language, with a dynamic type system.
|
||||
Because Tidal leans heavily on many of Haskell’s more unique features, it was not always clear that it could
|
||||
meaningfully be ported to a multi-paradigm scripting language. However, this possibility was already demonstrated
|
||||
with an earlier port to Python [TidalVortex;
|
||||
<span class="citation" data-cites="mcleanTidalVortexZero2022">McLean et al. (2022)</span>], and we have now
|
||||
successfully implemented Tidal’s pure functional representation of patterns in Strudel, including partial
|
||||
application, currying, and the functor, applicative and monadic structures that underlie Tidal’s expressive
|
||||
pattern transformations. The result is a terse and highly composable system, where everything is either a pattern,
|
||||
or a function for combining and manipulating patterns, offering a rich creative ground for exploration.
|
||||
</p>
|
||||
<p>
|
||||
This development process has been far from a one-way port, however. The process of porting Tidal’s concepts has
|
||||
also opened up new possibilities, some just from revisiting every design decision, and some from the particular
|
||||
affordances and constraints offered by JavaScript. This has lead to new features (and indeed bugfixes) that have
|
||||
found their way back to Tidal where appropriate, and ongoing work that we will return to in the conclusion of this
|
||||
paper.
|
||||
</p>
|
||||
<h1 data-number="3" id="representing-patterns">
|
||||
<span class="header-section-number">3</span> Representing Patterns
|
||||
</h1>
|
||||
<p>
|
||||
Patterns are the essence of Tidal. Its patterns are abstract entities that represent flows of time as functions,
|
||||
adapting a technique called pure functional reactive programming. Taking a time span as its input, a Pattern can
|
||||
output a set of events that happen within that time span. It depends on the structure of the Pattern how the
|
||||
events are located in time. From now on, this process of generating events from a time span will be called
|
||||
<strong>querying</strong>. Example:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb1">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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>
|
||||
<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>
|
||||
<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">=></span> e<span class="op">.</span><span class="fu">show</span>()))</span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
In this example, we create a pattern using the <code>sequence</code> function and <strong>query</strong> it for
|
||||
the time span from <code>0</code> to <code>1</code>. Those numbers represent units of time called
|
||||
<strong>cycles</strong>. The length of one cycle depends on the tempo, which defaults to one cycle per second. The
|
||||
resulting events are:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb2">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">'c3'</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>
|
||||
<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">'e3'</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>
|
||||
<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">'g3'</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>
|
||||
</div>
|
||||
<p>
|
||||
Each event has a value, a begin time and an end time, where time is represented as a fraction. In the above case,
|
||||
the events are placed in sequential order, where c3 takes the first half, and e3 and g3 together take the second
|
||||
half. This temporal placement is the result of the <code>sequence</code> function, which divides its arguments
|
||||
equally over one cycle. If an argument is an array, the same rule applies to that part of the cycle. In the
|
||||
example, e3 and g3 are divided equally over the second half of the whole cycle.
|
||||
</p>
|
||||
<p>
|
||||
The above examples do not represent how Strudel is used in practice. In the live coding editor, the user only has
|
||||
to type in the pattern itself, the querying will be handled by the scheduler. The scheduler will repeatedly query
|
||||
the pattern for events, which are then scheduled as sound synthesis or other event triggers. Also, the above event
|
||||
data structure has been simplified for readability.
|
||||
</p>
|
||||
<figure>
|
||||
<img
|
||||
src="images/strudel-screenshot2.png"
|
||||
style="width: 60%"
|
||||
alt="Screenshot of the Strudel ‘REPL’ live coding editor, including piano-roll visualisation."
|
||||
/>
|
||||
<figcaption aria-hidden="true">
|
||||
Screenshot of the Strudel ‘REPL’ live coding editor, including piano-roll visualisation.
|
||||
</figcaption>
|
||||
</figure>
|
||||
<h1 data-number="4" id="making-patterns"><span class="header-section-number">4</span> Making Patterns</h1>
|
||||
<p>
|
||||
In practice, the end-user live coder will not deal with constructing patterns directly, but will rather build
|
||||
patterns using Strudel’s extensive combinator library to create, combine and transform patterns.
|
||||
</p>
|
||||
<p>
|
||||
The live coder will rarely use the <code>sequence</code> function as seen above, as sequencing is implicit in many
|
||||
functions. For example in the following, the <code>note</code> function constructs a pattern of notes, sequencing
|
||||
its arguments in the same manner as the previous example.
|
||||
</p>
|
||||
<div class="sourceCode" id="cb3">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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>
|
||||
</div>
|
||||
<p>
|
||||
Perhaps more often, they will use the mini-notation for even terser notation of rhythmic sequences: [^This last
|
||||
example is also valid Tidal code, albeit the parenthesis is not required in its Haskell syntax in this case. Tidal
|
||||
does not support passing sequences as lists directly to the <code>note</code> function, however.].
|
||||
</p>
|
||||
<div class="sourceCode" id="cb4">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">"c3 [e3 g3]"</span>)</span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
Such sequences are often treated only a starting point for manipulation, where they then undergo pattern
|
||||
transformations such as repetition, symmetry, interference/combination or randomisation, potentially at multiple
|
||||
timescales. Because Strudel patterns are represented as pure functions of time rather than as data structures,
|
||||
very long and complex generative results can be represented and manipulated without having to store the resulting
|
||||
sequences in memory.
|
||||
</p>
|
||||
<h1 data-number="5" id="pattern-example"><span class="header-section-number">5</span> Pattern Example</h1>
|
||||
<p>
|
||||
The following example showcases how patterns can be utilized to create musical complexity from simple parts, using
|
||||
repetition and interference:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb5">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="st">"<0 2 [4 6](3,4,1) 3>"</span></span>
|
||||
<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>
|
||||
<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>
|
||||
<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">'D minor'</span>)</span>
|
||||
<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>
|
||||
<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">"sawtooth square"</span>)</span>
|
||||
<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>
|
||||
</div>
|
||||
<p>
|
||||
The pattern starts with a rhythm of numbers in mini notation, which are later interpreted inside the scale of D
|
||||
minor. The first line could also be expressed without mini notation:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb6">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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>
|
||||
</div>
|
||||
<p>
|
||||
These numbers then undergo various pattern transformations. Here is a short description of all the functions used:
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>cat</code>: play elements sequentially, where each lasts one cycle</li>
|
||||
<li><code>brackets</code>: elements inside brackets are divided equally over the time of their parent</li>
|
||||
<li>
|
||||
<code>.euclid(p, s, o)</code>: place p pulses evenly over s steps, with offset o
|
||||
<span class="citation" data-cites="toussaintEuclideanAlgorithmGenerates2005">(Toussaint 2005)</span>
|
||||
</li>
|
||||
<li>
|
||||
<code>.off(n, f)</code>: layers a pattern on top of itself, with the new layer offset by n cycles, and with
|
||||
function f applied
|
||||
</li>
|
||||
<li><code>.legato(n)</code>: multiply the duration of all events in a pattern by a factor of n</li>
|
||||
<li>
|
||||
<code>.echo(t, n, v)</code>: copy each event t times, with n cycles in between each copy, decreasing velocity by
|
||||
v
|
||||
</li>
|
||||
<li><code>.note()</code>: interpretes values as notes</li>
|
||||
<li><code>.s(name)</code>: play back each event with the given sound</li>
|
||||
<li><code>.delay(wet)</code>: add delay</li>
|
||||
<li><code>.delaytime(t)</code>: set delay time</li>
|
||||
</ul>
|
||||
<p>Much of the above will be familiar to Tidal users.</p>
|
||||
<!-- 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. -->
|
||||
<h1 data-number="6" id="ways-to-make-sound-and-other-events">
|
||||
<span class="header-section-number">6</span> Ways to make Sound (and other events)
|
||||
</h1>
|
||||
<p>To generate sound, Strudel supports bindings for different outputs:</p>
|
||||
<ul>
|
||||
<li>Tone.js (deprecated)</li>
|
||||
<li>Web Audio API</li>
|
||||
<li>WebDirt, a js recreation of Tidal’s <em>Dirt</em> sample engine (deprecated)</li>
|
||||
<li>OSC via osc-js, compatible with superdirt</li>
|
||||
<li>Csound via the Csound WebAssembly build</li>
|
||||
<li>MIDI via WebMIDI</li>
|
||||
<li>Serial via WebSerial</li>
|
||||
</ul>
|
||||
<p>
|
||||
At first, we used Tone.js as sound output, but it proved to be limited for the use case of Strudel, where each
|
||||
individual event could potentially have a completely different audio graph. While the Web Audio API takes a
|
||||
<em>fire-and-forget</em> approach, creating a lot of Tone.js instruments and effects causes performance issues
|
||||
quickly. For that reason, we chose to search for alternatives.
|
||||
</p>
|
||||
<p>
|
||||
Strudel’s new default output uses the Web Audio API to create a new audio graph for each event. It currently
|
||||
supports basic oscillators, sample playback, various effects and an experimental support for soundfonts.
|
||||
</p>
|
||||
<p>
|
||||
WebDirt <span class="citation" data-cites="ogbornDktr0WebDirt2022">(Ogborn [2016] 2022)</span> was created as part
|
||||
of the Estuary Live Coding System
|
||||
<span class="citation" data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al. 2017)</span>, and
|
||||
proved to be a solid choice for handling samples in Strudel as well. We are however focused on working more
|
||||
directly with the Web Audio API to be able to integrate new features more tightly.
|
||||
</p>
|
||||
<p>
|
||||
Using the OSC protocol via Strudel’s provided Node.js-based OSC proxy server, it is possible to send network
|
||||
messages to trigger events. This is mainly used to render sound using SuperDirt
|
||||
<span class="citation" data-cites="SuperDirt2022">(<em>SuperDirt</em> [2015] 2022)</span>, which is the
|
||||
well-developed Supercollider-based synthesis framework that Tidal live coders generally use as standard.
|
||||
</p>
|
||||
<p>
|
||||
Recently, the experimental integration of Csound proved to bring a new dimension of sound design capabilities to
|
||||
Strudel. Thanks to the WebAssembly distribution of this classic system
|
||||
<span class="citation" data-cites="CsoundWebAssembly">(Yi, Lazzarini, and Costello 2018)</span>, Csound
|
||||
‘orchestra’ synthesisers can be embedded in and then patterned with Strudel code.
|
||||
</p>
|
||||
<p>
|
||||
MIDI output can also be used to send MIDI messages to either external instruments or to other programs on the same
|
||||
device. Unlike OSC, Strudel is able to send MIDI directly without requiring additional proxy software, but only
|
||||
from web browsers that support it (at the time of writing, this means Chromium-based browsers).
|
||||
</p>
|
||||
<p>
|
||||
Finally, Strudel supports Serial output, for example to trigger events via microcontrollers. This has already been
|
||||
explored for robot choreography by Kate Sicchio and Alex McLean, via a performance presented at the International
|
||||
Conference on Live Interfaces 2022.
|
||||
</p>
|
||||
<h1 data-number="7" id="the-strudel-repl"><span class="header-section-number">7</span> The Strudel REPL</h1>
|
||||
<p>
|
||||
While Strudel can be used as a library in any JavaScript codebase, its main, reference user interface is the
|
||||
Strudel REPL[^REPL stands for read, evaluate, print/play, loop. It is friendly jargon for an interactive
|
||||
programming interface from computing heritage, usually for a commandline interface but also applied to live coding
|
||||
editors.], which is a browser-based live coding environment. This live code editor is dedicated to manipulating
|
||||
Strudel patterns while they play. The REPL features built-in visual feedback, which highlights which elements in
|
||||
the patterned (mini-notation) sequences are influencing the event that is currently being played. This feedback is
|
||||
designed to support both learning and live use of Strudel.
|
||||
</p>
|
||||
<p>
|
||||
Besides a UI for playback control and meta information, the main part of the REPL interface is the code editor
|
||||
powered by CodeMirror. In it, the user can edit and evaluate pattern code live, using one of the available
|
||||
synthesis outputs to create music and/or sound art. The control flow of the REPL follows 3 basic steps:
|
||||
</p>
|
||||
<ol type="1">
|
||||
<li>
|
||||
The user writes and updates code. Each update transpiles and evaluates it to create a
|
||||
<code>Pattern</code> instance
|
||||
</li>
|
||||
<li>
|
||||
While the REPL is running, the <code>Scheduler</code> queries the active <code>Pattern</code> by a regular
|
||||
interval, generating <code>Events</code> (also known as <code>Haps</code> in Strudel) for the next time span.
|
||||
</li>
|
||||
<li>
|
||||
For each scheduling tick, all generated <code>Events</code> are triggered by calling their
|
||||
<code>onTrigger</code> method, which is set by the output.
|
||||
</li>
|
||||
</ol>
|
||||
<figure>
|
||||
<img
|
||||
src="https://github.com/tidalcycles/strudel/raw/talk/talk/public/strudelflow.png?raw=true"
|
||||
style="width: 43%"
|
||||
alt="REPL control flow"
|
||||
/>
|
||||
<figcaption aria-hidden="true">REPL control flow</figcaption>
|
||||
</figure>
|
||||
<h2 data-number="7.1" id="user-code"><span class="header-section-number">7.1</span> User Code</h2>
|
||||
<p>To create a <code>Pattern</code> from the user code, two steps are needed:</p>
|
||||
<ol type="1">
|
||||
<li>Transpile the JS input code to make it functional</li>
|
||||
<li>Evaluate the transpiled code</li>
|
||||
</ol>
|
||||
<h3 data-number="7.1.1" id="transpilation-evaluation">
|
||||
<span class="header-section-number">7.1.1</span> Transpilation & Evaluation
|
||||
</h3>
|
||||
<p>
|
||||
In the JavaScript world, using transpilation is a common practise to be able to use language features that are not
|
||||
supported by the base language. Tools like <code>babel</code> will transpile code that contains unsupported
|
||||
language features into a version of the code without those features.
|
||||
</p>
|
||||
<p>
|
||||
In the same tradition, Strudel can add a transpilation step to simplify the user code in the context of live
|
||||
coding. For example, the Strudel REPL lets the user create mini notation patterns using just double quoted
|
||||
strings, while single quoted strings remain what they are:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb7">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="st">"c3 [e3 g3]*2"</span></span></code></pre>
|
||||
</div>
|
||||
<p>is transpiled to:</p>
|
||||
<div class="sourceCode" id="cb8">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">"c3 [e3 g3]*2"</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>
|
||||
</div>
|
||||
<p>
|
||||
Here, the string is wrapped in <code>mini</code>, which will create a pattern from a mini notation string.
|
||||
Additionally, the <code>withMiniLocation</code> method passes the original source code location of the string to
|
||||
the pattern, which enables highlighting active events.
|
||||
</p>
|
||||
<p>
|
||||
Other convenient features like pseudo variables, operator overloading and top level await are possible with
|
||||
transpilation.
|
||||
</p>
|
||||
<p>After the transpilation, the code is ready to be evaluated into a <code>Pattern</code>.</p>
|
||||
<p>
|
||||
Behind the scenes, the user code string is parsed with <code>acorn</code>, turning it into an Abstract Syntax Tree
|
||||
(AST). The AST allows changing the structure of the code before generating the transpiled version using
|
||||
<code>escodegen</code>.
|
||||
</p>
|
||||
<h3 data-number="7.1.2" id="mini-notation"><span class="header-section-number">7.1.2</span> Mini Notation</h3>
|
||||
<p>
|
||||
While the transpilation allows JavaScript to express Patterns in a less verbose way, it is still preferable to use
|
||||
the Mini Notation as a more compact way to express rhythm. Strudel aims to provide the same Mini Notation features
|
||||
and syntax as used in Tidal.
|
||||
</p>
|
||||
<p>
|
||||
The Mini Notation parser is implemented using <code>peggy</code>, which allows generating performant parsers for
|
||||
Domain Specific Languages (DSLs) using a concise grammar notation. The generated parser turns the Mini Notation
|
||||
string into an AST which is used to call the respective Strudel functions with the given structure. For example,
|
||||
<code>"c3 [e3 g3]*2"</code> will result in the following calls:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb9">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">seq</span>(</span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'c3'</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>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">seq</span>(</span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'e3'</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>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'g3'</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>
|
||||
<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>
|
||||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>)</span></code></pre>
|
||||
</div>
|
||||
<h3 data-number="7.1.3" id="highlighting-locations">
|
||||
<span class="header-section-number">7.1.3</span> Highlighting Locations
|
||||
</h3>
|
||||
<p>
|
||||
As seen in the examples above, both the JS and the Mini Notation parser add source code locations using
|
||||
<code>withMiniLocation</code> and <code>withLocation</code> methods. While the JS parser adds locations relative
|
||||
to the user code as a whole, the Mini Notation adds locations relative to the position of the mini notation
|
||||
string. The absolute location of elements within Mini Notation can be calculated by simply adding both locations
|
||||
together. This absolute location can be used to highlight active events in real time.
|
||||
</p>
|
||||
<h2 data-number="7.2" id="scheduling-events"><span class="header-section-number">7.2</span> Scheduling Events</h2>
|
||||
<p>
|
||||
After an instance of <code>Pattern</code> is obtained from the user code, it is used by the scheduler to get
|
||||
queried for events. Once started, the scheduler runs at a fixed interval to query active pattern for events
|
||||
withing the current interval’s time span. A simplified implementation looks like this:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb10">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">'c3'</span><span class="op">,</span> [<span class="st">'e3'</span><span class="op">,</span> <span class="st">'g3'</span>])<span class="op">;</span> <span class="co">// pattern from user</span></span>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="pp">setInterval</span>(() <span class="kw">=></span> {</span>
|
||||
<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>
|
||||
<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>
|
||||
<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">=></span> {</span>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a> })<span class="op">;</span></span>
|
||||
<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 "interval" seconds</span></span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
Note that the above code is simplified for illustrative purposes. The actual implementation has to work around
|
||||
imprecise callbacks of <code>setInterval</code>. More about the implementation details can be read in
|
||||
<a href="https://loophole-letters.vercel.app/web-audio-scheduling">this blog post</a>.
|
||||
</p>
|
||||
<p>
|
||||
The fact that <code>Pattern.queryArc</code> is a pure function that maps a time span to a set of events allows us
|
||||
to choose any interval we like without changing the resulting output. It also means that when the pattern is
|
||||
changed from outside, the next scheduling callback will work with the new pattern, keeping its clock running.
|
||||
</p>
|
||||
<p>
|
||||
The latency between the time the pattern is evaluated and the change is heard is between
|
||||
<code>minLatency</code> and <code>interval + minLatency</code>, in our example between 100ms and 600ms. In
|
||||
Strudel, the current query interval is 50ms with a minLatency of 100ms, meaning the latency is between 50ms and
|
||||
150ms.
|
||||
</p>
|
||||
<h2 data-number="7.3" id="output"><span class="header-section-number">7.3</span> Output</h2>
|
||||
<p>
|
||||
The last step is to trigger each event in the chosen output. This is where the given time and value of each event
|
||||
is used to generate audio or any other form of time based output. The default output of the Strudel REPL is the
|
||||
WebAudio output. To understand what an output does, we first have to understand what control parameters are.
|
||||
</p>
|
||||
<h3 data-number="7.3.1" id="control-parameters">
|
||||
<span class="header-section-number">7.3.1</span> Control Parameters
|
||||
</h3>
|
||||
<p>
|
||||
To be able to manipulate multiple aspects of sound in parallel, so called control parameters are used to shape the
|
||||
value of each event. Example:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb11">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">"c3 e3"</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">'sawtooth'</span>)</span>
|
||||
<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">=></span> hap<span class="op">.</span><span class="at">value</span>)</span>
|
||||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co">/* [</span></span>
|
||||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co"> { note: 'c3', cutoff: 1000, s: 'sawtooth' }</span></span>
|
||||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co"> { note: 'e3', cutoff: 1000, s: 'sawtooth' }</span></span>
|
||||
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">] */</span></span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
Here, the control parameter functions <code>note</code>, <code>cutoff</code> and <code>s</code> are used, where
|
||||
each controls a different property in the value object. Each control parameter function accepts a primitive value,
|
||||
a list of values to be sequenced into a <code>Pattern</code>, or a <code>Pattern</code>. In the example,
|
||||
<code>note</code> gets a <code>Pattern</code> from a Mini Notation expression (double quoted), while
|
||||
<code>cutoff</code> and <code>s</code> are given a <code>Number</code> and a (single quoted)
|
||||
<code>String</code> respectively.
|
||||
</p>
|
||||
<p>
|
||||
Strudel comes with a large default set of control parameter functions that are based on the ones used by Tidal and
|
||||
SuperDirt, focusing on music and audio terminology. It is however possible to create custom control paramters for
|
||||
any purpose:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb12">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">'x'</span><span class="op">,</span> <span class="st">'y'</span>)</span>
|
||||
<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>
|
||||
</div>
|
||||
<p>
|
||||
This example creates the custom control parameters <code>x</code> and <code>y</code> which are then used to form a
|
||||
pattern that descibes the coordinates of a circle.
|
||||
</p>
|
||||
<h3 data-number="7.3.2" id="outputs"><span class="header-section-number">7.3.2</span> Outputs</h3>
|
||||
<p>
|
||||
Now that we know how the value of an event is manipulated using control parameters, we can look at how outputs can
|
||||
use that value to generate anything. The scheduler above was calling the <code>onTrigger</code> function which is
|
||||
used to implement the output. A very simple version of the web audio output could look like this:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb13">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
The above example will create an <code>OscillatorNode</code> for each event, where the frequency is controlled by
|
||||
the <code>note</code> param. In essence, this is how the WebAudio API output of Strudel works, only with many more
|
||||
parameters to control synths, samples and effects.
|
||||
</p>
|
||||
<h1 data-number="8" id="pattern-alignment-and-combination">
|
||||
<span class="header-section-number">8</span> Pattern alignment and combination
|
||||
</h1>
|
||||
<p>
|
||||
One core aspect of Strudel, inherited from Tidal, is the flexible way that patterns can be combined, irrespective
|
||||
of their structure. Its declarative approach means a live coder does not have to think about the details of
|
||||
<em>how</em> this is done, only <em>what</em> is to be done.
|
||||
</p>
|
||||
<p>
|
||||
As a simple example, consider two number patterns <code>"0 [1 2] 3"</code>, and <code>"10 20"</code>. The first
|
||||
has three contiguous steps of equal lengths, with the second step broken down into two substeps, giving four
|
||||
events in total. There are a very large number of ways in which the structure of these two patterns could be
|
||||
combined, but the default method in both Strudel and Tidal is to line up the cycles of the two patterns, and then
|
||||
take events from the first pattern and match them with those in the second pattern. Therefore, the following two
|
||||
lines are equivalent:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb14">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 [1 2] 3"</span><span class="op">.</span><span class="fu">add</span>(<span class="st">"10 20"</span>)</span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="st">"10 [11 22] 23"</span></span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
Where the events only partially overlap, they are treated as fragments of the event in the first pattern. This is
|
||||
a little difficult to conceptualise, but lets start by comparing the two patterns in the following example:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb15">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 1 2"</span><span class="op">.</span><span class="fu">add</span>(<span class="st">"10 20"</span>)</span>
|
||||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="st">"10 [11 21] 20"</span></span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
They are similar to the previous example in that the number <code>1</code> is split in two, with its two halves
|
||||
added to <code>10</code> and <code>20</code> respectively. However, the <code>11</code> ‘remembers’ that it is a
|
||||
fragment of that original <code>1</code> event, and so is treated as having a duration of a third of a cycle,
|
||||
despite only being active for a sixth of a cycle. Likewise, the <code>21</code> is also a fragment of that
|
||||
original <code>1</code> event, but a fragment of its second half. Because the start of its event is missing, it
|
||||
wouldn’t actually trigger a sound (unless it underwent further pattern transformations/combinations).
|
||||
</p>
|
||||
<p>
|
||||
In practice, the effect of this default, implicit method for combining two patterns is that the second pattern is
|
||||
added <em>in</em> to the first one, and indeed this can be made explicit:
|
||||
</p>
|
||||
<div class="sourceCode" id="cb16">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><code class="sourceCode javascript"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 1 2"</span><span class="op">.</span><span class="at">add</span><span class="op">.</span><span class="fu">in</span>(<span class="st">"10 20"</span>)</span></code></pre>
|
||||
</div>
|
||||
<p>This makes way for other ways to align the pattern, and several are already defined, in particular:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<code>in</code> - as explained above, aligns cycles, and applies values from the pattern on the right
|
||||
<em>in</em> to the pattern on the left.
|
||||
</li>
|
||||
<li>
|
||||
<code>out</code> - as with <code>in</code>, but values are applied <em>out</em> of the pattern on the left
|
||||
(i.e. <em>in</em> to the one on the right).
|
||||
</li>
|
||||
<li>
|
||||
<code>mix</code> - structures from both patterns are combined, so that the new events are not fragments but are
|
||||
created at intersections of events from both sides.
|
||||
</li>
|
||||
<li>
|
||||
<code>squeeze</code> - cycles from the pattern on the right are squeezed into events on the left. So that
|
||||
e.g. <code>"0 1 2".add.squeeze("10 20")</code> is equivalent to <code>"[10 20] [11 21] [12 22]"</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code>squeezeout</code> - as with <code>squeeze</code>, but cycles from the left are squeezed into events on the
|
||||
right. So, <code>"0 1 2".add.squeezeout("10 20")</code> is equivalent to <code>[10 11 12] [20 21 22]</code>.
|
||||
</li>
|
||||
<li>
|
||||
<code>trig</code> is similar to <code>squeezeout</code> in that cycles from the right are aligned with events on
|
||||
the left. However those cycles are not ‘squeezed’, rather they are truncated to fit the event. So
|
||||
<code>"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")</code> would be equivalent to
|
||||
<code>10 11 12 13 20 21 30 31</code>. In effect, events on the right ‘trigger’ cycles on the left.
|
||||
</li>
|
||||
<li>
|
||||
<code>trigzero</code> is similar to <code>trig</code>, but the pattern is ‘triggered’ from its very first cycle,
|
||||
rather than from the current cycle. <code>trig</code> and <code>trigzero</code> therefore only give different
|
||||
results where the leftmost pattern differs from one cycle to the next.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
We will save going deeper into the background, design and practicalities of these alignment functions for future
|
||||
publications. However in the next section, we take them as a case study for looking at the different design
|
||||
affordances offered by Haskell to Tidal, and JavaScript to Strudel.
|
||||
</p>
|
||||
<h1 data-number="9" id="comparing-strudel-and-haskell-in-use">
|
||||
<span class="header-section-number">9</span> Comparing Strudel and Haskell in use
|
||||
</h1>
|
||||
<p>
|
||||
Unlike Haskell, JavaScript lacks the ability to define custom infix operators, or change the meaning of existing
|
||||
ones. So the above Strudel example of <code>"0 1 2".add.out("10 20")</code> is equivalent to the Tidal expression
|
||||
<code>"0 1 2" +| "10 20"</code>, where the vertical bar in the operator <code>+|</code> stands for
|
||||
<code>out</code> (where <code>a |+ b</code> would be equivalent of <code>a.add.in(b)</code>).
|
||||
</p>
|
||||
<p>
|
||||
From this we can already see that Tidal tends towards brevity through mixing infix operators with functions, and
|
||||
Strudel tends towards spelling out operations which are joined together with the <code>.</code> operator. This
|
||||
then is the design trade-off of Tidal’s tersity, versus Strudel’s simplicity.
|
||||
</p>
|
||||
<p>To demonstrate this, consider the following Tidal pattern:</p>
|
||||
<pre
|
||||
class="tidal"
|
||||
><code>iter 4 $ every 3 (||+ n "10 20") $ (n "0 1 3") # s "triangle" # crush 4</code></pre>
|
||||
<p>This can be directly translated to the Strudel equivalent:</p>
|
||||
<div class="sourceCode" id="cb18">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">"10 20"</span>)<span class="op">,</span> <span class="fu">n</span>(<span class="st">"0 1 3"</span>)<span class="op">.</span><span class="fu">s</span>(<span class="st">"triangle"</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)))</span></code></pre>
|
||||
</div>
|
||||
<p>Although for a more canonical Strudel expression, we would reorder it as:</p>
|
||||
<div class="sourceCode" id="cb19">
|
||||
<pre
|
||||
class="sourceCode js"
|
||||
><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">"0 1 3"</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">"10 20"</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">"triangle"</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)</span></code></pre>
|
||||
</div>
|
||||
<p>
|
||||
The Strudel example uses the <code>.</code> method call operator for all operations and combinations, whereas the
|
||||
Tidal example has <code>#</code> for the default method for combining patterns and uses infix operators for other
|
||||
methods. The lack of parenthesis in the Tidal example is partly due to the way that arguments are applied to
|
||||
Haskell’s functions, and partly due to the use of the <code>$</code> operator as an alternative way to establish
|
||||
precedence and control the order of evaluation.
|
||||
</p>
|
||||
<p>
|
||||
Considering the above, we argue that the Haskell syntax is a little cleaner, but that the Strudel syntax is easier
|
||||
to learn. Our informal observation is that while Haskell’s dollar <code>$</code> operator is very useful in making
|
||||
code easier to work with, it is one of the most difficult aspects of Tidal use for beginners to learn. On the
|
||||
other hand, the deeper levels of parenthesis in Strudel code can be difficult to keep track of, especially while
|
||||
coding under pressure of live musical performance. However this difficulty can be largely be mitigated by
|
||||
reordering expressions, and further mitigated by supporting editor features.
|
||||
</p>
|
||||
<p>
|
||||
With Strudel, we have little choice but to embrace the affordances and constraints offered by JavaScript, and
|
||||
while designing a domain-specific language entirely based on method calls is a challenge, through creative
|
||||
adoption of functional programming techniques like partial application, we are so far very happy with the results.
|
||||
Tidal’s functional reactive approach to pattern-making has in general translated well to JavaScript, and
|
||||
opportunities and constraints have overall traded off to create a very approachable and useable live coding
|
||||
environment.
|
||||
</p>
|
||||
<h2 data-number="9.1" id="the-trade-off-of-flexible-typing">
|
||||
<span class="header-section-number">9.1</span> The trade-off of flexible typing
|
||||
</h2>
|
||||
<p>
|
||||
We have identified one problem with porting Tidal to JavaScript where we have missed Haskell’s strict typing and
|
||||
type inference. In both Tidal and Strudel, time is rational, where any point in time is represented as the ratio
|
||||
of two integers. This allows representation of musical ratios such that are impossible to represent accurately
|
||||
using the more common floating point numbers. However while libraries are available that support rational numbers
|
||||
in JavaScript, the lack of strict typing means that it is easy to implement pattern methods where computationally
|
||||
expensive conversion from floating point to rational numbers are performed late, and therefore often enough to
|
||||
overload the CPUs, due to the large number of iterative calculations required to estimate a ratio for a given
|
||||
floating point number. To mitigate this problem, we might consider moving to TypeScript in the future.
|
||||
</p>
|
||||
<h1 data-number="10" id="future-outlook"><span class="header-section-number">10</span> Future Outlook</h1>
|
||||
<p>
|
||||
The project is still young, with many features on the horizon. As general guiding principles, Strudel aims to be
|
||||
</p>
|
||||
<ol type="1">
|
||||
<li>accessible</li>
|
||||
<li>consistent with Tidal’s approach to pattern</li>
|
||||
<li>modular and extensible</li>
|
||||
</ol>
|
||||
<p>
|
||||
While Haskell’s type system makes it a great language for the ongoing development of Tidal’s inner representation
|
||||
of pattern, JavaScript’s vibrant ecosystem, flexibility and accessibility makes it a great host for more ad-hoc
|
||||
experiments, including interface design. For the future, it is planned to integrate additional alternative sound
|
||||
engines such as Glicol <span class="citation" data-cites="lanChaosprintGlicol2022">(Lan [2020] 2022)</span> and
|
||||
Faust
|
||||
<span class="citation" data-cites="FaustProgrammingLanguage2022"
|
||||
>(<em>Faust - Programming Language for Audio Applications and Plugins</em> [2016] 2022)</span
|
||||
>. Strudel is already approaching feature parity with Tidal, but there are more Tidal functions to be ported, and
|
||||
work to be done to improve compatibility with Tidal’s mininotation. Tidal version 2.0 is under development, which
|
||||
brings a new representation for sequences to its patterns, which will then be brought to Strudel. Besides sound,
|
||||
other ways to render events are being explored, such as graphical, and choreographic output. We are also looking
|
||||
into alternative ways of editing patterns, including multi-user editing for network music, parsing a novel syntax
|
||||
to escape the constraints of javascript, and developing hardware/e-textile interfaces. In summary, there is a lot
|
||||
of fun ahead.
|
||||
</p>
|
||||
<h1 data-number="11" id="links"><span class="header-section-number">11</span> Links</h1>
|
||||
<p>
|
||||
The Strudel REPL is available at <a href="https://strudel.cc" class="uri">https://strudel.cc</a>, including an
|
||||
interactive tutorial. The repository is at
|
||||
<a href="https://github.com/tidalcycles/strudel" class="uri">https://github.com/tidalcycles/strudel</a>, all the
|
||||
code is open source under the AGPL-3.0 License.
|
||||
</p>
|
||||
<h1 data-number="12" id="acknowledgments"><span class="header-section-number">12</span> Acknowledgments</h1>
|
||||
<p>
|
||||
Thanks to the Strudel and wider Tidal, live coding, WebAudio and free/open source software communities for
|
||||
inspiration and support. Alex McLean’s work on this project is supported by a UKRI Future Leaders Fellowship
|
||||
[grant number MR/V025260/1].
|
||||
</p>
|
||||
<h1 class="unnumbered" id="references">References</h1>
|
||||
<div id="refs" class="references csl-bib-body hanging-indent" role="doc-bibliography">
|
||||
<div id="ref-FaustProgrammingLanguage2022" class="csl-entry" role="doc-biblioentry">
|
||||
<em>Faust - Programming Language for Audio Applications and Plugins</em>. (2016) 2022. C++. GRAME.
|
||||
<a href="https://github.com/grame-cncm/faust">https://github.com/grame-cncm/faust</a>.
|
||||
</div>
|
||||
<div id="ref-jackHydra2022" class="csl-entry" role="doc-biblioentry">
|
||||
Jack, Olivia. (2022) 2022. <em>Hydra</em>.
|
||||
<a href="https://github.com/ojack/hydra">https://github.com/ojack/hydra</a>.
|
||||
</div>
|
||||
<div id="ref-lanChaosprintGlicol2022" class="csl-entry" role="doc-biblioentry">
|
||||
Lan, Qichao. (2020) 2022. <em>Chaosprint/Glicol</em>. Rust.
|
||||
<a href="https://github.com/chaosprint/glicol">https://github.com/chaosprint/glicol</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanAlgorithmicPattern2020a" class="csl-entry" role="doc-biblioentry">
|
||||
Mclean, Alex. 2020. <span>“Algorithmic Pattern.”</span> In
|
||||
<em>Proceedings of the International Conference on New Interfaces for Musical Expression</em>, 265--270.
|
||||
Birmingham, UK. <a href="https://zenodo.org/record/4813352">https://zenodo.org/record/4813352</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanFeedforward2020" class="csl-entry" role="doc-biblioentry">
|
||||
McLean, Alex. 2020. <span>“Feedforward.”</span> In
|
||||
<em>Proceedings of New Interfaces for Musical Expression</em>. Birmingham.
|
||||
<a href="https://zenodo.org/record/6353969">https://zenodo.org/record/6353969</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanTidalVortexZero2022" class="csl-entry" role="doc-biblioentry">
|
||||
McLean, Alex, Raphaël Forment, Sylvain Le Beux, and Damián Silvani. 2022. <span>“TidalVortex Zero.”</span> In
|
||||
<em>Proceedings of the 7th International Conference on Live Coding</em>. Limerick, Ireland: Zenodo.
|
||||
<a href="https://doi.org/10.5281/zenodo.6456380">https://doi.org/10.5281/zenodo.6456380</a>.
|
||||
</div>
|
||||
<div id="ref-ogbornDktr0WebDirt2022" class="csl-entry" role="doc-biblioentry">
|
||||
Ogborn, David. (2016) 2022. <em>Dktr0/WebDirt</em>. JavaScript.
|
||||
<a href="https://github.com/dktr0/WebDirt">https://github.com/dktr0/WebDirt</a>.
|
||||
</div>
|
||||
<div id="ref-ogbornEstuaryBrowserbasedCollaborative2017" class="csl-entry" role="doc-biblioentry">
|
||||
Ogborn, David, Jamie Beverley, Luis Navarro del Angel, Eldad Tsabary, and Alex McLean. 2017.
|
||||
<span>“Estuary: Browser-Based Collaborative Projectional Live Coding of Musical Patterns.”</span> In
|
||||
<em>Proceedings of the International Conference on Live Coding</em>, 11. Morelia.
|
||||
</div>
|
||||
<div id="ref-robertsGibberLiveCoding2012" class="csl-entry" role="doc-biblioentry">
|
||||
Roberts, Charles, and Joann Kuchera-morin. 2012. <span>“Gibber: Live Coding Audio in the Browser.”</span> In
|
||||
<em>In Proceedings of the 2012 International Computer Music Conference</em>.
|
||||
</div>
|
||||
<div id="ref-StrudelWAC2022" class="csl-entry" role="doc-biblioentry">
|
||||
Roos, Felix, and Alex McLean. 2022. <span>“Strudel: Algorithmic Patterns for the Web.”</span> In. Zenodo.
|
||||
<a href="https://doi.org/10.5281/zenodo.6768844">https://doi.org/10.5281/zenodo.6768844</a>.
|
||||
</div>
|
||||
<div id="ref-solomonPurescriptocarina2022" class="csl-entry" role="doc-biblioentry">
|
||||
Solomon, Mike. (2021) 2022. <em>Purescript-Ocarina</em>. PureScript.
|
||||
<a href="https://github.com/mikesol/purescript-ocarina">https://github.com/mikesol/purescript-ocarina</a>.
|
||||
</div>
|
||||
<div id="ref-SuperDirt2022" class="csl-entry" role="doc-biblioentry">
|
||||
<em>SuperDirt</em>. (2015) 2022. SuperCollider. musikinformatik.
|
||||
<a href="https://github.com/musikinformatik/SuperDirt">https://github.com/musikinformatik/SuperDirt</a>.
|
||||
</div>
|
||||
<div id="ref-toussaintEuclideanAlgorithmGenerates2005" class="csl-entry" role="doc-biblioentry">
|
||||
Toussaint, Godfried. 2005. <span>“The Euclidean Algorithm Generates Traditional Musical Rhythms.”</span> In
|
||||
<em>In Proceedings of BRIDGES: Mathematical Connections in Art, Music and Science</em>, 47–56.
|
||||
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231"
|
||||
>http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231</a
|
||||
>.
|
||||
</div>
|
||||
<div id="ref-CsoundWebAssembly" class="csl-entry" role="doc-biblioentry">
|
||||
Yi, Steven, Victor Lazzarini, and Edward Costello. 2018.
|
||||
<span>“WebAssembly AudioWorklet Csound.”</span> In. Berlin, Germany.
|
||||
<a href="https://mural.maynoothuniversity.ie/16018/">https://mural.maynoothuniversity.ie/16018/</a>.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -451,7 +451,7 @@ While Haskell's type system makes it a great language for the ongoing developmen
|
||||
# Links
|
||||
|
||||
The Strudel REPL is available at <https://strudel.cc>, including an interactive tutorial.
|
||||
The repository is at <https://github.com/tidalcycles/strudel>, all the code is open source under the AGPL-3.0 License.
|
||||
The repository is at <https://codeberg.org/uzu/strudel>, all the code is open source under the AGPL-3.0 License.
|
||||
|
||||
# Acknowledgments
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 220 KiB |
|
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 83 KiB |
@@ -0,0 +1,63 @@
|
||||
$if(false)$ This is a pandoc template and should not be edited. $endif$
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" $if(lang)$ lang="$lang$" xml:lang="$lang$" $endif$>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$ $if(date-meta)$
|
||||
<meta name="date" content="$date-meta$" />
|
||||
$endif$
|
||||
<title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
|
||||
<style type="text/css">
|
||||
code {
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
$if(quotes)$
|
||||
<style type="text/css">
|
||||
q {
|
||||
quotes: '“' '”' '‘' '’';
|
||||
}
|
||||
</style>
|
||||
$endif$ $if(highlighting-css)$
|
||||
<style type="text/css">
|
||||
$highlighting-css$
|
||||
</style>
|
||||
$endif$
|
||||
<link rel="stylesheet" href="css/iclc.css" $if(html5)$$else$type="text/css" $endif$ />
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" $if(html5)$$else$type="text/css" $endif$ />
|
||||
$endfor$ $if(math)$ $math$ $endif$ $for(header-includes)$ $header-includes$ $endfor$
|
||||
</head>
|
||||
<body>
|
||||
$for(include-before)$ $include-before$ $endfor$ $if(title)$
|
||||
<div id="$idprefix$header">
|
||||
<h1 class="title">$title$</h1>
|
||||
$if(subtitle)$
|
||||
<h1 class="subtitle">$subtitle$</h1>
|
||||
$endif$
|
||||
<ul id="authorlist">
|
||||
$for(author)$
|
||||
<li>$author$</li>
|
||||
$endfor$
|
||||
</ul>
|
||||
$if(date)$
|
||||
<h3 class="date">$date$</h3>
|
||||
$endif$
|
||||
</div>
|
||||
$endif$ $if(toc)$
|
||||
<div id="$idprefix$TOC">$toc$</div>
|
||||
$endif$
|
||||
|
||||
<h2 class="abstract">Abstract</h2>
|
||||
<div id="abstract">
|
||||
$if(abstract)$ $abstract$ $else$ Please provide an abstract in the metadata block at the top of your markdown
|
||||
document. Refer to template.txt for details. $endif$
|
||||
</div>
|
||||
|
||||
$body$ $for(include-after)$ $include-after$ $endfor$
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,4 +1,8 @@
|
||||
This document introduces you to Strudel in a technical sense. If you just want to *use* Strudel, have a look at the [Tutorial](https://strudel.tidalcycles.org/tutorial/).
|
||||
This document introduces you to Strudel in a technical sense.
|
||||
|
||||
It is rather out of date, but there might still be useful info below.
|
||||
|
||||
If you just want to *use* Strudel, have a look at the [Tutorial](https://strudel.tidalcycles.org/tutorial/).
|
||||
|
||||
## Strudel Packages
|
||||
|
||||
@@ -17,11 +21,11 @@ More info in the [REPL README](https://codeberg.org/uzu/strudel/src/branch/main/
|
||||
|
||||
# High Level Overview
|
||||
|
||||
<img src="https://github.com/tidalcycles/strudel/blob/talk/talk/public/strudelflow.png?raw=true" width="600" />
|
||||
<img src="strudelflow.png" width="600" />
|
||||
|
||||
## 1. End User Code
|
||||
|
||||
The End User Code is written in JavaScript with added syntax sugar. The [eval package](https://codeberg.org/uzu/strudel/src/branch/main/packages/eval#strudelcycleseval) evaluates the user code
|
||||
The 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
|
||||
after 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.
|
||||
|
||||
### 🍭 Syntax Sugar
|
||||
@@ -54,13 +58,13 @@ This is how it works:
|
||||
- The AST is transformed to resolve the syntax sugar
|
||||
- The AST is used to generate code again (shift-codegen)
|
||||
|
||||
Shift will most likely be replaced with acorn in the future, see https://codeberg.org/uzu/strudel/issues/174
|
||||
Shift will most likely be replaced with acorn in the future, see https://github.com/tidalcycles/strudel/issues/174
|
||||
|
||||
### Mini Notation
|
||||
|
||||
Another important part of the user code is the mini notation, which allows to express rhythms in a short manner.
|
||||
|
||||
- the mini notation is [implemented as a PEG grammar](https://codeberg.org/uzu/strudel/src/branch/main/packages/mini/krill.pegjs), living in the [mini package](https://codeberg.org/uzu/strudel/src/branch/main/packages/mini)
|
||||
- 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)
|
||||
- it is based on [krill](https://github.com/Mdashdotdashn/krill) by Mdashdotdashn
|
||||
- the peg grammar is used to generate a parser with [peggyjs](https://peggyjs.org/)
|
||||
- the generated parser takes a mini notation string and outputs an AST
|
||||
@@ -171,7 +175,7 @@ Here is an example Hap value with different properties:
|
||||
```js
|
||||
{ note: 'a4', s: 'sawtooth', gain: 0.5, cutoff: 267 }
|
||||
```
|
||||
<img src="https://github.com/tidalcycles/strudel/blob/talk/talk/public/waa-nodes.png?raw=true" width="600" />
|
||||
<img src="waa-nodes.png" width="600" />
|
||||
|
||||
<div className="text-left">
|
||||
|
||||
@@ -182,12 +186,12 @@ Here is an example Hap value with different properties:
|
||||
|
||||
At the time of writing this doc, the following outputs are supported:
|
||||
|
||||
- Web Audio API `.out()` see [/webaudio](https://codeberg.org/uzu/strudel/src/branch/main/packages/webaudio)
|
||||
- MIDI `.midi()` see [/midi](https://codeberg.org/uzu/strudel/src/branch/main/packages/midi)
|
||||
- OSC `.osc()` see [/osc](https://codeberg.org/uzu/strudel/src/branch/main/packages/osc)
|
||||
- Serial `.serial()` see [/serial](https://codeberg.org/uzu/strudel/src/branch/main/packages/serial)
|
||||
- Tone.js `.tone()` (deprecated?) [/tone](https://codeberg.org/uzu/strudel/src/branch/main/packages/tone)
|
||||
- WebDirt `.webdirt()` (deprecated?) [/webdirt](https://codeberg.org/uzu/strudel/src/branch/main/packages/webdirt)
|
||||
- Speech `.speak()` (experimental) part of [/core](https://codeberg.org/uzu/strudel/src/branch/main/packages/core)
|
||||
- Web Audio API `.out()` see [/webaudio](https://github.com/tidalcycles/strudel/tree/main/packages/webaudio)
|
||||
- MIDI `.midi()` see [/midi](https://github.com/tidalcycles/strudel/tree/main/packages/midi)
|
||||
- OSC `.osc()` see [/osc](https://github.com/tidalcycles/strudel/tree/main/packages/osc)
|
||||
- Serial `.serial()` see [/serial](https://github.com/tidalcycles/strudel/tree/main/packages/serial)
|
||||
- Tone.js `.tone()` (deprecated?) [/tone](https://github.com/tidalcycles/strudel/tree/main/packages/tone)
|
||||
- WebDirt `.webdirt()` (deprecated?) [/webdirt](https://github.com/tidalcycles/strudel/tree/main/packages/webdirt)
|
||||
- Speech `.speak()` (experimental) part of [/core](https://github.com/tidalcycles/strudel/tree/main/packages/core)
|
||||
|
||||
These could change, so make sure to check the [packages folder](https://codeberg.org/uzu/strudel/src/branch/main/packages).
|
||||
These could change, so make sure to check the [packages folder](https://github.com/tidalcycles/strudel/tree/main/packages).
|
||||
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 49 KiB |
@@ -2,4 +2,4 @@
|
||||
|
||||
Each folder represents one of the @strudel/* packages [published to npm](https://www.npmjs.com/org/strudel).
|
||||
|
||||
To understand how those pieces connect, refer to the [Technical Manual](https://codeberg.org/uzu/strudel/src/branch/main/technical-manual.md) or the individual READMEs.
|
||||
To understand how those pieces connect, refer to the [Technical Manual](https://codeberg.org/uzu/strudel/wiki/Technical-Manual) or the individual READMEs.
|
||||
|
||||
@@ -10,9 +10,9 @@ https://rohandrape.net/?t=hmt
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Pattern, timeCat, register, silence } from './pattern.mjs';
|
||||
import { timeCat, register, silence } from './pattern.mjs';
|
||||
import { rotate, flatten, splitAt, zipWith } from './util.mjs';
|
||||
import Fraction from './fraction.mjs';
|
||||
import Fraction, { lcm } from './fraction.mjs';
|
||||
|
||||
const left = function (n, x) {
|
||||
const [ons, offs] = n;
|
||||
@@ -42,29 +42,26 @@ const _bjork = function (n, x) {
|
||||
|
||||
export const bjork = function (ons, steps) {
|
||||
const inverted = ons < 0;
|
||||
ons = Math.abs(ons);
|
||||
const offs = steps - ons;
|
||||
const x = Array(ons).fill([1]);
|
||||
const y = Array(offs).fill([0]);
|
||||
const result = _bjork([ons, offs], [x, y]);
|
||||
const p = flatten(result[1][0]).concat(flatten(result[1][1]));
|
||||
if (inverted) {
|
||||
return p.map((x) => (x === 0 ? 1 : 0));
|
||||
}
|
||||
return p;
|
||||
const absOns = Math.abs(ons);
|
||||
const offs = steps - absOns;
|
||||
const ones = Array(absOns).fill([1]);
|
||||
const zeros = Array(offs).fill([0]);
|
||||
const result = _bjork([absOns, offs], [ones, zeros]);
|
||||
const pattern = flatten(result[1][0]).concat(flatten(result[1][1]));
|
||||
return inverted ? pattern.map((x) => 1 - x) : pattern;
|
||||
};
|
||||
|
||||
/**
|
||||
* Changes the structure of the pattern to form an euclidean rhythm.
|
||||
* Euclidian rhythms are rhythms obtained using the greatest common
|
||||
* Changes the structure of the pattern to form an Euclidean rhythm.
|
||||
* Euclidean rhythms are rhythms obtained using the greatest common
|
||||
* divisor of two numbers. They were described in 2004 by Godfried
|
||||
* Toussaint, a canadian computer scientist. Euclidian rhythms are
|
||||
* Toussaint, a Canadian computer scientist. Euclidean rhythms are
|
||||
* really useful for computer/algorithmic music because they can
|
||||
* describe a large number of rhythms with a couple of numbers.
|
||||
*
|
||||
* @memberof Pattern
|
||||
* @name euclid
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} pulses the number of onsets/beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @returns Pattern
|
||||
* @example
|
||||
@@ -76,7 +73,7 @@ export const bjork = function (ons, steps) {
|
||||
* Like `euclid`, but has an additional parameter for 'rotating' the resulting sequence.
|
||||
* @memberof Pattern
|
||||
* @name euclidRot
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} pulses the number of onsets/beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @param {number} rotation offset in steps
|
||||
* @returns Pattern
|
||||
@@ -86,13 +83,13 @@ export const bjork = function (ons, steps) {
|
||||
*/
|
||||
|
||||
/**
|
||||
* @example // A thirteenth century Persian rhythm called Khafif-e-ramal.
|
||||
* @example // A thirteenth-century Persian rhythm called Khafif-e-ramal.
|
||||
* note("c3").euclid(2,5)
|
||||
* @example // The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.
|
||||
* note("c3").euclid(3,4)
|
||||
* @example // Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.
|
||||
* note("c3").euclidRot(3,5,2)
|
||||
* @example // A Ruchenitza rhythm used in a Bulgarian folk-dance.
|
||||
* @example // A Ruchenitza rhythm used in a Bulgarian folk dance.
|
||||
* note("c3").euclid(3,7)
|
||||
* @example // The Cuban tresillo pattern.
|
||||
* note("c3").euclid(3,8)
|
||||
@@ -151,8 +148,10 @@ export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], fun
|
||||
* so there will be no gaps.
|
||||
* @name euclidLegato
|
||||
* @memberof Pattern
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} pulses the number of onsets/beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @param rotation offset in steps
|
||||
* @param pat
|
||||
* @example
|
||||
* note("c3").euclidLegato(3,8)
|
||||
*/
|
||||
@@ -161,13 +160,13 @@ const _euclidLegato = function (pulses, steps, rotation, pat) {
|
||||
if (pulses < 1) {
|
||||
return silence;
|
||||
}
|
||||
const bin_pat = _euclidRot(pulses, steps, rotation);
|
||||
const bin_pat = _euclidRot(pulses, steps, 0);
|
||||
const gapless = bin_pat
|
||||
.join('')
|
||||
.split('1')
|
||||
.slice(1)
|
||||
.map((s) => [s.length + 1, true]);
|
||||
return pat.struct(timeCat(...gapless));
|
||||
return pat.struct(timeCat(...gapless)).late(Fraction(rotation).div(steps));
|
||||
};
|
||||
|
||||
export const euclidLegato = register(['euclidLegato'], function (pulses, steps, pat) {
|
||||
@@ -180,7 +179,7 @@ export const euclidLegato = register(['euclidLegato'], function (pulses, steps,
|
||||
* the resulting sequence
|
||||
* @name euclidLegatoRot
|
||||
* @memberof Pattern
|
||||
* @param {number} pulses the number of onsets / beats
|
||||
* @param {number} pulses the number of onsets/beats
|
||||
* @param {number} steps the number of steps to fill
|
||||
* @param {number} rotation offset in steps
|
||||
* @example
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
numeralArgs,
|
||||
parseNumeral,
|
||||
pairs,
|
||||
noteToMidi,
|
||||
} from './util.mjs';
|
||||
import drawLine from './drawLine.mjs';
|
||||
import { logger } from './logger.mjs';
|
||||
@@ -3340,3 +3341,45 @@ export const { beat } = register(
|
||||
['beat'],
|
||||
__beat((x) => x.innerJoin()),
|
||||
);
|
||||
|
||||
const __quantizeBy = (lens, scale, pat) => {
|
||||
// Supports ':' list syntax in mininotation
|
||||
scale = (Array.isArray(scale) ? scale.flat() : [scale]).flatMap((val) =>
|
||||
typeof val === 'number' ? val : noteToMidi(val) - 48,
|
||||
);
|
||||
|
||||
return pat.withHap((hap) => {
|
||||
const isObject = typeof hap.value === 'object';
|
||||
let note = isObject ? hap.value.n : hap.value;
|
||||
if (typeof note === 'number') {
|
||||
note = note;
|
||||
}
|
||||
if (typeof note === 'string') {
|
||||
note = noteToMidi(note);
|
||||
}
|
||||
|
||||
if (isObject) {
|
||||
delete hap.value.n; // remove n so it won't cause trouble
|
||||
}
|
||||
const octave = (note / lens) >> 0;
|
||||
const transpose = octave * lens;
|
||||
|
||||
const goal = note - transpose;
|
||||
note =
|
||||
scale.reduce((prev, curr) => {
|
||||
return Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev;
|
||||
}) + transpose;
|
||||
|
||||
return hap.withValue(() => (isObject ? { ...hap.value, note } : note));
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Snap note values to a chosen array of notes within a 12 note/octave scale
|
||||
* @name quantize
|
||||
* @example
|
||||
* note(irand(35).add(48).seg(16).quantize("d:a:a#:f")).s("pulse")
|
||||
*/
|
||||
export const { quantize } = register(['quantize'], (scale, pat) => {
|
||||
return __quantizeBy(12, scale, pat);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
controls.test.mjs - <short description TODO>
|
||||
Copyright (C) 2023 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/controls.test.mjs>
|
||||
Copyright (C) 2023 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/controls.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
drawLine.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/drawLine.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/drawLine.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { bjork } from '../euclid.mjs';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { fastcat } from '../pattern.mjs';
|
||||
|
||||
describe('bjork', () => {
|
||||
it('should apply bjorklund to ons and steps', () => {
|
||||
expect(bjork(3, 8)).toStrictEqual([1, 0, 0, 1, 0, 0, 1, 0]);
|
||||
expect(bjork(-3, 8)).toStrictEqual([0, 1, 1, 0, 1, 1, 0, 1]);
|
||||
expect(bjork(8, 8)).toStrictEqual([1, 1, 1, 1, 1, 1, 1, 1]);
|
||||
expect(bjork(-8, 8)).toStrictEqual([0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
expect(bjork(5, 8)).toStrictEqual([1, 0, 1, 1, 0, 1, 1, 0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('euclid', () => {
|
||||
it('Can create euclid', () => {
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclid(3, 8)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/8: a', '3/8 → 1/2: a', '3/4 → 7/8: a']);
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclid(5, 8)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/8: a', '1/4 → 3/8: a', '3/8 → 1/2: a', '5/8 → 3/4: a', '3/4 → 7/8: a']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('euclidRot', () => {
|
||||
it('Can create euclidRot', () => {
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidRot(3, 8, 2)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/8: a', '1/4 → 3/8: a', '5/8 → 3/4: a']);
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidRot(5, 8, 2)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/8: a', '1/4 → 3/8: a', '1/2 → 5/8: a', '5/8 → 3/4: a', '7/8 → 1/1: a']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('euclidLegato', () => {
|
||||
it('Can create euclidLegato', () => {
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidLegato(3, 8)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 3/8: a', '3/8 → 3/4: a', '3/4 → 1/1: a']);
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidLegato(5, 8)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/4: a', '1/4 → 3/8: a', '3/8 → 5/8: a', '5/8 → 3/4: a', '3/4 → 1/1: a']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('euclidLegatoRot', () => {
|
||||
it('Can create euclidLegatoRot', () => {
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidLegatoRot(3, 8, 2)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/4: a', '1/4 → 5/8: a', '5/8 → 1/1: a']);
|
||||
expect(
|
||||
fastcat('a')
|
||||
.euclidLegatoRot(5, 8, 2)
|
||||
.firstCycle()
|
||||
.sort((a, b) => a.part.begin.sub(b.part.begin))
|
||||
.map((a) => a.showWhole(true)),
|
||||
).toStrictEqual(['0/1 → 1/4: a', '1/4 → 1/2: a', '1/2 → 5/8: a', '5/8 → 7/8: a', '7/8 → 1/1: a']);
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
fraction.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/fraction.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/fraction.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
pattern.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/pattern.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/pattern.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
@@ -884,7 +884,7 @@ describe('Pattern', () => {
|
||||
);
|
||||
});
|
||||
it('Doesnt drop haps in the 9th cycle', () => {
|
||||
// fixed with https://github.com/tidalcycles/strudel/commit/72eeaf446e3d5e186d63cc0d2276f0723cde017a
|
||||
// fixed with https://codeberg.org/uzu/strudel/commit/72eeaf446e3d5e186d63cc0d2276f0723cde017a
|
||||
expect(sequence(1, 2, 3).ply(2).early(8).firstCycle().length).toBe(6);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
/*
|
||||
util.test.mjs - Tests for the core 'util' module
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/test/util.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/core/test/util.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { pure } from '../pattern.mjs';
|
||||
import {
|
||||
isNote,
|
||||
tokenizeNote,
|
||||
noteToMidi,
|
||||
midiToFreq,
|
||||
freqToMidi,
|
||||
_mod,
|
||||
compose,
|
||||
flatten,
|
||||
fractionalArgs,
|
||||
freqToMidi,
|
||||
getFrequency,
|
||||
getPlayableNoteValue,
|
||||
parseNumeral,
|
||||
parseFractional,
|
||||
isNote,
|
||||
midiToFreq,
|
||||
noteToMidi,
|
||||
numeralArgs,
|
||||
fractionalArgs,
|
||||
parseFractional,
|
||||
parseNumeral,
|
||||
rotate,
|
||||
splitAt,
|
||||
tokenizeNote,
|
||||
zipWith,
|
||||
} from '../util.mjs';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('isNote', () => {
|
||||
it('should recognize notes without accidentals', () => {
|
||||
@@ -233,3 +237,46 @@ describe('fractionalArgs', () => {
|
||||
expect(add('q', 2)).toBe(2.25);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rotate', () => {
|
||||
it('should rotate array to the left', () => {
|
||||
expect(rotate([0, 1, 2, 3], 2)).toStrictEqual([2, 3, 0, 1]);
|
||||
expect(rotate([0, 1, 2, 3], 0)).toStrictEqual([0, 1, 2, 3]);
|
||||
expect(rotate([0, 1, 2, 3], -3)).toStrictEqual([1, 2, 3, 0]);
|
||||
expect(rotate([0, 1, 2, 3], 3)).toStrictEqual([3, 0, 1, 2]);
|
||||
expect(rotate([0], 3)).toStrictEqual([0]);
|
||||
expect(rotate([], 3)).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('flatten', () => {
|
||||
it('should flatten array by one level', () => {
|
||||
expect(flatten([0, 1, 2, 3])).toStrictEqual([0, 1, 2, 3]);
|
||||
expect(flatten([0, 1, [2, 3]])).toStrictEqual([0, 1, 2, 3]);
|
||||
expect(flatten([0, [1, [2, 3]]])).toStrictEqual([0, 1, [2, 3]]);
|
||||
expect(flatten([0])).toStrictEqual([0]);
|
||||
expect(flatten([])).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('splitAt', () => {
|
||||
it('should split array into two', () => {
|
||||
expect(splitAt(2, [0, 1, 2, 3])).toStrictEqual([
|
||||
[0, 1],
|
||||
[2, 3],
|
||||
]);
|
||||
expect(splitAt(0, [0, 1, 2, 3])).toStrictEqual([[], [0, 1, 2, 3]]);
|
||||
expect(splitAt(-3, [0, 1, 2, 3])).toStrictEqual([[0], [1, 2, 3]]);
|
||||
expect(splitAt(3, [0, 1, 2, 3])).toStrictEqual([[0, 1, 2], [3]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('zipWith', () => {
|
||||
it('should use the function to combine the two arrays element-wise', () => {
|
||||
expect(zipWith((a, b) => a + b, [0, 1, 2, 3], [0, 1, 2, 3])).toStrictEqual([0, 2, 4, 6]);
|
||||
expect(zipWith((a, b) => a + b, [0, 1, 2, 3], [0, 1, 2])).toStrictEqual([0, 2, 4, NaN]);
|
||||
expect(zipWith((a, b) => a + b, [0, 1, 2], [0, 1, 2, 3])).toStrictEqual([0, 2, 4]);
|
||||
expect(zipWith((a) => a, [0, 1, 2], [1, 2, 3, 0])).toStrictEqual([0, 1, 2]);
|
||||
expect(zipWith((a, b) => b, [0, 1, 2], [1, 2, 3, 0])).toStrictEqual([1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -162,6 +162,7 @@ export const compose = (...funcs) => pipe(...funcs.reverse());
|
||||
// Removes 'None' values from given list
|
||||
export const removeUndefineds = (xs) => xs.filter((x) => x != undefined);
|
||||
|
||||
// flattens by one level
|
||||
export const flatten = (arr) => [].concat(...arr);
|
||||
|
||||
export const id = (a) => a;
|
||||
@@ -237,6 +238,7 @@ export const splitAt = function (index, value) {
|
||||
return [value.slice(0, index), value.slice(index)];
|
||||
};
|
||||
|
||||
// Uses the function f to combine the arrays xs, ys element-wise
|
||||
export const zipWith = (f, xs, ys) => xs.map((n, i) => f(n, ys[i]));
|
||||
|
||||
export const pairs = function (xs) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
mini.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/mini/test/mini.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/mini/test/mini.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ You can also pin the version like this:
|
||||
```
|
||||
|
||||
This has the advantage that your code will always work, regardless of potential breaking changes in the strudel codebase.
|
||||
See [releases](https://github.com/tidalcycles/strudel/releases) for the latest versions.
|
||||
See [releases](https://codeberg.org/uzu/strudel/releases) for the latest versions.
|
||||
|
||||
## Use Web Component
|
||||
|
||||
@@ -91,7 +91,7 @@ or
|
||||
</script>
|
||||
```
|
||||
|
||||
The `.editor` property on the `strudel-editor` web component gives you the instance of [StrudelMirror](https://github.com/tidalcycles/strudel/blob/a46bd9b36ea7d31c9f1d3fca484297c7da86893f/packages/codemirror/codemirror.mjs#L124) that runs the REPL.
|
||||
The `.editor` property on the `strudel-editor` web component gives you the instance of [StrudelMirror](https://codeberg.org/uzu/strudel/src/branch/a46bd9b36ea7d31c9f1d3fca484297c7da86893f/packages/codemirror/codemirror.mjs#L124) that runs the REPL.
|
||||
|
||||
For example, you could use `setCode` to change the code from the outside, `start` / `stop` to toggle playback or `evaluate` to evaluate the code.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
tonal.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/tonal/test/tonal.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/tonal/test/tonal.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
tonleiter.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/tonal/test/tonleiter.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/tonal/test/tonleiter.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
transpiler.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/transpiler/test/transpiler.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/transpiler/test/transpiler.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
xen.test.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/xen/test/xen.test.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/packages/xen/test/xen.test.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,818 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="date" content="2022-12-14" />
|
||||
<title>Strudel: live coding patterns on the Web</title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
<style type="text/css">
|
||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||
.sourceCode { overflow: visible; }
|
||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||
div.sourceCode { margin: 1em 0; }
|
||||
pre.sourceCode { margin: 0; }
|
||||
@media screen {
|
||||
div.sourceCode { overflow: auto; }
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode { white-space: pre-wrap; }
|
||||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||||
}
|
||||
pre.numberSource code
|
||||
{ counter-reset: source-line 0; }
|
||||
pre.numberSource code > span
|
||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||
pre.numberSource code > span > a:first-child::before
|
||||
{ content: counter(source-line);
|
||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||
border: none; display: inline-block;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
-khtml-user-select: none; -moz-user-select: none;
|
||||
-ms-user-select: none; user-select: none;
|
||||
padding: 0 4px; width: 4em;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||||
div.sourceCode
|
||||
{ }
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||
}
|
||||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||||
code span.at { color: #7d9029; } /* Attribute */
|
||||
code span.bn { color: #40a070; } /* BaseN */
|
||||
code span.bu { color: #008000; } /* BuiltIn */
|
||||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||||
code span.ch { color: #4070a0; } /* Char */
|
||||
code span.cn { color: #880000; } /* Constant */
|
||||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||||
code span.dt { color: #902000; } /* DataType */
|
||||
code span.dv { color: #40a070; } /* DecVal */
|
||||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||||
code span.ex { } /* Extension */
|
||||
code span.fl { color: #40a070; } /* Float */
|
||||
code span.fu { color: #06287e; } /* Function */
|
||||
code span.im { color: #008000; font-weight: bold; } /* Import */
|
||||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||||
code span.op { color: #666666; } /* Operator */
|
||||
code span.ot { color: #007020; } /* Other */
|
||||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||||
code span.ss { color: #bb6688; } /* SpecialString */
|
||||
code span.st { color: #4070a0; } /* String */
|
||||
code span.va { color: #19177c; } /* Variable */
|
||||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||||
</style>
|
||||
<link rel="stylesheet" href="css/iclc.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="header">
|
||||
<h1 class="title">Strudel: live coding patterns on the Web</h1>
|
||||
<ul id="authorlist">
|
||||
<li>true</li>
|
||||
<li>true</li>
|
||||
</ul>
|
||||
<h3 class="date">2022-12-14</h3>
|
||||
</div>
|
||||
|
||||
<h2 class="abstract">Abstract</h2>
|
||||
<div id="abstract">
|
||||
<p>This paper introduces Strudel, which brings the TidalCycles approach
|
||||
to live coding algorithmic patterns to native JavaScript and the web. We
|
||||
begin by giving a little background of the first year of development,
|
||||
before sharing some detail about its implementation and examples of use.
|
||||
We go on to outline the wide range of synthesis and other outputs
|
||||
available in Strudel, including WebAudio, MIDI, OSC (for SuperDirt),
|
||||
WebSerial and CSound, and introduce Strudel’s REPL live editor,
|
||||
including its built-in visualisations. We then compare Strudel with
|
||||
Tidal, the trade-offs involved between JavaScript and Haskell, and the
|
||||
unique capabilities offered by Strudel for aligning patterns.</p>
|
||||
</div>
|
||||
|
||||
<h1 data-number="1" id="introduction"><span
|
||||
class="header-section-number">1</span> Introduction</h1>
|
||||
<p>In the following paper, we introduce <em>Strudel</em>, an alternative
|
||||
implementation of the TidalCycles (or ‘Tidal’ for short) live coding
|
||||
system, using the JavaScript programming language. Strudel is an attempt
|
||||
to make live coding more accessible, by creating a system that runs
|
||||
entirely in the browser, while opening Tidal’s approach to algorithmic
|
||||
patterns <span class="citation"
|
||||
data-cites="mcleanAlgorithmicPattern2020a">(Mclean 2020)</span> up to
|
||||
modern audio/visual web technologies. The Strudel REPL is a live code
|
||||
editor dedicated to manipulating patterns while they play, with builtin
|
||||
visual feedback. While Strudel is written in JavaScript, the API is
|
||||
optimized for simplicity and readability by applying code
|
||||
transformations on the syntax tree level, allowing language operations
|
||||
that would otherwise be impossible. The application supports multiple
|
||||
ways to output sound, including Tone.js, Web Audio Nodes, OSC (Open
|
||||
Sound Control) messages, Web Serial, Web MIDI and Csound. The project is
|
||||
split into multiple packages, allowing granular reuse in other
|
||||
applications. Apart from TidalCycles, Strudel draws inspiration from
|
||||
many prior existing projects like TidalVortex <span class="citation"
|
||||
data-cites="mcleanTidalVortexZero2022">(McLean et al. 2022)</span>,
|
||||
Gibber <span class="citation"
|
||||
data-cites="robertsGibberLiveCoding2012">(Roberts and Kuchera-morin
|
||||
2012)</span>, Estuary <span class="citation"
|
||||
data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al.
|
||||
2017)</span>, Hydra <span class="citation"
|
||||
data-cites="jackHydra2022">(Jack [2022] 2022)</span>, Ocarina <span
|
||||
class="citation" data-cites="solomonPurescriptocarina2022">(Solomon
|
||||
[2021] 2022)</span> and Feedforward <span class="citation"
|
||||
data-cites="mcleanFeedforward2020">(McLean 2020)</span>. This paper
|
||||
expands the Strudel Demo paper for the Web Audio Conference 2022 <span
|
||||
class="citation" data-cites="StrudelWAC2022">(Roos and McLean
|
||||
2022)</span>.</p>
|
||||
<p>The first tentative commit to the Strudel project was on 22nd January
|
||||
2022 by Alex McLean, with the core representation implemented over the
|
||||
following few days. Although this was his first attempt at a
|
||||
JavaScript-based application, by 27th January, Alex had managed to
|
||||
upload the initial version to the ‘npm’ javascript package database,
|
||||
sharing with the wider community for comment. By 4th February, Felix
|
||||
Roos had discovered Strudel and contributed a ‘REPL’ user interface to
|
||||
it, and then contributed a scheduler the next day, so that Strudel could
|
||||
already make sound. At this point, Alex and Felix shared ownership to
|
||||
the repository, and the project has since proved to be a productive
|
||||
confluence of Felix’s own work into music representation and
|
||||
visualisation, with Alex’s experience with making Tidal. Felix has since
|
||||
become the primary contributor to Strudel, with Alex continuing to jump
|
||||
between developing both Strudel and Tidal. Aspects of Strudel’s
|
||||
development have therefore fed back into TidalCycles, and both systems
|
||||
have maintained a shared conceptual underpinning. We plan to continue
|
||||
working towards feature parity between these systems, although within
|
||||
the syntactical trade-offs and library ecosystems of JavaScript and
|
||||
Haskell, some divergence is inevitable and healthy.</p>
|
||||
<p>Over the first year of its life, Strudel is now a fully-fledged live
|
||||
coding environment, porting Tidal’s core represention of patterns,
|
||||
pattern transformations, and mininotation for polymetric sequences,
|
||||
combined with a wealth of features for synthesising and visualising
|
||||
those patterns.</p>
|
||||
<h1 data-number="2" id="from-tidal-to-strudel-and-back"><span
|
||||
class="header-section-number">2</span> From Tidal to Strudel and
|
||||
back</h1>
|
||||
<p>As mentioned above, the original Tidal is implemented as a domain
|
||||
specific language (DSL) embedded in the Haskell pure functional
|
||||
programming language, and takes advantage of Haskell’s terse syntax and
|
||||
advanced, ‘strong’ type system. JavaScript on the other hand, is a
|
||||
multi-paradigm programming language, with a dynamic type system. Because
|
||||
Tidal leans heavily on many of Haskell’s more unique features, it was
|
||||
not always clear that it could meaningfully be ported to a
|
||||
multi-paradigm scripting language. However, this possibility was already
|
||||
demonstrated with an earlier port to Python [TidalVortex; <span
|
||||
class="citation" data-cites="mcleanTidalVortexZero2022">McLean et al.
|
||||
(2022)</span>], and we have now successfully implemented Tidal’s pure
|
||||
functional representation of patterns in Strudel, including partial
|
||||
application, currying, and the functor, applicative and monadic
|
||||
structures that underlie Tidal’s expressive pattern transformations. The
|
||||
result is a terse and highly composable system, where everything is
|
||||
either a pattern, or a function for combining and manipulating patterns,
|
||||
offering a rich creative ground for exploration.</p>
|
||||
<p>This development process has been far from a one-way port, however.
|
||||
The process of porting Tidal’s concepts has also opened up new
|
||||
possibilities, some just from revisiting every design decision, and some
|
||||
from the particular affordances and constraints offered by JavaScript.
|
||||
This has lead to new features (and indeed bugfixes) that have found
|
||||
their way back to Tidal where appropriate, and ongoing work that we will
|
||||
return to in the conclusion of this paper.</p>
|
||||
<h1 data-number="3" id="representing-patterns"><span
|
||||
class="header-section-number">3</span> Representing Patterns</h1>
|
||||
<p>Patterns are the essence of Tidal. Its patterns are abstract entities
|
||||
that represent flows of time as functions, adapting a technique called
|
||||
pure functional reactive programming. Taking a time span as its input, a
|
||||
Pattern can output a set of events that happen within that time span. It
|
||||
depends on the structure of the Pattern how the events are located in
|
||||
time. From now on, this process of generating events from a time span
|
||||
will be called <strong>querying</strong>. Example:</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><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>
|
||||
<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>
|
||||
<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">=></span> e<span class="op">.</span><span class="fu">show</span>()))</span></code></pre></div>
|
||||
<p>In this example, we create a pattern using the <code>sequence</code>
|
||||
function and <strong>query</strong> it for the time span from
|
||||
<code>0</code> to <code>1</code>. Those numbers represent units of time
|
||||
called <strong>cycles</strong>. The length of one cycle depends on the
|
||||
tempo, which defaults to one cycle per second. The resulting events
|
||||
are:</p>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode js"><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">'c3'</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>
|
||||
<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">'e3'</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>
|
||||
<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">'g3'</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></div>
|
||||
<p>Each event has a value, a begin time and an end time, where time is
|
||||
represented as a fraction. In the above case, the events are placed in
|
||||
sequential order, where c3 takes the first half, and e3 and g3 together
|
||||
take the second half. This temporal placement is the result of the
|
||||
<code>sequence</code> function, which divides its arguments equally over
|
||||
one cycle. If an argument is an array, the same rule applies to that
|
||||
part of the cycle. In the example, e3 and g3 are divided equally over
|
||||
the second half of the whole cycle.</p>
|
||||
<p>The above examples do not represent how Strudel is used in practice.
|
||||
In the live coding editor, the user only has to type in the pattern
|
||||
itself, the querying will be handled by the scheduler. The scheduler
|
||||
will repeatedly query the pattern for events, which are then scheduled
|
||||
as sound synthesis or other event triggers. Also, the above event data
|
||||
structure has been simplified for readability.</p>
|
||||
<figure>
|
||||
<img src="images/strudel-screenshot2.png" style="width:60.0%"
|
||||
alt="Screenshot of the Strudel ‘REPL’ live coding editor, including piano-roll visualisation." />
|
||||
<figcaption aria-hidden="true">Screenshot of the Strudel ‘REPL’ live
|
||||
coding editor, including piano-roll visualisation.</figcaption>
|
||||
</figure>
|
||||
<h1 data-number="4" id="making-patterns"><span
|
||||
class="header-section-number">4</span> Making Patterns</h1>
|
||||
<p>In practice, the end-user live coder will not deal with constructing
|
||||
patterns directly, but will rather build patterns using Strudel’s
|
||||
extensive combinator library to create, combine and transform
|
||||
patterns.</p>
|
||||
<p>The live coder will rarely use the <code>sequence</code> function as
|
||||
seen above, as sequencing is implicit in many functions. For example in
|
||||
the following, the <code>note</code> function constructs a pattern of
|
||||
notes, sequencing its arguments in the same manner as the previous
|
||||
example.</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode js"><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></div>
|
||||
<p>Perhaps more often, they will use the mini-notation for even terser
|
||||
notation of rhythmic sequences: [^This last example is also valid Tidal
|
||||
code, albeit the parenthesis is not required in its Haskell syntax in
|
||||
this case. Tidal does not support passing sequences as lists directly to
|
||||
the <code>note</code> function, however.].</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode js"><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">"c3 [e3 g3]"</span>)</span></code></pre></div>
|
||||
<p>Such sequences are often treated only a starting point for
|
||||
manipulation, where they then undergo pattern transformations such as
|
||||
repetition, symmetry, interference/combination or randomisation,
|
||||
potentially at multiple timescales. Because Strudel patterns are
|
||||
represented as pure functions of time rather than as data structures,
|
||||
very long and complex generative results can be represented and
|
||||
manipulated without having to store the resulting sequences in
|
||||
memory.</p>
|
||||
<h1 data-number="5" id="pattern-example"><span
|
||||
class="header-section-number">5</span> Pattern Example</h1>
|
||||
<p>The following example showcases how patterns can be utilized to
|
||||
create musical complexity from simple parts, using repetition and
|
||||
interference:</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="st">"<0 2 [4 6](3,4,1) 3>"</span></span>
|
||||
<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>
|
||||
<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>
|
||||
<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">'D minor'</span>)</span>
|
||||
<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>
|
||||
<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">"sawtooth square"</span>)</span>
|
||||
<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></div>
|
||||
<p>The pattern starts with a rhythm of numbers in mini notation, which
|
||||
are later interpreted inside the scale of D minor. The first line could
|
||||
also be expressed without mini notation:</p>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode js"><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></div>
|
||||
<p>These numbers then undergo various pattern transformations. Here is a
|
||||
short description of all the functions used:</p>
|
||||
<ul>
|
||||
<li><code>cat</code>: play elements sequentially, where each lasts one
|
||||
cycle</li>
|
||||
<li><code>brackets</code>: elements inside brackets are divided equally
|
||||
over the time of their parent</li>
|
||||
<li><code>.euclid(p, s, o)</code>: place p pulses evenly over s steps,
|
||||
with offset o <span class="citation"
|
||||
data-cites="toussaintEuclideanAlgorithmGenerates2005">(Toussaint
|
||||
2005)</span></li>
|
||||
<li><code>.off(n, f)</code>: layers a pattern on top of itself, with the
|
||||
new layer offset by n cycles, and with function f applied</li>
|
||||
<li><code>.legato(n)</code>: multiply the duration of all events in a
|
||||
pattern by a factor of n</li>
|
||||
<li><code>.echo(t, n, v)</code>: copy each event t times, with n cycles
|
||||
in between each copy, decreasing velocity by v</li>
|
||||
<li><code>.note()</code>: interpretes values as notes</li>
|
||||
<li><code>.s(name)</code>: play back each event with the given
|
||||
sound</li>
|
||||
<li><code>.delay(wet)</code>: add delay</li>
|
||||
<li><code>.delaytime(t)</code>: set delay time</li>
|
||||
</ul>
|
||||
<p>Much of the above will be familiar to Tidal users.</p>
|
||||
<!-- 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. -->
|
||||
<h1 data-number="6" id="ways-to-make-sound-and-other-events"><span
|
||||
class="header-section-number">6</span> Ways to make Sound (and other
|
||||
events)</h1>
|
||||
<p>To generate sound, Strudel supports bindings for different
|
||||
outputs:</p>
|
||||
<ul>
|
||||
<li>Tone.js (deprecated)</li>
|
||||
<li>Web Audio API</li>
|
||||
<li>WebDirt, a js recreation of Tidal’s <em>Dirt</em> sample engine
|
||||
(deprecated)</li>
|
||||
<li>OSC via osc-js, compatible with superdirt</li>
|
||||
<li>Csound via the Csound WebAssembly build</li>
|
||||
<li>MIDI via WebMIDI</li>
|
||||
<li>Serial via WebSerial</li>
|
||||
</ul>
|
||||
<p>At first, we used Tone.js as sound output, but it proved to be
|
||||
limited for the use case of Strudel, where each individual event could
|
||||
potentially have a completely different audio graph. While the Web Audio
|
||||
API takes a <em>fire-and-forget</em> approach, creating a lot of Tone.js
|
||||
instruments and effects causes performance issues quickly. For that
|
||||
reason, we chose to search for alternatives.</p>
|
||||
<p>Strudel’s new default output uses the Web Audio API to create a new
|
||||
audio graph for each event. It currently supports basic oscillators,
|
||||
sample playback, various effects and an experimental support for
|
||||
soundfonts.</p>
|
||||
<p>WebDirt <span class="citation"
|
||||
data-cites="ogbornDktr0WebDirt2022">(Ogborn [2016] 2022)</span> was
|
||||
created as part of the Estuary Live Coding System <span class="citation"
|
||||
data-cites="ogbornEstuaryBrowserbasedCollaborative2017">(Ogborn et al.
|
||||
2017)</span>, and proved to be a solid choice for handling samples in
|
||||
Strudel as well. We are however focused on working more directly with
|
||||
the Web Audio API to be able to integrate new features more tightly.</p>
|
||||
<p>Using the OSC protocol via Strudel’s provided Node.js-based OSC proxy
|
||||
server, it is possible to send network messages to trigger events. This
|
||||
is mainly used to render sound using SuperDirt <span class="citation"
|
||||
data-cites="SuperDirt2022">(<em>SuperDirt</em> [2015] 2022)</span>,
|
||||
which is the well-developed Supercollider-based synthesis framework that
|
||||
Tidal live coders generally use as standard.</p>
|
||||
<p>Recently, the experimental integration of Csound proved to bring a
|
||||
new dimension of sound design capabilities to Strudel. Thanks to the
|
||||
WebAssembly distribution of this classic system <span class="citation"
|
||||
data-cites="CsoundWebAssembly">(Yi, Lazzarini, and Costello
|
||||
2018)</span>, Csound ‘orchestra’ synthesisers can be embedded in and
|
||||
then patterned with Strudel code.</p>
|
||||
<p>MIDI output can also be used to send MIDI messages to either external
|
||||
instruments or to other programs on the same device. Unlike OSC, Strudel
|
||||
is able to send MIDI directly without requiring additional proxy
|
||||
software, but only from web browsers that support it (at the time of
|
||||
writing, this means Chromium-based browsers).</p>
|
||||
<p>Finally, Strudel supports Serial output, for example to trigger
|
||||
events via microcontrollers. This has already been explored for robot
|
||||
choreography by Kate Sicchio and Alex McLean, via a performance
|
||||
presented at the International Conference on Live Interfaces 2022.</p>
|
||||
<h1 data-number="7" id="the-strudel-repl"><span
|
||||
class="header-section-number">7</span> The Strudel REPL</h1>
|
||||
<p>While Strudel can be used as a library in any JavaScript codebase,
|
||||
its main, reference user interface is the Strudel REPL[^REPL stands for
|
||||
read, evaluate, print/play, loop. It is friendly jargon for an
|
||||
interactive programming interface from computing heritage, usually for a
|
||||
commandline interface but also applied to live coding editors.], which
|
||||
is a browser-based live coding environment. This live code editor is
|
||||
dedicated to manipulating Strudel patterns while they play. The REPL
|
||||
features built-in visual feedback, which highlights which elements in
|
||||
the patterned (mini-notation) sequences are influencing the event that
|
||||
is currently being played. This feedback is designed to support both
|
||||
learning and live use of Strudel.</p>
|
||||
<p>Besides a UI for playback control and meta information, the main part
|
||||
of the REPL interface is the code editor powered by CodeMirror. In it,
|
||||
the user can edit and evaluate pattern code live, using one of the
|
||||
available synthesis outputs to create music and/or sound art. The
|
||||
control flow of the REPL follows 3 basic steps:</p>
|
||||
<ol type="1">
|
||||
<li>The user writes and updates code. Each update transpiles and
|
||||
evaluates it to create a <code>Pattern</code> instance</li>
|
||||
<li>While the REPL is running, the <code>Scheduler</code> queries the
|
||||
active <code>Pattern</code> by a regular interval, generating
|
||||
<code>Events</code> (also known as <code>Haps</code> in Strudel) for the
|
||||
next time span.</li>
|
||||
<li>For each scheduling tick, all generated <code>Events</code> are
|
||||
triggered by calling their <code>onTrigger</code> method, which is set
|
||||
by the output.</li>
|
||||
</ol>
|
||||
<figure>
|
||||
<img
|
||||
src="https://github.com/tidalcycles/strudel/raw/talk/talk/public/strudelflow.png?raw=true"
|
||||
style="width:43.0%" alt="REPL control flow" />
|
||||
<figcaption aria-hidden="true">REPL control flow</figcaption>
|
||||
</figure>
|
||||
<h2 data-number="7.1" id="user-code"><span
|
||||
class="header-section-number">7.1</span> User Code</h2>
|
||||
<p>To create a <code>Pattern</code> from the user code, two steps are
|
||||
needed:</p>
|
||||
<ol type="1">
|
||||
<li>Transpile the JS input code to make it functional</li>
|
||||
<li>Evaluate the transpiled code</li>
|
||||
</ol>
|
||||
<h3 data-number="7.1.1" id="transpilation-evaluation"><span
|
||||
class="header-section-number">7.1.1</span> Transpilation &
|
||||
Evaluation</h3>
|
||||
<p>In the JavaScript world, using transpilation is a common practise to
|
||||
be able to use language features that are not supported by the base
|
||||
language. Tools like <code>babel</code> will transpile code that
|
||||
contains unsupported language features into a version of the code
|
||||
without those features.</p>
|
||||
<p>In the same tradition, Strudel can add a transpilation step to
|
||||
simplify the user code in the context of live coding. For example, the
|
||||
Strudel REPL lets the user create mini notation patterns using just
|
||||
double quoted strings, while single quoted strings remain what they
|
||||
are:</p>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="st">"c3 [e3 g3]*2"</span></span></code></pre></div>
|
||||
<p>is transpiled to:</p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode js"><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">"c3 [e3 g3]*2"</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></div>
|
||||
<p>Here, the string is wrapped in <code>mini</code>, which will create a
|
||||
pattern from a mini notation string. Additionally, the
|
||||
<code>withMiniLocation</code> method passes the original source code
|
||||
location of the string to the pattern, which enables highlighting active
|
||||
events.</p>
|
||||
<p>Other convenient features like pseudo variables, operator overloading
|
||||
and top level await are possible with transpilation.</p>
|
||||
<p>After the transpilation, the code is ready to be evaluated into a
|
||||
<code>Pattern</code>.</p>
|
||||
<p>Behind the scenes, the user code string is parsed with
|
||||
<code>acorn</code>, turning it into an Abstract Syntax Tree (AST). The
|
||||
AST allows changing the structure of the code before generating the
|
||||
transpiled version using <code>escodegen</code>.</p>
|
||||
<h3 data-number="7.1.2" id="mini-notation"><span
|
||||
class="header-section-number">7.1.2</span> Mini Notation</h3>
|
||||
<p>While the transpilation allows JavaScript to express Patterns in a
|
||||
less verbose way, it is still preferable to use the Mini Notation as a
|
||||
more compact way to express rhythm. Strudel aims to provide the same
|
||||
Mini Notation features and syntax as used in Tidal.</p>
|
||||
<p>The Mini Notation parser is implemented using <code>peggy</code>,
|
||||
which allows generating performant parsers for Domain Specific Languages
|
||||
(DSLs) using a concise grammar notation. The generated parser turns the
|
||||
Mini Notation string into an AST which is used to call the respective
|
||||
Strudel functions with the given structure. For example,
|
||||
<code>"c3 [e3 g3]*2"</code> will result in the following calls:</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="fu">seq</span>(</span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'c3'</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>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">seq</span>(</span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'e3'</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>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">reify</span>(<span class="st">'g3'</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>
|
||||
<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>
|
||||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>)</span></code></pre></div>
|
||||
<h3 data-number="7.1.3" id="highlighting-locations"><span
|
||||
class="header-section-number">7.1.3</span> Highlighting Locations</h3>
|
||||
<p>As seen in the examples above, both the JS and the Mini Notation
|
||||
parser add source code locations using <code>withMiniLocation</code> and
|
||||
<code>withLocation</code> methods. While the JS parser adds locations
|
||||
relative to the user code as a whole, the Mini Notation adds locations
|
||||
relative to the position of the mini notation string. The absolute
|
||||
location of elements within Mini Notation can be calculated by simply
|
||||
adding both locations together. This absolute location can be used to
|
||||
highlight active events in real time.</p>
|
||||
<h2 data-number="7.2" id="scheduling-events"><span
|
||||
class="header-section-number">7.2</span> Scheduling Events</h2>
|
||||
<p>After an instance of <code>Pattern</code> is obtained from the user
|
||||
code, it is used by the scheduler to get queried for events. Once
|
||||
started, the scheduler runs at a fixed interval to query active pattern
|
||||
for events withing the current interval’s time span. A simplified
|
||||
implementation looks like this:</p>
|
||||
<div class="sourceCode" id="cb10"><pre
|
||||
class="sourceCode js"><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">'c3'</span><span class="op">,</span> [<span class="st">'e3'</span><span class="op">,</span> <span class="st">'g3'</span>])<span class="op">;</span> <span class="co">// pattern from user</span></span>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="pp">setInterval</span>(() <span class="kw">=></span> {</span>
|
||||
<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>
|
||||
<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>
|
||||
<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">=></span> {</span>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a> })<span class="op">;</span></span>
|
||||
<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 "interval" seconds</span></span></code></pre></div>
|
||||
<p>Note that the above code is simplified for illustrative purposes. The
|
||||
actual implementation has to work around imprecise callbacks of
|
||||
<code>setInterval</code>. More about the implementation details can be
|
||||
read in <a
|
||||
href="https://loophole-letters.vercel.app/web-audio-scheduling">this
|
||||
blog post</a>.</p>
|
||||
<p>The fact that <code>Pattern.queryArc</code> is a pure function that
|
||||
maps a time span to a set of events allows us to choose any interval we
|
||||
like without changing the resulting output. It also means that when the
|
||||
pattern is changed from outside, the next scheduling callback will work
|
||||
with the new pattern, keeping its clock running.</p>
|
||||
<p>The latency between the time the pattern is evaluated and the change
|
||||
is heard is between <code>minLatency</code> and
|
||||
<code>interval + minLatency</code>, in our example between 100ms and
|
||||
600ms. In Strudel, the current query interval is 50ms with a minLatency
|
||||
of 100ms, meaning the latency is between 50ms and 150ms.</p>
|
||||
<h2 data-number="7.3" id="output"><span
|
||||
class="header-section-number">7.3</span> Output</h2>
|
||||
<p>The last step is to trigger each event in the chosen output. This is
|
||||
where the given time and value of each event is used to generate audio
|
||||
or any other form of time based output. The default output of the
|
||||
Strudel REPL is the WebAudio output. To understand what an output does,
|
||||
we first have to understand what control parameters are.</p>
|
||||
<h3 data-number="7.3.1" id="control-parameters"><span
|
||||
class="header-section-number">7.3.1</span> Control Parameters</h3>
|
||||
<p>To be able to manipulate multiple aspects of sound in parallel, so
|
||||
called control parameters are used to shape the value of each event.
|
||||
Example:</p>
|
||||
<div class="sourceCode" id="cb11"><pre
|
||||
class="sourceCode js"><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">"c3 e3"</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">'sawtooth'</span>)</span>
|
||||
<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">=></span> hap<span class="op">.</span><span class="at">value</span>)</span>
|
||||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a><span class="co">/* [</span></span>
|
||||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="co"> { note: 'c3', cutoff: 1000, s: 'sawtooth' }</span></span>
|
||||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co"> { note: 'e3', cutoff: 1000, s: 'sawtooth' }</span></span>
|
||||
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co">] */</span></span></code></pre></div>
|
||||
<p>Here, the control parameter functions <code>note</code>,
|
||||
<code>cutoff</code> and <code>s</code> are used, where each controls a
|
||||
different property in the value object. Each control parameter function
|
||||
accepts a primitive value, a list of values to be sequenced into a
|
||||
<code>Pattern</code>, or a <code>Pattern</code>. In the example,
|
||||
<code>note</code> gets a <code>Pattern</code> from a Mini Notation
|
||||
expression (double quoted), while <code>cutoff</code> and <code>s</code>
|
||||
are given a <code>Number</code> and a (single quoted)
|
||||
<code>String</code> respectively.</p>
|
||||
<p>Strudel comes with a large default set of control parameter functions
|
||||
that are based on the ones used by Tidal and SuperDirt, focusing on
|
||||
music and audio terminology. It is however possible to create custom
|
||||
control paramters for any purpose:</p>
|
||||
<div class="sourceCode" id="cb12"><pre
|
||||
class="sourceCode js"><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">'x'</span><span class="op">,</span> <span class="st">'y'</span>)</span>
|
||||
<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></div>
|
||||
<p>This example creates the custom control parameters <code>x</code> and
|
||||
<code>y</code> which are then used to form a pattern that descibes the
|
||||
coordinates of a circle.</p>
|
||||
<h3 data-number="7.3.2" id="outputs"><span
|
||||
class="header-section-number">7.3.2</span> Outputs</h3>
|
||||
<p>Now that we know how the value of an event is manipulated using
|
||||
control parameters, we can look at how outputs can use that value to
|
||||
generate anything. The scheduler above was calling the
|
||||
<code>onTrigger</code> function which is used to implement the output. A
|
||||
very simple version of the web audio output could look like this:</p>
|
||||
<div class="sourceCode" id="cb13"><pre
|
||||
class="sourceCode js"><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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||||
<p>The above example will create an <code>OscillatorNode</code> for each
|
||||
event, where the frequency is controlled by the <code>note</code> param.
|
||||
In essence, this is how the WebAudio API output of Strudel works, only
|
||||
with many more parameters to control synths, samples and effects.</p>
|
||||
<h1 data-number="8" id="pattern-alignment-and-combination"><span
|
||||
class="header-section-number">8</span> Pattern alignment and
|
||||
combination</h1>
|
||||
<p>One core aspect of Strudel, inherited from Tidal, is the flexible way
|
||||
that patterns can be combined, irrespective of their structure. Its
|
||||
declarative approach means a live coder does not have to think about the
|
||||
details of <em>how</em> this is done, only <em>what</em> is to be
|
||||
done.</p>
|
||||
<p>As a simple example, consider two number patterns
|
||||
<code>"0 [1 2] 3"</code>, and <code>"10 20"</code>. The first has three
|
||||
contiguous steps of equal lengths, with the second step broken down into
|
||||
two substeps, giving four events in total. There are a very large number
|
||||
of ways in which the structure of these two patterns could be combined,
|
||||
but the default method in both Strudel and Tidal is to line up the
|
||||
cycles of the two patterns, and then take events from the first pattern
|
||||
and match them with those in the second pattern. Therefore, the
|
||||
following two lines are equivalent:</p>
|
||||
<div class="sourceCode" id="cb14"><pre
|
||||
class="sourceCode js"><code class="sourceCode javascript"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 [1 2] 3"</span><span class="op">.</span><span class="fu">add</span>(<span class="st">"10 20"</span>)</span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="st">"10 [11 22] 23"</span></span></code></pre></div>
|
||||
<p>Where the events only partially overlap, they are treated as
|
||||
fragments of the event in the first pattern. This is a little difficult
|
||||
to conceptualise, but lets start by comparing the two patterns in the
|
||||
following example:</p>
|
||||
<div class="sourceCode" id="cb15"><pre
|
||||
class="sourceCode js"><code class="sourceCode javascript"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 1 2"</span><span class="op">.</span><span class="fu">add</span>(<span class="st">"10 20"</span>)</span>
|
||||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="st">"10 [11 21] 20"</span></span></code></pre></div>
|
||||
<p>They are similar to the previous example in that the number
|
||||
<code>1</code> is split in two, with its two halves added to
|
||||
<code>10</code> and <code>20</code> respectively. However, the
|
||||
<code>11</code> ‘remembers’ that it is a fragment of that original
|
||||
<code>1</code> event, and so is treated as having a duration of a third
|
||||
of a cycle, despite only being active for a sixth of a cycle. Likewise,
|
||||
the <code>21</code> is also a fragment of that original <code>1</code>
|
||||
event, but a fragment of its second half. Because the start of its event
|
||||
is missing, it wouldn’t actually trigger a sound (unless it underwent
|
||||
further pattern transformations/combinations).</p>
|
||||
<p>In practice, the effect of this default, implicit method for
|
||||
combining two patterns is that the second pattern is added <em>in</em>
|
||||
to the first one, and indeed this can be made explicit:</p>
|
||||
<div class="sourceCode" id="cb16"><pre
|
||||
class="sourceCode js"><code class="sourceCode javascript"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="st">"0 1 2"</span><span class="op">.</span><span class="at">add</span><span class="op">.</span><span class="fu">in</span>(<span class="st">"10 20"</span>)</span></code></pre></div>
|
||||
<p>This makes way for other ways to align the pattern, and several are
|
||||
already defined, in particular:</p>
|
||||
<ul>
|
||||
<li><code>in</code> - as explained above, aligns cycles, and applies
|
||||
values from the pattern on the right <em>in</em> to the pattern on the
|
||||
left.</li>
|
||||
<li><code>out</code> - as with <code>in</code>, but values are applied
|
||||
<em>out</em> of the pattern on the left (i.e. <em>in</em> to the one on
|
||||
the right).</li>
|
||||
<li><code>mix</code> - structures from both patterns are combined, so
|
||||
that the new events are not fragments but are created at intersections
|
||||
of events from both sides.</li>
|
||||
<li><code>squeeze</code> - cycles from the pattern on the right are
|
||||
squeezed into events on the left. So that
|
||||
e.g. <code>"0 1 2".add.squeeze("10 20")</code> is equivalent to
|
||||
<code>"[10 20] [11 21] [12 22]"</code>.</li>
|
||||
<li><code>squeezeout</code> - as with <code>squeeze</code>, but cycles
|
||||
from the left are squeezed into events on the right. So,
|
||||
<code>"0 1 2".add.squeezeout("10 20")</code> is equivalent to
|
||||
<code>[10 11 12] [20 21 22]</code>.</li>
|
||||
<li><code>trig</code> is similar to <code>squeezeout</code> in that
|
||||
cycles from the right are aligned with events on the left. However those
|
||||
cycles are not ‘squeezed’, rather they are truncated to fit the event.
|
||||
So <code>"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")</code> would be
|
||||
equivalent to <code>10 11 12 13 20 21 30 31</code>. In effect, events on
|
||||
the right ‘trigger’ cycles on the left.</li>
|
||||
<li><code>trigzero</code> is similar to <code>trig</code>, but the
|
||||
pattern is ‘triggered’ from its very first cycle, rather than from the
|
||||
current cycle. <code>trig</code> and <code>trigzero</code> therefore
|
||||
only give different results where the leftmost pattern differs from one
|
||||
cycle to the next.</li>
|
||||
</ul>
|
||||
<p>We will save going deeper into the background, design and
|
||||
practicalities of these alignment functions for future publications.
|
||||
However in the next section, we take them as a case study for looking at
|
||||
the different design affordances offered by Haskell to Tidal, and
|
||||
JavaScript to Strudel.</p>
|
||||
<h1 data-number="9" id="comparing-strudel-and-haskell-in-use"><span
|
||||
class="header-section-number">9</span> Comparing Strudel and Haskell in
|
||||
use</h1>
|
||||
<p>Unlike Haskell, JavaScript lacks the ability to define custom infix
|
||||
operators, or change the meaning of existing ones. So the above Strudel
|
||||
example of <code>"0 1 2".add.out("10 20")</code> is equivalent to the
|
||||
Tidal expression <code>"0 1 2" +| "10 20"</code>, where the vertical bar
|
||||
in the operator <code>+|</code> stands for <code>out</code> (where
|
||||
<code>a |+ b</code> would be equivalent of
|
||||
<code>a.add.in(b)</code>).</p>
|
||||
<p>From this we can already see that Tidal tends towards brevity through
|
||||
mixing infix operators with functions, and Strudel tends towards
|
||||
spelling out operations which are joined together with the
|
||||
<code>.</code> operator. This then is the design trade-off of Tidal’s
|
||||
tersity, versus Strudel’s simplicity.</p>
|
||||
<p>To demonstrate this, consider the following Tidal pattern:</p>
|
||||
<pre class="tidal"><code>iter 4 $ every 3 (||+ n "10 20") $ (n "0 1 3") # s "triangle" # crush 4</code></pre>
|
||||
<p>This can be directly translated to the Strudel equivalent:</p>
|
||||
<div class="sourceCode" id="cb18"><pre
|
||||
class="sourceCode js"><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">"10 20"</span>)<span class="op">,</span> <span class="fu">n</span>(<span class="st">"0 1 3"</span>)<span class="op">.</span><span class="fu">s</span>(<span class="st">"triangle"</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)))</span></code></pre></div>
|
||||
<p>Although for a more canonical Strudel expression, we would reorder it
|
||||
as:</p>
|
||||
<div class="sourceCode" id="cb19"><pre
|
||||
class="sourceCode js"><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">"0 1 3"</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">"10 20"</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">"triangle"</span>)<span class="op">.</span><span class="fu">crush</span>(<span class="dv">4</span>)</span></code></pre></div>
|
||||
<p>The Strudel example uses the <code>.</code> method call operator for
|
||||
all operations and combinations, whereas the Tidal example has
|
||||
<code>#</code> for the default method for combining patterns and uses
|
||||
infix operators for other methods. The lack of parenthesis in the Tidal
|
||||
example is partly due to the way that arguments are applied to Haskell’s
|
||||
functions, and partly due to the use of the <code>$</code> operator as
|
||||
an alternative way to establish precedence and control the order of
|
||||
evaluation.</p>
|
||||
<p>Considering the above, we argue that the Haskell syntax is a little
|
||||
cleaner, but that the Strudel syntax is easier to learn. Our informal
|
||||
observation is that while Haskell’s dollar <code>$</code> operator is
|
||||
very useful in making code easier to work with, it is one of the most
|
||||
difficult aspects of Tidal use for beginners to learn. On the other
|
||||
hand, the deeper levels of parenthesis in Strudel code can be difficult
|
||||
to keep track of, especially while coding under pressure of live musical
|
||||
performance. However this difficulty can be largely be mitigated by
|
||||
reordering expressions, and further mitigated by supporting editor
|
||||
features.</p>
|
||||
<p>With Strudel, we have little choice but to embrace the affordances
|
||||
and constraints offered by JavaScript, and while designing a
|
||||
domain-specific language entirely based on method calls is a challenge,
|
||||
through creative adoption of functional programming techniques like
|
||||
partial application, we are so far very happy with the results. Tidal’s
|
||||
functional reactive approach to pattern-making has in general translated
|
||||
well to JavaScript, and opportunities and constraints have overall
|
||||
traded off to create a very approachable and useable live coding
|
||||
environment.</p>
|
||||
<h2 data-number="9.1" id="the-trade-off-of-flexible-typing"><span
|
||||
class="header-section-number">9.1</span> The trade-off of flexible
|
||||
typing</h2>
|
||||
<p>We have identified one problem with porting Tidal to JavaScript where
|
||||
we have missed Haskell’s strict typing and type inference. In both Tidal
|
||||
and Strudel, time is rational, where any point in time is represented as
|
||||
the ratio of two integers. This allows representation of musical ratios
|
||||
such that are impossible to represent accurately using the more common
|
||||
floating point numbers. However while libraries are available that
|
||||
support rational numbers in JavaScript, the lack of strict typing means
|
||||
that it is easy to implement pattern methods where computationally
|
||||
expensive conversion from floating point to rational numbers are
|
||||
performed late, and therefore often enough to overload the CPUs, due to
|
||||
the large number of iterative calculations required to estimate a ratio
|
||||
for a given floating point number. To mitigate this problem, we might
|
||||
consider moving to TypeScript in the future.</p>
|
||||
<h1 data-number="10" id="future-outlook"><span
|
||||
class="header-section-number">10</span> Future Outlook</h1>
|
||||
<p>The project is still young, with many features on the horizon. As
|
||||
general guiding principles, Strudel aims to be</p>
|
||||
<ol type="1">
|
||||
<li>accessible</li>
|
||||
<li>consistent with Tidal’s approach to pattern</li>
|
||||
<li>modular and extensible</li>
|
||||
</ol>
|
||||
<p>While Haskell’s type system makes it a great language for the ongoing
|
||||
development of Tidal’s inner representation of pattern, JavaScript’s
|
||||
vibrant ecosystem, flexibility and accessibility makes it a great host
|
||||
for more ad-hoc experiments, including interface design. For the future,
|
||||
it is planned to integrate additional alternative sound engines such as
|
||||
Glicol <span class="citation" data-cites="lanChaosprintGlicol2022">(Lan
|
||||
[2020] 2022)</span> and Faust <span class="citation"
|
||||
data-cites="FaustProgrammingLanguage2022">(<em>Faust - Programming
|
||||
Language for Audio Applications and Plugins</em> [2016] 2022)</span>.
|
||||
Strudel is already approaching feature parity with Tidal, but there are
|
||||
more Tidal functions to be ported, and work to be done to improve
|
||||
compatibility with Tidal’s mininotation. Tidal version 2.0 is under
|
||||
development, which brings a new representation for sequences to its
|
||||
patterns, which will then be brought to Strudel. Besides sound, other
|
||||
ways to render events are being explored, such as graphical, and
|
||||
choreographic output. We are also looking into alternative ways of
|
||||
editing patterns, including multi-user editing for network music,
|
||||
parsing a novel syntax to escape the constraints of javascript, and
|
||||
developing hardware/e-textile interfaces. In summary, there is a lot of
|
||||
fun ahead.</p>
|
||||
<h1 data-number="11" id="links"><span
|
||||
class="header-section-number">11</span> Links</h1>
|
||||
<p>The Strudel REPL is available at <a
|
||||
href="https://strudel.cc"
|
||||
class="uri">https://strudel.cc</a>, including an
|
||||
interactive tutorial. The repository is at <a
|
||||
href="https://github.com/tidalcycles/strudel"
|
||||
class="uri">https://github.com/tidalcycles/strudel</a>, all the code is
|
||||
open source under the AGPL-3.0 License.</p>
|
||||
<h1 data-number="12" id="acknowledgments"><span
|
||||
class="header-section-number">12</span> Acknowledgments</h1>
|
||||
<p>Thanks to the Strudel and wider Tidal, live coding, WebAudio and
|
||||
free/open source software communities for inspiration and support. Alex
|
||||
McLean’s work on this project is supported by a UKRI Future Leaders
|
||||
Fellowship [grant number MR/V025260/1].</p>
|
||||
<h1 class="unnumbered" id="references">References</h1>
|
||||
<div id="refs" class="references csl-bib-body hanging-indent"
|
||||
role="doc-bibliography">
|
||||
<div id="ref-FaustProgrammingLanguage2022" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
<em>Faust - Programming Language for Audio Applications and
|
||||
Plugins</em>. (2016) 2022. C++. GRAME. <a
|
||||
href="https://github.com/grame-cncm/faust">https://github.com/grame-cncm/faust</a>.
|
||||
</div>
|
||||
<div id="ref-jackHydra2022" class="csl-entry" role="doc-biblioentry">
|
||||
Jack, Olivia. (2022) 2022. <em>Hydra</em>. <a
|
||||
href="https://github.com/ojack/hydra">https://github.com/ojack/hydra</a>.
|
||||
</div>
|
||||
<div id="ref-lanChaosprintGlicol2022" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Lan, Qichao. (2020) 2022. <em>Chaosprint/Glicol</em>. Rust. <a
|
||||
href="https://github.com/chaosprint/glicol">https://github.com/chaosprint/glicol</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanAlgorithmicPattern2020a" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Mclean, Alex. 2020. <span>“Algorithmic Pattern.”</span> In
|
||||
<em>Proceedings of the International Conference on New Interfaces for
|
||||
Musical Expression</em>, 265--270. Birmingham, UK. <a
|
||||
href="https://zenodo.org/record/4813352">https://zenodo.org/record/4813352</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanFeedforward2020" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
McLean, Alex. 2020. <span>“Feedforward.”</span> In <em>Proceedings of
|
||||
New Interfaces for Musical Expression</em>. Birmingham. <a
|
||||
href="https://zenodo.org/record/6353969">https://zenodo.org/record/6353969</a>.
|
||||
</div>
|
||||
<div id="ref-mcleanTidalVortexZero2022" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
McLean, Alex, Raphaël Forment, Sylvain Le Beux, and Damián Silvani.
|
||||
2022. <span>“TidalVortex Zero.”</span> In <em>Proceedings of the 7th
|
||||
International Conference on Live Coding</em>. Limerick, Ireland: Zenodo.
|
||||
<a
|
||||
href="https://doi.org/10.5281/zenodo.6456380">https://doi.org/10.5281/zenodo.6456380</a>.
|
||||
</div>
|
||||
<div id="ref-ogbornDktr0WebDirt2022" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Ogborn, David. (2016) 2022. <em>Dktr0/WebDirt</em>. JavaScript. <a
|
||||
href="https://github.com/dktr0/WebDirt">https://github.com/dktr0/WebDirt</a>.
|
||||
</div>
|
||||
<div id="ref-ogbornEstuaryBrowserbasedCollaborative2017"
|
||||
class="csl-entry" role="doc-biblioentry">
|
||||
Ogborn, David, Jamie Beverley, Luis Navarro del Angel, Eldad Tsabary,
|
||||
and Alex McLean. 2017. <span>“Estuary: Browser-Based Collaborative
|
||||
Projectional Live Coding of Musical Patterns.”</span> In <em>Proceedings
|
||||
of the International Conference on Live Coding</em>, 11. Morelia.
|
||||
</div>
|
||||
<div id="ref-robertsGibberLiveCoding2012" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Roberts, Charles, and Joann Kuchera-morin. 2012. <span>“Gibber: Live
|
||||
Coding Audio in the Browser.”</span> In <em>In Proceedings of the 2012
|
||||
International Computer Music Conference</em>.
|
||||
</div>
|
||||
<div id="ref-StrudelWAC2022" class="csl-entry" role="doc-biblioentry">
|
||||
Roos, Felix, and Alex McLean. 2022. <span>“Strudel: Algorithmic Patterns
|
||||
for the Web.”</span> In. Zenodo. <a
|
||||
href="https://doi.org/10.5281/zenodo.6768844">https://doi.org/10.5281/zenodo.6768844</a>.
|
||||
</div>
|
||||
<div id="ref-solomonPurescriptocarina2022" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Solomon, Mike. (2021) 2022. <em>Purescript-Ocarina</em>. PureScript. <a
|
||||
href="https://github.com/mikesol/purescript-ocarina">https://github.com/mikesol/purescript-ocarina</a>.
|
||||
</div>
|
||||
<div id="ref-SuperDirt2022" class="csl-entry" role="doc-biblioentry">
|
||||
<em>SuperDirt</em>. (2015) 2022. SuperCollider. musikinformatik. <a
|
||||
href="https://github.com/musikinformatik/SuperDirt">https://github.com/musikinformatik/SuperDirt</a>.
|
||||
</div>
|
||||
<div id="ref-toussaintEuclideanAlgorithmGenerates2005" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Toussaint, Godfried. 2005. <span>“The Euclidean Algorithm Generates
|
||||
Traditional Musical Rhythms.”</span> In <em>In Proceedings of BRIDGES:
|
||||
Mathematical Connections in Art, Music and Science</em>, 47–56. <a
|
||||
href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231">http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.62.231</a>.
|
||||
</div>
|
||||
<div id="ref-CsoundWebAssembly" class="csl-entry"
|
||||
role="doc-biblioentry">
|
||||
Yi, Steven, Victor Lazzarini, and Edward Costello. 2018.
|
||||
<span>“WebAssembly AudioWorklet Csound.”</span> In. Berlin, Germany. <a
|
||||
href="https://mural.maynoothuniversity.ie/16018/">https://mural.maynoothuniversity.ie/16018/</a>.
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,80 +0,0 @@
|
||||
$if(false)$
|
||||
|
||||
This is a pandoc template and should not be edited.
|
||||
|
||||
$endif$
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"$if(lang)$ lang="$lang$" xml:lang="$lang$"$endif$>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="Content-Style-Type" content="text/css" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$
|
||||
$if(date-meta)$
|
||||
<meta name="date" content="$date-meta$" />
|
||||
$endif$
|
||||
<title>$if(title-prefix)$$title-prefix$ - $endif$$pagetitle$</title>
|
||||
<style type="text/css">code{white-space: pre;}</style>
|
||||
$if(quotes)$
|
||||
<style type="text/css">q { quotes: "“" "”" "‘" "’"; }</style>
|
||||
$endif$
|
||||
$if(highlighting-css)$
|
||||
<style type="text/css">
|
||||
$highlighting-css$
|
||||
</style>
|
||||
$endif$
|
||||
<link rel="stylesheet" href="css/iclc.css" $if(html5)$$else$type="text/css" $endif$/>
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" $if(html5)$$else$type="text/css" $endif$/>
|
||||
$endfor$
|
||||
$if(math)$
|
||||
$math$
|
||||
$endif$
|
||||
$for(header-includes)$
|
||||
$header-includes$
|
||||
$endfor$
|
||||
</head>
|
||||
<body>
|
||||
$for(include-before)$
|
||||
$include-before$
|
||||
$endfor$
|
||||
$if(title)$
|
||||
<div id="$idprefix$header">
|
||||
<h1 class="title">$title$</h1>
|
||||
$if(subtitle)$
|
||||
<h1 class="subtitle">$subtitle$</h1>
|
||||
$endif$
|
||||
<ul id="authorlist">
|
||||
$for(author)$
|
||||
<li>$author$</li>
|
||||
$endfor$
|
||||
</ul>
|
||||
$if(date)$
|
||||
<h3 class="date">$date$</h3>
|
||||
$endif$
|
||||
</div>
|
||||
$endif$
|
||||
$if(toc)$
|
||||
<div id="$idprefix$TOC">
|
||||
$toc$
|
||||
</div>
|
||||
$endif$
|
||||
|
||||
<h2 class="abstract">Abstract</h2>
|
||||
<div id="abstract">
|
||||
$if(abstract)$
|
||||
$abstract$
|
||||
$else$
|
||||
Please provide an abstract in the metadata block at the top of your
|
||||
markdown document. Refer to template.txt for details.
|
||||
$endif$
|
||||
</div>
|
||||
|
||||
$body$
|
||||
$for(include-after)$
|
||||
$include-after$
|
||||
$endfor$
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,6 +1,12 @@
|
||||
packages:
|
||||
# all packages in direct subdirs of packages/
|
||||
- "packages/*"
|
||||
- "examples/*"
|
||||
- "tools/dbpatch"
|
||||
- "website/"
|
||||
- packages/*
|
||||
- examples/*
|
||||
- tools/dbpatch
|
||||
- website/
|
||||
|
||||
onlyBuiltDependencies:
|
||||
- esbuild
|
||||
- nx
|
||||
- sharp
|
||||
- tree-sitter
|
||||
- tree-sitter-haskell
|
||||
|
||||
@@ -3145,18 +3145,19 @@ exports[`runs examples > example "euclidLegato" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "euclidLegatoRot" example index 0 1`] = `
|
||||
[
|
||||
"[ 0/1 → 1/4 | note:c3 ]",
|
||||
"[ 1/4 → 3/4 | note:c3 ]",
|
||||
"[ 3/4 → 1/1 | note:c3 ]",
|
||||
"[ 1/1 → 5/4 | note:c3 ]",
|
||||
"[ 5/4 → 7/4 | note:c3 ]",
|
||||
"[ 7/4 → 2/1 | note:c3 ]",
|
||||
"[ 2/1 → 9/4 | note:c3 ]",
|
||||
"[ 9/4 → 11/4 | note:c3 ]",
|
||||
"[ 11/4 → 3/1 | note:c3 ]",
|
||||
"[ 3/1 → 13/4 | note:c3 ]",
|
||||
"[ 13/4 → 15/4 | note:c3 ]",
|
||||
"[ 15/4 → 4/1 | note:c3 ]",
|
||||
"[ -1/5 ⇜ (0/1 → 1/5) | note:c3 ]",
|
||||
"[ 1/5 → 2/5 | note:c3 ]",
|
||||
"[ 2/5 → 4/5 | note:c3 ]",
|
||||
"[ 4/5 → 6/5 | note:c3 ]",
|
||||
"[ 6/5 → 7/5 | note:c3 ]",
|
||||
"[ 7/5 → 9/5 | note:c3 ]",
|
||||
"[ 9/5 → 11/5 | note:c3 ]",
|
||||
"[ 11/5 → 12/5 | note:c3 ]",
|
||||
"[ 12/5 → 14/5 | note:c3 ]",
|
||||
"[ 14/5 → 16/5 | note:c3 ]",
|
||||
"[ 16/5 → 17/5 | note:c3 ]",
|
||||
"[ 17/5 → 19/5 | note:c3 ]",
|
||||
"[ (19/5 → 4/1) ⇝ 21/5 | note:c3 ]",
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
@@ -7318,12 +7318,12 @@ exports[`renders tunes > tune: randomBells 1`] = `
|
||||
[
|
||||
"[ -9/8 ⇜ (0/1 → 3/8) | gain:0.6 note:A3 velocity:0.5989903202280402 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ -3/4 ⇜ (0/1 → 3/4) | gain:0.6 note:C5 velocity:0.8369929669424891 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 0/1 → 3/2 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 0/1 → 3/2 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 0/1 → 9/4 | gain:0.6 note:D3 velocity:0.5 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 3/8 → 21/8 | gain:0.6 note:F5 velocity:0.9213038925081491 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 3/4 → 3/1 | gain:0.6 note:C5 velocity:0.8426077850162983 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 3/2 → 9/4 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 9/4 → 3/1 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 3/2 → 9/4 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 9/4 → 3/1 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 9/4 → 9/2 | gain:0.6 note:D4 velocity:0.7006962578743696 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 21/8 → 39/8 | gain:0.6 note:C4 velocity:0.6507943943142891 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 3/1 → 9/2 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
@@ -7335,12 +7335,12 @@ exports[`renders tunes > tune: randomBells 1`] = `
|
||||
"[ (21/4 → 6/1) ⇝ 27/4 | gain:0.6 note:D4 velocity:0.6988155404105783 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 39/8 ⇜ (6/1 → 51/8) | gain:0.6 note:D5 velocity:0.8758113365620375 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 21/4 ⇜ (6/1 → 27/4) | gain:0.6 note:D4 velocity:0.6988155404105783 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 6/1 → 15/2 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 6/1 → 15/2 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 6/1 → 33/4 | gain:0.6 note:G4 velocity:0.7597710825502872 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 51/8 → 69/8 | gain:0.6 note:G4 velocity:0.7743164440616965 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 27/4 → 9/1 | gain:0.6 note:C5 velocity:0.8362447572872043 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 15/2 → 33/4 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 33/4 → 9/1 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 15/2 → 33/4 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 33/4 → 9/1 | note:D2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 33/4 → 21/2 | gain:0.6 note:A3 velocity:0.5914018759503961 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 69/8 → 87/8 | gain:0.6 note:G4 velocity:0.754063542932272 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 9/1 → 21/2 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
@@ -7352,12 +7352,12 @@ exports[`renders tunes > tune: randomBells 1`] = `
|
||||
"[ (45/4 → 12/1) ⇝ 51/4 | gain:0.6 note:A4 velocity:0.7972785895690322 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 87/8 ⇜ (12/1 → 99/8) | gain:0.6 note:F4 velocity:0.7347871446982026 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 45/4 ⇜ (12/1 → 51/4) | gain:0.6 note:A4 velocity:0.7972785895690322 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 12/1 → 27/2 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 12/1 → 27/2 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 12/1 → 57/4 | gain:0.6 note:G5 velocity:0.9797635599970818 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 99/8 → 117/8 | gain:0.6 note:C4 velocity:0.6662392104044557 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 51/4 → 15/1 | gain:0.6 note:F5 velocity:0.9516951469704509 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 27/2 → 57/4 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 57/4 → 15/1 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 27/2 → 57/4 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 57/4 → 15/1 | note:A2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 57/4 → 33/2 | gain:0.6 note:F5 velocity:0.9182533202692866 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 117/8 → 135/8 | gain:0.6 note:G3 velocity:0.5711571052670479 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 15/1 → 33/2 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
@@ -7369,12 +7369,12 @@ exports[`renders tunes > tune: randomBells 1`] = `
|
||||
"[ (69/4 → 18/1) ⇝ 75/4 | gain:0.6 note:F3 velocity:0.5081270858645439 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 135/8 ⇜ (18/1 → 147/8) | gain:0.6 note:F5 velocity:0.9456470254808664 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 69/4 ⇜ (18/1 → 75/4) | gain:0.6 note:F3 velocity:0.5081270858645439 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 18/1 → 39/2 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 18/1 → 39/2 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 18/1 → 81/4 | gain:0.6 note:A3 velocity:0.6086445553228259 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 147/8 → 165/8 | gain:0.6 note:F3 velocity:0.5062594395130873 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 75/4 → 21/1 | gain:0.6 note:D4 velocity:0.6716219391673803 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 39/2 → 81/4 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 81/4 → 21/1 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 39/2 → 81/4 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 81/4 → 21/1 | note:G2 s:bass clip:1 gain:0.8 ]",
|
||||
"[ 81/4 → 45/2 | gain:0.6 note:D4 velocity:0.7043459005653858 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 165/8 → 183/8 | gain:0.6 note:D5 velocity:0.8878388572484255 s:bell delay:0.2 delaytime:0.3333333333333333 delayfeedback:0.8 ]",
|
||||
"[ 21/1 → 45/2 | note:F2 s:bass clip:1 gain:0.8 ]",
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
---
|
||||
// fetch all commits for just this page's path
|
||||
type Props = {
|
||||
path: string;
|
||||
};
|
||||
const { path } = Astro.props as Props;
|
||||
const resolvedPath = `website/src/pages${path}.mdx`;
|
||||
const url = `https://api.github.com/repos/tidalcycles/strudel/commits?path=${resolvedPath}`;
|
||||
const commitsURL = `https://github.com/tidalcycles/strudel/commits/main/${resolvedPath}`;
|
||||
|
||||
type Commit = {
|
||||
author: {
|
||||
id: string;
|
||||
login: string;
|
||||
};
|
||||
};
|
||||
|
||||
async function getCommits(url: string) {
|
||||
try {
|
||||
const token = import.meta.env.SNOWPACK_PUBLIC_GITHUB_TOKEN ?? 'hello';
|
||||
if (!token) {
|
||||
throw new Error('Cannot find "SNOWPACK_PUBLIC_GITHUB_TOKEN" used for escaping rate-limiting.');
|
||||
}
|
||||
|
||||
const auth = `Basic ${Buffer.from(token, 'binary').toString('base64')}`;
|
||||
|
||||
const res = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: auth,
|
||||
'User-Agent': 'astro-docs/1.0',
|
||||
},
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Request to fetch commits failed. Reason: ${res.statusText}
|
||||
Message: ${data.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
return data as Commit[];
|
||||
} catch (e) {
|
||||
console.warn(`[error] /src/components/AvatarList.astro
|
||||
${(e as any)?.message ?? e}`);
|
||||
return [] as Commit[];
|
||||
}
|
||||
}
|
||||
|
||||
function removeDups(arr: Commit[]) {
|
||||
const map = new Map<string, Commit['author']>();
|
||||
for (let item of arr) {
|
||||
const author = item.author;
|
||||
// Deduplicate based on author.id
|
||||
//map.set(author.id, { login: author.login, id: author.id });
|
||||
author && map.set(author.id, { login: author.login, id: author.id });
|
||||
}
|
||||
|
||||
return [...map.values()];
|
||||
}
|
||||
|
||||
const data = await getCommits(url);
|
||||
const unique = removeDups(data);
|
||||
const recentContributors = unique.slice(0, 3); // only show avatars for the 3 most recent contributors
|
||||
const additionalContributors = unique.length - recentContributors.length; // list the rest of them as # of extra contributors
|
||||
---
|
||||
|
||||
<!-- Thanks to @5t3ph for https://smolcss.dev/#smol-avatar-list! -->
|
||||
<div class="contributors px-4 mb-8">
|
||||
<ul class="avatar-list" style={`--avatar-count: ${recentContributors.length}`}>
|
||||
{
|
||||
recentContributors.map((item) => (
|
||||
<li>
|
||||
<a href={`https://github.com/${item.login}`}>
|
||||
<img
|
||||
alt={`Contributor ${item.login}`}
|
||||
title={`Contributor ${item.login}`}
|
||||
width="64"
|
||||
height="64"
|
||||
src={`https://avatars.githubusercontent.com/u/${item.id}`}
|
||||
/>
|
||||
</a>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
{
|
||||
additionalContributors > 0 && (
|
||||
<span>
|
||||
<a href={commitsURL}>{`and ${additionalContributors} additional contributor${
|
||||
additionalContributors > 1 ? 's' : ''
|
||||
}.`}</a>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
{unique.length === 0 && <a href={commitsURL}>Contributors</a>}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.avatar-list {
|
||||
--avatar-size: 2.5rem;
|
||||
--avatar-count: 3;
|
||||
|
||||
display: grid;
|
||||
list-style: none;
|
||||
/* Default to displaying most of the avatar to
|
||||
enable easier access on touch devices, ensuring
|
||||
the WCAG touch target size is met or exceeded */
|
||||
grid-template-columns: repeat(var(--avatar-count), max(44px, calc(var(--avatar-size) / 1.15)));
|
||||
/* `padding` matches added visual dimensions of
|
||||
the `box-shadow` to help create a more accurate
|
||||
computed component size */
|
||||
padding: 0.08em;
|
||||
font-size: var(--avatar-size);
|
||||
}
|
||||
|
||||
@media (any-hover: hover) and (any-pointer: fine) {
|
||||
.avatar-list {
|
||||
/* We create 1 extra cell to enable the computed
|
||||
width to match the final visual width */
|
||||
grid-template-columns: repeat(calc(var(--avatar-count) + 1), calc(var(--avatar-size) / 1.75));
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-list li {
|
||||
width: var(--avatar-size);
|
||||
height: var(--avatar-size);
|
||||
}
|
||||
|
||||
.avatar-list li:hover ~ li a,
|
||||
.avatar-list li:focus-within ~ li a {
|
||||
transform: translateX(33%);
|
||||
}
|
||||
|
||||
.avatar-list img,
|
||||
.avatar-list a {
|
||||
display: block;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-list a {
|
||||
transition: transform 180ms ease-in-out;
|
||||
}
|
||||
|
||||
.avatar-list img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 0 0.05em #fff, 0 0 0 0.08em rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.avatar-list a:focus {
|
||||
outline: 2px solid transparent;
|
||||
/* Double-layer trick to work for dark and light backgrounds */
|
||||
box-shadow: 0 0 0 0.08em var(--theme-accent), 0 0 0 0.12em white;
|
||||
}
|
||||
|
||||
.contributors {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.contributors > * + * {
|
||||
margin-left: 0.75rem;
|
||||
}
|
||||
</style>
|
||||
@@ -82,7 +82,7 @@ export default function Search() {
|
||||
appId={ALGOLIA.appId}
|
||||
apiKey={ALGOLIA.apiKey}
|
||||
getMissingResultsUrl={({ query }) => {
|
||||
return `https://github.com/tidalcycles/strudel/issues/new?title=Missing doc for ${query}`;
|
||||
return `https://codeberg.org/uzu/strudel/issues/new?title=Missing%20doc%20for${encodeURIComponent(query)}`;
|
||||
}}
|
||||
transformItems={(items) => {
|
||||
return items.map((item) => {
|
||||
|
||||
@@ -18,5 +18,4 @@ currentPage = currentPage.endsWith('/') ? currentPage.slice(0, -1) : currentPage
|
||||
<nav aria-labelledby="grid-right" class="w-64 text-foreground">
|
||||
<TableOfContents client:media="(min-width: 50em)" headings={headings} currentPage={currentPage} />
|
||||
<MoreMenu editHref={githubEditUrl} />
|
||||
<!-- <AvatarList path={currentPage} /> -->
|
||||
</nav>
|
||||
|
||||
@@ -8,33 +8,33 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Most work done as [commits to main](https://github.com/tidalcycles/strudel/commits/2a0d8c3f77ff7b34e82602e2d02400707f367316)
|
||||
- repl + reify functions by @felixroos in https://github.com/tidalcycles/strudel/pull/2
|
||||
- Fix path by @yaxu in https://github.com/tidalcycles/strudel/pull/3
|
||||
- update readme for local dev by @kindohm in https://github.com/tidalcycles/strudel/pull/4
|
||||
- Patternify all the things by @yaxu in https://github.com/tidalcycles/strudel/pull/5
|
||||
- krill parser + improved repl by @felixroos in https://github.com/tidalcycles/strudel/pull/6
|
||||
- fixed editor crash by @felixroos in https://github.com/tidalcycles/strudel/pull/7
|
||||
- timeCat by @yaxu in https://github.com/tidalcycles/strudel/pull/8
|
||||
- Bugfix every, and create more top level functions by @yaxu in https://github.com/tidalcycles/strudel/pull/9
|
||||
- Failing test for `when` WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/10
|
||||
- Added mask() and struct() by @yaxu in https://github.com/tidalcycles/strudel/pull/11
|
||||
- Add continuous signals (sine, cosine, saw, etc) by @yaxu in https://github.com/tidalcycles/strudel/pull/13
|
||||
- add apply and layer, and missing div/mul methods by @yaxu in https://github.com/tidalcycles/strudel/pull/15
|
||||
- higher latencyHint by @felixroos in https://github.com/tidalcycles/strudel/pull/16
|
||||
- test: 📦 Add missing dependency and a CI check, to prevent oversights ;p by @puria in https://github.com/tidalcycles/strudel/pull/17
|
||||
- fix: 💄 Enhance visualisation of the Tutorial on mobile by @puria in https://github.com/tidalcycles/strudel/pull/19
|
||||
- Stateful queries and events (WIP) by @yaxu in https://github.com/tidalcycles/strudel/pull/14
|
||||
- Fix resolveState by @yaxu in https://github.com/tidalcycles/strudel/pull/22
|
||||
- added \_asNumber + interpret numbers as midi by @felixroos in https://github.com/tidalcycles/strudel/pull/21
|
||||
- Update package.json by @ChiakiUehira in https://github.com/tidalcycles/strudel/pull/23
|
||||
- packaging by @felixroos in https://github.com/tidalcycles/strudel/pull/24
|
||||
- Most work done as [commits to main](https://codeberg.org/uzu/strudel/commit/2a0d8c3f77ff7b34e82602e2d02400707f367316)
|
||||
- repl + reify functions by @felixroos in https://codeberg.org/uzu/strudel/pulls/2
|
||||
- Fix path by @yaxu in https://codeberg.org/uzu/strudel/pulls/3
|
||||
- update readme for local dev by @kindohm in https://codeberg.org/uzu/strudel/pulls/4
|
||||
- Patternify all the things by @yaxu in https://codeberg.org/uzu/strudel/pulls/5
|
||||
- krill parser + improved repl by @felixroos in https://codeberg.org/uzu/strudel/pulls/6
|
||||
- fixed editor crash by @felixroos in https://codeberg.org/uzu/strudel/pulls/7
|
||||
- timeCat by @yaxu in https://codeberg.org/uzu/strudel/pulls/8
|
||||
- Bugfix every, and create more top level functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/9
|
||||
- Failing test for `when` WIP by @yaxu in https://codeberg.org/uzu/strudel/pulls/10
|
||||
- Added mask() and struct() by @yaxu in https://codeberg.org/uzu/strudel/pulls/11
|
||||
- Add continuous signals (sine, cosine, saw, etc) by @yaxu in https://codeberg.org/uzu/strudel/pulls/13
|
||||
- add apply and layer, and missing div/mul methods by @yaxu in https://codeberg.org/uzu/strudel/pulls/15
|
||||
- higher latencyHint by @felixroos in https://codeberg.org/uzu/strudel/pulls/16
|
||||
- test: 📦 Add missing dependency and a CI check, to prevent oversights ;p by @puria in https://codeberg.org/uzu/strudel/pulls/17
|
||||
- fix: 💄 Enhance visualisation of the Tutorial on mobile by @puria in https://codeberg.org/uzu/strudel/pulls/19
|
||||
- Stateful queries and events (WIP) by @yaxu in https://codeberg.org/uzu/strudel/pulls/14
|
||||
- Fix resolveState by @yaxu in https://codeberg.org/uzu/strudel/pulls/22
|
||||
- added \_asNumber + interpret numbers as midi by @felixroos in https://codeberg.org/uzu/strudel/pulls/21
|
||||
- Update package.json by @ChiakiUehira in https://codeberg.org/uzu/strudel/pulls/23
|
||||
- packaging by @felixroos in https://codeberg.org/uzu/strudel/pulls/24
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @felixroos made their first contribution in https://github.com/tidalcycles/strudel/pull/2
|
||||
- @kindohm made their first contribution in https://github.com/tidalcycles/strudel/pull/4
|
||||
- @puria made their first contribution in https://github.com/tidalcycles/strudel/pull/17
|
||||
- @ChiakiUehira made their first contribution in https://github.com/tidalcycles/strudel/pull/23
|
||||
- @felixroos made their first contribution in https://codeberg.org/uzu/strudel/pulls/2
|
||||
- @kindohm made their first contribution in https://codeberg.org/uzu/strudel/pulls/4
|
||||
- @puria made their first contribution in https://codeberg.org/uzu/strudel/pulls/17
|
||||
- @ChiakiUehira made their first contribution in https://codeberg.org/uzu/strudel/pulls/23
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/commits/2a0d8c3f77ff7b34e82602e2d02400707f367316
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/commit/2a0d8c3f77ff7b34e82602e2d02400707f367316
|
||||
|
||||
@@ -7,47 +7,47 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25
|
||||
- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/37
|
||||
- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/38
|
||||
- Compose by @felixroos in https://github.com/tidalcycles/strudel/pull/40
|
||||
- Fix polymeter by @yaxu in https://github.com/tidalcycles/strudel/pull/44
|
||||
- First run at squeezeBind, ref #32 by @yaxu in https://github.com/tidalcycles/strudel/pull/48
|
||||
- Implement `chop()` by @yaxu in https://github.com/tidalcycles/strudel/pull/50
|
||||
- OSC and SuperDirt support by @yaxu in https://github.com/tidalcycles/strudel/pull/27
|
||||
- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/56
|
||||
- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/61
|
||||
- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://github.com/tidalcycles/strudel/pull/62
|
||||
- Speech output by @felixroos in https://github.com/tidalcycles/strudel/pull/67
|
||||
- use new fixed version of osc-js package by @felixroos in https://github.com/tidalcycles/strudel/pull/68
|
||||
- First effort at rand() by @yaxu in https://github.com/tidalcycles/strudel/pull/69
|
||||
- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://github.com/tidalcycles/strudel/pull/70
|
||||
- webaudio package by @felixroos in https://github.com/tidalcycles/strudel/pull/26
|
||||
- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://github.com/tidalcycles/strudel/pull/73
|
||||
- More random functions by @yaxu in https://github.com/tidalcycles/strudel/pull/74
|
||||
- Try to fix appLeft / appRight by @yaxu in https://github.com/tidalcycles/strudel/pull/75
|
||||
- Basic webserial support by @yaxu in https://github.com/tidalcycles/strudel/pull/80
|
||||
- Webaudio in REPL by @felixroos in https://github.com/tidalcycles/strudel/pull/77
|
||||
- add `striate()` by @yaxu in https://github.com/tidalcycles/strudel/pull/76
|
||||
- Tidy up a couple of old files by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/84
|
||||
- Add pattern composers, implements #82 by @yaxu in https://github.com/tidalcycles/strudel/pull/83
|
||||
- Fiddles with cat/stack by @yaxu in https://github.com/tidalcycles/strudel/pull/90
|
||||
- Paper by @felixroos in https://github.com/tidalcycles/strudel/pull/98
|
||||
- Change to Affero GPL by @yaxu in https://github.com/tidalcycles/strudel/pull/101
|
||||
- Work on Codemirror 6 highlighting by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/102
|
||||
- Codemirror 6 by @felixroos in https://github.com/tidalcycles/strudel/pull/97
|
||||
- Tune tests by @felixroos in https://github.com/tidalcycles/strudel/pull/104
|
||||
- /embed package: web component for repl by @felixroos in https://github.com/tidalcycles/strudel/pull/106
|
||||
- Reset, Restart and other composers by @felixroos in https://github.com/tidalcycles/strudel/pull/88
|
||||
- Embed style by @felixroos in https://github.com/tidalcycles/strudel/pull/109
|
||||
- In source doc by @yaxu in https://github.com/tidalcycles/strudel/pull/105
|
||||
- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://github.com/tidalcycles/strudel/pull/112
|
||||
- loopAt by @yaxu in https://github.com/tidalcycles/strudel/pull/114
|
||||
- Osc timing improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/113
|
||||
- Add chunk, chunkBack and iterBack by @yaxu in https://codeberg.org/uzu/strudel/pulls/25
|
||||
- Update tutorial.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/37
|
||||
- Update tutorial.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/38
|
||||
- Compose by @felixroos in https://codeberg.org/uzu/strudel/pulls/40
|
||||
- Fix polymeter by @yaxu in https://codeberg.org/uzu/strudel/pulls/44
|
||||
- First run at squeezeBind, ref #32 by @yaxu in https://codeberg.org/uzu/strudel/pulls/48
|
||||
- Implement `chop()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/50
|
||||
- OSC and SuperDirt support by @yaxu in https://codeberg.org/uzu/strudel/pulls/27
|
||||
- More functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/56
|
||||
- More functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/61
|
||||
- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://codeberg.org/uzu/strudel/pulls/62
|
||||
- Speech output by @felixroos in https://codeberg.org/uzu/strudel/pulls/67
|
||||
- use new fixed version of osc-js package by @felixroos in https://codeberg.org/uzu/strudel/pulls/68
|
||||
- First effort at rand() by @yaxu in https://codeberg.org/uzu/strudel/pulls/69
|
||||
- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://codeberg.org/uzu/strudel/pulls/70
|
||||
- webaudio package by @felixroos in https://codeberg.org/uzu/strudel/pulls/26
|
||||
- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://codeberg.org/uzu/strudel/pulls/73
|
||||
- More random functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/74
|
||||
- Try to fix appLeft / appRight by @yaxu in https://codeberg.org/uzu/strudel/pulls/75
|
||||
- Basic webserial support by @yaxu in https://codeberg.org/uzu/strudel/pulls/80
|
||||
- Webaudio in REPL by @felixroos in https://codeberg.org/uzu/strudel/pulls/77
|
||||
- add `striate()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/76
|
||||
- Tidy up a couple of old files by @mindofmatthew in https://codeberg.org/uzu/strudel/pulls/84
|
||||
- Add pattern composers, implements #82 by @yaxu in https://codeberg.org/uzu/strudel/pulls/83
|
||||
- Fiddles with cat/stack by @yaxu in https://codeberg.org/uzu/strudel/pulls/90
|
||||
- Paper by @felixroos in https://codeberg.org/uzu/strudel/pulls/98
|
||||
- Change to Affero GPL by @yaxu in https://codeberg.org/uzu/strudel/pulls/101
|
||||
- Work on Codemirror 6 highlighting by @mindofmatthew in https://codeberg.org/uzu/strudel/pulls/102
|
||||
- Codemirror 6 by @felixroos in https://codeberg.org/uzu/strudel/pulls/97
|
||||
- Tune tests by @felixroos in https://codeberg.org/uzu/strudel/pulls/104
|
||||
- /embed package: web component for repl by @felixroos in https://codeberg.org/uzu/strudel/pulls/106
|
||||
- Reset, Restart and other composers by @felixroos in https://codeberg.org/uzu/strudel/pulls/88
|
||||
- Embed style by @felixroos in https://codeberg.org/uzu/strudel/pulls/109
|
||||
- In source doc by @yaxu in https://codeberg.org/uzu/strudel/pulls/105
|
||||
- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/112
|
||||
- loopAt by @yaxu in https://codeberg.org/uzu/strudel/pulls/114
|
||||
- Osc timing improvements by @yaxu in https://codeberg.org/uzu/strudel/pulls/113
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @bwagner made their first contribution in https://github.com/tidalcycles/strudel/pull/37
|
||||
- @mindofmatthew made their first contribution in https://github.com/tidalcycles/strudel/pull/84
|
||||
- @bwagner made their first contribution in https://codeberg.org/uzu/strudel/pulls/37
|
||||
- @mindofmatthew made their first contribution in https://codeberg.org/uzu/strudel/pulls/84
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.2...@strudel.cycles/core@0.1.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.0.2...@strudel.cycles/core@0.1.0
|
||||
|
||||
@@ -8,59 +8,59 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Add chunk, chunkBack and iterBack by @yaxu in https://github.com/tidalcycles/strudel/pull/25
|
||||
- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/37
|
||||
- Update tutorial.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/38
|
||||
- Compose by @felixroos in https://github.com/tidalcycles/strudel/pull/40
|
||||
- Fix polymeter by @yaxu in https://github.com/tidalcycles/strudel/pull/44
|
||||
- First run at squeezeBind, ref #32 by @yaxu in https://github.com/tidalcycles/strudel/pull/48
|
||||
- Implement `chop()` by @yaxu in https://github.com/tidalcycles/strudel/pull/50
|
||||
- OSC and SuperDirt support by @yaxu in https://github.com/tidalcycles/strudel/pull/27
|
||||
- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/56
|
||||
- More functions by @yaxu in https://github.com/tidalcycles/strudel/pull/61
|
||||
- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://github.com/tidalcycles/strudel/pull/62
|
||||
- Speech output by @felixroos in https://github.com/tidalcycles/strudel/pull/67
|
||||
- use new fixed version of osc-js package by @felixroos in https://github.com/tidalcycles/strudel/pull/68
|
||||
- First effort at rand() by @yaxu in https://github.com/tidalcycles/strudel/pull/69
|
||||
- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://github.com/tidalcycles/strudel/pull/70
|
||||
- webaudio package by @felixroos in https://github.com/tidalcycles/strudel/pull/26
|
||||
- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://github.com/tidalcycles/strudel/pull/73
|
||||
- More random functions by @yaxu in https://github.com/tidalcycles/strudel/pull/74
|
||||
- Try to fix appLeft / appRight by @yaxu in https://github.com/tidalcycles/strudel/pull/75
|
||||
- Basic webserial support by @yaxu in https://github.com/tidalcycles/strudel/pull/80
|
||||
- Webaudio in REPL by @felixroos in https://github.com/tidalcycles/strudel/pull/77
|
||||
- add `striate()` by @yaxu in https://github.com/tidalcycles/strudel/pull/76
|
||||
- Tidy up a couple of old files by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/84
|
||||
- Add pattern composers, implements #82 by @yaxu in https://github.com/tidalcycles/strudel/pull/83
|
||||
- Fiddles with cat/stack by @yaxu in https://github.com/tidalcycles/strudel/pull/90
|
||||
- Paper by @felixroos in https://github.com/tidalcycles/strudel/pull/98
|
||||
- Change to Affero GPL by @yaxu in https://github.com/tidalcycles/strudel/pull/101
|
||||
- Work on Codemirror 6 highlighting by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/102
|
||||
- Codemirror 6 by @felixroos in https://github.com/tidalcycles/strudel/pull/97
|
||||
- Tune tests by @felixroos in https://github.com/tidalcycles/strudel/pull/104
|
||||
- /embed package: web component for repl by @felixroos in https://github.com/tidalcycles/strudel/pull/106
|
||||
- Reset, Restart and other composers by @felixroos in https://github.com/tidalcycles/strudel/pull/88
|
||||
- Embed style by @felixroos in https://github.com/tidalcycles/strudel/pull/109
|
||||
- In source doc by @yaxu in https://github.com/tidalcycles/strudel/pull/105
|
||||
- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://github.com/tidalcycles/strudel/pull/112
|
||||
- loopAt by @yaxu in https://github.com/tidalcycles/strudel/pull/114
|
||||
- Osc timing improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/113
|
||||
- react package + vite build by @felixroos in https://github.com/tidalcycles/strudel/pull/116
|
||||
- In source doc by @felixroos in https://github.com/tidalcycles/strudel/pull/117
|
||||
- fix: #108 by @felixroos in https://github.com/tidalcycles/strudel/pull/123
|
||||
- fix: #122 ctrl enter would add newline by @felixroos in https://github.com/tidalcycles/strudel/pull/124
|
||||
- Webdirt by @felixroos in https://github.com/tidalcycles/strudel/pull/121
|
||||
- Fix link to contributing to tutorial docs by @stephendwolff in https://github.com/tidalcycles/strudel/pull/129
|
||||
- Pianoroll enhancements by @felixroos in https://github.com/tidalcycles/strudel/pull/131
|
||||
- add createParam + createParams by @felixroos in https://github.com/tidalcycles/strudel/pull/110
|
||||
- remove cycle + delta from onTrigger by @felixroos in https://github.com/tidalcycles/strudel/pull/135
|
||||
- Scheduler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/134
|
||||
- add onTrigger helper by @felixroos in https://github.com/tidalcycles/strudel/pull/136
|
||||
- Add chunk, chunkBack and iterBack by @yaxu in https://codeberg.org/uzu/strudel/pulls/25
|
||||
- Update tutorial.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/37
|
||||
- Update tutorial.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/38
|
||||
- Compose by @felixroos in https://codeberg.org/uzu/strudel/pulls/40
|
||||
- Fix polymeter by @yaxu in https://codeberg.org/uzu/strudel/pulls/44
|
||||
- First run at squeezeBind, ref #32 by @yaxu in https://codeberg.org/uzu/strudel/pulls/48
|
||||
- Implement `chop()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/50
|
||||
- OSC and SuperDirt support by @yaxu in https://codeberg.org/uzu/strudel/pulls/27
|
||||
- More functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/56
|
||||
- More functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/61
|
||||
- Separate out strudel.mjs, make index.mjs aggregate module by @yaxu in https://codeberg.org/uzu/strudel/pulls/62
|
||||
- Speech output by @felixroos in https://codeberg.org/uzu/strudel/pulls/67
|
||||
- use new fixed version of osc-js package by @felixroos in https://codeberg.org/uzu/strudel/pulls/68
|
||||
- First effort at rand() by @yaxu in https://codeberg.org/uzu/strudel/pulls/69
|
||||
- More randomness, fix `rand`, and add `brand`, `irand` and `choose` by @yaxu in https://codeberg.org/uzu/strudel/pulls/70
|
||||
- webaudio package by @felixroos in https://codeberg.org/uzu/strudel/pulls/26
|
||||
- Port `perlin` noise, `rangex`, and `palindrome` by @yaxu in https://codeberg.org/uzu/strudel/pulls/73
|
||||
- More random functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/74
|
||||
- Try to fix appLeft / appRight by @yaxu in https://codeberg.org/uzu/strudel/pulls/75
|
||||
- Basic webserial support by @yaxu in https://codeberg.org/uzu/strudel/pulls/80
|
||||
- Webaudio in REPL by @felixroos in https://codeberg.org/uzu/strudel/pulls/77
|
||||
- add `striate()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/76
|
||||
- Tidy up a couple of old files by @mindofmatthew in https://codeberg.org/uzu/strudel/pulls/84
|
||||
- Add pattern composers, implements #82 by @yaxu in https://codeberg.org/uzu/strudel/pulls/83
|
||||
- Fiddles with cat/stack by @yaxu in https://codeberg.org/uzu/strudel/pulls/90
|
||||
- Paper by @felixroos in https://codeberg.org/uzu/strudel/pulls/98
|
||||
- Change to Affero GPL by @yaxu in https://codeberg.org/uzu/strudel/pulls/101
|
||||
- Work on Codemirror 6 highlighting by @mindofmatthew in https://codeberg.org/uzu/strudel/pulls/102
|
||||
- Codemirror 6 by @felixroos in https://codeberg.org/uzu/strudel/pulls/97
|
||||
- Tune tests by @felixroos in https://codeberg.org/uzu/strudel/pulls/104
|
||||
- /embed package: web component for repl by @felixroos in https://codeberg.org/uzu/strudel/pulls/106
|
||||
- Reset, Restart and other composers by @felixroos in https://codeberg.org/uzu/strudel/pulls/88
|
||||
- Embed style by @felixroos in https://codeberg.org/uzu/strudel/pulls/109
|
||||
- In source doc by @yaxu in https://codeberg.org/uzu/strudel/pulls/105
|
||||
- `.brak()`, `.inside()` and `.outside()` by @yaxu in https://codeberg.org/uzu/strudel/pulls/112
|
||||
- loopAt by @yaxu in https://codeberg.org/uzu/strudel/pulls/114
|
||||
- Osc timing improvements by @yaxu in https://codeberg.org/uzu/strudel/pulls/113
|
||||
- react package + vite build by @felixroos in https://codeberg.org/uzu/strudel/pulls/116
|
||||
- In source doc by @felixroos in https://codeberg.org/uzu/strudel/pulls/117
|
||||
- fix: #108 by @felixroos in https://codeberg.org/uzu/strudel/pulls/123
|
||||
- fix: #122 ctrl enter would add newline by @felixroos in https://codeberg.org/uzu/strudel/pulls/124
|
||||
- Webdirt by @felixroos in https://codeberg.org/uzu/strudel/pulls/121
|
||||
- Fix link to contributing to tutorial docs by @stephendwolff in https://codeberg.org/uzu/strudel/pulls/129
|
||||
- Pianoroll enhancements by @felixroos in https://codeberg.org/uzu/strudel/pulls/131
|
||||
- add createParam + createParams by @felixroos in https://codeberg.org/uzu/strudel/pulls/110
|
||||
- remove cycle + delta from onTrigger by @felixroos in https://codeberg.org/uzu/strudel/pulls/135
|
||||
- Scheduler improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/134
|
||||
- add onTrigger helper by @felixroos in https://codeberg.org/uzu/strudel/pulls/136
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @bwagner made their first contribution in https://github.com/tidalcycles/strudel/pull/37
|
||||
- @mindofmatthew made their first contribution in https://github.com/tidalcycles/strudel/pull/84
|
||||
- @stephendwolff made their first contribution in https://github.com/tidalcycles/strudel/pull/129
|
||||
- @bwagner made their first contribution in https://codeberg.org/uzu/strudel/pulls/37
|
||||
- @mindofmatthew made their first contribution in https://codeberg.org/uzu/strudel/pulls/84
|
||||
- @stephendwolff made their first contribution in https://codeberg.org/uzu/strudel/pulls/129
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.2...v0.0.3
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.0.2...v0.0.3
|
||||
|
||||
@@ -8,38 +8,38 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Webaudio rewrite by @felixroos in https://github.com/tidalcycles/strudel/pull/138
|
||||
- Fix createParam() by @yaxu in https://github.com/tidalcycles/strudel/pull/140
|
||||
- Soundfont Support by @felixroos in https://github.com/tidalcycles/strudel/pull/139
|
||||
- Serial twiddles by @yaxu in https://github.com/tidalcycles/strudel/pull/141
|
||||
- Pianoroll Object Support by @felixroos in https://github.com/tidalcycles/strudel/pull/142
|
||||
- flash effect on ctrl enter by @felixroos in https://github.com/tidalcycles/strudel/pull/144
|
||||
- can now generate short link for sharing by @felixroos in https://github.com/tidalcycles/strudel/pull/146
|
||||
- Sampler optimizations and more by @felixroos in https://github.com/tidalcycles/strudel/pull/148
|
||||
- Final update to demo.pdf by @yaxu in https://github.com/tidalcycles/strudel/pull/151
|
||||
- add webdirt drum samples to prebake for general availability by @larkob in https://github.com/tidalcycles/strudel/pull/150
|
||||
- update to tutorial documentation by @larkob in https://github.com/tidalcycles/strudel/pull/162
|
||||
- add chooseInWith/chooseCycles by @yaxu in https://github.com/tidalcycles/strudel/pull/166
|
||||
- fix: jsdoc comments by @felixroos in https://github.com/tidalcycles/strudel/pull/169
|
||||
- Pianoroll fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/163
|
||||
- Talk fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/164
|
||||
- Amend shapeshifter to allow use of dynamic import by @debrisapron in https://github.com/tidalcycles/strudel/pull/171
|
||||
- add more shapeshifter flags by @felixroos in https://github.com/tidalcycles/strudel/pull/99
|
||||
- Replace react-codemirror6 with @uiw/react-codemirror by @felixroos in https://github.com/tidalcycles/strudel/pull/173
|
||||
- fix some annoying bugs by @felixroos in https://github.com/tidalcycles/strudel/pull/177
|
||||
- incorporate elements of randomness to the mini notation by @bpow in https://github.com/tidalcycles/strudel/pull/165
|
||||
- replace mocha with vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/175
|
||||
- scheduler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/181
|
||||
- Fix codemirror bug by @felixroos in https://github.com/tidalcycles/strudel/pull/186
|
||||
- wait for prebake to finish before evaluating by @felixroos in https://github.com/tidalcycles/strudel/pull/189
|
||||
- fix regression: old way of setting frequencies was broken by @felixroos in https://github.com/tidalcycles/strudel/pull/190
|
||||
- Soundfont file support by @felixroos in https://github.com/tidalcycles/strudel/pull/183
|
||||
- change "stride"/"offset" of successive degradeBy/chooseIn by @bpow in https://github.com/tidalcycles/strudel/pull/185
|
||||
- Webaudio rewrite by @felixroos in https://codeberg.org/uzu/strudel/pulls/138
|
||||
- Fix createParam() by @yaxu in https://codeberg.org/uzu/strudel/pulls/140
|
||||
- Soundfont Support by @felixroos in https://codeberg.org/uzu/strudel/pulls/139
|
||||
- Serial twiddles by @yaxu in https://codeberg.org/uzu/strudel/pulls/141
|
||||
- Pianoroll Object Support by @felixroos in https://codeberg.org/uzu/strudel/pulls/142
|
||||
- flash effect on ctrl enter by @felixroos in https://codeberg.org/uzu/strudel/pulls/144
|
||||
- can now generate short link for sharing by @felixroos in https://codeberg.org/uzu/strudel/pulls/146
|
||||
- Sampler optimizations and more by @felixroos in https://codeberg.org/uzu/strudel/pulls/148
|
||||
- Final update to demo.pdf by @yaxu in https://codeberg.org/uzu/strudel/pulls/151
|
||||
- add webdirt drum samples to prebake for general availability by @larkob in https://codeberg.org/uzu/strudel/pulls/150
|
||||
- update to tutorial documentation by @larkob in https://codeberg.org/uzu/strudel/pulls/162
|
||||
- add chooseInWith/chooseCycles by @yaxu in https://codeberg.org/uzu/strudel/pulls/166
|
||||
- fix: jsdoc comments by @felixroos in https://codeberg.org/uzu/strudel/pulls/169
|
||||
- Pianoroll fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/163
|
||||
- Talk fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/164
|
||||
- Amend shapeshifter to allow use of dynamic import by @debrisapron in https://codeberg.org/uzu/strudel/pulls/171
|
||||
- add more shapeshifter flags by @felixroos in https://codeberg.org/uzu/strudel/pulls/99
|
||||
- Replace react-codemirror6 with @uiw/react-codemirror by @felixroos in https://codeberg.org/uzu/strudel/pulls/173
|
||||
- fix some annoying bugs by @felixroos in https://codeberg.org/uzu/strudel/pulls/177
|
||||
- incorporate elements of randomness to the mini notation by @bpow in https://codeberg.org/uzu/strudel/pulls/165
|
||||
- replace mocha with vitest by @felixroos in https://codeberg.org/uzu/strudel/pulls/175
|
||||
- scheduler improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/181
|
||||
- Fix codemirror bug by @felixroos in https://codeberg.org/uzu/strudel/pulls/186
|
||||
- wait for prebake to finish before evaluating by @felixroos in https://codeberg.org/uzu/strudel/pulls/189
|
||||
- fix regression: old way of setting frequencies was broken by @felixroos in https://codeberg.org/uzu/strudel/pulls/190
|
||||
- Soundfont file support by @felixroos in https://codeberg.org/uzu/strudel/pulls/183
|
||||
- change "stride"/"offset" of successive degradeBy/chooseIn by @bpow in https://codeberg.org/uzu/strudel/pulls/185
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @larkob made their first contribution in https://github.com/tidalcycles/strudel/pull/150
|
||||
- @debrisapron made their first contribution in https://github.com/tidalcycles/strudel/pull/171
|
||||
- @bpow made their first contribution in https://github.com/tidalcycles/strudel/pull/165
|
||||
- @larkob made their first contribution in https://codeberg.org/uzu/strudel/pulls/150
|
||||
- @debrisapron made their first contribution in https://codeberg.org/uzu/strudel/pulls/171
|
||||
- @bpow made their first contribution in https://codeberg.org/uzu/strudel/pulls/165
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.3...v0.0.4
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.0.3...v0.0.4
|
||||
|
||||
@@ -22,44 +22,44 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Fix numbers in sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/196
|
||||
- document random functions by @felixroos in https://github.com/tidalcycles/strudel/pull/199
|
||||
- add rollup-plugin-visualizer to build by @felixroos in https://github.com/tidalcycles/strudel/pull/200
|
||||
- add vowel to .out by @felixroos in https://github.com/tidalcycles/strudel/pull/201
|
||||
- Coarse crush shape by @felixroos in https://github.com/tidalcycles/strudel/pull/205
|
||||
- Webaudio guide by @felixroos in https://github.com/tidalcycles/strudel/pull/207
|
||||
- Even more docs by @felixroos in https://github.com/tidalcycles/strudel/pull/212
|
||||
- Just another docs PR by @felixroos in https://github.com/tidalcycles/strudel/pull/215
|
||||
- sampler features + fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/217
|
||||
- samples now have envelopes by @felixroos in https://github.com/tidalcycles/strudel/pull/218
|
||||
- encapsulate webaudio output by @felixroos in https://github.com/tidalcycles/strudel/pull/219
|
||||
- Fix squeeze join by @yaxu in https://github.com/tidalcycles/strudel/pull/220
|
||||
- Feedback Delay by @felixroos in https://github.com/tidalcycles/strudel/pull/213
|
||||
- support negative speeds by @felixroos in https://github.com/tidalcycles/strudel/pull/222
|
||||
- focus tweak for squeezeJoin - another go at fixing #216 by @yaxu in https://github.com/tidalcycles/strudel/pull/221
|
||||
- Reverb by @felixroos in https://github.com/tidalcycles/strudel/pull/224
|
||||
- fix fastgap for events that go across cycle boundaries by @yaxu in https://github.com/tidalcycles/strudel/pull/225
|
||||
- Core util tests by @mystery-house in https://github.com/tidalcycles/strudel/pull/226
|
||||
- Refactor tunes away from tone by @felixroos in https://github.com/tidalcycles/strudel/pull/230
|
||||
- Just another docs branch by @felixroos in https://github.com/tidalcycles/strudel/pull/228
|
||||
- Patternify range by @yaxu in https://github.com/tidalcycles/strudel/pull/231
|
||||
- Out by default by @felixroos in https://github.com/tidalcycles/strudel/pull/232
|
||||
- Fix zero length queries WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/234
|
||||
- add vcsl sample library by @felixroos in https://github.com/tidalcycles/strudel/pull/235
|
||||
- fx on stereo speakers by @felixroos in https://github.com/tidalcycles/strudel/pull/236
|
||||
- Tidal drum machines by @felixroos in https://github.com/tidalcycles/strudel/pull/237
|
||||
- Object arithmetic by @felixroos in https://github.com/tidalcycles/strudel/pull/238
|
||||
- Load samples from url by @felixroos in https://github.com/tidalcycles/strudel/pull/239
|
||||
- feat: support github: links by @felixroos in https://github.com/tidalcycles/strudel/pull/240
|
||||
- in source example tests by @felixroos in https://github.com/tidalcycles/strudel/pull/242
|
||||
- Readme + TLC by @felixroos in https://github.com/tidalcycles/strudel/pull/244
|
||||
- patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/246
|
||||
- Some tunes by @felixroos in https://github.com/tidalcycles/strudel/pull/247
|
||||
- snapshot tests on shared snippets by @felixroos in https://github.com/tidalcycles/strudel/pull/243
|
||||
- General purpose scheduler by @felixroos in https://github.com/tidalcycles/strudel/pull/248
|
||||
- Fix numbers in sampler by @felixroos in https://codeberg.org/uzu/strudel/pulls/196
|
||||
- document random functions by @felixroos in https://codeberg.org/uzu/strudel/pulls/199
|
||||
- add rollup-plugin-visualizer to build by @felixroos in https://codeberg.org/uzu/strudel/pulls/200
|
||||
- add vowel to .out by @felixroos in https://codeberg.org/uzu/strudel/pulls/201
|
||||
- Coarse crush shape by @felixroos in https://codeberg.org/uzu/strudel/pulls/205
|
||||
- Webaudio guide by @felixroos in https://codeberg.org/uzu/strudel/pulls/207
|
||||
- Even more docs by @felixroos in https://codeberg.org/uzu/strudel/pulls/212
|
||||
- Just another docs PR by @felixroos in https://codeberg.org/uzu/strudel/pulls/215
|
||||
- sampler features + fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/217
|
||||
- samples now have envelopes by @felixroos in https://codeberg.org/uzu/strudel/pulls/218
|
||||
- encapsulate webaudio output by @felixroos in https://codeberg.org/uzu/strudel/pulls/219
|
||||
- Fix squeeze join by @yaxu in https://codeberg.org/uzu/strudel/pulls/220
|
||||
- Feedback Delay by @felixroos in https://codeberg.org/uzu/strudel/pulls/213
|
||||
- support negative speeds by @felixroos in https://codeberg.org/uzu/strudel/pulls/222
|
||||
- focus tweak for squeezeJoin - another go at fixing #216 by @yaxu in https://codeberg.org/uzu/strudel/pulls/221
|
||||
- Reverb by @felixroos in https://codeberg.org/uzu/strudel/pulls/224
|
||||
- fix fastgap for events that go across cycle boundaries by @yaxu in https://codeberg.org/uzu/strudel/pulls/225
|
||||
- Core util tests by @mystery-house in https://codeberg.org/uzu/strudel/pulls/226
|
||||
- Refactor tunes away from tone by @felixroos in https://codeberg.org/uzu/strudel/pulls/230
|
||||
- Just another docs branch by @felixroos in https://codeberg.org/uzu/strudel/pulls/228
|
||||
- Patternify range by @yaxu in https://codeberg.org/uzu/strudel/pulls/231
|
||||
- Out by default by @felixroos in https://codeberg.org/uzu/strudel/pulls/232
|
||||
- Fix zero length queries WIP by @yaxu in https://codeberg.org/uzu/strudel/pulls/234
|
||||
- add vcsl sample library by @felixroos in https://codeberg.org/uzu/strudel/pulls/235
|
||||
- fx on stereo speakers by @felixroos in https://codeberg.org/uzu/strudel/pulls/236
|
||||
- Tidal drum machines by @felixroos in https://codeberg.org/uzu/strudel/pulls/237
|
||||
- Object arithmetic by @felixroos in https://codeberg.org/uzu/strudel/pulls/238
|
||||
- Load samples from url by @felixroos in https://codeberg.org/uzu/strudel/pulls/239
|
||||
- feat: support github: links by @felixroos in https://codeberg.org/uzu/strudel/pulls/240
|
||||
- in source example tests by @felixroos in https://codeberg.org/uzu/strudel/pulls/242
|
||||
- Readme + TLC by @felixroos in https://codeberg.org/uzu/strudel/pulls/244
|
||||
- patchday by @felixroos in https://codeberg.org/uzu/strudel/pulls/246
|
||||
- Some tunes by @felixroos in https://codeberg.org/uzu/strudel/pulls/247
|
||||
- snapshot tests on shared snippets by @felixroos in https://codeberg.org/uzu/strudel/pulls/243
|
||||
- General purpose scheduler by @felixroos in https://codeberg.org/uzu/strudel/pulls/248
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @mystery-house made their first contribution in https://github.com/tidalcycles/strudel/pull/226
|
||||
- @mystery-house made their first contribution in https://codeberg.org/uzu/strudel/pulls/226
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.0.4...v0.3.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.0.4...v0.3.0
|
||||
|
||||
@@ -8,8 +8,8 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- new transpiler based on acorn by @felixroos in https://github.com/tidalcycles/strudel/pull/249
|
||||
- Webaudio build by @felixroos in https://github.com/tidalcycles/strudel/pull/250
|
||||
- Repl refactoring by @felixroos in https://github.com/tidalcycles/strudel/pull/255
|
||||
- new transpiler based on acorn by @felixroos in https://codeberg.org/uzu/strudel/pulls/249
|
||||
- Webaudio build by @felixroos in https://codeberg.org/uzu/strudel/pulls/250
|
||||
- Repl refactoring by @felixroos in https://codeberg.org/uzu/strudel/pulls/255
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.3.0...v0.4.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.3.0...v0.4.0
|
||||
|
||||
@@ -26,34 +26,34 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- Binaries by @felixroos in https://github.com/tidalcycles/strudel/pull/254
|
||||
- fix tutorial bugs by @felixroos in https://github.com/tidalcycles/strudel/pull/263
|
||||
- fix performance bottleneck by @felixroos in https://github.com/tidalcycles/strudel/pull/266
|
||||
- Tidying up core by @yaxu in https://github.com/tidalcycles/strudel/pull/256
|
||||
- tonal update with fixed memory leak by @felixroos in https://github.com/tidalcycles/strudel/pull/272
|
||||
- add eslint by @felixroos in https://github.com/tidalcycles/strudel/pull/271
|
||||
- release version bumps by @felixroos in https://github.com/tidalcycles/strudel/pull/273
|
||||
- Support sending CRC16 bytes with serial messages by @yaxu in https://github.com/tidalcycles/strudel/pull/276
|
||||
- add licenses / credits to all tunes + remove some by @felixroos in https://github.com/tidalcycles/strudel/pull/277
|
||||
- add basic csound output by @felixroos in https://github.com/tidalcycles/strudel/pull/275
|
||||
- do not recompile orc by @felixroos in https://github.com/tidalcycles/strudel/pull/278
|
||||
- implement collect + arp function by @felixroos in https://github.com/tidalcycles/strudel/pull/281
|
||||
- Switch 'operators' from .whatHow to .what.how by @yaxu in https://github.com/tidalcycles/strudel/pull/285
|
||||
- Fancy hap show, include part in snapshots by @yaxu in https://github.com/tidalcycles/strudel/pull/291
|
||||
- Reorganise pattern.mjs with a 'toplevel first' regime by @yaxu in https://github.com/tidalcycles/strudel/pull/286
|
||||
- add prettier task by @felixroos in https://github.com/tidalcycles/strudel/pull/296
|
||||
- Move stuff to new register function by @felixroos in https://github.com/tidalcycles/strudel/pull/295
|
||||
- can now add bare numbers to numeral object props by @felixroos in https://github.com/tidalcycles/strudel/pull/287
|
||||
- update vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/297
|
||||
- remove whitespace from highlighted region by @felixroos in https://github.com/tidalcycles/strudel/pull/298
|
||||
- .defragmentHaps() for merging touching haps that share a whole and value by @yaxu in https://github.com/tidalcycles/strudel/pull/299
|
||||
- fix whitespace trimming by @felixroos in https://github.com/tidalcycles/strudel/pull/300
|
||||
- add freq support to sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/301
|
||||
- add lint + prettier check before test by @felixroos in https://github.com/tidalcycles/strudel/pull/305
|
||||
- Updated csoundm to use the register facility . by @gogins in https://github.com/tidalcycles/strudel/pull/303
|
||||
- Binaries by @felixroos in https://codeberg.org/uzu/strudel/pulls/254
|
||||
- fix tutorial bugs by @felixroos in https://codeberg.org/uzu/strudel/pulls/263
|
||||
- fix performance bottleneck by @felixroos in https://codeberg.org/uzu/strudel/pulls/266
|
||||
- Tidying up core by @yaxu in https://codeberg.org/uzu/strudel/pulls/256
|
||||
- tonal update with fixed memory leak by @felixroos in https://codeberg.org/uzu/strudel/pulls/272
|
||||
- add eslint by @felixroos in https://codeberg.org/uzu/strudel/pulls/271
|
||||
- release version bumps by @felixroos in https://codeberg.org/uzu/strudel/pulls/273
|
||||
- Support sending CRC16 bytes with serial messages by @yaxu in https://codeberg.org/uzu/strudel/pulls/276
|
||||
- add licenses / credits to all tunes + remove some by @felixroos in https://codeberg.org/uzu/strudel/pulls/277
|
||||
- add basic csound output by @felixroos in https://codeberg.org/uzu/strudel/pulls/275
|
||||
- do not recompile orc by @felixroos in https://codeberg.org/uzu/strudel/pulls/278
|
||||
- implement collect + arp function by @felixroos in https://codeberg.org/uzu/strudel/pulls/281
|
||||
- Switch 'operators' from .whatHow to .what.how by @yaxu in https://codeberg.org/uzu/strudel/pulls/285
|
||||
- Fancy hap show, include part in snapshots by @yaxu in https://codeberg.org/uzu/strudel/pulls/291
|
||||
- Reorganise pattern.mjs with a 'toplevel first' regime by @yaxu in https://codeberg.org/uzu/strudel/pulls/286
|
||||
- add prettier task by @felixroos in https://codeberg.org/uzu/strudel/pulls/296
|
||||
- Move stuff to new register function by @felixroos in https://codeberg.org/uzu/strudel/pulls/295
|
||||
- can now add bare numbers to numeral object props by @felixroos in https://codeberg.org/uzu/strudel/pulls/287
|
||||
- update vitest by @felixroos in https://codeberg.org/uzu/strudel/pulls/297
|
||||
- remove whitespace from highlighted region by @felixroos in https://codeberg.org/uzu/strudel/pulls/298
|
||||
- .defragmentHaps() for merging touching haps that share a whole and value by @yaxu in https://codeberg.org/uzu/strudel/pulls/299
|
||||
- fix whitespace trimming by @felixroos in https://codeberg.org/uzu/strudel/pulls/300
|
||||
- add freq support to sampler by @felixroos in https://codeberg.org/uzu/strudel/pulls/301
|
||||
- add lint + prettier check before test by @felixroos in https://codeberg.org/uzu/strudel/pulls/305
|
||||
- Updated csoundm to use the register facility . by @gogins in https://codeberg.org/uzu/strudel/pulls/303
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @gogins made their first contribution in https://github.com/tidalcycles/strudel/pull/303
|
||||
- @gogins made their first contribution in https://codeberg.org/uzu/strudel/pulls/303
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.4.0...v0.5.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.4.0...v0.5.0
|
||||
|
||||
@@ -26,59 +26,59 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- support freq in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/308
|
||||
- ICLC2023 paper WIP by @yaxu in https://github.com/tidalcycles/strudel/pull/306
|
||||
- fix: copy share link to clipboard was broken for some browsers by @felixroos in https://github.com/tidalcycles/strudel/pull/311
|
||||
- Jsdoc component by @felixroos in https://github.com/tidalcycles/strudel/pull/312
|
||||
- object support for .scale by @felixroos in https://github.com/tidalcycles/strudel/pull/307
|
||||
- Astro build by @felixroos in https://github.com/tidalcycles/strudel/pull/315
|
||||
- Reference tab sort by @felixroos in https://github.com/tidalcycles/strudel/pull/318
|
||||
- tutorial updates by @jarmitage in https://github.com/tidalcycles/strudel/pull/320
|
||||
- support notes without octave by @felixroos in https://github.com/tidalcycles/strudel/pull/323
|
||||
- mini repl improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/324
|
||||
- fix: workaround Object.assign globalThis by @felixroos in https://github.com/tidalcycles/strudel/pull/326
|
||||
- add examples route by @felixroos in https://github.com/tidalcycles/strudel/pull/327
|
||||
- add my-patterns by @felixroos in https://github.com/tidalcycles/strudel/pull/328
|
||||
- my-patterns build + deploy by @felixroos in https://github.com/tidalcycles/strudel/pull/329
|
||||
- my-patterns: fix paths + update readme by @felixroos in https://github.com/tidalcycles/strudel/pull/330
|
||||
- improve displaying 's' in pianoroll by @felixroos in https://github.com/tidalcycles/strudel/pull/331
|
||||
- fix: can now multiply floats in mini notation by @felixroos in https://github.com/tidalcycles/strudel/pull/332
|
||||
- Embed mode improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/333
|
||||
- testing + docs docs by @felixroos in https://github.com/tidalcycles/strudel/pull/334
|
||||
- animate mvp by @felixroos in https://github.com/tidalcycles/strudel/pull/335
|
||||
- Tidy parser, implement polymeters by @yaxu in https://github.com/tidalcycles/strudel/pull/336
|
||||
- animation options by @felixroos in https://github.com/tidalcycles/strudel/pull/337
|
||||
- move /my-patterns to /swatch by @yaxu in https://github.com/tidalcycles/strudel/pull/338
|
||||
- more animate functions + mini repl fix by @felixroos in https://github.com/tidalcycles/strudel/pull/340
|
||||
- Patternify euclid, fast, slow and polymeter step parameters in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/341
|
||||
- fixes #346 by @felixroos in https://github.com/tidalcycles/strudel/pull/347
|
||||
- Fix prebake base path by @felixroos in https://github.com/tidalcycles/strudel/pull/345
|
||||
- Fix Bjorklund by @yaxu in https://github.com/tidalcycles/strudel/pull/343
|
||||
- docs: tidal comparison + add global fx + add missing sampler fx by @felixroos in https://github.com/tidalcycles/strudel/pull/356
|
||||
- Fix .out(), renaming webaudio's out() to webaudio() by @yaxu in https://github.com/tidalcycles/strudel/pull/361
|
||||
- Support for multiple mininotation operators by @yaxu in https://github.com/tidalcycles/strudel/pull/350
|
||||
- doc structuring by @felixroos in https://github.com/tidalcycles/strudel/pull/360
|
||||
- add https to url by @urswilke in https://github.com/tidalcycles/strudel/pull/364
|
||||
- document more functions + change arp join by @felixroos in https://github.com/tidalcycles/strudel/pull/369
|
||||
- improve new draw logic by @felixroos in https://github.com/tidalcycles/strudel/pull/372
|
||||
- Draw fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/377
|
||||
- update my-patterns instructions by @felixroos in https://github.com/tidalcycles/strudel/pull/384
|
||||
- docs: use note instead of n to mitigate confusion by @felixroos in https://github.com/tidalcycles/strudel/pull/385
|
||||
- add run + test + docs by @felixroos in https://github.com/tidalcycles/strudel/pull/386
|
||||
- Rename a to angle by @felixroos in https://github.com/tidalcycles/strudel/pull/387
|
||||
- document csound by @felixroos in https://github.com/tidalcycles/strudel/pull/391
|
||||
- Notes are not essential :) by @yaxu in https://github.com/tidalcycles/strudel/pull/393
|
||||
- add ribbon + test + docs by @felixroos in https://github.com/tidalcycles/strudel/pull/388
|
||||
- Add tidal-drum-patterns to examples by @urswilke in https://github.com/tidalcycles/strudel/pull/379
|
||||
- add pattern methods hurry, press and pressBy by @yaxu in https://github.com/tidalcycles/strudel/pull/397
|
||||
- proper builds + use pnpm workspaces by @felixroos in https://github.com/tidalcycles/strudel/pull/396
|
||||
- fix: minirepl styles by @felixroos in https://github.com/tidalcycles/strudel/pull/398
|
||||
- can now await initAudio + initAudioOnFirstClick by @felixroos in https://github.com/tidalcycles/strudel/pull/399
|
||||
- release webaudio by @felixroos in https://github.com/tidalcycles/strudel/pull/400
|
||||
- support freq in pianoroll by @felixroos in https://codeberg.org/uzu/strudel/pulls/308
|
||||
- ICLC2023 paper WIP by @yaxu in https://codeberg.org/uzu/strudel/pulls/306
|
||||
- fix: copy share link to clipboard was broken for some browsers by @felixroos in https://codeberg.org/uzu/strudel/pulls/311
|
||||
- Jsdoc component by @felixroos in https://codeberg.org/uzu/strudel/pulls/312
|
||||
- object support for .scale by @felixroos in https://codeberg.org/uzu/strudel/pulls/307
|
||||
- Astro build by @felixroos in https://codeberg.org/uzu/strudel/pulls/315
|
||||
- Reference tab sort by @felixroos in https://codeberg.org/uzu/strudel/pulls/318
|
||||
- tutorial updates by @jarmitage in https://codeberg.org/uzu/strudel/pulls/320
|
||||
- support notes without octave by @felixroos in https://codeberg.org/uzu/strudel/pulls/323
|
||||
- mini repl improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/324
|
||||
- fix: workaround Object.assign globalThis by @felixroos in https://codeberg.org/uzu/strudel/pulls/326
|
||||
- add examples route by @felixroos in https://codeberg.org/uzu/strudel/pulls/327
|
||||
- add my-patterns by @felixroos in https://codeberg.org/uzu/strudel/pulls/328
|
||||
- my-patterns build + deploy by @felixroos in https://codeberg.org/uzu/strudel/pulls/329
|
||||
- my-patterns: fix paths + update readme by @felixroos in https://codeberg.org/uzu/strudel/pulls/330
|
||||
- improve displaying 's' in pianoroll by @felixroos in https://codeberg.org/uzu/strudel/pulls/331
|
||||
- fix: can now multiply floats in mini notation by @felixroos in https://codeberg.org/uzu/strudel/pulls/332
|
||||
- Embed mode improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/333
|
||||
- testing + docs docs by @felixroos in https://codeberg.org/uzu/strudel/pulls/334
|
||||
- animate mvp by @felixroos in https://codeberg.org/uzu/strudel/pulls/335
|
||||
- Tidy parser, implement polymeters by @yaxu in https://codeberg.org/uzu/strudel/pulls/336
|
||||
- animation options by @felixroos in https://codeberg.org/uzu/strudel/pulls/337
|
||||
- move /my-patterns to /swatch by @yaxu in https://codeberg.org/uzu/strudel/pulls/338
|
||||
- more animate functions + mini repl fix by @felixroos in https://codeberg.org/uzu/strudel/pulls/340
|
||||
- Patternify euclid, fast, slow and polymeter step parameters in mininotation by @yaxu in https://codeberg.org/uzu/strudel/pulls/341
|
||||
- fixes #346 by @felixroos in https://codeberg.org/uzu/strudel/pulls/347
|
||||
- Fix prebake base path by @felixroos in https://codeberg.org/uzu/strudel/pulls/345
|
||||
- Fix Bjorklund by @yaxu in https://codeberg.org/uzu/strudel/pulls/343
|
||||
- docs: tidal comparison + add global fx + add missing sampler fx by @felixroos in https://codeberg.org/uzu/strudel/pulls/356
|
||||
- Fix .out(), renaming webaudio's out() to webaudio() by @yaxu in https://codeberg.org/uzu/strudel/pulls/361
|
||||
- Support for multiple mininotation operators by @yaxu in https://codeberg.org/uzu/strudel/pulls/350
|
||||
- doc structuring by @felixroos in https://codeberg.org/uzu/strudel/pulls/360
|
||||
- add https to url by @urswilke in https://codeberg.org/uzu/strudel/pulls/364
|
||||
- document more functions + change arp join by @felixroos in https://codeberg.org/uzu/strudel/pulls/369
|
||||
- improve new draw logic by @felixroos in https://codeberg.org/uzu/strudel/pulls/372
|
||||
- Draw fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/377
|
||||
- update my-patterns instructions by @felixroos in https://codeberg.org/uzu/strudel/pulls/384
|
||||
- docs: use note instead of n to mitigate confusion by @felixroos in https://codeberg.org/uzu/strudel/pulls/385
|
||||
- add run + test + docs by @felixroos in https://codeberg.org/uzu/strudel/pulls/386
|
||||
- Rename a to angle by @felixroos in https://codeberg.org/uzu/strudel/pulls/387
|
||||
- document csound by @felixroos in https://codeberg.org/uzu/strudel/pulls/391
|
||||
- Notes are not essential :) by @yaxu in https://codeberg.org/uzu/strudel/pulls/393
|
||||
- add ribbon + test + docs by @felixroos in https://codeberg.org/uzu/strudel/pulls/388
|
||||
- Add tidal-drum-patterns to examples by @urswilke in https://codeberg.org/uzu/strudel/pulls/379
|
||||
- add pattern methods hurry, press and pressBy by @yaxu in https://codeberg.org/uzu/strudel/pulls/397
|
||||
- proper builds + use pnpm workspaces by @felixroos in https://codeberg.org/uzu/strudel/pulls/396
|
||||
- fix: minirepl styles by @felixroos in https://codeberg.org/uzu/strudel/pulls/398
|
||||
- can now await initAudio + initAudioOnFirstClick by @felixroos in https://codeberg.org/uzu/strudel/pulls/399
|
||||
- release webaudio by @felixroos in https://codeberg.org/uzu/strudel/pulls/400
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @jarmitage made their first contribution in https://github.com/tidalcycles/strudel/pull/320
|
||||
- @urswilke made their first contribution in https://github.com/tidalcycles/strudel/pull/364
|
||||
- @jarmitage made their first contribution in https://codeberg.org/uzu/strudel/pulls/320
|
||||
- @urswilke made their first contribution in https://codeberg.org/uzu/strudel/pulls/364
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.5.0...v0.6.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.5.0...v0.6.0
|
||||
|
||||
@@ -23,66 +23,66 @@ author: froos
|
||||
|
||||
## What's Changed
|
||||
|
||||
- pin @csound/browser to 6.18.3 + bump by @felixroos in https://github.com/tidalcycles/strudel/pull/403
|
||||
- update csound + fix sound output by @felixroos in https://github.com/tidalcycles/strudel/pull/404
|
||||
- fix: share url on subpath by @felixroos in https://github.com/tidalcycles/strudel/pull/405
|
||||
- add shabda doc by @felixroos in https://github.com/tidalcycles/strudel/pull/407
|
||||
- Update effects.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/410
|
||||
- improve effects doc by @felixroos in https://github.com/tidalcycles/strudel/pull/409
|
||||
- google gtfo by @felixroos in https://github.com/tidalcycles/strudel/pull/413
|
||||
- improve samples doc by @felixroos in https://github.com/tidalcycles/strudel/pull/411
|
||||
- PWA with offline support by @felixroos in https://github.com/tidalcycles/strudel/pull/417
|
||||
- add caching strategy for missing file types + cache all samples loaded from github by @felixroos in https://github.com/tidalcycles/strudel/pull/419
|
||||
- add more offline caching by @felixroos in https://github.com/tidalcycles/strudel/pull/421
|
||||
- add cdn.freesound to cache list by @felixroos in https://github.com/tidalcycles/strudel/pull/425
|
||||
- minirepl: add keyboard shortcuts by @felixroos in https://github.com/tidalcycles/strudel/pull/429
|
||||
- Themes by @felixroos in https://github.com/tidalcycles/strudel/pull/431
|
||||
- autocomplete preparations by @felixroos in https://github.com/tidalcycles/strudel/pull/427
|
||||
- Fix anchors by @felixroos in https://github.com/tidalcycles/strudel/pull/433
|
||||
- Update code.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/436
|
||||
- Update mini-notation.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/437
|
||||
- Update synths.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/438
|
||||
- FIXES: Warning about jsxBracketSameLine deprecation by @bwagner in https://github.com/tidalcycles/strudel/pull/461
|
||||
- Composable functions by @yaxu in https://github.com/tidalcycles/strudel/pull/390
|
||||
- weave and weaveWith by @yaxu in https://github.com/tidalcycles/strudel/pull/465
|
||||
- slice and splice by @yaxu in https://github.com/tidalcycles/strudel/pull/466
|
||||
- fix: osc should not return a promise by @felixroos in https://github.com/tidalcycles/strudel/pull/472
|
||||
- FIXES: freqs instead of pitches by @bwagner in https://github.com/tidalcycles/strudel/pull/464
|
||||
- Update input-output.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/471
|
||||
- settings tab with vim / emacs modes + additional themes and fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/467
|
||||
- fix: hash links by @felixroos in https://github.com/tidalcycles/strudel/pull/473
|
||||
- midi cc support by @felixroos in https://github.com/tidalcycles/strudel/pull/478
|
||||
- Fix array args by @felixroos in https://github.com/tidalcycles/strudel/pull/480
|
||||
- docs: packages + offline by @felixroos in https://github.com/tidalcycles/strudel/pull/482
|
||||
- Update mini-notation.mdx by @yaxu in https://github.com/tidalcycles/strudel/pull/365
|
||||
- Revert "Another attempt at composable functions - WIP (#390)" by @felixroos in https://github.com/tidalcycles/strudel/pull/484
|
||||
- fix app height by @felixroos in https://github.com/tidalcycles/strudel/pull/485
|
||||
- add algolia creds + optimize sidebar for crawling by @felixroos in https://github.com/tidalcycles/strudel/pull/488
|
||||
- refactor react package by @felixroos in https://github.com/tidalcycles/strudel/pull/490
|
||||
- react style fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/491
|
||||
- implement cps in scheduler by @felixroos in https://github.com/tidalcycles/strudel/pull/493
|
||||
- Add control aliases by @yaxu in https://github.com/tidalcycles/strudel/pull/497
|
||||
- fix: nano-repl highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/501
|
||||
- Reinstate slice and splice by @yaxu in https://github.com/tidalcycles/strudel/pull/500
|
||||
- can now use : as a replacement for space in scales by @felixroos in https://github.com/tidalcycles/strudel/pull/502
|
||||
- Support list syntax in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/512
|
||||
- update react to 18 by @felixroos in https://github.com/tidalcycles/strudel/pull/514
|
||||
- add arrange function by @felixroos in https://github.com/tidalcycles/strudel/pull/508
|
||||
- Update README.md by @bwagner in https://github.com/tidalcycles/strudel/pull/474
|
||||
- add 2 illegible fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/518
|
||||
- registerSound API + improved sounds tab + regroup soundfonts by @felixroos in https://github.com/tidalcycles/strudel/pull/516
|
||||
- fix: envelopes in chrome by @felixroos in https://github.com/tidalcycles/strudel/pull/521
|
||||
- Update samples.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/524
|
||||
- Update intro.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/525
|
||||
- fix(footer): fix link to tidalcycles by @revolunet in https://github.com/tidalcycles/strudel/pull/529
|
||||
- FIXES: alias pm for polymeter by @bwagner in https://github.com/tidalcycles/strudel/pull/527
|
||||
- Maintain random seed state in parser, not globally by @ijc8 in https://github.com/tidalcycles/strudel/pull/531
|
||||
- feat: add freq support to gm soundfonts by @felixroos in https://github.com/tidalcycles/strudel/pull/534
|
||||
- Update lerna by @felixroos in https://github.com/tidalcycles/strudel/pull/535
|
||||
- pin @csound/browser to 6.18.3 + bump by @felixroos in https://codeberg.org/uzu/strudel/pulls/403
|
||||
- update csound + fix sound output by @felixroos in https://codeberg.org/uzu/strudel/pulls/404
|
||||
- fix: share url on subpath by @felixroos in https://codeberg.org/uzu/strudel/pulls/405
|
||||
- add shabda doc by @felixroos in https://codeberg.org/uzu/strudel/pulls/407
|
||||
- Update effects.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/410
|
||||
- improve effects doc by @felixroos in https://codeberg.org/uzu/strudel/pulls/409
|
||||
- google gtfo by @felixroos in https://codeberg.org/uzu/strudel/pulls/413
|
||||
- improve samples doc by @felixroos in https://codeberg.org/uzu/strudel/pulls/411
|
||||
- PWA with offline support by @felixroos in https://codeberg.org/uzu/strudel/pulls/417
|
||||
- add caching strategy for missing file types + cache all samples loaded from github by @felixroos in https://codeberg.org/uzu/strudel/pulls/419
|
||||
- add more offline caching by @felixroos in https://codeberg.org/uzu/strudel/pulls/421
|
||||
- add cdn.freesound to cache list by @felixroos in https://codeberg.org/uzu/strudel/pulls/425
|
||||
- minirepl: add keyboard shortcuts by @felixroos in https://codeberg.org/uzu/strudel/pulls/429
|
||||
- Themes by @felixroos in https://codeberg.org/uzu/strudel/pulls/431
|
||||
- autocomplete preparations by @felixroos in https://codeberg.org/uzu/strudel/pulls/427
|
||||
- Fix anchors by @felixroos in https://codeberg.org/uzu/strudel/pulls/433
|
||||
- Update code.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/436
|
||||
- Update mini-notation.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/437
|
||||
- Update synths.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/438
|
||||
- FIXES: Warning about jsxBracketSameLine deprecation by @bwagner in https://codeberg.org/uzu/strudel/pulls/461
|
||||
- Composable functions by @yaxu in https://codeberg.org/uzu/strudel/pulls/390
|
||||
- weave and weaveWith by @yaxu in https://codeberg.org/uzu/strudel/pulls/465
|
||||
- slice and splice by @yaxu in https://codeberg.org/uzu/strudel/pulls/466
|
||||
- fix: osc should not return a promise by @felixroos in https://codeberg.org/uzu/strudel/pulls/472
|
||||
- FIXES: freqs instead of pitches by @bwagner in https://codeberg.org/uzu/strudel/pulls/464
|
||||
- Update input-output.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/471
|
||||
- settings tab with vim / emacs modes + additional themes and fonts by @felixroos in https://codeberg.org/uzu/strudel/pulls/467
|
||||
- fix: hash links by @felixroos in https://codeberg.org/uzu/strudel/pulls/473
|
||||
- midi cc support by @felixroos in https://codeberg.org/uzu/strudel/pulls/478
|
||||
- Fix array args by @felixroos in https://codeberg.org/uzu/strudel/pulls/480
|
||||
- docs: packages + offline by @felixroos in https://codeberg.org/uzu/strudel/pulls/482
|
||||
- Update mini-notation.mdx by @yaxu in https://codeberg.org/uzu/strudel/pulls/365
|
||||
- Revert "Another attempt at composable functions - WIP (#390)" by @felixroos in https://codeberg.org/uzu/strudel/pulls/484
|
||||
- fix app height by @felixroos in https://codeberg.org/uzu/strudel/pulls/485
|
||||
- add algolia creds + optimize sidebar for crawling by @felixroos in https://codeberg.org/uzu/strudel/pulls/488
|
||||
- refactor react package by @felixroos in https://codeberg.org/uzu/strudel/pulls/490
|
||||
- react style fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/491
|
||||
- implement cps in scheduler by @felixroos in https://codeberg.org/uzu/strudel/pulls/493
|
||||
- Add control aliases by @yaxu in https://codeberg.org/uzu/strudel/pulls/497
|
||||
- fix: nano-repl highlighting by @felixroos in https://codeberg.org/uzu/strudel/pulls/501
|
||||
- Reinstate slice and splice by @yaxu in https://codeberg.org/uzu/strudel/pulls/500
|
||||
- can now use : as a replacement for space in scales by @felixroos in https://codeberg.org/uzu/strudel/pulls/502
|
||||
- Support list syntax in mininotation by @yaxu in https://codeberg.org/uzu/strudel/pulls/512
|
||||
- update react to 18 by @felixroos in https://codeberg.org/uzu/strudel/pulls/514
|
||||
- add arrange function by @felixroos in https://codeberg.org/uzu/strudel/pulls/508
|
||||
- Update README.md by @bwagner in https://codeberg.org/uzu/strudel/pulls/474
|
||||
- add 2 illegible fonts by @felixroos in https://codeberg.org/uzu/strudel/pulls/518
|
||||
- registerSound API + improved sounds tab + regroup soundfonts by @felixroos in https://codeberg.org/uzu/strudel/pulls/516
|
||||
- fix: envelopes in chrome by @felixroos in https://codeberg.org/uzu/strudel/pulls/521
|
||||
- Update samples.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/524
|
||||
- Update intro.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/525
|
||||
- fix(footer): fix link to tidalcycles by @revolunet in https://codeberg.org/uzu/strudel/pulls/529
|
||||
- FIXES: alias pm for polymeter by @bwagner in https://codeberg.org/uzu/strudel/pulls/527
|
||||
- Maintain random seed state in parser, not globally by @ijc8 in https://codeberg.org/uzu/strudel/pulls/531
|
||||
- feat: add freq support to gm soundfonts by @felixroos in https://codeberg.org/uzu/strudel/pulls/534
|
||||
- Update lerna by @felixroos in https://codeberg.org/uzu/strudel/pulls/535
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @revolunet made their first contribution in https://github.com/tidalcycles/strudel/pull/529
|
||||
- @ijc8 made their first contribution in https://github.com/tidalcycles/strudel/pull/531
|
||||
- @revolunet made their first contribution in https://codeberg.org/uzu/strudel/pulls/529
|
||||
- @ijc8 made their first contribution in https://codeberg.org/uzu/strudel/pulls/531
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.6.0...v0.7.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.6.0...v0.7.0
|
||||
|
||||
@@ -6,7 +6,7 @@ tags: ['meta']
|
||||
author: froos
|
||||
---
|
||||
|
||||
import BlogVideo from '../../components/BlogVideo.astro';
|
||||
import { Youtube } from '@src/components/Youtube';
|
||||
|
||||
These are the release notes for Strudel 0.8.0 aka "Himbeermuffin"!
|
||||
|
||||
@@ -18,11 +18,11 @@ Let me write up some of the highlights:
|
||||
|
||||
Besides the REPL (https://strudel.tidalcycles.org/), Strudel is now also distributed as a Desktop App via https://tauri.app/! Thanks to [vasilymilovidov](https://github.com/vasilymilovidov)!
|
||||
|
||||
- [Linux: Debian based](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.deb)
|
||||
- [Linux: AppImage](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.AppImage)
|
||||
- [MacOS](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64.dmg)
|
||||
- [Windows .exe](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64-setup.exe)
|
||||
- [Windows .msi](https://github.com/tidalcycles/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64_en-US.msi)
|
||||
- [Linux: Debian based](https://codeberg.org/uzu/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.deb)
|
||||
- [Linux: AppImage](https://codeberg.org/uzu/strudel/releases/download/v0.8.0/strudel_0.1.0_amd64.AppImage)
|
||||
- [MacOS](https://codeberg.org/uzu/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64.dmg)
|
||||
- [Windows .exe](https://codeberg.org/uzu/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64-setup.exe)
|
||||
- [Windows .msi](https://codeberg.org/uzu/strudel/releases/download/v0.8.0/Strudel_0.1.0_x64_en-US.msi)
|
||||
|
||||
edit: the desktop app performance on linux is currently not that great.. the web REPL runs much smoother (using firefox or chromium)
|
||||
|
||||
@@ -43,7 +43,7 @@ I would be very happy to collect some feedback on how it works across different
|
||||
|
||||
Also still undocumented, but you can now visualize patterns as a spiral via `.spiral()`:
|
||||
|
||||
<BlogVideo src="https://github.com/tidalcycles/strudel/assets/12023032/05bc2dba-b304-4298-9465-a1a6fafe5ded" />
|
||||
<Youtube client:only="react" id="24bSHhEdUeM" />
|
||||
|
||||
This is especially nice because strudel is not only the name of a dessert but also the german word for vortex! The spiral is very fitting to visualize cycles because you can align cycles vertically, while surfing along an infinite twisted timeline.
|
||||
|
||||
@@ -82,49 +82,49 @@ A big thanks to all the contributors!
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix period key for dvorak + remove duplicated code by @felixroos in https://github.com/tidalcycles/strudel/pull/537
|
||||
- improve initial loading + wait before eval by @felixroos in https://github.com/tidalcycles/strudel/pull/538
|
||||
- do not reset cps before eval #517 by @felixroos in https://github.com/tidalcycles/strudel/pull/539
|
||||
- feat: add loader bar to animate loading state by @felixroos in https://github.com/tidalcycles/strudel/pull/542
|
||||
- add firacode font by @felixroos in https://github.com/tidalcycles/strudel/pull/544
|
||||
- fix: allow whitespace at the end of a mini pattern by @felixroos in https://github.com/tidalcycles/strudel/pull/547
|
||||
- fix: reset time on stop by @felixroos in https://github.com/tidalcycles/strudel/pull/548
|
||||
- fix: load soundfonts in prebake by @felixroos in https://github.com/tidalcycles/strudel/pull/550
|
||||
- fix: colorable highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/553
|
||||
- fix: make soundfonts import dynamic by @felixroos in https://github.com/tidalcycles/strudel/pull/556
|
||||
- add basic triads and guidetone voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/557
|
||||
- Patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/559
|
||||
- Vanilla JS Refactoring by @felixroos in https://github.com/tidalcycles/strudel/pull/563
|
||||
- repl: add option to display line numbers by @roipoussiere in https://github.com/tidalcycles/strudel/pull/582
|
||||
- learn/tonal: fix typo in "scaleTran[s]pose" by @srenatus in https://github.com/tidalcycles/strudel/pull/585
|
||||
- Music metadata by @roipoussiere in https://github.com/tidalcycles/strudel/pull/580
|
||||
- New Workshop by @felixroos in https://github.com/tidalcycles/strudel/pull/587
|
||||
- Fix option dot by @felixroos in https://github.com/tidalcycles/strudel/pull/596
|
||||
- fix: allow f for flat notes like tidal by @felixroos in https://github.com/tidalcycles/strudel/pull/593
|
||||
- fix: division by zero by @felixroos in https://github.com/tidalcycles/strudel/pull/591
|
||||
- Solmization added by @dariacotocu in https://github.com/tidalcycles/strudel/pull/570
|
||||
- improve cursor by @felixroos in https://github.com/tidalcycles/strudel/pull/597
|
||||
- enable auto-completion by @roipoussiere in https://github.com/tidalcycles/strudel/pull/588
|
||||
- add ratio function by @felixroos in https://github.com/tidalcycles/strudel/pull/602
|
||||
- editor: enable line wrapping by @roipoussiere in https://github.com/tidalcycles/strudel/pull/581
|
||||
- tonal fixes by @felixroos in https://github.com/tidalcycles/strudel/pull/607
|
||||
- fix: flatten scale lists by @felixroos in https://github.com/tidalcycles/strudel/pull/605
|
||||
- clip now works like legato in tidal by @felixroos in https://github.com/tidalcycles/strudel/pull/598
|
||||
- fix: doc links by @felixroos in https://github.com/tidalcycles/strudel/pull/612
|
||||
- tauri desktop app by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/613
|
||||
- add spiral viz by @felixroos in https://github.com/tidalcycles/strudel/pull/614
|
||||
- patterning ui settings by @felixroos in https://github.com/tidalcycles/strudel/pull/606
|
||||
- Fix typo on packages.mdx by @paikwiki in https://github.com/tidalcycles/strudel/pull/520
|
||||
- cps dependent functions by @felixroos in https://github.com/tidalcycles/strudel/pull/620
|
||||
- desktop: play samples from disk by @felixroos in https://github.com/tidalcycles/strudel/pull/621
|
||||
- fix: midi clock drift by @felixroos in https://github.com/tidalcycles/strudel/pull/627
|
||||
- fix period key for dvorak + remove duplicated code by @felixroos in https://codeberg.org/uzu/strudel/pulls/537
|
||||
- improve initial loading + wait before eval by @felixroos in https://codeberg.org/uzu/strudel/pulls/538
|
||||
- do not reset cps before eval #517 by @felixroos in https://codeberg.org/uzu/strudel/pulls/539
|
||||
- feat: add loader bar to animate loading state by @felixroos in https://codeberg.org/uzu/strudel/pulls/542
|
||||
- add firacode font by @felixroos in https://codeberg.org/uzu/strudel/pulls/544
|
||||
- fix: allow whitespace at the end of a mini pattern by @felixroos in https://codeberg.org/uzu/strudel/pulls/547
|
||||
- fix: reset time on stop by @felixroos in https://codeberg.org/uzu/strudel/pulls/548
|
||||
- fix: load soundfonts in prebake by @felixroos in https://codeberg.org/uzu/strudel/pulls/550
|
||||
- fix: colorable highlighting by @felixroos in https://codeberg.org/uzu/strudel/pulls/553
|
||||
- fix: make soundfonts import dynamic by @felixroos in https://codeberg.org/uzu/strudel/pulls/556
|
||||
- add basic triads and guidetone voicings by @felixroos in https://codeberg.org/uzu/strudel/pulls/557
|
||||
- Patchday by @felixroos in https://codeberg.org/uzu/strudel/pulls/559
|
||||
- Vanilla JS Refactoring by @felixroos in https://codeberg.org/uzu/strudel/pulls/563
|
||||
- repl: add option to display line numbers by @roipoussiere in https://codeberg.org/uzu/strudel/pulls/582
|
||||
- learn/tonal: fix typo in "scaleTran[s]pose" by @srenatus in https://codeberg.org/uzu/strudel/pulls/585
|
||||
- Music metadata by @roipoussiere in https://codeberg.org/uzu/strudel/pulls/580
|
||||
- New Workshop by @felixroos in https://codeberg.org/uzu/strudel/pulls/587
|
||||
- Fix option dot by @felixroos in https://codeberg.org/uzu/strudel/pulls/596
|
||||
- fix: allow f for flat notes like tidal by @felixroos in https://codeberg.org/uzu/strudel/pulls/593
|
||||
- fix: division by zero by @felixroos in https://codeberg.org/uzu/strudel/pulls/591
|
||||
- Solmization added by @dariacotocu in https://codeberg.org/uzu/strudel/pulls/570
|
||||
- improve cursor by @felixroos in https://codeberg.org/uzu/strudel/pulls/597
|
||||
- enable auto-completion by @roipoussiere in https://codeberg.org/uzu/strudel/pulls/588
|
||||
- add ratio function by @felixroos in https://codeberg.org/uzu/strudel/pulls/602
|
||||
- editor: enable line wrapping by @roipoussiere in https://codeberg.org/uzu/strudel/pulls/581
|
||||
- tonal fixes by @felixroos in https://codeberg.org/uzu/strudel/pulls/607
|
||||
- fix: flatten scale lists by @felixroos in https://codeberg.org/uzu/strudel/pulls/605
|
||||
- clip now works like legato in tidal by @felixroos in https://codeberg.org/uzu/strudel/pulls/598
|
||||
- fix: doc links by @felixroos in https://codeberg.org/uzu/strudel/pulls/612
|
||||
- tauri desktop app by @vasilymilovidov in https://codeberg.org/uzu/strudel/pulls/613
|
||||
- add spiral viz by @felixroos in https://codeberg.org/uzu/strudel/pulls/614
|
||||
- patterning ui settings by @felixroos in https://codeberg.org/uzu/strudel/pulls/606
|
||||
- Fix typo on packages.mdx by @paikwiki in https://codeberg.org/uzu/strudel/pulls/520
|
||||
- cps dependent functions by @felixroos in https://codeberg.org/uzu/strudel/pulls/620
|
||||
- desktop: play samples from disk by @felixroos in https://codeberg.org/uzu/strudel/pulls/621
|
||||
- fix: midi clock drift by @felixroos in https://codeberg.org/uzu/strudel/pulls/627
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @roipoussiere made their first contribution in https://github.com/tidalcycles/strudel/pull/582
|
||||
- @srenatus made their first contribution in https://github.com/tidalcycles/strudel/pull/585
|
||||
- @dariacotocu made their first contribution in https://github.com/tidalcycles/strudel/pull/570
|
||||
- @vasilymilovidov made their first contribution in https://github.com/tidalcycles/strudel/pull/613
|
||||
- @paikwiki made their first contribution in https://github.com/tidalcycles/strudel/pull/520
|
||||
- @roipoussiere made their first contribution in https://codeberg.org/uzu/strudel/pulls/582
|
||||
- @srenatus made their first contribution in https://codeberg.org/uzu/strudel/pulls/585
|
||||
- @dariacotocu made their first contribution in https://codeberg.org/uzu/strudel/pulls/570
|
||||
- @vasilymilovidov made their first contribution in https://codeberg.org/uzu/strudel/pulls/613
|
||||
- @paikwiki made their first contribution in https://codeberg.org/uzu/strudel/pulls/520
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.7.0...v0.8.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.7.0...v0.8.0
|
||||
|
||||
@@ -6,8 +6,6 @@ tags: ['meta']
|
||||
author: froos
|
||||
---
|
||||
|
||||
import BlogVideo from '../../components/BlogVideo.astro';
|
||||
|
||||
These are the release notes for Strudel 0.9.0 aka "Bananenbrot"!
|
||||
|
||||
The last release was over 11 weeks ago, so a lot of things have happened!
|
||||
@@ -25,18 +23,20 @@ Main new features include:
|
||||
- [vibrato](https://strudel.tidalcycles.org/learn/synths#vibrato)
|
||||
- an integration of [ZZFX](https://strudel.tidalcycles.org/learn/synths#zzfx)
|
||||
|
||||
<BlogVideo src="https://github.com/tidalcycles/strudel/assets/12023032/652e7042-f296-496b-95cd-b2a4987fe238" />
|
||||
import { Youtube } from '@src/components/Youtube';
|
||||
|
||||
<Youtube client:only="react" id="5ByKVG7jiO4" />
|
||||
|
||||
Related PRs:
|
||||
|
||||
- superdough: encapsulates web audio output by @felixroos in https://github.com/tidalcycles/strudel/pull/664
|
||||
- basic fm by @felixroos in https://github.com/tidalcycles/strudel/pull/669
|
||||
- Wave Selection and Global Envelope on the FM Synth Modulator by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/683
|
||||
- control osc partial count with n by @felixroos in https://github.com/tidalcycles/strudel/pull/674
|
||||
- ZZFX Synth support by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/684
|
||||
- Adding filter envelopes and filter order selection by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/692
|
||||
- Adding loop points and thus wavetable synthesis by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/698
|
||||
- Adding vibrato to base oscillators by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/693
|
||||
- superdough: encapsulates web audio output by @felixroos in https://codeberg.org/uzu/strudel/pulls/664
|
||||
- basic fm by @felixroos in https://codeberg.org/uzu/strudel/pulls/669
|
||||
- Wave Selection and Global Envelope on the FM Synth Modulator by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/683
|
||||
- control osc partial count with n by @felixroos in https://codeberg.org/uzu/strudel/pulls/674
|
||||
- ZZFX Synth support by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/684
|
||||
- Adding filter envelopes and filter order selection by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/692
|
||||
- Adding loop points and thus wavetable synthesis by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/698
|
||||
- Adding vibrato to base oscillators by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/693
|
||||
|
||||
## Desktop App Improvements
|
||||
|
||||
@@ -45,70 +45,70 @@ which do not depend on browser APIs!
|
||||
|
||||
You can see superdough, superdirt via OSC + hardware synths via MIDI all together playing in harmony in this [awesome video](https://www.youtube.com/watch?v=lxQgBeLQBgk). These are the related PRs:
|
||||
|
||||
- Create Midi Integration for Tauri Desktop app by @daslyfe in https://github.com/tidalcycles/strudel/pull/685
|
||||
- add sleep timer + improve message iterating by @daslyfe in https://github.com/tidalcycles/strudel/pull/688
|
||||
- fix MIDI CC messages by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/690
|
||||
- Direct OSC Support in Tauri by @daslyfe in https://github.com/tidalcycles/strudel/pull/694
|
||||
- Add logging from tauri by @daslyfe in https://github.com/tidalcycles/strudel/pull/697
|
||||
- fix osc bundle timestamp glitches caused by drifting clock by @daslyfe in https://github.com/tidalcycles/strudel/pull/666
|
||||
- Midi time fixes by @daslyfe in https://github.com/tidalcycles/strudel/pull/668
|
||||
- [Bug Fix] Account for numeral notation when converting to midi by @daslyfe in https://github.com/tidalcycles/strudel/pull/656
|
||||
- [Bug Fix] Midi: Don't treat note 0 as false by @daslyfe in https://github.com/tidalcycles/strudel/pull/657
|
||||
- Create Midi Integration for Tauri Desktop app by @daslyfe in https://codeberg.org/uzu/strudel/pulls/685
|
||||
- add sleep timer + improve message iterating by @daslyfe in https://codeberg.org/uzu/strudel/pulls/688
|
||||
- fix MIDI CC messages by @vasilymilovidov in https://codeberg.org/uzu/strudel/pulls/690
|
||||
- Direct OSC Support in Tauri by @daslyfe in https://codeberg.org/uzu/strudel/pulls/694
|
||||
- Add logging from tauri by @daslyfe in https://codeberg.org/uzu/strudel/pulls/697
|
||||
- fix osc bundle timestamp glitches caused by drifting clock by @daslyfe in https://codeberg.org/uzu/strudel/pulls/666
|
||||
- Midi time fixes by @daslyfe in https://codeberg.org/uzu/strudel/pulls/668
|
||||
- [Bug Fix] Account for numeral notation when converting to midi by @daslyfe in https://codeberg.org/uzu/strudel/pulls/656
|
||||
- [Bug Fix] Midi: Don't treat note 0 as false by @daslyfe in https://codeberg.org/uzu/strudel/pulls/657
|
||||
|
||||
## Visuals
|
||||
|
||||
- 2 new FFT based vizualisations have now landed: [scope and fscope](https://github.com/tidalcycles/strudel/pull/677) (featured in the video at the top).
|
||||
- pianoroll has new options, see [PR](https://github.com/tidalcycles/strudel/pull/679)
|
||||
- 2 new FFT based vizualisations have now landed: [scope and fscope](https://codeberg.org/uzu/strudel/pulls/677) (featured in the video at the top).
|
||||
- pianoroll has new options, see [PR](https://codeberg.org/uzu/strudel/pulls/679)
|
||||
|
||||
Related PRs:
|
||||
|
||||
- Scope by @felixroos in https://github.com/tidalcycles/strudel/pull/677 ([demo](https://strudel.tidalcycles.org/?hXVQF-KxMI8p))
|
||||
- Pianoroll improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/679 ([demo](https://strudel.tidalcycles.org/?aPMKqXGVMgSM))
|
||||
- Scope by @felixroos in https://codeberg.org/uzu/strudel/pulls/677 ([demo](https://strudel.tidalcycles.org/?hXVQF-KxMI8p))
|
||||
- Pianoroll improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/679 ([demo](https://strudel.tidalcycles.org/?aPMKqXGVMgSM))
|
||||
|
||||
## Voicings
|
||||
|
||||
There is now a new way to play chord voicings + a huge selection of chord voicings available. Find out more in these PRs:
|
||||
|
||||
- stateless voicings + tonleiter lib by @felixroos in https://github.com/tidalcycles/strudel/pull/647 ([demo](https://strudel.tidalcycles.org/?FoILM0Hs9y9f))
|
||||
- ireal voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/653 ([demo](https://strudel.tidalcycles.org/?bv_TjY9hOC28))
|
||||
- stateless voicings + tonleiter lib by @felixroos in https://codeberg.org/uzu/strudel/pulls/647 ([demo](https://strudel.tidalcycles.org/?FoILM0Hs9y9f))
|
||||
- ireal voicings by @felixroos in https://codeberg.org/uzu/strudel/pulls/653 ([demo](https://strudel.tidalcycles.org/?bv_TjY9hOC28))
|
||||
|
||||
## Adaptive Highlighting
|
||||
|
||||
Thanks to @mindofmatthew , the highlighting will adapt to edits instantly! Related PRs:
|
||||
|
||||
- More work on highlight IDs by @mindofmatthew in https://github.com/tidalcycles/strudel/pull/636
|
||||
- Adaptive Highlighting by @felixroos in https://github.com/tidalcycles/strudel/pull/634
|
||||
- More work on highlight IDs by @mindofmatthew in https://codeberg.org/uzu/strudel/pulls/636
|
||||
- Adaptive Highlighting by @felixroos in https://codeberg.org/uzu/strudel/pulls/634
|
||||
|
||||
## UI Changes
|
||||
|
||||
- teletext theme + fonts by @felixroos in https://github.com/tidalcycles/strudel/pull/681 (featured in video at the top)
|
||||
- togglable panel position by @felixroos in https://github.com/tidalcycles/strudel/pull/667
|
||||
- teletext theme + fonts by @felixroos in https://codeberg.org/uzu/strudel/pulls/681 (featured in video at the top)
|
||||
- togglable panel position by @felixroos in https://codeberg.org/uzu/strudel/pulls/667
|
||||
|
||||
## Other New Features
|
||||
|
||||
- slice: list mode by @felixroos in https://github.com/tidalcycles/strudel/pull/645 ([demo](https://strudel.tidalcycles.org/?bAYIqz5NLjRr))
|
||||
- add emoji support by @felixroos in https://github.com/tidalcycles/strudel/pull/680 ([demo](https://strudel.tidalcycles.org/?a6FgLz475gN9))
|
||||
- slice: list mode by @felixroos in https://codeberg.org/uzu/strudel/pulls/645 ([demo](https://strudel.tidalcycles.org/?bAYIqz5NLjRr))
|
||||
- add emoji support by @felixroos in https://codeberg.org/uzu/strudel/pulls/680 ([demo](https://strudel.tidalcycles.org/?a6FgLz475gN9))
|
||||
|
||||
## Articles
|
||||
|
||||
- Understand pitch by @felixroos in https://github.com/tidalcycles/strudel/pull/652
|
||||
- Understand pitch by @felixroos in https://codeberg.org/uzu/strudel/pulls/652
|
||||
|
||||
## Other Fixes & Enhancements
|
||||
|
||||
- fix: out of range error by @felixroos in https://github.com/tidalcycles/strudel/pull/630
|
||||
- fix: update canvas size on window resize by @felixroos in https://github.com/tidalcycles/strudel/pull/631
|
||||
- FIXES: TODO in rotateChroma by @bwagner in https://github.com/tidalcycles/strudel/pull/650
|
||||
- snapshot tests: sort haps by part by @felixroos in https://github.com/tidalcycles/strudel/pull/637
|
||||
- Delete old packages by @felixroos in https://github.com/tidalcycles/strudel/pull/639
|
||||
- update vitest by @felixroos in https://github.com/tidalcycles/strudel/pull/651
|
||||
- fix: welcome message for latestCode by @felixroos in https://github.com/tidalcycles/strudel/pull/659
|
||||
- fix: always run previous trigger by @felixroos in https://github.com/tidalcycles/strudel/pull/660
|
||||
- fix: out of range error by @felixroos in https://codeberg.org/uzu/strudel/pulls/630
|
||||
- fix: update canvas size on window resize by @felixroos in https://codeberg.org/uzu/strudel/pulls/631
|
||||
- FIXES: TODO in rotateChroma by @bwagner in https://codeberg.org/uzu/strudel/pulls/650
|
||||
- snapshot tests: sort haps by part by @felixroos in https://codeberg.org/uzu/strudel/pulls/637
|
||||
- Delete old packages by @felixroos in https://codeberg.org/uzu/strudel/pulls/639
|
||||
- update vitest by @felixroos in https://codeberg.org/uzu/strudel/pulls/651
|
||||
- fix: welcome message for latestCode by @felixroos in https://codeberg.org/uzu/strudel/pulls/659
|
||||
- fix: always run previous trigger by @felixroos in https://codeberg.org/uzu/strudel/pulls/660
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @daslyfe made their first contribution in https://github.com/tidalcycles/strudel/pull/656
|
||||
- @Bubobubobubobubo made their first contribution in https://github.com/tidalcycles/strudel/pull/683
|
||||
- @daslyfe made their first contribution in https://codeberg.org/uzu/strudel/pulls/656
|
||||
- @Bubobubobubobubo made their first contribution in https://codeberg.org/uzu/strudel/pulls/683
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.8.0...v0.9.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.8.0...v0.9.0
|
||||
|
||||
A big thanks to all the contributors!
|
||||
|
||||
@@ -6,8 +6,6 @@ tags: ['meta']
|
||||
author: froos
|
||||
---
|
||||
|
||||
import BlogVideo from '../../components/BlogVideo.astro';
|
||||
|
||||
These are the release notes for Strudel 1.0.0 aka "Geburtstagskuchen"
|
||||
|
||||
This release marks the 2 year anniversary of the project, the first commit was on the 22nd January 2022 by Alex McLean.
|
||||
@@ -27,13 +25,13 @@ Let me write up some of the highlights:
|
||||
This version changes the default cps value from 1 to 0.5 to give patterns a little bit more time by default.
|
||||
If you find your existing patterns to be suddenly half the speed, just add a `setcps(1)` to the top and it should sound as it did before!
|
||||
|
||||
- make 0.5hz cps the default by @yaxu in https://github.com/tidalcycles/strudel/pull/931
|
||||
- make 0.5hz cps the default by @yaxu in https://codeberg.org/uzu/strudel/pulls/931
|
||||
|
||||
## New Domain
|
||||
|
||||
Strudel is now available under [strudel.cc](https://strudel.cc/). The old domain still works but you might not get the most recent version.
|
||||
|
||||
- replace strudel.tidalcycles.org with strudel.cc by @felixroos in https://github.com/tidalcycles/strudel/pull/768
|
||||
- replace strudel.tidalcycles.org with strudel.cc by @felixroos in https://codeberg.org/uzu/strudel/pulls/768
|
||||
|
||||
## Strudel on Mastodon
|
||||
|
||||
@@ -43,52 +41,52 @@ Strudel now has a mastodon presence: https://social.toplap.org/@strudel
|
||||
|
||||
superdough, the audio engine of strudel has gotten some new features:
|
||||
|
||||
- Create phaser effect by @daslyfe in https://github.com/tidalcycles/strudel/pull/798
|
||||
- Multichannel audio by @daslyfe in https://github.com/tidalcycles/strudel/pull/820
|
||||
- Audio device selection by @daslyfe in https://github.com/tidalcycles/strudel/pull/854
|
||||
- Better convolution reverb by generating impulse responses by @Bubobubobubobubo and @felixroos in https://github.com/tidalcycles/strudel/pull/718
|
||||
- Add 'white', 'pink' and 'brown' oscillators + refactor synth by @Bubobubobubobubo and @felixroos in https://github.com/tidalcycles/strudel/pull/713
|
||||
- New noise type: "crackle" by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/806
|
||||
- Add support for using samples as impulse response buffers for the reverb by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/717
|
||||
- Compressor by @felixroos in https://github.com/tidalcycles/strudel/pull/729
|
||||
- Adding vibrato to Superdough sampler by @Bubobubobubobubo and @felixroos in https://github.com/tidalcycles/strudel/pull/706
|
||||
- Further Envelope improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/868
|
||||
- Add more vowel qualities for the vowels function by @fnordomat in https://github.com/tidalcycles/strudel/pull/907
|
||||
- pitch envelope by @felixroos in https://github.com/tidalcycles/strudel/pull/913
|
||||
- Create phaser effect by @daslyfe in https://codeberg.org/uzu/strudel/pulls/798
|
||||
- Multichannel audio by @daslyfe in https://codeberg.org/uzu/strudel/pulls/820
|
||||
- Audio device selection by @daslyfe in https://codeberg.org/uzu/strudel/pulls/854
|
||||
- Better convolution reverb by generating impulse responses by @Bubobubobubobubo and @felixroos in https://codeberg.org/uzu/strudel/pulls/718
|
||||
- Add 'white', 'pink' and 'brown' oscillators + refactor synth by @Bubobubobubobubo and @felixroos in https://codeberg.org/uzu/strudel/pulls/713
|
||||
- New noise type: "crackle" by @Bubobubobubobubo in https://codeberg.org/uzu/strudel/pulls/806
|
||||
- Add support for using samples as impulse response buffers for the reverb by @vasilymilovidov in https://codeberg.org/uzu/strudel/pulls/717
|
||||
- Compressor by @felixroos in https://codeberg.org/uzu/strudel/pulls/729
|
||||
- Adding vibrato to Superdough sampler by @Bubobubobubobubo and @felixroos in https://codeberg.org/uzu/strudel/pulls/706
|
||||
- Further Envelope improvements by @daslyfe in https://codeberg.org/uzu/strudel/pulls/868
|
||||
- Add more vowel qualities for the vowels function by @fnordomat in https://codeberg.org/uzu/strudel/pulls/907
|
||||
- pitch envelope by @felixroos in https://codeberg.org/uzu/strudel/pulls/913
|
||||
|
||||
## Slider Controls
|
||||
|
||||
The new `slider` function inlines a draggable slider element into the code, bridging the gap between code and GUI.
|
||||
|
||||
- widgets by @felixroos in https://github.com/tidalcycles/strudel/pull/714
|
||||
- Slider afterthoughts by @felixroos in https://github.com/tidalcycles/strudel/pull/723
|
||||
- add xfade by @felixroos in https://github.com/tidalcycles/strudel/pull/780
|
||||
- widgets by @felixroos in https://codeberg.org/uzu/strudel/pulls/714
|
||||
- Slider afterthoughts by @felixroos in https://codeberg.org/uzu/strudel/pulls/723
|
||||
- add xfade by @felixroos in https://codeberg.org/uzu/strudel/pulls/780
|
||||
|
||||
## Improved MIDI integration
|
||||
|
||||
Pattern params [can now be controlled with cc messages](https://www.youtube.com/watch?v=e2-Sv_jjDQk) + you can now send a MIDI clock to sync your DAW with strudel.
|
||||
|
||||
- Midi in by @felixroos in https://github.com/tidalcycles/strudel/pull/699
|
||||
- add midi clock support by @felixroos in https://github.com/tidalcycles/strudel/pull/710
|
||||
- Midi in by @felixroos in https://codeberg.org/uzu/strudel/pulls/699
|
||||
- add midi clock support by @felixroos in https://codeberg.org/uzu/strudel/pulls/710
|
||||
|
||||
## hydra
|
||||
|
||||
[hydra](https://hydra.ojack.xyz), the live coding video synth [can now be used directly inside the strudel REPL](https://strudel.cc/learn/hydra/).
|
||||
|
||||
- Hydra integration by @felixroos in https://github.com/tidalcycles/strudel/pull/759
|
||||
- add options param to initHydra by @kasparsj in https://github.com/tidalcycles/strudel/pull/808
|
||||
- Hydra fixes and improvements by @atfornes in https://github.com/tidalcycles/strudel/pull/818
|
||||
- Hydra integration by @felixroos in https://codeberg.org/uzu/strudel/pulls/759
|
||||
- add options param to initHydra by @kasparsj in https://codeberg.org/uzu/strudel/pulls/808
|
||||
- Hydra fixes and improvements by @atfornes in https://codeberg.org/uzu/strudel/pulls/818
|
||||
|
||||
## Vanilla REPL
|
||||
|
||||
The codemirror editor and the repl abstraction have been refactored from react to vanilla JS!
|
||||
This should give some performance improvements and less dependency / maintenance burden:
|
||||
|
||||
- Vanilla repl 2 by @felixroos in https://github.com/tidalcycles/strudel/pull/863
|
||||
- Vanilla repl 3 by @felixroos in https://github.com/tidalcycles/strudel/pull/865
|
||||
- more work on vanilla repl: repl web component + package + MicroRepl by @felixroos in https://github.com/tidalcycles/strudel/pull/866
|
||||
- main repl vanillification by @felixroos in https://github.com/tidalcycles/strudel/pull/873
|
||||
- final vanillification by @felixroos in https://github.com/tidalcycles/strudel/pull/876
|
||||
- Vanilla repl 2 by @felixroos in https://codeberg.org/uzu/strudel/pulls/863
|
||||
- Vanilla repl 3 by @felixroos in https://codeberg.org/uzu/strudel/pulls/865
|
||||
- more work on vanilla repl: repl web component + package + MicroRepl by @felixroos in https://codeberg.org/uzu/strudel/pulls/866
|
||||
- main repl vanillification by @felixroos in https://codeberg.org/uzu/strudel/pulls/873
|
||||
- final vanillification by @felixroos in https://codeberg.org/uzu/strudel/pulls/876
|
||||
|
||||
## Doc Changes
|
||||
|
||||
@@ -97,25 +95,25 @@ Plenty of things have been added to the docs, including a [showcase of what peop
|
||||
<details>
|
||||
<summary>show PRs</summary>
|
||||
|
||||
- Showcase by @felixroos in https://github.com/tidalcycles/strudel/pull/885
|
||||
- Recipes by @felixroos in https://github.com/tidalcycles/strudel/pull/742
|
||||
- Document striate function by @ilesinge in https://github.com/tidalcycles/strudel/pull/766
|
||||
- Document adsr function by @ilesinge in https://github.com/tidalcycles/strudel/pull/767
|
||||
- Add function params in reference tab by @ilesinge in https://github.com/tidalcycles/strudel/pull/785
|
||||
- Update first-sounds.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/794
|
||||
- Update recap.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/797
|
||||
- Update pattern-effects.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/796
|
||||
- Update first-effects.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/795
|
||||
- Document pianoroll by @ilesinge in https://github.com/tidalcycles/strudel/pull/784
|
||||
- Add doc for euclidLegatoRot, wordfall and slider by @ilesinge in https://github.com/tidalcycles/strudel/pull/801
|
||||
- Improve documentation for synonym functions by @ilesinge in https://github.com/tidalcycles/strudel/pull/800
|
||||
- Add and style algolia search by @ilesinge in https://github.com/tidalcycles/strudel/pull/827
|
||||
- Fix a typo by @drewgbarnes in https://github.com/tidalcycles/strudel/pull/830
|
||||
- add mastodon link by @felixroos in https://github.com/tidalcycles/strudel/pull/884
|
||||
- adds a blog by @felixroos in https://github.com/tidalcycles/strudel/pull/911
|
||||
- community bakery by @felixroos in https://github.com/tidalcycles/strudel/pull/923
|
||||
- Blog improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/919
|
||||
- 2 years blog post by @felixroos in https://github.com/tidalcycles/strudel/pull/929
|
||||
- Showcase by @felixroos in https://codeberg.org/uzu/strudel/pulls/885
|
||||
- Recipes by @felixroos in https://codeberg.org/uzu/strudel/pulls/742
|
||||
- Document striate function by @ilesinge in https://codeberg.org/uzu/strudel/pulls/766
|
||||
- Document adsr function by @ilesinge in https://codeberg.org/uzu/strudel/pulls/767
|
||||
- Add function params in reference tab by @ilesinge in https://codeberg.org/uzu/strudel/pulls/785
|
||||
- Update first-sounds.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/794
|
||||
- Update recap.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/797
|
||||
- Update pattern-effects.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/796
|
||||
- Update first-effects.mdx by @bwagner in https://codeberg.org/uzu/strudel/pulls/795
|
||||
- Document pianoroll by @ilesinge in https://codeberg.org/uzu/strudel/pulls/784
|
||||
- Add doc for euclidLegatoRot, wordfall and slider by @ilesinge in https://codeberg.org/uzu/strudel/pulls/801
|
||||
- Improve documentation for synonym functions by @ilesinge in https://codeberg.org/uzu/strudel/pulls/800
|
||||
- Add and style algolia search by @ilesinge in https://codeberg.org/uzu/strudel/pulls/827
|
||||
- Fix a typo by @drewgbarnes in https://codeberg.org/uzu/strudel/pulls/830
|
||||
- add mastodon link by @felixroos in https://codeberg.org/uzu/strudel/pulls/884
|
||||
- adds a blog by @felixroos in https://codeberg.org/uzu/strudel/pulls/911
|
||||
- community bakery by @felixroos in https://codeberg.org/uzu/strudel/pulls/923
|
||||
- Blog improvements by @felixroos in https://codeberg.org/uzu/strudel/pulls/919
|
||||
- 2 years blog post by @felixroos in https://codeberg.org/uzu/strudel/pulls/929
|
||||
|
||||
</details>
|
||||
|
||||
@@ -124,34 +122,34 @@ Plenty of things have been added to the docs, including a [showcase of what peop
|
||||
<details>
|
||||
<summary>There is a lot more</summary>
|
||||
|
||||
- mini notation: international alphabets support by @ilesinge in https://github.com/tidalcycles/strudel/pull/751
|
||||
- Add shabda shortcut by @ilesinge in https://github.com/tidalcycles/strudel/pull/740
|
||||
- add play function by @felixroos in https://github.com/tidalcycles/strudel/pull/758 (superseded by next)
|
||||
- tidal style d1 ... d9 functions + more by @felixroos in https://github.com/tidalcycles/strudel/pull/805
|
||||
- add vscode bindings by @Dsm0 in https://github.com/tidalcycles/strudel/pull/773
|
||||
- Implement optional hover tooltip with function documentation by @ilesinge in https://github.com/tidalcycles/strudel/pull/783
|
||||
- samples loading shortcuts: by @felixroos in https://github.com/tidalcycles/strudel/pull/788
|
||||
- add option to disable active line highlighting in Code Settings by @kasparsj in https://github.com/tidalcycles/strudel/pull/804
|
||||
- Color hsl by @felixroos in https://github.com/tidalcycles/strudel/pull/815
|
||||
- Patterns tab + Refactor Panel by @felixroos in https://github.com/tidalcycles/strudel/pull/769
|
||||
- patterns tab: import patterns + style by @felixroos in https://github.com/tidalcycles/strudel/pull/852
|
||||
- Export patterns + ui tweaks by @felixroos in https://github.com/tidalcycles/strudel/pull/855
|
||||
- Pattern organization by @felixroos in https://github.com/tidalcycles/strudel/pull/858
|
||||
- Sound Import from local file system by @daslyfe in https://github.com/tidalcycles/strudel/pull/839
|
||||
- bugfix: suspend and close existing audio context when changing interface by @daslyfe in https://github.com/tidalcycles/strudel/pull/882
|
||||
- add root mode for voicings by @felixroos in https://github.com/tidalcycles/strudel/pull/887
|
||||
- scales can now be anchored by @felixroos in https://github.com/tidalcycles/strudel/pull/888
|
||||
- add dough function for raw dsp by @felixroos in https://github.com/tidalcycles/strudel/pull/707 (experimental)
|
||||
- support mininotation '..' range operator, fixes #715 by @yaxu in https://github.com/tidalcycles/strudel/pull/716
|
||||
- Add pick and squeeze functions by @daslyfe in https://github.com/tidalcycles/strudel/pull/771
|
||||
- support , in < > by @felixroos in https://github.com/tidalcycles/strudel/pull/886
|
||||
- public sharing by @felixroos in https://github.com/tidalcycles/strudel/pull/910
|
||||
- pick, pickmod, inhabit, inhabitmod by @yaxu in https://github.com/tidalcycles/strudel/pull/921
|
||||
- Mini-notation additions towards tidal compatibility by @yaxu in https://github.com/tidalcycles/strudel/pull/926
|
||||
- add pickF and pickmodF by @geikha in https://github.com/tidalcycles/strudel/pull/924
|
||||
- Make splice cps-aware by @yaxu in https://github.com/tidalcycles/strudel/pull/932
|
||||
- Refactor cps functions by @felixroos in https://github.com/tidalcycles/strudel/pull/933
|
||||
- Add useful pattern selection behavior for performing. by @daslyfe in https://github.com/tidalcycles/strudel/pull/897
|
||||
- mini notation: international alphabets support by @ilesinge in https://codeberg.org/uzu/strudel/pulls/751
|
||||
- Add shabda shortcut by @ilesinge in https://codeberg.org/uzu/strudel/pulls/740
|
||||
- add play function by @felixroos in https://codeberg.org/uzu/strudel/pulls/758 (superseded by next)
|
||||
- tidal style d1 ... d9 functions + more by @felixroos in https://codeberg.org/uzu/strudel/pulls/805
|
||||
- add vscode bindings by @Dsm0 in https://codeberg.org/uzu/strudel/pulls/773
|
||||
- Implement optional hover tooltip with function documentation by @ilesinge in https://codeberg.org/uzu/strudel/pulls/783
|
||||
- samples loading shortcuts: by @felixroos in https://codeberg.org/uzu/strudel/pulls/788
|
||||
- add option to disable active line highlighting in Code Settings by @kasparsj in https://codeberg.org/uzu/strudel/pulls/804
|
||||
- Color hsl by @felixroos in https://codeberg.org/uzu/strudel/pulls/815
|
||||
- Patterns tab + Refactor Panel by @felixroos in https://codeberg.org/uzu/strudel/pulls/769
|
||||
- patterns tab: import patterns + style by @felixroos in https://codeberg.org/uzu/strudel/pulls/852
|
||||
- Export patterns + ui tweaks by @felixroos in https://codeberg.org/uzu/strudel/pulls/855
|
||||
- Pattern organization by @felixroos in https://codeberg.org/uzu/strudel/pulls/858
|
||||
- Sound Import from local file system by @daslyfe in https://codeberg.org/uzu/strudel/pulls/839
|
||||
- bugfix: suspend and close existing audio context when changing interface by @daslyfe in https://codeberg.org/uzu/strudel/pulls/882
|
||||
- add root mode for voicings by @felixroos in https://codeberg.org/uzu/strudel/pulls/887
|
||||
- scales can now be anchored by @felixroos in https://codeberg.org/uzu/strudel/pulls/888
|
||||
- add dough function for raw dsp by @felixroos in https://codeberg.org/uzu/strudel/pulls/707 (experimental)
|
||||
- support mininotation '..' range operator, fixes #715 by @yaxu in https://codeberg.org/uzu/strudel/pulls/716
|
||||
- Add pick and squeeze functions by @daslyfe in https://codeberg.org/uzu/strudel/pulls/771
|
||||
- support , in < > by @felixroos in https://codeberg.org/uzu/strudel/pulls/886
|
||||
- public sharing by @felixroos in https://codeberg.org/uzu/strudel/pulls/910
|
||||
- pick, pickmod, inhabit, inhabitmod by @yaxu in https://codeberg.org/uzu/strudel/pulls/921
|
||||
- Mini-notation additions towards tidal compatibility by @yaxu in https://codeberg.org/uzu/strudel/pulls/926
|
||||
- add pickF and pickmodF by @geikha in https://codeberg.org/uzu/strudel/pulls/924
|
||||
- Make splice cps-aware by @yaxu in https://codeberg.org/uzu/strudel/pulls/932
|
||||
- Refactor cps functions by @felixroos in https://codeberg.org/uzu/strudel/pulls/933
|
||||
- Add useful pattern selection behavior for performing. by @daslyfe in https://codeberg.org/uzu/strudel/pulls/897
|
||||
|
||||
</details>
|
||||
|
||||
@@ -160,79 +158,79 @@ Plenty of things have been added to the docs, including a [showcase of what peop
|
||||
<details>
|
||||
<summary>show</summary>
|
||||
|
||||
- fix: finally repair envelopes by @felixroos in https://github.com/tidalcycles/strudel/pull/861
|
||||
- fix: reverb regenerate loophole by @felixroos in https://github.com/tidalcycles/strudel/pull/726
|
||||
- fix: reverb roomsize not required by @felixroos in https://github.com/tidalcycles/strudel/pull/731
|
||||
- fix: reverb sampleRate by @felixroos in https://github.com/tidalcycles/strudel/pull/732
|
||||
- consume n with scale by @felixroos in https://github.com/tidalcycles/strudel/pull/727
|
||||
- fix: hashes in urls by @felixroos in https://github.com/tidalcycles/strudel/pull/728
|
||||
- [Bug Fix] chooseWith: prevent pattern from stopping audio when selection is >= 1 or < 0 by @daslyfe in https://github.com/tidalcycles/strudel/pull/741
|
||||
- Fix addivite synthesis phases by @felixroos in https://github.com/tidalcycles/strudel/pull/762
|
||||
- fix: scale offset by @felixroos in https://github.com/tidalcycles/strudel/pull/764
|
||||
- fix zen mode logo overlap by @felixroos in https://github.com/tidalcycles/strudel/pull/760
|
||||
- fix: share copy to clipboard + alert by @felixroos in https://github.com/tidalcycles/strudel/pull/774
|
||||
- fix: style issues by @felixroos in https://github.com/tidalcycles/strudel/pull/781
|
||||
- Fix scope pos + document by @felixroos in https://github.com/tidalcycles/strudel/pull/786
|
||||
- don't use anchor links for reference by @felixroos in https://github.com/tidalcycles/strudel/pull/791
|
||||
- remove unwanted cm6 outline for strudelTheme by @kasparsj in https://github.com/tidalcycles/strudel/pull/802
|
||||
- FIXES: palindrome abc -> abccba by @bwagner in https://github.com/tidalcycles/strudel/pull/831
|
||||
- Bug Fix #119: Clock drift by @daslyfe in https://github.com/tidalcycles/strudel/pull/874
|
||||
- bugfix: sound select indexes out of bounds by @daslyfe in https://github.com/tidalcycles/strudel/pull/871
|
||||
- Error tolerance by @felixroos in https://github.com/tidalcycles/strudel/pull/880
|
||||
- fix: make sure n is never undefined before nanFallback by @felixroos in https://github.com/tidalcycles/strudel/pull/881
|
||||
- fix: invisible selection on vim + emacs mode by @felixroos in https://github.com/tidalcycles/strudel/pull/889
|
||||
- fix: autocomplete / tooltip code example bug by @felixroos in https://github.com/tidalcycles/strudel/pull/898
|
||||
- Fix examples page, piano() and a few workshop imgs by @shiyouganai in https://github.com/tidalcycles/strudel/pull/848
|
||||
- fix: trailing slash confusion by @felixroos in https://github.com/tidalcycles/strudel/pull/743
|
||||
- fix: try different trailing slash behavior by @felixroos in https://github.com/tidalcycles/strudel/pull/744
|
||||
- Fix krill build command in README by @ilesinge in https://github.com/tidalcycles/strudel/pull/748
|
||||
- Fix for #1. Enables named instruments for csoundm. by @gogins in https://github.com/tidalcycles/strudel/pull/662
|
||||
- fix: missing hash for links starting with / by @felixroos in https://github.com/tidalcycles/strudel/pull/845
|
||||
- fix: swatch png src by @felixroos in https://github.com/tidalcycles/strudel/pull/846
|
||||
- Fix edge case with rehype-urls and trailing slashes in image file paths by @shiyouganai in https://github.com/tidalcycles/strudel/pull/849
|
||||
- fix: multiple repls by @felixroos in https://github.com/tidalcycles/strudel/pull/813
|
||||
- Fix chunk, add fastChunk and repeatCycles by @yaxu in https://github.com/tidalcycles/strudel/pull/712
|
||||
- Update tauri.yml workflow file by @vasilymilovidov in https://github.com/tidalcycles/strudel/pull/705
|
||||
- vite-vanilla-repl readme fix by @felixroos in https://github.com/tidalcycles/strudel/pull/737
|
||||
- completely revert config mess by @felixroos in https://github.com/tidalcycles/strudel/pull/745
|
||||
- hopefully fix trailing slashes bug by @felixroos in https://github.com/tidalcycles/strudel/pull/753
|
||||
- Update vite pwa by @felixroos in https://github.com/tidalcycles/strudel/pull/772
|
||||
- Update to Astro 3 by @felixroos in https://github.com/tidalcycles/strudel/pull/775
|
||||
- support multiple named serial connections, change default baudrate by @yaxu in https://github.com/tidalcycles/strudel/pull/551
|
||||
- CHANGES: github action checkout v2 -> v4 by @bwagner in https://github.com/tidalcycles/strudel/pull/837
|
||||
- CHANGES: pin pnpm to version 8.3.1 by @bwagner in https://github.com/tidalcycles/strudel/pull/834
|
||||
- CHANGES: github action pnpm version from 7 to 8.3.1 by @bwagner in https://github.com/tidalcycles/strudel/pull/835
|
||||
- ADDS: JetBrains IDE files and directories to .gitignore by @bwagner in https://github.com/tidalcycles/strudel/pull/840
|
||||
- Prevent 404 on Algolia crawls by @ilesinge in https://github.com/tidalcycles/strudel/pull/838
|
||||
- Add in fixes from my fork to slashocalypse branch by @shiyouganai in https://github.com/tidalcycles/strudel/pull/843
|
||||
- improve slashing + base href behavior by @felixroos in https://github.com/tidalcycles/strudel/pull/842
|
||||
- CHANGES: pnpm 8.1.3 to 8.11.0 by @bwagner in https://github.com/tidalcycles/strudel/pull/850
|
||||
- add missing trailing slashes by @felixroos in https://github.com/tidalcycles/strudel/pull/860
|
||||
- move all examples to separate examples folder by @felixroos in https://github.com/tidalcycles/strudel/pull/878
|
||||
- Dependency update by @felixroos in https://github.com/tidalcycles/strudel/pull/879
|
||||
- Update Vite version so hot reload works properly with newest pnpm version by @daslyfe in https://github.com/tidalcycles/strudel/pull/892
|
||||
- prevent vite from complaining about additional exports in jsx files by @daslyfe in https://github.com/tidalcycles/strudel/pull/891
|
||||
- fix some build warnings by @felixroos in https://github.com/tidalcycles/strudel/pull/902
|
||||
- Remove hideHeader for better mobile UI and consistency by @rjulian in https://github.com/tidalcycles/strudel/pull/894
|
||||
- Fix: swatch/[name].png.js static path by @oscarbyrne in https://github.com/tidalcycles/strudel/pull/916
|
||||
- rename @strudel.cycles/_ packages to @strudel/_ by @felixroos in https://github.com/tidalcycles/strudel/pull/917
|
||||
- `pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function by @yaxu in https://github.com/tidalcycles/strudel/pull/918
|
||||
- Revert "`pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function" by @yaxu in https://github.com/tidalcycles/strudel/pull/920
|
||||
- Fix pattern tab not showing patterns without created date by @daslyfe in https://github.com/tidalcycles/strudel/pull/934
|
||||
- fix: finally repair envelopes by @felixroos in https://codeberg.org/uzu/strudel/pulls/861
|
||||
- fix: reverb regenerate loophole by @felixroos in https://codeberg.org/uzu/strudel/pulls/726
|
||||
- fix: reverb roomsize not required by @felixroos in https://codeberg.org/uzu/strudel/pulls/731
|
||||
- fix: reverb sampleRate by @felixroos in https://codeberg.org/uzu/strudel/pulls/732
|
||||
- consume n with scale by @felixroos in https://codeberg.org/uzu/strudel/pulls/727
|
||||
- fix: hashes in urls by @felixroos in https://codeberg.org/uzu/strudel/pulls/728
|
||||
- [Bug Fix] chooseWith: prevent pattern from stopping audio when selection is >= 1 or < 0 by @daslyfe in https://codeberg.org/uzu/strudel/pulls/741
|
||||
- Fix addivite synthesis phases by @felixroos in https://codeberg.org/uzu/strudel/pulls/762
|
||||
- fix: scale offset by @felixroos in https://codeberg.org/uzu/strudel/pulls/764
|
||||
- fix zen mode logo overlap by @felixroos in https://codeberg.org/uzu/strudel/pulls/760
|
||||
- fix: share copy to clipboard + alert by @felixroos in https://codeberg.org/uzu/strudel/pulls/774
|
||||
- fix: style issues by @felixroos in https://codeberg.org/uzu/strudel/pulls/781
|
||||
- Fix scope pos + document by @felixroos in https://codeberg.org/uzu/strudel/pulls/786
|
||||
- don't use anchor links for reference by @felixroos in https://codeberg.org/uzu/strudel/pulls/791
|
||||
- remove unwanted cm6 outline for strudelTheme by @kasparsj in https://codeberg.org/uzu/strudel/pulls/802
|
||||
- FIXES: palindrome abc -> abccba by @bwagner in https://codeberg.org/uzu/strudel/pulls/831
|
||||
- Bug Fix #119: Clock drift by @daslyfe in https://codeberg.org/uzu/strudel/pulls/874
|
||||
- bugfix: sound select indexes out of bounds by @daslyfe in https://codeberg.org/uzu/strudel/pulls/871
|
||||
- Error tolerance by @felixroos in https://codeberg.org/uzu/strudel/pulls/880
|
||||
- fix: make sure n is never undefined before nanFallback by @felixroos in https://codeberg.org/uzu/strudel/pulls/881
|
||||
- fix: invisible selection on vim + emacs mode by @felixroos in https://codeberg.org/uzu/strudel/pulls/889
|
||||
- fix: autocomplete / tooltip code example bug by @felixroos in https://codeberg.org/uzu/strudel/pulls/898
|
||||
- Fix examples page, piano() and a few workshop imgs by @shiyouganai in https://codeberg.org/uzu/strudel/pulls/848
|
||||
- fix: trailing slash confusion by @felixroos in https://codeberg.org/uzu/strudel/pulls/743
|
||||
- fix: try different trailing slash behavior by @felixroos in https://codeberg.org/uzu/strudel/pulls/744
|
||||
- Fix krill build command in README by @ilesinge in https://codeberg.org/uzu/strudel/pulls/748
|
||||
- Fix for #1. Enables named instruments for csoundm. by @gogins in https://codeberg.org/uzu/strudel/pulls/662
|
||||
- fix: missing hash for links starting with / by @felixroos in https://codeberg.org/uzu/strudel/pulls/845
|
||||
- fix: swatch png src by @felixroos in https://codeberg.org/uzu/strudel/pulls/846
|
||||
- Fix edge case with rehype-urls and trailing slashes in image file paths by @shiyouganai in https://codeberg.org/uzu/strudel/pulls/849
|
||||
- fix: multiple repls by @felixroos in https://codeberg.org/uzu/strudel/pulls/813
|
||||
- Fix chunk, add fastChunk and repeatCycles by @yaxu in https://codeberg.org/uzu/strudel/pulls/712
|
||||
- Update tauri.yml workflow file by @vasilymilovidov in https://codeberg.org/uzu/strudel/pulls/705
|
||||
- vite-vanilla-repl readme fix by @felixroos in https://codeberg.org/uzu/strudel/pulls/737
|
||||
- completely revert config mess by @felixroos in https://codeberg.org/uzu/strudel/pulls/745
|
||||
- hopefully fix trailing slashes bug by @felixroos in https://codeberg.org/uzu/strudel/pulls/753
|
||||
- Update vite pwa by @felixroos in https://codeberg.org/uzu/strudel/pulls/772
|
||||
- Update to Astro 3 by @felixroos in https://codeberg.org/uzu/strudel/pulls/775
|
||||
- support multiple named serial connections, change default baudrate by @yaxu in https://codeberg.org/uzu/strudel/pulls/551
|
||||
- CHANGES: github action checkout v2 -> v4 by @bwagner in https://codeberg.org/uzu/strudel/pulls/837
|
||||
- CHANGES: pin pnpm to version 8.3.1 by @bwagner in https://codeberg.org/uzu/strudel/pulls/834
|
||||
- CHANGES: github action pnpm version from 7 to 8.3.1 by @bwagner in https://codeberg.org/uzu/strudel/pulls/835
|
||||
- ADDS: JetBrains IDE files and directories to .gitignore by @bwagner in https://codeberg.org/uzu/strudel/pulls/840
|
||||
- Prevent 404 on Algolia crawls by @ilesinge in https://codeberg.org/uzu/strudel/pulls/838
|
||||
- Add in fixes from my fork to slashocalypse branch by @shiyouganai in https://codeberg.org/uzu/strudel/pulls/843
|
||||
- improve slashing + base href behavior by @felixroos in https://codeberg.org/uzu/strudel/pulls/842
|
||||
- CHANGES: pnpm 8.1.3 to 8.11.0 by @bwagner in https://codeberg.org/uzu/strudel/pulls/850
|
||||
- add missing trailing slashes by @felixroos in https://codeberg.org/uzu/strudel/pulls/860
|
||||
- move all examples to separate examples folder by @felixroos in https://codeberg.org/uzu/strudel/pulls/878
|
||||
- Dependency update by @felixroos in https://codeberg.org/uzu/strudel/pulls/879
|
||||
- Update Vite version so hot reload works properly with newest pnpm version by @daslyfe in https://codeberg.org/uzu/strudel/pulls/892
|
||||
- prevent vite from complaining about additional exports in jsx files by @daslyfe in https://codeberg.org/uzu/strudel/pulls/891
|
||||
- fix some build warnings by @felixroos in https://codeberg.org/uzu/strudel/pulls/902
|
||||
- Remove hideHeader for better mobile UI and consistency by @rjulian in https://codeberg.org/uzu/strudel/pulls/894
|
||||
- Fix: swatch/[name].png.js static path by @oscarbyrne in https://codeberg.org/uzu/strudel/pulls/916
|
||||
- rename @strudel.cycles/_ packages to @strudel/_ by @felixroos in https://codeberg.org/uzu/strudel/pulls/917
|
||||
- `pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function by @yaxu in https://codeberg.org/uzu/strudel/pulls/918
|
||||
- Revert "`pick` now accepts lookup tables, with alternate cycle squeezing behaviour as new `inhabit` function" by @yaxu in https://codeberg.org/uzu/strudel/pulls/920
|
||||
- Fix pattern tab not showing patterns without created date by @daslyfe in https://codeberg.org/uzu/strudel/pulls/934
|
||||
|
||||
</details>
|
||||
|
||||
## New Contributors
|
||||
|
||||
- @ilesinge made their first contribution in https://github.com/tidalcycles/strudel/pull/748
|
||||
- @Dsm0 made their first contribution in https://github.com/tidalcycles/strudel/pull/773
|
||||
- @kasparsj made their first contribution in https://github.com/tidalcycles/strudel/pull/802
|
||||
- @atfornes made their first contribution in https://github.com/tidalcycles/strudel/pull/818
|
||||
- @drewgbarnes made their first contribution in https://github.com/tidalcycles/strudel/pull/830
|
||||
- @shiyouganai made their first contribution in https://github.com/tidalcycles/strudel/pull/843
|
||||
- @rjulian made their first contribution in https://github.com/tidalcycles/strudel/pull/894
|
||||
- @fnordomat made their first contribution in https://github.com/tidalcycles/strudel/pull/907
|
||||
- @oscarbyrne made their first contribution in https://github.com/tidalcycles/strudel/pull/916
|
||||
- @geikha made their first contribution in https://github.com/tidalcycles/strudel/pull/924
|
||||
- @ilesinge made their first contribution in https://codeberg.org/uzu/strudel/pulls/748
|
||||
- @Dsm0 made their first contribution in https://codeberg.org/uzu/strudel/pulls/773
|
||||
- @kasparsj made their first contribution in https://codeberg.org/uzu/strudel/pulls/802
|
||||
- @atfornes made their first contribution in https://codeberg.org/uzu/strudel/pulls/818
|
||||
- @drewgbarnes made their first contribution in https://codeberg.org/uzu/strudel/pulls/830
|
||||
- @shiyouganai made their first contribution in https://codeberg.org/uzu/strudel/pulls/843
|
||||
- @rjulian made their first contribution in https://codeberg.org/uzu/strudel/pulls/894
|
||||
- @fnordomat made their first contribution in https://codeberg.org/uzu/strudel/pulls/907
|
||||
- @oscarbyrne made their first contribution in https://codeberg.org/uzu/strudel/pulls/916
|
||||
- @geikha made their first contribution in https://codeberg.org/uzu/strudel/pulls/924
|
||||
|
||||
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v0.9.0...v1.0.0
|
||||
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v0.9.0...v1.0.0
|
||||
|
||||
@@ -216,9 +216,9 @@ Here is a recording of the first session we organized over the discord server:
|
||||
|
||||
The midi integration has gotten a few new features:
|
||||
|
||||
- [clock out](https://github.com/tidalcycles/strudel/pull/710) to sync your midi devices / DAW to the strudel clock (better doc coming soon)
|
||||
- [clock out](https://codeberg.org/uzu/strudel/pulls/710) to sync your midi devices / DAW to the strudel clock (better doc coming soon)
|
||||
- [cc output](https://strudel.cc/learn/input-output/#ccn--ccv) to send cc values to your gear
|
||||
- [cc input](https://github.com/tidalcycles/strudel/pull/699) to control strudel via MIDI (better doc coming soon)
|
||||
- [cc input](https://codeberg.org/uzu/strudel/pulls/699) to control strudel via MIDI (better doc coming soon)
|
||||
|
||||
Here is a little demo of me fiddling with a midi controller, changing a piano pattern:
|
||||
|
||||
@@ -228,7 +228,7 @@ Here is a little demo of me fiddling with a midi controller, changing a piano pa
|
||||
|
||||
- You can now run [hydra inside strudel](https://strudel.cc/learn/hydra/) + you can even run strudel in [hydra](https://hydra.ojack.xyz), thanks to [Olivia Jack](https://ojack.xyz/) and [Ámbar Tenorio Fornés](https://atenor.io/)! Read more [here](https://alpaca.pubpub.org/pub/b7hwrjfk/release/2?readingCollection=1def0192)
|
||||
- There is now a [VSCode Plugin](https://marketplace.visualstudio.com/items?itemName=roipoussiere.tidal-strudel) thanks to [roipoussiere](https://github.com/roipoussiere)! It allows you run patterns from a `.strudel` file inside VSCode.
|
||||
- Strudel can now be downloaded as a desktop app, thanks to [vasilymilovidov](https://github.com/vasilymilovidov) who has wrapped the REPL with [tauri](https://tauri.app/). You can download it [on the releases page](https://github.com/tidalcycles/strudel/releases) (scroll down to Assets). The performance is not optimal on MacOS and Linux, which is why it is still considered experimental
|
||||
- Strudel can now be downloaded as a desktop app, thanks to [vasilymilovidov](https://github.com/vasilymilovidov) who has wrapped the REPL with [tauri](https://tauri.app/). You can download it [on the releases page](https://codeberg.org/uzu/strudel/releases) (scroll down to Assets). The performance is not optimal on MacOS and Linux, which is why it is still considered experimental
|
||||
|
||||
## Stats
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
cx.js - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/repl/src/cx.js>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/repl/src/cx.js>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ These pages will introduce you to [Strudel](https://strudel.cc/), a web-based [l
|
||||
|
||||
# What is Strudel?
|
||||
|
||||
[Strudel](https://strudel.cc/) is a version of [Tidal Cycles](https://tidalcycles.org) written in [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript), initiated by [Alex McLean](https://slab.org) and [Felix Roos](https://github.com/felixroos) in 2022.
|
||||
[Strudel](https://strudel.cc/) is a version of [Tidal Cycles](https://tidalcycles.org) written in [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript), initiated by [Alex McLean](https://slab.org) and [Felix Roos](https://froos.cc/) in 2022.
|
||||
Tidal Cycles, also known as Tidal, is a language for [algorithmic pattern](https://algorithmicpattern.org), and though it is most commonly used for [making music](https://tidalcycles.org/docs/showcase), it can be used for any kind of pattern making activity, including [weaving](https://www.youtube.com/watch?v=TfEmEsusXjU).
|
||||
|
||||
Tidal was first implemented as a library written in the [Haskell](https://www.haskell.org/) functional programming language, and by itself it does not make any sound.
|
||||
@@ -81,7 +81,7 @@ s("bd,[~ <sd!3 sd(3,4,2)>],hh*8") // drums
|
||||
Please note that this project is still in its experimental state.
|
||||
In the future, parts of it might change significantly.
|
||||
This tutorial is also far from complete.
|
||||
You can contribute to it clicking 'Edit this page' in the top right, or by visiting the [Strudel GitHub page](https://github.com/tidalcycles/strudel/).
|
||||
You can contribute to it clicking 'Edit this page' in the top right, or by visiting the [Strudel GitHub page](https://codeberg.org/uzu/strudel/).
|
||||
|
||||
# What's next?
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
# MIDI, OSC and MQTT
|
||||
|
||||
Normally, Strudel is used to pattern sound, using its own '[web audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)'-based synthesiser called [SuperDough](https://github.com/tidalcycles/strudel/tree/main/packages/superdough).
|
||||
Normally, Strudel is used to pattern sound, using its own '[web audio](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)'-based synthesiser called [SuperDough](https://codeberg.org/uzu/strudel/src/branch/main/packages/superdough).
|
||||
|
||||
It is also possible to pattern other things with Strudel, such as software and hardware synthesisers with MIDI, other software using Open Sound Control/OSC (including the [SuperDirt](https://github.com/musikinformatik/SuperDirt/) synthesiser commonly used with Strudel's sibling [TidalCycles](https://tidalcycles.org/)), or the MQTT 'internet of things' protocol.
|
||||
|
||||
@@ -184,7 +184,7 @@ To get SuperDirt to work with Strudel, you need to
|
||||
1. install SuperCollider + sc3 plugins, see [Tidal Docs](https://tidalcycles.org/docs/) (Install Tidal) for more info.
|
||||
2. install SuperDirt, or the [StrudelDirt](https://github.com/daslyfe/StrudelDirt) fork which is optimised for use with Strudel
|
||||
3. install [node.js](https://nodejs.org/en/)
|
||||
4. download [Strudel Repo](https://github.com/tidalcycles/strudel/) (or git clone, if you have git installed)
|
||||
4. download [Strudel Repo](https://codeberg.org/uzu/strudel/) (or git clone, if you have git installed)
|
||||
5. run `pnpm i` in the strudel directory
|
||||
6. run `pnpm run osc` to start the osc server, which forwards OSC messages from Strudel REPL to SuperCollider
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ You can optionally add some music metadata in your Strudel code, by using tags i
|
||||
|
||||
Like other comments, those are ignored by Strudel, but it can be used by other tools to retrieve some information about the music.
|
||||
|
||||
It is for instance used by the [swatch tool](https://github.com/tidalcycles/strudel/tree/main/my-patterns) to display pattern titles in the [examples page](https://strudel.cc/examples/).
|
||||
|
||||
## Alternative syntax
|
||||
|
||||
You can also use comment blocks:
|
||||
|
||||
@@ -62,7 +62,7 @@ To see which sample names are available, open the `sounds` tab in the [REPL](htt
|
||||
Note that only the sample maps (mapping names to URLs) are loaded initially, while the audio samples themselves are not loaded until they are actually played.
|
||||
This behaviour of loading things only when they are needed is also called `lazy loading`.
|
||||
While it saves resources, it can also lead to sounds not being audible the first time they are triggered, because the sound is still loading.
|
||||
[This might be fixed in the future](https://github.com/tidalcycles/strudel/issues/187)
|
||||
[This might be fixed in the future](https://codeberg.org/uzu/strudel/issues/187)
|
||||
|
||||
# Sound Banks
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ Instead of `+` / `add`, you can use any of the available operators of the first
|
||||
|
||||
## Function Compatibility
|
||||
|
||||
[This issue](https://github.com/tidalcycles/strudel/issues/31) tracks which Tidal functions are implemented in Strudel.
|
||||
[This issue](https://codeberg.org/uzu/strudel/issues/31) tracks which Tidal functions are implemented in Strudel.
|
||||
The list might not be 100% up to date and probably also misses some functions completely..
|
||||
Feel encouraged to search the source code for a function you're looking for.
|
||||
If you find a function that's not on the list, please tell!
|
||||
@@ -89,7 +89,7 @@ If you find a function that's not on the list, please tell!
|
||||
As seen in the example, the `#` operator (shorthand for `|>`) is also just a function call in strudel.
|
||||
So `note "c5" # s "gtr"` becomes `note("c5").s('gtr')`.
|
||||
|
||||
[This file](https://github.com/tidalcycles/strudel/blob/main/packages/core/controls.mjs) lists all available control params.
|
||||
[This file](https://codeberg.org/uzu/strudel/src/branch/main/packages/core/controls.mjs) lists all available control params.
|
||||
Note that not all of those work in the Webaudio Output of Strudel.
|
||||
If you find a tidal control that's not on the list, please tell!
|
||||
|
||||
@@ -107,11 +107,11 @@ You can find a [list of available effects here](/learn/effects/).
|
||||
### Sampler
|
||||
|
||||
Strudel's sampler supports [a subset](/learn/samples) of Superdirt's sampler.
|
||||
Also, samples are always loaded from a URL rather than from the disk, although [that might be possible in the future](https://github.com/tidalcycles/strudel/issues/118).
|
||||
Also, samples are always loaded from a URL rather than from the disk, although [that might be possible in the future](https://codeberg.org/uzu/strudel/issues/118).
|
||||
|
||||
## Evaluation
|
||||
|
||||
The Strudel REPL does not support [block based evaluation](https://github.com/tidalcycles/strudel/issues/34) yet.
|
||||
The Strudel REPL does not support [block based evaluation](https://codeberg.org/uzu/strudel/issues/34) yet.
|
||||
You can use labeled statements and `_` to mute:
|
||||
|
||||
<MiniRepl
|
||||
|
||||
@@ -9,9 +9,9 @@ The docs page is built ontop of astro's [docs site](https://github.com/withastro
|
||||
|
||||
## Adding a new Docs Page
|
||||
|
||||
1. add a `.mdx` file in a path under `website/src/pages/`, e.g. [website/src/pages/learn/code.mdx](https://raw.githubusercontent.com/tidalcycles/strudel/main/website/src/pages/learn/code.mdx) will be available under https://strudel.cc/learn/code/ (or locally under `http://localhost:4321/learn/code/`)
|
||||
1. add a `.mdx` file in a path under `website/src/pages/`, e.g. [website/src/pages/learn/code.mdx](https://codeberg.org/uzu/strudel/src/branch/main/website/src/pages/learn/code.mdx) will be available under https://strudel.cc/learn/code/ (or locally under `http://localhost:4321/learn/code/`)
|
||||
2. make sure to copy the top part of another existing docs page. Adjust the title accordingly
|
||||
3. To add a link to the sidebar, add a new entry to `SIDEBAR` to [`config.ts`](https://github.com/tidalcycles/strudel/blob/main/website/src/config.ts)
|
||||
3. To add a link to the sidebar, add a new entry to `SIDEBAR` to [`config.ts`](https://codeberg.org/uzu/strudel/src/branch/main/website/src/config.ts)
|
||||
|
||||
## Using the Mini REPL
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { MiniRepl } from '../../docs/MiniRepl';
|
||||
|
||||
# Strudel Packages
|
||||
|
||||
The [strudel repo](https://github.com/tidalcycles/strudel) is organized as a monorepo, containing multiple npm packages.
|
||||
The [strudel repo](https://codeberg.org/uzu/strudel) is organized as a monorepo, containing multiple npm packages.
|
||||
The purpose of the multiple packages is to
|
||||
|
||||
- organize the codebase into more modular, encapsulated pieces
|
||||
@@ -23,8 +23,8 @@ Here is an overview of all the packages:
|
||||
|
||||
These packages give you a batteries-included point of getting started, and most likely the thing you'd want to use in your project:
|
||||
|
||||
- [repl](https://github.com/tidalcycles/strudel/tree/main/packages/repl): The Strudel REPL as a web component.
|
||||
- [web](https://github.com/tidalcycles/strudel/tree/main/packages/web): Strudel library for the browser, without UI.
|
||||
- [repl](https://codeberg.org/uzu/strudel/src/branch/main/packages/repl): The Strudel REPL as a web component.
|
||||
- [web](https://codeberg.org/uzu/strudel/src/branch/main/packages/web): Strudel library for the browser, without UI.
|
||||
|
||||
To find out more about these two, read [Using Strudel in Your Project](/technical-manual/project-start)
|
||||
|
||||
@@ -32,31 +32,31 @@ To find out more about these two, read [Using Strudel in Your Project](/technica
|
||||
|
||||
These package are the most essential. You might want to use all of those if you're using strudel in your project:
|
||||
|
||||
- [core](https://github.com/tidalcycles/strudel/tree/main/packages/core#strudelcore): tidal pattern engine with core primitives
|
||||
- [mini](https://github.com/tidalcycles/strudel/tree/main/packages/mini#strudelmini): mini notation parser + core bindings
|
||||
- [transpiler](https://github.com/tidalcycles/strudel/tree/main/packages/transpiler#strudeltranspiler): user code transpiler. syntax sugar + highlighting
|
||||
- [core](https://codeberg.org/uzu/strudel/src/branch/main/packages/core#strudelcore): tidal pattern engine with core primitives
|
||||
- [mini](https://codeberg.org/uzu/strudel/src/branch/main/packages/mini#strudelmini): mini notation parser + core bindings
|
||||
- [transpiler](https://codeberg.org/uzu/strudel/src/branch/main/packages/transpiler#strudeltranspiler): user code transpiler. syntax sugar + highlighting
|
||||
|
||||
### Language Extensions
|
||||
|
||||
These packages extend the pattern language by specific functions
|
||||
|
||||
- [tonal](https://github.com/tidalcycles/strudel/tree/main/packages/tonal): tonal functions for scales and chords
|
||||
- [xen](https://github.com/tidalcycles/strudel/tree/main/packages/xen): microtonal / xenharmonic functions
|
||||
- [tonal](https://codeberg.org/uzu/strudel/src/branch/main/packages/tonal): tonal functions for scales and chords
|
||||
- [xen](https://codeberg.org/uzu/strudel/src/branch/main/packages/xen): microtonal / xenharmonic functions
|
||||
|
||||
### Outputs
|
||||
|
||||
These packages provide bindings for different ways to output strudel patterns:
|
||||
|
||||
- [webaudio](https://github.com/tidalcycles/strudel/tree/main/packages/webaudio#strudelwebaudio): the default webaudio output
|
||||
- [osc](https://github.com/tidalcycles/strudel/tree/main/packages/osc#strudelosc): bindings to communicate via OSC
|
||||
- [midi](https://github.com/tidalcycles/strudel/tree/main/packages/midi#strudelmidi): webmidi bindings
|
||||
- [csound](https://github.com/tidalcycles/strudel/tree/main/packages/csound#strudelcsound): csound bindings
|
||||
- [soundfonts](https://github.com/tidalcycles/strudel/tree/main/packages/serial#strudelsoundfonts): Soundfont support
|
||||
- [serial](https://github.com/tidalcycles/strudel/tree/main/packages/serial#strudelserial): webserial bindings
|
||||
- [webaudio](https://codeberg.org/uzu/strudel/src/branch/main/packages/webaudio#strudelwebaudio): the default webaudio output
|
||||
- [osc](https://codeberg.org/uzu/strudel/src/branch/main/packages/osc#strudelosc): bindings to communicate via OSC
|
||||
- [midi](https://codeberg.org/uzu/strudel/src/branch/main/packages/midi#strudelmidi): webmidi bindings
|
||||
- [csound](https://codeberg.org/uzu/strudel/src/branch/main/packages/csound#strudelcsound): csound bindings
|
||||
- [soundfonts](https://codeberg.org/uzu/strudel/src/branch/main/packages/serial#strudelsoundfonts): Soundfont support
|
||||
- [serial](https://codeberg.org/uzu/strudel/src/branch/main/packages/serial#strudelserial): webserial bindings
|
||||
|
||||
### Others
|
||||
|
||||
- [embed](https://github.com/tidalcycles/strudel/tree/main/packages/embed#strudelembed): embeddable REPL web component
|
||||
- [embed](https://codeberg.org/uzu/strudel/src/branch/main/packages/embed#strudelembed): embeddable REPL web component
|
||||
|
||||
### No Longer Maintained
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ n("<0 1 2 3 4>*8").scale('G4 minor')
|
||||
This will load the strudel website in an iframe, using the code provided within the HTML comments `<!-- -->`.
|
||||
The HTML comments are needed to make sure the browser won't interpret it as HTML.
|
||||
|
||||
For alternative ways to load this package, see the [@strudel/embed README](https://github.com/tidalcycles/strudel/tree/main/packages/embed#strudelembed).
|
||||
For alternative ways to load this package, see the [@strudel/embed README](https://codeberg.org/uzu/strudel/src/branch/main/packages/embed#strudel-embed).
|
||||
|
||||
### @strudel/repl
|
||||
|
||||
@@ -99,7 +99,7 @@ The upside of using the repl without an iframe is that you can pin the strudel v
|
||||
|
||||
This will guarantee your pattern wont break due to changes to the strudel project in the future.
|
||||
|
||||
For more info on this package, see the [@strudel/repl README](https://github.com/tidalcycles/strudel/tree/main/packages/repl#strudelrepl).
|
||||
For more info on this package, see the [@strudel/repl README](https://codeberg.org/uzu/strudel/src/branch/main/packages/repl#strudel-repl).
|
||||
|
||||
## With your own UI
|
||||
|
||||
@@ -118,7 +118,7 @@ If you'd rather use your own UI, you can use the `@strudel/web` package:
|
||||
</script>
|
||||
```
|
||||
|
||||
For more info on this package, see the [@strudel/web README](https://github.com/tidalcycles/strudel/tree/main/packages/web#strudelweb).
|
||||
For more info on this package, see the [@strudel/web README]https://codeberg.org/uzu/strudel/src/branch/main/packages/web#strudel-web).
|
||||
|
||||
## Via npm
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Besides a UI for playback control and meta information, the main part of the REP
|
||||
2. While the REPL is running, the `Scheduler` queries the active `Pattern` by a regular interval, generating `Events` (also known as `Haps` in Strudel) for the next time span.
|
||||
3. For each scheduling tick, all generated `Events` are triggered by calling their `onTrigger` method, which is set by the output.
|
||||
|
||||
<img src="https://github.com/tidalcycles/strudel/blob/talk/talk/public/strudelflow.png?raw=true" width="600" />
|
||||
<img src="https://codeberg.org/uzu/strudel/raw/branch/talk/talk/public/strudelflow.png" width="600" />
|
||||
|
||||
## User Code
|
||||
|
||||
@@ -75,7 +75,7 @@ The sum of both is passed to `withLoc` to tell each element its location, which
|
||||
|
||||
Another important part of the user code is the mini notation, which allows to express rhythms in a short manner.
|
||||
|
||||
- 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)
|
||||
- the mini notation is [implemented as a PEG grammar](https://codeberg.org/uzu/strudel/src/branch/talk/packages/mini/krill.pegjs), living in the [mini package](https://codeberg.org/uzu/strudel/src/branch/main/packages/mini)
|
||||
- it is based on [krill](https://github.com/Mdashdotdashn/krill) by Mdashdotdashn
|
||||
- the peg grammar is used to generate a parser with [peggyjs](https://peggyjs.org/)
|
||||
- the generated parser takes a mini notation string and outputs an AST
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Repl.jsx - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/repl/src/App.js>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/repl/src/App.js>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ export function Reference() {
|
||||
<ul>
|
||||
{entry.params?.map(({ name, type, description }, i) => (
|
||||
<li key={i}>
|
||||
{name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)}</> : ''}
|
||||
{name} : {type?.names?.join(' | ')} {description ? <> - {getInnerText(description)}</> : ''}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -38,11 +38,11 @@ export function WelcomeTab({ context }) {
|
||||
</a>
|
||||
, which is a popular live coding language for music, written in Haskell. Strudel is free/open source software:
|
||||
you can redistribute and/or modify it under the terms of the{' '}
|
||||
<a href="https://github.com/tidalcycles/strudel/blob/main/LICENSE" target="_blank">
|
||||
<a href="https://codeberg.org/uzu/strudel/src/branch/main/LICENSE" target="_blank">
|
||||
GNU Affero General Public License
|
||||
</a>
|
||||
. You can find the source code at{' '}
|
||||
<a href="https://github.com/tidalcycles/strudel" target="_blank">
|
||||
<a href="https://codeberg.org/uzu/strudel" target="_blank">
|
||||
github
|
||||
</a>
|
||||
. You can also find <a href="https://github.com/felixroos/dough-samples/blob/main/README.md">licensing info</a>{' '}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
tunes.mjs - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/repl/src/tunes.mjs>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/repl/src/tunes.mjs>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Repl.jsx - <short description TODO>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/repl/src/App.js>
|
||||
Copyright (C) 2022 Strudel contributors - see <https://codeberg.org/uzu/strudel/src/branch/main/repl/src/App.js>
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||