Merge branch 'tidalcycles:main' into repl_sync_fixes

This commit is contained in:
Jade (Rose) Rowland 2024-03-23 16:47:22 -04:00 committed by GitHub
commit af740c3abb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 3266 additions and 2872 deletions

View file

@ -102,9 +102,10 @@ export const SIDEBAR: Sidebar = {
{ text: 'Strudel vs Tidal', link: 'learn/strudel-vs-tidal' },
],
Development: [
{ text: 'Strudel in your Project', link: 'technical-manual/project-start' },
{ text: 'Packages', link: 'technical-manual/packages' },
{ text: 'REPL', link: 'technical-manual/repl' },
{ text: 'Sounds', link: 'technical-manual/sounds' },
{ text: 'Packages', link: 'technical-manual/packages' },
{ text: 'Docs', link: 'technical-manual/docs' },
{ text: 'Testing', link: 'technical-manual/testing' },
// { text: 'Internals', link: 'technical-manual/internals' },

View file

@ -5,7 +5,6 @@ import { getPunchcardPainter } from '@strudel/draw';
import { transpiler } from '@strudel/transpiler';
import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio';
import { StrudelMirror } from '@strudel/codemirror';
// import { prebake } from '@strudel/repl';
import { prebake } from '../repl/prebake.mjs';
import { loadModules } from '../repl/util.mjs';
import Claviature from '@components/Claviature';

View file

@ -41,8 +41,8 @@ This makes way for other ways to align the pattern, and several are already defi
- `mix` - structures from both patterns are combined, so that the new events are not fragments but are created at intersections of events from both sides.
- `squeeze` - cycles from the pattern on the right are squeezed into events on the left. So that e.g. `"0 1 2".add.squeeze("10 20")` is equivalent to `"[10 20] [11 21] [12 22]"`.
- `squeezeout` - as with `squeeze`, but cycles from the left are squeezed into events on the right. So, `"0 1 2".add.squeezeout("10 20")` is equivalent to `[10 11 12] [20 21 22]`.
- `trig` is similar to `squeezeout` 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 `"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")` would be equivalent to `10 11 12 13 20 21 30 31`. In effect, events on the right 'trigger' cycles on the left.
- `trigzero` is similar to `trig`, but the pattern is 'triggered' from its very first cycle, rather than from the current cycle. `trig` and `trigzero` therefore only give different results where the leftmost pattern differs from one cycle to the next.
- `reset` is similar to `squeezeout` 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 `"0 1 2 3 4 5 6 7".add.trig("10 [20 30]")` would be equivalent to `10 11 12 13 20 21 30 31`. In effect, events on the right 'trigger' cycles on the left.
- `restart` is similar to `reset`, but the pattern is 'restarted' from its very first cycle, rather than from the current cycle. `reset` and `restart` therefore only give different results where the leftmost pattern differs from one cycle to the next.
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.

View file

@ -60,13 +60,13 @@ These functions are more low level, probably not needed by the live coder.
<JsDoc client:idle name="Pattern#innerJoin" h={0} />
## trigJoin
## resetJoin
<JsDoc client:idle name="Pattern#trigJoin" h={0} />
<JsDoc client:idle name="Pattern#resetJoin" h={0} />
## trigzeroJoin
## restartJoin
<JsDoc client:idle name="Pattern#trigzeroJoin" h={0} />
<JsDoc client:idle name="Pattern#restartJoin" h={0} />
## squeezeJoin

View file

@ -19,6 +19,15 @@ The purpose of the multiple packages is to
[See the latest published packages on npm](https://www.npmjs.com/search?q=%40strudel).
Here is an overview of all the packages:
### Umbrella 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.
To find out more about these two, read [Using Strudel in Your Project](/technical-manual/project-start)
### Essential Packages
These package are the most essential. You might want to use all of those if you're using strudel in your project:

View file

@ -0,0 +1,129 @@
---
title: Using Strudel in your Project
layout: ../../layouts/MainLayout.astro
---
# Using Strudel in your Project
This Guide shows you the different ways to get started with using Strudel in your own project.
## Embedding the Strudel REPL
There are 3 quick ways to embed strudel in your website:
1. Embed the strudel website as an iframe directly
2. Embed the strudel website as an iframe using `@strudel/embed`
3. Embed the REPL directly using `@strudel/repl`
### Inside an iframe
Using an iframe is the most easy way to embed a studel tune.
You can embed any pattern of your choice via an iframe and the URL of the pattern of your choice:
```html
<iframe src="https://strudel.cc/?xwWRfuCE8TAR" width="600" height="300"></iframe>
```
The URL can be obtained by pressing `share` in the REPL.
Note that these share links depend on a database, which is not guaranteed to live forever.
To make sure your code is not lost, you can also use the long url:
```html
<iframe
src="https://strudel.cc/#c2V0Y3BzKDEpCm4oIjwwIDEgMiAzIDQ%2BKjgiKS5zY2FsZSgnRzQgbWlub3InKQoucygiZ21fbGVhZF82X3ZvaWNlIikKLmNsaXAoc2luZS5yYW5nZSguMiwuOCkuc2xvdyg4KSkKLmp1eChyZXYpCi5yb29tKDIpCi5zb21ldGltZXMoYWRkKG5vdGUoIjEyIikpKQoubHBmKHBlcmxpbi5yYW5nZSgyMDAsMjAwMDApLnNsb3coNCkp"
width="600"
height="300"
></iframe>
```
That long URL can just be copy pasted from the URL bar when you're on the strudel website. It always reflects the latest evaluation of your code.
### @strudel/embed
To simplify the process of emebdding via an iframe, you can use the package `@strudel/embed`:
```html
<script src="https://unpkg.com/@strudel/embed@latest"></script>
<strudel-repl>
<!--
setcps(1)
n("<0 1 2 3 4>*8").scale('G4 minor')
.s("gm_lead_6_voice")
.clip(sine.range(.2,.8).slow(8))
.jux(rev)
.room(2)
.sometimes(add(note("12")))
.lpf(perlin.range(200,20000).slow(4))
-->
</strudel-repl>
```
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).
### @strudel/repl
Loading strudel directly in your site, without an iframe, looks similar to the iframe variant:
```html
<script src="https://unpkg.com/@strudel/repl@latest"></script>
<strudel-editor>
<!--
setcps(1)
n("<0 1 2 3 4>*8").scale('G4 minor')
.s("gm_lead_6_voice")
.clip(sine.range(.2,.8).slow(8))
.jux(rev)
.room(2)
.sometimes(add(note("12")))
.lpf(perlin.range(200,20000).slow(4))
-->
</strudel-editor>
```
Here, we're loading `@strudel/repl` instead of `@strudel/embed`, and the component is called `strudel-editor` instead of `strudel-repl`.
Yes the naming is a bit confusing..
The upside of using the repl without an iframe is that you can pin the strudel version you're using:
```html
<script src="https://unpkg.com/@strudel/repl@1.0.2"></script>
<strudel-editor>
<!--
...
-->
</strudel-editor>
```
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).
## With your own UI
The above approach assumes you want to use the builtin [codemirror](https://codemirror.net/) editor.
If you'd rather use your own UI, you can use the `@strudel/web` package:
```html
<!doctype html>
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
<button id="play">play</button>
<button id="stop">stop</button>
<script>
initStrudel();
document.getElementById('play').addEventListener('click', () => note('<c a f e>(3,8)').jux(rev).play());
document.getElementById('stop').addEventListener('click', () => hush());
</script>
```
For more info on this package, see the [@strudel/web README](https://github.com/tidalcycles/strudel/tree/main/packages/web#strudelweb).
## Via npm
[All the packages and many more are available on npm under the @strudel namespace](https://www.npmjs.com/search?q=%40strudel).
There are actually many more packages you can use to have fine grained control over what you use and what not.
To use these packages, you have to use a bundler that supports es modules, like [vite](https://vitejs.dev/).
To find out more about the purpose of each package, see [Packages](/technical-manual/packages)

View file

@ -106,8 +106,7 @@ stack(
[B3@2 D4] [A3@2 [G3 A3]] [B3@2 D4] [A3]
[B3@2 D4] [A4@2 G4] D5@2
[D5@2 [C5 B4]] [[C5 B4] G4@2] [C5@2 [B4 A4]] [[B4 A4] E4@2]
[D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`
.color('#9C7C38'),
[D5@2 [C5 B4]] [[C5 B4] G4 C5] [G5] [~ ~ B3]\`,
// bass
\`[[C2 G2] E3@2] [[C2 G2] F#3@2] [[C2 G2] E3@2] [[C2 G2] F#3@2]
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
@ -115,7 +114,6 @@ stack(
[[B1 D3] G3@2] [[Bb1 Db3] G3@2] [[A1 C3] G3@2] [[D2 C3] F#3@2]
[[F2 C3] E3@2] [[E2 B2] D3@2] [[D2 A2] C3@2] [[C2 G2] B2@2]
[[F2 C3] E3@2] [[E2 B2] D3@2] [[Eb2 Bb2] Db3@2] [[D2 A2] C3 [F3,G2]]\`
.color('#4C4646')
).transpose(12).slow(48)
.superimpose(x=>x.add(0.06)) // add slightly detuned voice
.note()
@ -447,58 +445,6 @@ note(
.room(.5)
.lpa(.125).lpenv(-2).v("8:.125").fanchor(.25)`;
export const hyperpop = `// "Hyperpop"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos
const lfo = cosine.slow(15);
const lfo2 = sine.slow(16);
const filter1 = x=>x.cutoff(lfo2.range(300,3000));
const filter2 = x=>x.hcutoff(lfo.range(1000,6000)).cutoff(4000)
const scales = cat('D3 major', 'G3 major').slow(8)
samples({
bd: '344/344757_1676145-lq.mp3',
sn: '387/387186_7255534-lq.mp3',
hh: '561/561241_12517458-lq.mp3',
hh2:'44/44944_236326-lq.mp3',
hh3: '44/44944_236326-lq.mp3',
}, 'https://cdn.freesound.org/previews/')
stack(
"-7 0 -7 7".struct("x(5,8,1)").fast(2).sub(7)
.scale(scales)
.note()
.s("sawtooth,square")
.gain(.3).attack(0.01).decay(0.1).sustain(.5)
.apply(filter1)
.lpa(.1).lpenv(2).ftype('24db')
,
n("~@3 [<2 3>,<4 5>]")
.echo(4,1/16,.7)
.scale(scales)
.s('square').gain(.7)
.attack(0.01).decay(0.1).sustain(0)
.apply(filter1),
"6 4 2".add(14)
.superimpose(sub("5"))
.fast(1).euclidLegato(3,8)
.mask("<1 0@7>")
.fast(2).n()
.echo(32, 1/8, .8)
.scale(scales)
.s("sawtooth")
.mul(gain(sine.range(.1,.4).slow(8)))
.attack(.001).decay(.2).sustain(0)
.apply(filter2)
).stack(
stack(
"bd <~@7 [~ bd]>".fast(2),
"~ sn",
"[~ hh3]*2"
).s().fast(2).gain(.7)
).slow(2)`;
export const festivalOfFingers3 = `// "Festival of fingers 3"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos
@ -615,7 +561,7 @@ setcps(1)
"<8(3,8) <7 7*2> [4 5@3] 8>".sub(1) // sub 1 -> 1-indexed
.layer(
x=>x,
x=>x.add(7).color('steelblue')
x=>x.add(7)
.off(1/8,x=>x.add("2,4").off(1/8,x=>x.add(5).echo(4,.125,.5)))
.slow(2),
).n().scale('A1 minor')