From d856e567c17c04cad083850955d838e3e328e404 Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 14 Jun 2025 15:22:27 +0100 Subject: [PATCH] link back to tech manual in wiki --- packages/README.md | 2 +- technical.manual.md | 193 -------------------------------------------- 2 files changed, 1 insertion(+), 194 deletions(-) delete mode 100644 technical.manual.md diff --git a/packages/README.md b/packages/README.md index a5b93d321..98938d6c3 100644 --- a/packages/README.md +++ b/packages/README.md @@ -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. diff --git a/technical.manual.md b/technical.manual.md deleted file mode 100644 index 6068b48fe..000000000 --- a/technical.manual.md +++ /dev/null @@ -1,193 +0,0 @@ -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/). - -## Strudel Packages - -There are different packages for different purposes. They.. - -- split up the code into smaller chunks -- can be selectively used to implement some sort of time based system - -Please refer to the individual README files in the [packages folder](https://codeberg.org/uzu/strudel/src/branch/main/packages) - -## REPL - -The [REPL](https://strudel.tidalcycles.org/) is the place where all packages come together to form a live coding system. It can also be seen as a reference implementation for users of the library. - -More info in the [REPL README](https://codeberg.org/uzu/strudel/src/branch/main/packages/repl/README.md) - -# High Level Overview - - - -## 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 -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 - -JavaScript Transpilation = converting valid JavaScript to valid JavaScript: - -```js -"c3 [e3 g3]".fast(2) -``` - -becomes - -```js -mini('c3 [e3 g3]') - .withMiniLocation([1, 0, 0], [1, 11, 11]) // source location - .fast(2); -``` - -- double quoted strings and backtick strings are turned into `mini` calls (single quoted strings are left as is) -- The source location is added by chaining `withMiniLocation`, which enables the real time highlighting later -- (psuedo) variable names that look like notes (like `c4`, `bb2` or `fs3`) are turned into strings -- support for top level await -- operator overloading could be implemented in the future - -This is how it works: - - - -- The user code is parsed with a [shift parser](https://github.com/shapesecurity/shift-parser-js), generating an AST -- 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 - -### 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) -- 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 -- the AST can then be used to construct a pattern using the regular Strudel API - -Here's an example AST: - -```json -{ - "type_": "pattern", - "arguments_": { "alignment": "h" }, - "source_": [ - { - "type_": "element", "source_": "c3", - "location_": { "start": { "offset": 1, "line": 1, "column": 2 }, "end": { "offset": 4, "line": 1, "column": 5 } } - }, - { - "type_": "element", - "location_": { "start": { "offset": 4, "line": 1, "column": 5 }, "end": { "offset": 11, "line": 1, "column": 12 } } - "source_": { - "type_": "pattern", "arguments_": { "alignment": "h" }, - "source_": [ - { - "type_": "element", "source_": "e3", - "location_": { "start": { "offset": 5, "line": 1, "column": 6 }, "end": { "offset": 8, "line": 1, "column": 9 } } - }, - { - "type_": "element", "source_": "g3", - "location_": { "start": { "offset": 8, "line": 1, "column": 9 }, "end": { "offset": 10, "line": 1, "column": 11 } } - } - ] - }, - } - ] -} -``` - -which translates to `seq(c3, seq(e3, g3))` - -## 2. Querying & Scheduling - -When the user code has been evaluated, we hopefully get a Pattern instance, which we can use to query events from. -These events can then be used to trigger side effects in the real world. On that note, Events are mostly called Hap(s) in the codebase, because JS already has a built in `Event` class. - -### Querying - -> Querying = Asking a Pattern for Events within a certain time span - -```js -seq('c3', ['e3', 'g3']) // <--- Pattern - .queryArc(0, 2) // query events within 0 and 2 cycles - .map((hap) => hap.showWhole()); // make readable -``` - -yields - -```js -[ - '0/1 -> 1/2: c3', // cycle 0 - '1/2 -> 3/4: e3', - '3/4 -> 1/1: g3', - '1/1 -> 3/2: c3', // cycle 1 - '3/2 -> 7/4: e3', - '7/4 -> 2/1: g3', -]; -``` - -### 🗓️ Scheduling - -The scheduler will query events repeatedly, creating a possibly endless loop of time slices. -Here is a simplified example of how it works - -```js -let step = 0.5; // query interval in seconds -let tick = 0; // how many intervals have passed -let pattern = seq('c3', ['e3', 'g3']); // pattern from user -setInterval(() => { - const events = pattern.queryArc(tick * step, ++tick * step); - events.forEach((event) => { - console.log(event.showWhole()); - const o = getAudioContext().createOscillator(); - o.frequency.value = getFreq(event.value); - o.start(event.whole.begin); - o.stop(event.whole.begin + event.duration); - o.connect(getAudioContext().destination); - }); -}, step * 1000); // query each "step" seconds -``` - -## 3. Sound Output - -The third and last step is to use the scheduled events to make sound. -Patterns are wrapped with param functions to compose different properties of the sound. - -```js -note("[c2(3,8) [ bb1]]") // sets frequency - .s("") // sound source - .gain(.5) // turn down volume - .cutoff(sine.range(200,1000).slow(4)) // modulated cutoff - .slow(2) - .out().logValues()`, - ]} -/> -``` - -Here is an example Hap value with different properties: - -```js -{ note: 'a4', s: 'sawtooth', gain: 0.5, cutoff: 267 } -``` - - -
- -- Patterns represent just values in time! -- Suitable for any time based output (music, visuals, movement, .. ?) - -### Supported Outputs - -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) - -These could change, so make sure to check the [packages folder](https://codeberg.org/uzu/strudel/src/branch/main/packages).