Compare commits

...

78 Commits

Author SHA1 Message Date
Felix Roos 1fdd87a4f3 doc: def 2025-07-15 09:35:24 +02:00
Felix Roos 16e9aca222 fix: can now use def in mondough 2025-07-15 09:33:14 +02:00
froos 4a3d5ca44f Merge pull request 'fixed keybinding presedence issue' (#1456) from Dsm0/strudel:keyboard_binding_presedence_fix into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1456
2025-07-11 11:10:23 +02:00
froos 6c0e8a0833 Merge pull request 'added multicursor support on ctrl/cmd + click' (#1457) from Dsm0/strudel:multicursor-on-click into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1457
2025-07-11 11:09:04 +02:00
Dsm0 eb4f1f69f6 pnpm codeformat 2025-07-10 17:28:56 -07:00
Dsm0 e7e321fe03 added multicursor support on ctrl/cmd + click 2025-07-10 15:03:22 -07:00
Dsm0 bf3de368f0 added codemirror as an option + removed fallback on defaults 2025-07-10 12:11:10 -07:00
Dsm0 d645cc6fe5 fixed keybinding presedence issue 2025-07-09 13:28:22 -07:00
froos 6fe11be218 Merge pull request 'added tab-indent setting' (#1454) from Dsm0/strudel:tab-indentation into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1454
2025-07-09 09:39:45 +02:00
Dsm0 8defdc424c added tab-indent setting 2025-07-08 17:57:24 -07:00
froos d0a544d7a7 Merge pull request 'ontrigger-refactoring' (#1442) from ontrigger-refactoring into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1442
2025-07-08 15:48:40 +02:00
Felix Roos 671a22fc22 chore: add link to contributors 2025-07-07 23:28:41 +02:00
froos 976955dae3 Merge pull request 'fix: remove first gm_synth_bass_1, as it doesn't work in safari' (#1452) from gm_synth_bass_1 into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1452
2025-07-07 23:14:24 +02:00
Felix Roos a6ad58a375 fix: remove first gm_synth_bass_1, as it doesn't work in safari 2025-07-07 23:12:15 +02:00
Felix Roos 681eed3d0e revert add logo 2025-07-07 22:23:40 +02:00
Felix Roos 81a9811803 add logo 2025-07-07 22:23:16 +02:00
Felix Roos 72b582c605 fix: remove github contributor avatars 2025-07-07 22:20:04 +02:00
froos 2f0891d4e5 Merge pull request 'fix: minor doc changes' (#1435) from Aurel300/strudel:fix/minor-docs into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1435
2025-07-07 00:06:15 +02:00
Felix Roos a7a283a99e doc: add version tagging guide to contributing.md 2025-07-06 17:00:33 +02:00
Alex McLean acd5661106 Merge pull request 'Fix randrun and deps including shuffle. Fixes #1441' (#1447) from fix-randrun into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1447
2025-07-05 12:53:44 +02:00
froos b0b2b6a120 Merge pull request 'add setDefault + resetDefaults to superdough' (#1433) from set-default-default into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1433
2025-07-05 12:15:51 +02:00
Felix Roos 664d76cf1b resetDefaults when editor is reset 2025-07-05 11:32:16 +02:00
alex a901e2e387 snapshot 2025-07-05 10:28:20 +01:00
Felix Roos 82b14b5292 fix: lint 2025-07-05 11:13:40 +02:00
alex 05bcd5e32f Fix randrun and deps including shuffle. Fixes #1441 2025-07-05 09:01:48 +01:00
froos b0c0a393a1 Merge pull request 'disable fm for supersaw' (#1443) from supersaw-no-fm into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1443
2025-07-04 22:36:18 +02:00
Felix Roos 168269a839 disable fm for supersaw 2025-07-04 22:29:18 +02:00
Felix Roos 34771f03d4 some clarification comments 2025-07-04 22:17:23 +02:00
Aurel Bílý 504fe9ed40 document setcps in cycles reference 2025-07-01 13:45:36 +02:00
froos caf6686d01 Merge pull request 'corrected minor spelling mistake (#1425)' (#1434) from tj-mueller/strudel_1425:spelling_mistake_1425 into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1434
2025-06-30 13:28:09 +02:00
tj-mueller c063fb6b1c correct rd to cr 2025-06-30 11:51:39 +02:00
Felix Roos e3680b96de refactor: remove first param of all onTrigger calls 2025-06-30 10:18:54 +02:00
Felix Roos 2e33569786 add setDefault + resetDefaults to superdough 2025-06-30 05:48:08 +02:00
froos 46fe6d3c4d Merge pull request 'Add browser cache explanation in samples.mdx' (#1369) from wyan/patch-1 into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1369
2025-06-30 05:26:10 +02:00
froos 9220b95677 Merge branch 'main' into wyan/patch-1 2025-06-30 05:24:26 +02:00
froos 5b27b19972 Merge pull request 'add-release-notes' (#1432) from add-release-notes into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1432
2025-06-30 05:18:41 +02:00
Felix Roos 5a72ea94b1 fix: format 2025-06-30 05:15:30 +02:00
Felix Roos eac6f27ca4 add 1.2.0 release notes 2025-06-29 21:29:11 +02:00
Felix Roos f2330a2307 add 1.1.0 release notes 2025-06-29 20:18:15 +02:00
Jade Rose db413881db Merge pull request 'feat: delaytime in cycles' (#1341) from daslyfe/jade/delaycycle into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1341
2025-06-28 20:30:48 +02:00
Jade (Rose) Rowland 77bab433e0 cf 2025-06-28 14:06:16 -04:00
daslyfe f8cc1c2022 Merge branch 'main' into daslyfe/jade/delaycycle 2025-06-28 20:01:57 +02:00
froos e0bf9ea4d6 Merge pull request 'Case insensitive search in the reference tab' (#1420) from kdiab/strudel:main into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1420
2025-06-28 13:44:47 +02:00
Alex McLean 374661eb23 Merge pull request 'add unjoin, into and chunkinto' (#1418) from add-unjoin into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1418
2025-06-28 00:04:12 +02:00
alex df06248c54 snapshot 2025-06-27 22:59:01 +01:00
alex 27073d6c17 format 2025-06-27 22:56:19 +01:00
alex f44caf9096 tests and tweaks, and add chunkBackInto 2025-06-27 22:51:47 +01:00
alex ff5b11f5ed test + bugfix for chunkinto 2025-06-27 22:44:15 +01:00
Alex McLean 719c70a598 Merge branch 'main' into add-unjoin 2025-06-27 22:40:40 +02:00
Jade (Rose) Rowland 7a53f6c021 add test 2025-06-27 15:56:37 -04:00
Jade (Rose) Rowland 09d05abd70 delaysync 2025-06-27 15:54:39 -04:00
Jade (Rose) Rowland 3acc364a03 Merge branch 'main' into daslyfe/jade/delaycycle 2025-06-27 15:53:48 -04:00
Felix Roos b1aba294ad hotfix: fix upstream test 2025-06-26 15:39:35 +02:00
froos 63ac80eb79 Merge pull request 'mondo notation' (#1311) from uzu into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1311
2025-06-26 15:29:45 +02:00
Khalid e19fd24447 Case insensitive search in the reference tab 2025-06-25 08:44:12 -04:00
alex fe9a91d1e4 add unjoin, into and chunkinto 2025-06-24 23:22:42 +01:00
froos 860bb58d61 Merge pull request 'allow calling all multiple times' (#1417) from multiple-all-calls into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1417
2025-06-24 06:14:15 +02:00
Felix Roos d58b3e490b fix: reset all transforms before eval 2025-06-24 06:12:21 +02:00
Felix Roos 0003ce174e allow calling all multiple times 2025-06-24 06:06:37 +02:00
froos 8e0f23e081 Merge pull request 'tonal: allow scales without tonic (default to C)' (#1092) from kasparsj/tonal-fix into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1092
2025-06-24 05:53:21 +02:00
Felix Roos 71e60ed8de add back comment 2025-06-24 05:45:36 +02:00
Felix Roos e2a29914c7 don't interpret note as n 2025-06-24 05:43:06 +02:00
Felix Roos a9a3d491a2 Merge branch 'main' into kasparsj/tonal-fix 2025-06-24 05:39:59 +02:00
yaxu a750764f88 Update CONTRIBUTING.md 2025-06-23 11:13:00 +02:00
froos 5b397009ab Merge pull request 'website intro: fix whitespace and code hosting name' (#1400) from trofi/strudel:website-intro-minor into main
Reviewed-on: https://codeberg.org/uzu/strudel/pulls/1400
2025-06-20 20:00:11 +02:00
Sergei Trofimovich e68df9e789 website intro: fix whitespace and code hosting name 2025-06-20 18:33:58 +01:00
yaxu 4d3bbd5057 Update README.md 2025-06-19 17:44:45 +02:00
Alice Wyan 1b7fbecf50 Fix style issue 2025-06-10 13:20:21 +02:00
Alice Wyan 117cf7e18a Update samples.mdx 2025-06-09 19:45:21 +02:00
Alice Wyan ae15bb7274 Add browser cache explanation in samples.mdx
Several users (including me) have been bitten by this, so it's perhaps worth mentioning in the docs that the strudel.json file gets cached by the browser and doesn't reload properly unless forced.
2025-06-09 15:03:41 +02:00
Jade (Rose) Rowland 94257e81ee lint 2025-05-02 23:44:55 -04:00
Jade (Rose) Rowland 006ce9d1da delaytime 2025-05-02 23:33:58 -04:00
Kaspars 81ca199a96 Merge branch 'upstream-main' into tonal-fix 2024-06-02 12:39:14 +03:00
Kaspars 8d8b8ab99e codeformat 2024-05-08 10:42:06 +02:00
Kaspars a4f10d5339 bug fix 2024-05-08 10:38:06 +02:00
Kaspars 33a73c37bc fix tests 2024-05-08 00:46:27 +02:00
Kaspars 4e6d39666a codeformat 2024-05-08 00:00:58 +02:00
Kaspars a5b6022506 - fix scale() to allow both n() and note() at the same time
- fix scale() to allow scale names without tonic and then default it to C
2024-05-07 23:56:39 +02:00
40 changed files with 981 additions and 99 deletions
+77 -1
View File
@@ -17,7 +17,7 @@ git remote set-url origin git@codeberg.org:uzu/strudel.git
To get in touch with the contributors, either
- [join the Tidal Discord Channel](https://discord.gg/remJ6gQA) and go to the #strudel channel
- [join the Tidal Discord Channel](https://discord.com/invite/HGEdXmRkzT) and go to the #strudel channel
- Find related discussions on the [tidal club forum](https://club.tidalcycles.org/)
## Ask a Question
@@ -150,6 +150,7 @@ Important: Always publish with `pnpm`, as `npm` does not support overriding main
## useful commands
```sh
#regenerate the test snapshots (ex: when updating or creating new pattern functions)
pnpm snapshot
@@ -160,6 +161,81 @@ pnpm run osc
#build the standalone version
pnpm tauri build
```
## version tag patching
here's a little guide on how to patch patterns in the database to prevent breaking old patterns due to breaking changes in newer versions.
the general tactic is to use `// @version x.y` to tag a pattern with a specific strudel version. when a pattern is evaluated, this metadata will de-activate any breaking changes that came after the specified version.
for example, in version 1.1, the default value for `fanchor` was changed from `0.5` to `0`.
if play a pattern that was made before that change, sounds that use filter evenlopes can sound very different, so by adding `// @version 1.0` will make it sound like it used to.
before releasing a new version with breaking changes, we can edit all patterns in the database, inserting the version tag they were created under:
as an example, to release version 1.2, do the following:
1. get date range
```sh
# get date of last version:
git log -1 --format=%aI @strudel/core@1.1.0
# 2024-05-31T23:07:26+02:00
# get date of current version:
git log -1 --format=%aI @strudel/core@1.2.0
# 2025-05-01T12:39:24+02:00
# might also use todays timestamp if version is not yet released
```
now we know, all patterns between these 2 dates have to receive a version tag (unless they already have one).
2. get patterns in question
```sql
SELECT *
FROM code_v1
WHERE code NOT LIKE '%@version%'
AND created_at > '2024-05-31T23:07:26+02:00'
AND created_at < '2025-05-01T12:39:24+02:00'
ORDER BY created_at ASC;
```
this gives us all unversioned patterns that were saved between 1.1.0 and 1.2.0. in this case, it's 9373 patterns!
3. insert version tags
we are now ready to insert the version tag to these patterns.
before updating thousands of patterns, it's probably a good idea to test if a single one gets udpated:
```sql
UPDATE code_v1
SET code = code || E'\n// @version 1.1'
WHERE hash = 'Ns2sMB40yIw4';
```
after [verifying](https://strudel.cc/?Ns2sMB40yIw4) that the version tag has been added, let's insert it everywhere:
```sql
UPDATE code_v1
SET code = code || E'\n// @version 1.1'
WHERE code NOT LIKE '%@version%'
AND created_at > '2024-05-31T23:07:26+02:00'
AND created_at < '2025-05-01T12:39:24+02:00'
```
4. verify
we can verify that the edits worked by querying all patterns that contain the new version tag:
```sql
SELECT *
FROM code_v1
WHERE code LIKE '%@version 1.1%'
AND created_at > '2024-05-31T23:07:26+02:00'
AND created_at < '2025-05-01T12:39:24+02:00'
ORDER BY created_at ASC;
```
## Have Fun
Remember to have fun, and that this project is driven by the passion of volunteers!
+2 -8
View File
@@ -32,19 +32,13 @@ This project is organized into many [packages](./packages), which are also avail
Read more about how to use these in your own project [here](https://strudel.cc/technical-manual/project-start).
You will need to abide by the terms of the [GNU Affero Public Licence v3](LICENSE.md). As such, Strudel code can only be shared within free/open source projects under the same license -- see the license for details.
You will need to abide by the terms of the [GNU Affero Public Licence v3](LICENSE). As such, Strudel code can only be shared within free/open source projects under the same license -- see the license for details.
Licensing info for the default sound banks can be found over on the [dough-samples](https://github.com/felixroos/dough-samples/blob/main/README.md) repository.
## Contributing
There are many ways to contribute to this project! See [contribution guide](./CONTRIBUTING.md).
<a href="https://codeberg.org/uzu/strudel/activity/contributors">
<img src="https://contrib.rocks/image?repo=tidalcycles/strudel" />
</a>
Made with [contrib.rocks](https://contrib.rocks).
There are many ways to contribute to this project! See [contribution guide](./CONTRIBUTING.md). You can find the full list of contributors [here](https://codeberg.org/uzu/strudel/activity/contributors).
## Community
+11 -1
View File
@@ -1,7 +1,7 @@
import { closeBrackets } from '@codemirror/autocomplete';
export { toggleComment, toggleBlockComment, toggleLineComment, toggleBlockCommentByLine } from '@codemirror/commands';
// import { search, highlightSelectionMatches } from '@codemirror/search';
import { history } from '@codemirror/commands';
import { history, indentWithTab } from '@codemirror/commands';
import { javascript } from '@codemirror/lang-javascript';
import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from '@codemirror/language';
import { Compartment, EditorState, Prec } from '@codemirror/state';
@@ -37,6 +37,14 @@ const extensions = {
isActiveLineHighlighted: (on) => (on ? [highlightActiveLine(), highlightActiveLineGutter()] : []),
isFlashEnabled,
keybindings,
isTabIndentationEnabled: (on) => (on ? keymap.of([indentWithTab]) : []),
isMultiCursorEnabled: (on) =>
on
? [
EditorState.allowMultipleSelections.of(true),
EditorView.clickAddsSelectionRange.of((ev) => ev.metaKey || ev.ctrlKey),
]
: [],
};
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
@@ -51,6 +59,8 @@ export const defaultSettings = {
isFlashEnabled: true,
isTooltipEnabled: false,
isLineWrappingEnabled: false,
isTabIndentationEnabled: false,
isMultiCursorEnabled: false,
theme: 'strudelTheme',
fontFamily: 'monospace',
fontSize: 18,
+2 -2
View File
@@ -21,11 +21,11 @@ const vscodeExtension = (options) => [vscodePlugin].concat(options ?? []);
const keymaps = {
vim,
emacs,
codemirror: () => keymap.of(defaultKeymap),
vscode: vscodeExtension,
};
export function keybindings(name) {
const active = keymaps[name];
return [keymap.of(defaultKeymap), keymap.of(historyKeymap), active ? active() : []];
// keymap.of(searchKeymap),
return [active ? active() : [], keymap.of(historyKeymap)];
}
+17 -1
View File
@@ -985,15 +985,31 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback',
*
*/
export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt', 'dt');
/* // TODO: test
/**
* Sets the time of the delay effect in cycles.
*
* @name delaysync
* @param {number | Pattern} cycles delay length in cycles
* @synonyms delayt, dt
* @example
* s("bd bd").delay(.25).delaysync("<1 2 3 5>".div(8))
*
*/
export const { delaysync } = registerControl('delaysync');
/**
* Specifies whether delaytime is calculated relative to cps.
*
* @name lock
* @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
* @superdirtOnly
* @example
* s("sd").delay().lock(1).osc()
*
*
*/
export const { lock } = registerControl('lock');
/**
* Set detune for stacked voices of supported oscillators
+1
View File
@@ -67,6 +67,7 @@ export class Cyclist {
// the following line is dumb and only here for backwards compatibility
// see https://codeberg.org/uzu/strudel/pulls/1004
const deadline = targetTime - phase;
// this onTrigger has another signature
onTrigger?.(hap, deadline, duration, this.cps, targetTime);
if (hap.value.cps !== undefined && this.cps != hap.value.cps) {
this.cps = hap.value.cps;
+57 -1
View File
@@ -869,6 +869,31 @@ export class Pattern {
console.log(drawLine(this));
return this;
}
//////////////////////////////////////////////////////////////////////
// methods relating to breaking patterns into subcycles
// Breaks a pattern into a pattern of patterns, according to the structure of the given binary pattern.
unjoin(pieces, func = id) {
return pieces.withHap((hap) =>
hap.withValue((v) => (v ? func(this.ribbon(hap.whole.begin, hap.whole.duration)) : this)),
);
}
/**
* Breaks a pattern into pieces according to the structure of a given pattern.
* True values in the given pattern cause the corresponding subcycle of the
* source pattern to be looped, and for an (optional) given function to be
* applied. False values result in the corresponding part of the source pattern
* to be played unchanged.
* @name into
* @memberof Pattern
* @example
* sound("bd sd ht lt").into("1 0", hurry(2))
*/
into(pieces, func) {
return this.unjoin(pieces, func).innerJoin();
}
}
//////////////////////////////////////////////////////////////////////
@@ -2494,6 +2519,37 @@ export const { fastchunk, fastChunk } = register(
true,
);
/**
* Like `chunk`, but the function is applied to a looped subcycle of the source pattern.
* @name chunkInto
* @synonym chunkinto
* @memberof Pattern
* @example
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
* .bank("tr909")
*/
export const { chunkinto, chunkInto } = register(['chunkinto', 'chunkInto'], function (n, func, pat) {
return pat.into(fastcat(true, ...Array(n - 1).fill(false))._iterback(n), func);
});
/**
* Like `chunkInto`, but moves backwards through the chunks.
* @name chunkBackInto
* @synonym chunkbackinto
* @memberof Pattern
* @example
* sound("bd sd ht lt bd - cp lt").chunkInto(4, hurry(2))
* .bank("tr909")
*/
export const { chunkbackinto, chunkBackInto } = register(['chunkbackinto', 'chunkBackInto'], function (n, func, pat) {
return pat.into(
fastcat(true, ...Array(n - 1).fill(false))
._iter(n)
._early(1),
func,
);
});
// TODO - redefine elsewhere in terms of mask
export const bypass = register(
'bypass',
@@ -3207,7 +3263,7 @@ export const slice = register(
* s("bd!8").onTriggerTime((hap) => {console.info(hap)})
*/
Pattern.prototype.onTriggerTime = function (func) {
return this.onTrigger((t_deprecate, hap, currentTime, cps = 1, targetTime) => {
return this.onTrigger((hap, currentTime, _cps, targetTime) => {
const diff = targetTime - currentTime;
window.setTimeout(() => {
func(hap);
+9 -4
View File
@@ -114,8 +114,9 @@ export function repl({
* all(x => x.pianoroll())
* ```
*/
let allTransforms = [];
const all = function (transform) {
allTransform = transform;
allTransforms.push(transform);
return silence;
};
/** Applies a function to each of the running patterns separately. This is intended for future use with upcoming 'stepwise' features. See `all` for a version that applies the function to all the patterns stacked together into a single pattern.
@@ -191,6 +192,7 @@ export function repl({
await injectPatternMethods();
setTime(() => scheduler.now()); // TODO: refactor?
await beforeEval?.({ code });
allTransforms = []; // reset all transforms
shouldHush && hush();
if (mondo) {
@@ -207,8 +209,10 @@ export function repl({
} else if (eachTransform) {
pattern = eachTransform(pattern);
}
if (allTransform) {
pattern = allTransform(pattern);
if (allTransforms.length) {
for (let i in allTransforms) {
pattern = allTransforms[i](pattern);
}
}
if (!isPattern(pattern)) {
const message = `got "${typeof evaluated}" instead of pattern`;
@@ -241,6 +245,7 @@ export function repl({
export const getTrigger =
({ getTime, defaultOutput }) =>
async (hap, deadline, duration, cps, t) => {
// ^ this signature is different from hap.context.onTrigger, as set by Pattern.onTrigger(onTrigger)
// TODO: get rid of deadline after https://codeberg.org/uzu/strudel/pulls/1004
try {
if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
@@ -248,7 +253,7 @@ export const getTrigger =
}
if (hap.context.onTrigger) {
// call signature of output / onTrigger is different...
await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps, t);
await hap.context.onTrigger(hap, getTime(), cps, t);
}
} catch (err) {
logger(`[cyclist] error: ${err.message}`, 'error');
+1 -1
View File
@@ -264,7 +264,7 @@ export const randrun = (n) => {
const rands = timeToRands(t.floor().add(0.5), n);
const nums = rands
.map((n, i) => [n, i])
.sort((a, b) => a[0] > b[0] - a[0] < b[0])
.sort((a, b) => (a[0] > b[0]) - (a[0] < b[0]))
.map((x) => x[1]);
const i = t.cyclePos().mul(n).floor() % n;
return nums[i];
+1 -1
View File
@@ -32,7 +32,7 @@ function triggerSpeech(words, lang, voice) {
}
export const speak = register('speak', function (lang, voice, pat) {
return pat.onTrigger((_, hap) => {
return pat.onTrigger((hap) => {
triggerSpeech(hap.value, lang, voice);
});
});
+35
View File
@@ -1271,4 +1271,39 @@ describe('Pattern', () => {
);
});
});
describe('unjoin', () => {
it('destructures a pattern into subcycles', () => {
sameFirst(
fastcat('a', 'b', 'c', 'd')
.unjoin(fastcat(true, fastcat(true, true)))
.fmap(fast(2))
.join(),
fastcat('a', 'b', 'a', 'b', 'c', 'c', 'd', 'd'),
);
});
});
describe('into', () => {
it('applies a function to subcycles of a pattern', () => {
sameFirst(
fastcat('a', 'b', 'c', 'd').into(fastcat(fastcat('true', 'true'), 'true'), fast(2)),
fastcat('a', 'a', 'b', 'b', 'c', 'd', 'c', 'd'),
);
});
});
describe('chunkinto', () => {
it('chunks into subcycles', () => {
sameFirst(
fastcat('a', 'b', 'c').chunkInto(3, fast(2)).fast(3),
fastcat(fastcat('a', 'a'), 'b', 'c', 'a', fastcat('b', 'b'), 'c', 'a', 'b', fastcat('c', 'c')),
);
});
});
describe('chunkbackinto', () => {
it('chunks into subcycles backwards', () => {
sameFirst(
fastcat('a', 'b', 'c').chunkBackInto(3, fast(2)).fast(3),
fastcat('a', 'b', fastcat('c', 'c'), 'a', fastcat('b', 'b'), 'c', fastcat('a', 'a'), 'b', 'c'),
);
});
});
});
+3 -3
View File
@@ -23,7 +23,7 @@ export const csound = register('csound', (instrument, pat) => {
instrument = instrument || 'triangle';
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
// TODO: find a alternative way to wait for csound to load (to wait with first time playback)
return pat.onTrigger((time_deprecate, hap, currentTime, _cps, targetTime) => {
return pat.onTrigger((hap, currentTime, _cps, targetTime) => {
if (!_csound) {
logger('[csound] not loaded yet', 'warning');
return;
@@ -142,7 +142,7 @@ export const csoundm = register('csoundm', (instrument, pat) => {
p1 = `"${instrument}"`;
}
init(); // not async to support csound inside other patterns + to be able to call pattern methods after it
return pat.onTrigger((tidal_time, hap) => {
return pat.onTrigger((hap, currentTime, _cps, targetTime) => {
if (!_csound) {
logger('[csound] not loaded yet', 'warning');
return;
@@ -151,7 +151,7 @@ export const csoundm = register('csoundm', (instrument, pat) => {
throw new Error('csound only support objects as hap values');
}
// Time in seconds counting from now.
const p2 = tidal_time - getAudioContext().currentTime;
const p2 = targetTime - currentTime;
const p3 = hap.duration.valueOf() + 0;
const frequency = getFrequency(hap);
let { gain = 1, velocity = 0.9 } = hap.value;
+1 -1
View File
@@ -6,7 +6,7 @@ const OFF_MESSAGE = 0x80;
const CC_MESSAGE = 0xb0;
Pattern.prototype.midi = function (output) {
return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => {
return this.onTrigger((hap, currentTime, cps, targetTime) => {
let { note, nrpnn, nrpv, ccn, ccv, velocity = 0.9, gain = 1 } = hap.value;
//magic number to get audio engine to line up, can probably be calculated somehow
const latencyMs = 34;
+1 -1
View File
@@ -4,7 +4,7 @@ import { Invoke } from './utils.mjs';
const collator = new ClockCollator({});
export async function oscTriggerTauri(t_deprecate, hap, currentTime, cps = 1, targetTime) {
export async function oscTriggerTauri(hap, currentTime, cps = 1, targetTime) {
const controls = parseControlsFromHap(hap, cps);
const params = [];
const timestamp = collator.calculateTimestamp(currentTime, targetTime);
+1 -1
View File
@@ -333,7 +333,7 @@ Pattern.prototype.midi = function (midiport, options = {}) {
logger(`Midi device disconnected! Available: ${getMidiDeviceNamesString(outputs)}`),
});
return this.onTrigger((time_deprecate, hap, currentTime, cps, targetTime) => {
return this.onTrigger((hap, currentTime, cps, targetTime) => {
if (!WebMidi.enabled) {
logger('Midi not enabled');
return;
+1
View File
@@ -42,6 +42,7 @@ lib['%'] = pace;
lib['?'] = degradeBy; // todo: default 0.5 not working..
lib[':'] = tail;
lib['..'] = range;
lib['def'] = () => silence;
lib['or'] = (...children) => chooseIn(...children); // always has structure but is cyclewise.. e.g. "s oh*8.dec[.04 | .5]"
//lib['or'] = (...children) => chooseOut(...children); // "s oh*8.dec[.04 | .5]" is better but "dec[.04 | .5].s oh*8" has no struct
+1 -1
View File
@@ -60,7 +60,7 @@ export function parseControlsFromHap(hap, cps) {
const collator = new ClockCollator({});
export async function oscTrigger(t_deprecate, hap, currentTime, cps = 1, targetTime) {
export async function oscTrigger(hap, currentTime, cps = 1, targetTime) {
const osc = await connect();
const controls = parseControlsFromHap(hap, cps);
const keyvals = Object.entries(controls).flat();
+1 -1
View File
@@ -537,7 +537,7 @@ export default {
],
gm_synth_bass_1: [
// Synth Bass 1: Bass
'0380_Aspirin_sf2_file',
// '0380_Aspirin_sf2_file', // broken in safari https://codeberg.org/uzu/strudel/issues/1384
'0380_Chaos_sf2_file',
'0380_FluidR3_GM_sf2_file',
// 0380_GeneralUserGS_sf2_file // laut
+1 -1
View File
@@ -3,7 +3,7 @@ import { getAudioContext, registerSound } from '@strudel/webaudio';
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';
Pattern.prototype.soundfont = function (sf, n = 0) {
return this.onTrigger((time_deprecate, h, ct, cps, targetTime) => {
return this.onTrigger((h, ct, cps, targetTime) => {
const ctx = getAudioContext();
const note = getPlayableNoteValue(h);
const preset = sf.presets[n % sf.presets.length];
+1 -1
View File
@@ -74,6 +74,6 @@ export const dough = async (code) => {
worklet.node.connect(ac.destination);
};
export function doughTrigger(time_deprecate, hap, currentTime, cps, targetTime) {
export function doughTrigger(hap, currentTime, cps, targetTime) {
window.postMessage({ time: targetTime, dough: hap.value, currentTime, duration: hap.duration, cps });
}
+22 -8
View File
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
import './feedbackdelay.mjs';
import './reverb.mjs';
import './vowel.mjs';
import { clamp, nanFallback, _mod } from './util.mjs';
import { clamp, nanFallback, _mod, cycleToSeconds } from './util.mjs';
import workletsUrl from './worklets.mjs?audioworklet';
import { createFilter, gainNode, getCompressor, getWorklet } from './helpers.mjs';
import { map } from 'nanostores';
@@ -126,7 +126,7 @@ export const getAudioDevices = async () => {
return devicesMap;
};
const defaultDefaultValues = {
let defaultDefaultValues = {
s: 'triangle',
gain: 0.8,
postgain: 1,
@@ -143,13 +143,24 @@ const defaultDefaultValues = {
delay: 0,
byteBeatExpression: '0',
delayfeedback: 0.5,
delaytime: 0.25,
delaysync: 3 / 16,
orbit: 1,
i: 1,
velocity: 1,
fft: 8,
};
const defaultDefaultDefaultValues = Object.freeze({ ...defaultDefaultValues });
export function setDefault(control, value) {
// const main = getControlName(control); // we cant do this because superdough is independent of strudel/core
defaultDefaultValues[control] = value;
}
export function resetDefaults() {
defaultDefaultValues = { ...defaultDefaultDefaultValues };
}
let defaultControls = new Map(Object.entries(defaultDefaultValues));
export function setDefaultValue(key, value) {
@@ -450,9 +461,9 @@ function mapChannelNumbers(channels) {
return (Array.isArray(channels) ? channels : [channels]).map((ch) => ch - 1);
}
export const superdough = async (value, t, hapDuration, cps) => {
export const superdough = async (value, t, hapDuration, cps = 0.5) => {
// new: t is always expected to be the absolute target onset time
const ac = getAudioContext();
t = typeof t === 'string' && t.startsWith('=') ? Number(t.slice(1)) : ac.currentTime + t;
let { stretch } = value;
if (stretch != null) {
//account for phase vocoder latency
@@ -528,7 +539,8 @@ export const superdough = async (value, t, hapDuration, cps) => {
vowel,
delay = getDefaultValue('delay'),
delayfeedback = getDefaultValue('delayfeedback'),
delaytime = getDefaultValue('delaytime'),
delaysync = getDefaultValue('delaysync'),
delaytime,
orbit = getDefaultValue('orbit'),
room,
roomfade,
@@ -547,6 +559,8 @@ export const superdough = async (value, t, hapDuration, cps) => {
compressorRelease,
} = value;
delaytime = delaytime ?? cycleToSeconds(delaysync, cps);
const orbitChannels = mapChannelNumbers(
multiChannelOrbits && orbit > 0 ? [orbit * 2 - 1, orbit * 2] : getDefaultValue('channels'),
);
@@ -725,8 +739,8 @@ export const superdough = async (value, t, hapDuration, cps) => {
// delay
let delaySend;
if (delay > 0 && delaytime > 0 && delayfeedback > 0) {
const delyNode = getDelay(orbit, delaytime, delayfeedback, t, orbitChannels);
delaySend = effectSend(post, delyNode, delay);
const delayNode = getDelay(orbit, delaytime, delayfeedback, t, orbitChannels);
delaySend = effectSend(post, delayNode, delay);
audioNodes.push(delaySend);
}
// reverb
+5 -2
View File
@@ -121,7 +121,10 @@ export function registerSynthSounds() {
const gainAdjustment = 1 / Math.sqrt(voices);
getPitchEnvelope(o.parameters.get('detune'), value, begin, holdend);
const vibratoOscillator = getVibratoOscillator(o.parameters.get('detune'), value, begin);
const fm = applyFM(o.parameters.get('frequency'), value, begin);
// const fm = applyFM(o.parameters.get('frequency'), value, begin);
// https://codeberg.org/uzu/strudel/issues/1428
// if you think about re-enabling this, please test with fm > 1 first
// it's like 10x gain, so it's really dangerous
let envGain = gainNode(1);
envGain = o.connect(envGain);
@@ -133,7 +136,7 @@ export function registerSynthSounds() {
destroyAudioWorkletNode(o);
envGain.disconnect();
onended();
fm?.stop();
// fm?.stop();
vibratoOscillator?.stop();
},
begin,
+4
View File
@@ -68,3 +68,7 @@ export const _mod = (n, m) => ((n % m) + m) % m;
export const getSoundIndex = (n, numSounds) => {
return _mod(Math.round(nanFallback(n, 0)), numSounds);
};
export function cycleToSeconds(cycle, cps) {
return cycle / cps;
}
+7
View File
@@ -37,6 +37,13 @@ describe('tonal', () => {
.firstCycleValues.map((h) => h.note),
).toEqual(['C3', 'D3', 'E3']);
});
it('scale without tonic', () => {
expect(
n(seq(0, 1, 2))
.scale('major')
.firstCycleValues.map((h) => h.note),
).toEqual(['C3', 'D3', 'E3']);
});
it('scale with mininotation colon', () => {
expect(
n(seq(0, 1, 2))
+1 -1
View File
@@ -14,7 +14,7 @@ function scaleStep(step, scale) {
scale = scale.replaceAll(':', ' ');
step = Math.ceil(step);
let { intervals, tonic, empty } = Scale.get(scale);
if ((empty && isNote(scale)) || (!empty && !tonic)) {
if ((empty && isNote(scale)) || (empty && !tonic)) {
throw new Error(`incomplete scale. Make sure to use ":" instead of spaces, example: .scale("C:major")`);
} else if (empty) {
throw new Error(`invalid scale "${scale}"`);
+4 -7
View File
@@ -15,13 +15,10 @@ const hap2value = (hap) => {
return hap.value;
};
export const webaudioOutputTrigger = (t, hap, ct, cps) => superdough(hap2value(hap), t - ct, hap.duration / cps, cps);
// uses more precise, absolute t if available, see https://codeberg.org/uzu/strudel/pulls/1004
export const webaudioOutput = (hap, deadline, hapDuration, cps, t) =>
superdough(hap2value(hap), t ? `=${t}` : deadline, hapDuration);
Pattern.prototype.webaudio = function () {
return this.onTrigger(webaudioOutputTrigger);
// uses more precise, absolute t if available, see https://github.com/tidalcycles/strudel/pull/1004
// TODO: refactor output callbacks to eliminate deadline
export const webaudioOutput = (hap, deadline, hapDuration, cps, t) => {
return superdough(hap2value(hap), t, hapDuration, cps);
};
export function webaudioRepl(options = {}) {
+155 -24
View File
@@ -1889,6 +1889,86 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
]
`;
exports[`runs examples > example "chunkBackInto" example index 0 1`] = `
[
"[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]",
"[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]",
"[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]",
"[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]",
"[ 1/4 → 3/8 | s:ht bank:tr909 ]",
"[ 3/8 → 1/2 | s:lt bank:tr909 ]",
"[ 1/2 → 5/8 | s:bd bank:tr909 ]",
"[ 3/4 → 7/8 | s:cp bank:tr909 ]",
"[ 7/8 → 1/1 | s:lt bank:tr909 ]",
"[ 1/1 → 9/8 | s:bd bank:tr909 ]",
"[ 9/8 → 5/4 | s:sd bank:tr909 ]",
"[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]",
"[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]",
"[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]",
"[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]",
"[ 3/2 → 13/8 | s:bd bank:tr909 ]",
"[ 7/4 → 15/8 | s:cp bank:tr909 ]",
"[ 15/8 → 2/1 | s:lt bank:tr909 ]",
"[ 2/1 → 17/8 | s:bd bank:tr909 ]",
"[ 17/8 → 9/4 | s:sd bank:tr909 ]",
"[ 9/4 → 19/8 | s:ht bank:tr909 ]",
"[ 19/8 → 5/2 | s:lt bank:tr909 ]",
"[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]",
"[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]",
"[ 11/4 → 23/8 | s:cp bank:tr909 ]",
"[ 23/8 → 3/1 | s:lt bank:tr909 ]",
"[ 3/1 → 25/8 | s:bd bank:tr909 ]",
"[ 25/8 → 13/4 | s:sd bank:tr909 ]",
"[ 13/4 → 27/8 | s:ht bank:tr909 ]",
"[ 27/8 → 7/2 | s:lt bank:tr909 ]",
"[ 7/2 → 29/8 | s:bd bank:tr909 ]",
"[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]",
"[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]",
"[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]",
"[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]",
]
`;
exports[`runs examples > example "chunkInto" example index 0 1`] = `
[
"[ 0/1 → 1/16 | s:bd speed:2 bank:tr909 ]",
"[ 1/16 → 1/8 | s:sd speed:2 bank:tr909 ]",
"[ 1/8 → 3/16 | s:bd speed:2 bank:tr909 ]",
"[ 3/16 → 1/4 | s:sd speed:2 bank:tr909 ]",
"[ 1/4 → 3/8 | s:ht bank:tr909 ]",
"[ 3/8 → 1/2 | s:lt bank:tr909 ]",
"[ 1/2 → 5/8 | s:bd bank:tr909 ]",
"[ 3/4 → 7/8 | s:cp bank:tr909 ]",
"[ 7/8 → 1/1 | s:lt bank:tr909 ]",
"[ 1/1 → 9/8 | s:bd bank:tr909 ]",
"[ 9/8 → 5/4 | s:sd bank:tr909 ]",
"[ 5/4 → 21/16 | s:ht speed:2 bank:tr909 ]",
"[ 21/16 → 11/8 | s:lt speed:2 bank:tr909 ]",
"[ 11/8 → 23/16 | s:ht speed:2 bank:tr909 ]",
"[ 23/16 → 3/2 | s:lt speed:2 bank:tr909 ]",
"[ 3/2 → 13/8 | s:bd bank:tr909 ]",
"[ 7/4 → 15/8 | s:cp bank:tr909 ]",
"[ 15/8 → 2/1 | s:lt bank:tr909 ]",
"[ 2/1 → 17/8 | s:bd bank:tr909 ]",
"[ 17/8 → 9/4 | s:sd bank:tr909 ]",
"[ 9/4 → 19/8 | s:ht bank:tr909 ]",
"[ 19/8 → 5/2 | s:lt bank:tr909 ]",
"[ 5/2 → 41/16 | s:bd speed:2 bank:tr909 ]",
"[ 21/8 → 43/16 | s:bd speed:2 bank:tr909 ]",
"[ 11/4 → 23/8 | s:cp bank:tr909 ]",
"[ 23/8 → 3/1 | s:lt bank:tr909 ]",
"[ 3/1 → 25/8 | s:bd bank:tr909 ]",
"[ 25/8 → 13/4 | s:sd bank:tr909 ]",
"[ 13/4 → 27/8 | s:ht bank:tr909 ]",
"[ 27/8 → 7/2 | s:lt bank:tr909 ]",
"[ 7/2 → 29/8 | s:bd bank:tr909 ]",
"[ 15/4 → 61/16 | s:cp speed:2 bank:tr909 ]",
"[ 61/16 → 31/8 | s:lt speed:2 bank:tr909 ]",
"[ 31/8 → 63/16 | s:cp speed:2 bank:tr909 ]",
"[ 63/16 → 4/1 | s:lt speed:2 bank:tr909 ]",
]
`;
exports[`runs examples > example "clip" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]",
@@ -2505,6 +2585,19 @@ exports[`runs examples > example "delayfeedback" example index 0 1`] = `
]
`;
exports[`runs examples > example "delaysync" example index 0 1`] = `
[
"[ 0/1 → 1/2 | s:bd delay:0.25 delaysync:0.125 ]",
"[ 1/2 → 1/1 | s:bd delay:0.25 delaysync:0.125 ]",
"[ 1/1 → 3/2 | s:bd delay:0.25 delaysync:0.25 ]",
"[ 3/2 → 2/1 | s:bd delay:0.25 delaysync:0.25 ]",
"[ 2/1 → 5/2 | s:bd delay:0.25 delaysync:0.375 ]",
"[ 5/2 → 3/1 | s:bd delay:0.25 delaysync:0.375 ]",
"[ 3/1 → 7/2 | s:bd delay:0.25 delaysync:0.625 ]",
"[ 7/2 → 4/1 | s:bd delay:0.25 delaysync:0.625 ]",
]
`;
exports[`runs examples > example "delaytime" example index 0 1`] = `
[
"[ 0/1 → 1/2 | s:bd delay:0.25 delaytime:0.125 ]",
@@ -4391,6 +4484,35 @@ exports[`runs examples > example "inside" example index 0 1`] = `
]
`;
exports[`runs examples > example "into" example index 0 1`] = `
[
"[ 0/1 → 1/8 | s:bd speed:2 ]",
"[ 1/8 → 1/4 | s:sd speed:2 ]",
"[ 1/4 → 3/8 | s:bd speed:2 ]",
"[ 3/8 → 1/2 | s:sd speed:2 ]",
"[ 1/2 → 3/4 | s:ht ]",
"[ 3/4 → 1/1 | s:lt ]",
"[ 1/1 → 9/8 | s:bd speed:2 ]",
"[ 9/8 → 5/4 | s:sd speed:2 ]",
"[ 5/4 → 11/8 | s:bd speed:2 ]",
"[ 11/8 → 3/2 | s:sd speed:2 ]",
"[ 3/2 → 7/4 | s:ht ]",
"[ 7/4 → 2/1 | s:lt ]",
"[ 2/1 → 17/8 | s:bd speed:2 ]",
"[ 17/8 → 9/4 | s:sd speed:2 ]",
"[ 9/4 → 19/8 | s:bd speed:2 ]",
"[ 19/8 → 5/2 | s:sd speed:2 ]",
"[ 5/2 → 11/4 | s:ht ]",
"[ 11/4 → 3/1 | s:lt ]",
"[ 3/1 → 25/8 | s:bd speed:2 ]",
"[ 25/8 → 13/4 | s:sd speed:2 ]",
"[ 13/4 → 27/8 | s:bd speed:2 ]",
"[ 27/8 → 7/2 | s:sd speed:2 ]",
"[ 7/2 → 15/4 | s:ht ]",
"[ 15/4 → 4/1 | s:lt ]",
]
`;
exports[`runs examples > example "invert" example index 0 1`] = `
[
"[ 0/1 → 1/8 | s:bd ]",
@@ -5016,6 +5138,15 @@ exports[`runs examples > example "linger" example index 0 1`] = `
]
`;
exports[`runs examples > example "lock" example index 0 1`] = `
[
"[ 0/1 → 1/1 | delay:{s:sd} lock:1 ]",
"[ 1/1 → 2/1 | delay:{s:sd} lock:1 ]",
"[ 2/1 → 3/1 | delay:{s:sd} lock:1 ]",
"[ 3/1 → 4/1 | delay:{s:sd} lock:1 ]",
]
`;
exports[`runs examples > example "loop" example index 0 1`] = `
[
"[ 0/1 → 1/1 | s:casio loop:1 ]",
@@ -8682,46 +8813,46 @@ exports[`runs examples > example "shrink" example index 3 1`] = `
exports[`runs examples > example "shuffle" example index 0 1`] = `
[
"[ 0/1 → 1/4 | note:c s:piano ]",
"[ 0/1 → 1/4 | note:e s:piano ]",
"[ 1/4 → 1/2 | note:d s:piano ]",
"[ 1/2 → 3/4 | note:e s:piano ]",
"[ 3/4 → 1/1 | note:f s:piano ]",
"[ 1/1 → 5/4 | note:c s:piano ]",
"[ 5/4 → 3/2 | note:d s:piano ]",
"[ 3/2 → 7/4 | note:e s:piano ]",
"[ 7/4 → 2/1 | note:f s:piano ]",
"[ 2/1 → 9/4 | note:c s:piano ]",
"[ 9/4 → 5/2 | note:d s:piano ]",
"[ 1/2 → 3/4 | note:f s:piano ]",
"[ 3/4 → 1/1 | note:c s:piano ]",
"[ 1/1 → 5/4 | note:e s:piano ]",
"[ 5/4 → 3/2 | note:c s:piano ]",
"[ 3/2 → 7/4 | note:f s:piano ]",
"[ 7/4 → 2/1 | note:d s:piano ]",
"[ 2/1 → 9/4 | note:d s:piano ]",
"[ 9/4 → 5/2 | note:c s:piano ]",
"[ 5/2 → 11/4 | note:e s:piano ]",
"[ 11/4 → 3/1 | note:f s:piano ]",
"[ 3/1 → 13/4 | note:c s:piano ]",
"[ 13/4 → 7/2 | note:d s:piano ]",
"[ 7/2 → 15/4 | note:e s:piano ]",
"[ 15/4 → 4/1 | note:f s:piano ]",
"[ 13/4 → 7/2 | note:e s:piano ]",
"[ 7/2 → 15/4 | note:f s:piano ]",
"[ 15/4 → 4/1 | note:d s:piano ]",
]
`;
exports[`runs examples > example "shuffle" example index 1 1`] = `
[
"[ 0/1 → 1/8 | note:c s:piano ]",
"[ 0/1 → 1/8 | note:e s:piano ]",
"[ 1/8 → 1/4 | note:d s:piano ]",
"[ 1/4 → 3/8 | note:e s:piano ]",
"[ 3/8 → 1/2 | note:f s:piano ]",
"[ 1/4 → 3/8 | note:f s:piano ]",
"[ 3/8 → 1/2 | note:c s:piano ]",
"[ 1/2 → 1/1 | note:g s:piano ]",
"[ 1/1 → 9/8 | note:c s:piano ]",
"[ 9/8 → 5/4 | note:d s:piano ]",
"[ 5/4 → 11/8 | note:e s:piano ]",
"[ 11/8 → 3/2 | note:f s:piano ]",
"[ 1/1 → 9/8 | note:e s:piano ]",
"[ 9/8 → 5/4 | note:c s:piano ]",
"[ 5/4 → 11/8 | note:f s:piano ]",
"[ 11/8 → 3/2 | note:d s:piano ]",
"[ 3/2 → 2/1 | note:g s:piano ]",
"[ 2/1 → 17/8 | note:c s:piano ]",
"[ 17/8 → 9/4 | note:d s:piano ]",
"[ 2/1 → 17/8 | note:d s:piano ]",
"[ 17/8 → 9/4 | note:c s:piano ]",
"[ 9/4 → 19/8 | note:e s:piano ]",
"[ 19/8 → 5/2 | note:f s:piano ]",
"[ 5/2 → 3/1 | note:g s:piano ]",
"[ 3/1 → 25/8 | note:c s:piano ]",
"[ 25/8 → 13/4 | note:d s:piano ]",
"[ 13/4 → 27/8 | note:e s:piano ]",
"[ 27/8 → 7/2 | note:f s:piano ]",
"[ 25/8 → 13/4 | note:e s:piano ]",
"[ 13/4 → 27/8 | note:f s:piano ]",
"[ 27/8 → 7/2 | note:d s:piano ]",
"[ 7/2 → 4/1 | note:g s:piano ]",
]
`;
-22
View File
@@ -359,28 +359,6 @@ stack(
"[~ [0 ~]] 0 [~ [4 ~]] 4".sub(7).restart(scales).scale(scales).early(.25)
).note().piano().slow(2)`;
/*
export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
freq("440(5,8)".clip(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext;
t = ac.currentTime + t - ct;
const { freq, s, gain = 1 } = hap.value;
const master = ac.createGain();
master.gain.value = 0.1 * gain;
master.connect(ac.destination);
const o = ac.createOscillator();
o.type = s || 'triangle';
o.frequency.value = Number(freq);
o.connect(master);
o.start(t);
o.stop(t + hap.duration);
}).stack(s("bd(3,8),hh*4,~ sd").webdirt())`; */
export const swimmingWithSoundfonts = `// Koji Kondo - Swimming (Super Mario World)
stack(
n(
-1
View File
@@ -647,7 +647,6 @@
"evaluate"
],
"/packages/webaudio/webaudio.mjs": [
"webaudioOutputTrigger",
"webaudioOutput",
"webaudioRepl"
],
@@ -0,0 +1,317 @@
---
title: 'Release Notes v1.1.0'
description: ''
date: '2024-06-02'
tags: ['meta']
author: froos
---
These are the release notes for Strudel 1.1.0 aka "Bananensplit".
The last release was over 19 weeks ago, so a lot of things have happened!
First, here's a little demo, teasing some of the new features:
import { Youtube } from '@src/components/Youtube';
<Youtube client:only="react" id="2Qu5lMHruio" />
Let's write up some of the highlights:
## New DSP Features
### Stereo Supersaw
with spread, unison, and detune parameters
```plaintext
note("d f a a# a d3").fast(2)
.s("supersaw").spread(".8").detune(.3).unison("2 7")
```
### Analog "ladder" filter type
works great for acid basslines and vibey tones
```plaintext
note("{d d d a a# d3 f4}%16".sub(12)).gain(1).s("sawtooth")
.lpf(200).lpenv(slider(1.36,0,8)).lpq(7).distort("1.5:.7")`
.ftype('ladder')
```
### stereo distortion effect
```plaintext
note("{g g a# g g4}%8".add("{0 7 12 0}%8")).lpf(500)
.s("supersaw").dist("4:.2")
```
## Editor Features
### inline viz
The editor now supports multiple visuals within the code, using the `_` prefix for viz functions:
<img
width="595"
alt="Screenshot 2024-06-01 at 01 23 51"
src="https://codeberg.org/uzu/strudel/assets/12023032/978fee85-e533-4da6-a245-d20d0083f57e"
/>
- `._pianoroll()`: inline pianoroll
- `._punchcard()`: inline punchcard
- `._scope()`: inline scope
- `._pitchwheel()`: inline pitchwheel
For more info, check out the new [Visual Feedback Page](https://strudel.cc/learn/visual-feedback/)
### label notation
This new notation simplifies writing patterns at the top level:
```plaintext
d1: s("bd*4")
d2: s("[- hh]*4")
```
This is equivalent to:
```plaintext
stack(
s("bd*4"),
s("[- hh]*4")
)
```
The labels you choose are arbitrary, the above `d1` and `d2` are a typical thing you'd write in tidal, for example `d1 $ s "bd*4"`.
If the same label is used multiple times, the last one wins:
```plaintext
d1: s("bd*4")
d1: s("[- hh]*4") // <-- only this plays
```
There is a special label anonymous label `$`, which can appear multiple times without overriding itself:
```plaintext
// both of these will play:
$: s("bd*4")
$: s("[- hh]*4")
```
You can mute a pattern by prefixing `_`:
```plaintext
_$: s("bd*4") // <-- this one is muted
$: s("[- hh]*4")
```
To run a transformation on all patterns, you can use `all`:
```plaintext
$: s("bd*4")
$: s("[- hh]*4")
all(x=>x.room(.5))
```
This notation is now the recommended way to [play patterns in parallel](https://strudel.cc/workshop/first-notes/#playing-multiple-patterns)
### Clock sync between multiple instances
timing has received a major overhaul, and is now much more accurate on all browsers. Additionally, you can now sync timing across multiple windows.
![Screenshot 2024-06-02 at 11 24 40PM](https://codeberg.org/uzu/strudel/assets/47068718/840be744-a13e-4d7b-ab09-50d3a70b1f85)
### Better sample upload support
you can now upload large amounts of samples much faster across all browsers including on IOS devices. supported filetypes now include: ogg flac mp3 wav aac m4a
### experimental tidal syntax
The new `tidal` function allows you to write strudel patterns in tidal syntax:
```plaintext
await initTidal()
tidal`
d1 $ s "bd*4"
d2 $ s "[- hh]*4"
`
```
As we're looking to improve compatibility with tidal, we're happy to hear feedback.
## breaking changes
This release comes with a bunch of breaking changes. If you find your patterns to sound different, check out the PRs below for guidance on how to update them. Most of these changes shouldn't affect a lot of patterns.
In case of doubt, add the line `// @version 1.0` to your old pattern.
If you're having problems, please let us know!
- remove legacy legato + duration implementations by @felixroos in https://codeberg.org/uzu/strudel/pull/965
- Velocity in value by @felixroos in https://codeberg.org/uzu/strudel/pull/974
- use ireal as default voicing dict by @felixroos https://codeberg.org/uzu/strudel/pull/967
- Color in hap value by @felixroos https://codeberg.org/uzu/strudel/pull/1007
- rename trig -> reset, trigzero -> restart by @felixroos https://codeberg.org/uzu/strudel/pull/1010
- remove dangerous arithmetic feature by @felixroos https://codeberg.org/uzu/strudel/pull/1030
- change fanchor to 0 by @daslyfe https://codeberg.org/uzu/strudel/pull/1107
## superdough features
- replace shape with distort in learn doc by @daslyfe https://codeberg.org/uzu/strudel/pull/982
- Worklet Improvents / fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/963
- supersaw oscillator by @daslyfe https://codeberg.org/uzu/strudel/pull/978
- Add analog-style ladder filter by @daslyfe https://codeberg.org/uzu/strudel/pull/1103
- Calculate phaser modulation phase based on time by @daslyfe https://codeberg.org/uzu/strudel/pull/1110
- rollback phaser by @daslyfe https://codeberg.org/uzu/strudel/pull/1113
## editor / ui features
- 'Enable Bracket Matching' option in Codemirror by @eefano https://codeberg.org/uzu/strudel/pull/956
- REPL sync between windows by @daslyfe https://codeberg.org/uzu/strudel/pull/900
- inline viz / widgets package by @felixroos https://codeberg.org/uzu/strudel/pull/989
- Inline punchcard + spiral by @felixroos https://codeberg.org/uzu/strudel/pull/1008
- More fonts by @felixroos https://codeberg.org/uzu/strudel/pull/1023
- better theme integration for visuals + various fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1024
- add setting for sync flag by @felixroos https://codeberg.org/uzu/strudel/pull/1025
- add closeBrackets setting by @felixroos https://codeberg.org/uzu/strudel/pull/1031
- add font file types to offline cache by @felixroos https://codeberg.org/uzu/strudel/pull/1032
- pitchwheel visual by @felixroos https://codeberg.org/uzu/strudel/pull/1041
- repl: set document.title from @title by @kasparsj https://codeberg.org/uzu/strudel/pull/1090
- Samples tab improvements by @daslyfe https://codeberg.org/uzu/strudel/pull/1102
## language features
- pickOut(), pickRestart(), pickReset() by @eefano https://codeberg.org/uzu/strudel/pull/950
- Auto await samples by @felixroos https://codeberg.org/uzu/strudel/pull/955
- feat: can now invert euclid pulses with negative numbers by @felixroos https://codeberg.org/uzu/strudel/pull/959
- Nested controls by @felixroos https://codeberg.org/uzu/strudel/pull/973
- alias - for ~ by @yaxu https://codeberg.org/uzu/strudel/pull/981
- Beat-oriented functionality by @yaxu https://codeberg.org/uzu/strudel/pull/976
- Labeled statements by @felixroos https://codeberg.org/uzu/strudel/pull/991
- accidentals in scale degrees by @eefano https://codeberg.org/uzu/strudel/pull/1000
- Feature: tactus marking by @yaxu https://codeberg.org/uzu/strudel/pull/1021
- Tactus tidy by @yaxu https://codeberg.org/uzu/strudel/pull/1027
- Wax, wane, taper and taperlist by @yaxu https://codeberg.org/uzu/strudel/pull/1042
- transpose: support all combinations of numbers and strings for notes and intervals by @felixroos https://codeberg.org/uzu/strudel/pull/1048
- anonymous patterns + muting by @felixroos https://codeberg.org/uzu/strudel/pull/1059
- add swing + swingBy by @felixroos https://codeberg.org/uzu/strudel/pull/1038
- Stepwise functions from Tidal by @yaxu https://codeberg.org/uzu/strudel/pull/1060
- Tactus tweaks - fixes for maintaining tactus and highlight locations by @yaxu https://codeberg.org/uzu/strudel/pull/1065
- Fix stepjoin by @yaxu https://codeberg.org/uzu/strudel/pull/1067
- More tactus tidying by @yaxu https://codeberg.org/uzu/strudel/pull/1071
- Tactus calculation toggle and breaking change to tactus calculation in fast/slow/hurry by @yaxu https://codeberg.org/uzu/strudel/pull/1081
- hs2js package / tidal parser by @felixroos https://codeberg.org/uzu/strudel/pull/870
- Add the mousex and mousey signal by @Enelg52 https://codeberg.org/uzu/strudel/pull/1112
- can now access strudelMirror from repl by @felixroos https://codeberg.org/uzu/strudel/pull/1117
## sampler
If you have nodejs installed on your system, you can now use [@strudel/sampler](https://www.npmjs.com/package/@strudel/sampler) to serve samples from disk to the REPL or flok.
- local sample server cli by @felixroos https://codeberg.org/uzu/strudel/pull/1033
- Fix sampler paths by @felixroos https://codeberg.org/uzu/strudel/pull/1034
- Fix sampler windows by @felixroos https://codeberg.org/uzu/strudel/pull/1108
- fix sampler on windows by @geikha https://codeberg.org/uzu/strudel/pull/1109
## docs
- V1 release notes by @felixroos https://codeberg.org/uzu/strudel/pull/935
- Minor documentation error: Update first-sounds.mdx by @mhetrick https://codeberg.org/uzu/strudel/pull/941
- Update synths.mdx by @andresgottlieb https://codeberg.org/uzu/strudel/pull/984
- using strudel in your project guide + cleanup examples by @felixroos https://codeberg.org/uzu/strudel/pull/1006
- Document signals by @ilesinge https://codeberg.org/uzu/strudel/pull/1015
- improve tutorial + custom samples doc by @felixroos https://codeberg.org/uzu/strudel/pull/1053
- fix cr typo on first-sounds.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1068
- fix first sounds typo by @cleary https://codeberg.org/uzu/strudel/pull/1069
- add `<...>` to first-sounds.mdx recap by @cleary https://codeberg.org/uzu/strudel/pull/1070
- add nesting to `off` example variation in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1075
- fix translation issue in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1072
- add signals to recap in first-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1073
- fix docs on alignment.mdx by @diegodorado https://codeberg.org/uzu/strudel/pull/1076
- fix little dub tune example by @lukad https://codeberg.org/uzu/strudel/pull/1104
- clarify `off` in pattern-effects.mdx by @cleary https://codeberg.org/uzu/strudel/pull/1074
- Fixes drawPianoroll import in codemirror example by @giohappy https://codeberg.org/uzu/strudel/pull/1116
- Migrate tutorial fanchor by @felixroos https://codeberg.org/uzu/strudel/pull/1122
## internals
- remove cjs builds by @felixroos https://codeberg.org/uzu/strudel/pull/945
- controls refactoring: simplify exports by @felixroos https://codeberg.org/uzu/strudel/pull/962
- move canvas related helpers from core to new draw package by @felixroos https://codeberg.org/uzu/strudel/pull/971
- remove canvas, externalize samples, delete junk by @felixroos https://codeberg.org/uzu/strudel/pull/1003
- Improve performance of ! (replicate) by @yaxu https://codeberg.org/uzu/strudel/pull/1084
- Benchmarks by @yaxu https://codeberg.org/uzu/strudel/pull/1079
## fixes
- fix midi issue on firefox and added quote error by @Enelg52 https://codeberg.org/uzu/strudel/pull/936
- fix: pianoroll sorting by @felixroos https://codeberg.org/uzu/strudel/pull/938
- account for cps in midi time duration by @daslyfe https://codeberg.org/uzu/strudel/pull/954
- fix script importable packages (web + repl) by @felixroos https://codeberg.org/uzu/strudel/pull/957
- fix: reset global fx on pattern change by @felixroos https://codeberg.org/uzu/strudel/pull/960
- add debounce to logger by @felixroos https://codeberg.org/uzu/strudel/pull/968
- fix for transpose(): preserve hap value object structure by @eefano https://codeberg.org/uzu/strudel/pull/966
- fix: clear hydra on reset by @felixroos https://codeberg.org/uzu/strudel/pull/983
- little fix for withVal by @eefano https://codeberg.org/uzu/strudel/pull/980
- fix: share now shares what's visible instead of active by @felixroos https://codeberg.org/uzu/strudel/pull/985
- Fix pure mini highlight by @yaxu https://codeberg.org/uzu/strudel/pull/994
- fix: await injectPatternMethods by @felixroos https://codeberg.org/uzu/strudel/pull/1012
- update undocumented script by @felixroos https://codeberg.org/uzu/strudel/pull/1013
- eliminate chromium clock jitter by @felixroos https://codeberg.org/uzu/strudel/pull/1004
- Repl sync fixes by @daslyfe https://codeberg.org/uzu/strudel/pull/1014
- hotfix for 1017 by @daslyfe https://codeberg.org/uzu/strudel/pull/1020
- fix cyclist fizzling out by @felixroos https://codeberg.org/uzu/strudel/pull/1046
- Midi Time hotfix for scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1047
- fix: do not reset cc input values on each eval by @felixroos https://codeberg.org/uzu/strudel/pull/1054
- Fix wchooseCycles not picking the whole pattern by @ilesinge https://codeberg.org/uzu/strudel/pull/1061
- fix OSC timing for recent scheduler updates by @daslyfe https://codeberg.org/uzu/strudel/pull/1062
- clarify license by @yaxu https://codeberg.org/uzu/strudel/pull/1064
- fix failing format test by @daslyfe https://codeberg.org/uzu/strudel/pull/1077
- fix: url parsing with extra params by @felixroos https://codeberg.org/uzu/strudel/pull/1083
- fix: csound + dough timing by @felixroos https://codeberg.org/uzu/strudel/pull/1086
- fix: missing events due to premature worklet cleanup by @felixroos https://codeberg.org/uzu/strudel/pull/1089
- Use sessionStorage for viewingPatternData and activePattern by @kasparsj https://codeberg.org/uzu/strudel/pull/1091
- osc: couple of fixes by @kasparsj https://codeberg.org/uzu/strudel/pull/1093
- web package fixes by @felixroos https://codeberg.org/uzu/strudel/pull/1044
- Fix audio worklets by @daslyfe https://codeberg.org/uzu/strudel/pull/1114
- fix: use full repl in web package by @felixroos https://codeberg.org/uzu/strudel/pull/1119
- [BUG FIX] Audio worklets sometimes dont load by @daslyfe https://codeberg.org/uzu/strudel/pull/1121
## New Contributors
- @mhetrick made their first contribution https://codeberg.org/uzu/strudel/pull/941
- @eefano made their first contribution https://codeberg.org/uzu/strudel/pull/956
- @Enelg52 made their first contribution https://codeberg.org/uzu/strudel/pull/936
- @andresgottlieb made their first contribution https://codeberg.org/uzu/strudel/pull/984
- @cleary made their first contribution https://codeberg.org/uzu/strudel/pull/1068
- @diegodorado made their first contribution https://codeberg.org/uzu/strudel/pull/1076
- @lukad made their first contribution https://codeberg.org/uzu/strudel/pull/1104
- @giohappy made their first contribution https://codeberg.org/uzu/strudel/pull/1116
A huge thanks to all contributors!!!
## Packages
- @strudel/codemirror@1.1.0
- @strudel/core@1.1.0
- @strudel/csound@1.1.0
- @strudel/draw@1.1.0
- @strudel/embed@1.1.0
- hs2js@0.1.0
- @strudel/hydra@1.1.0
- @strudel/midi@1.1.0
- @strudel/mini@1.1.0
- @strudel/osc@1.1.0
- @strudel/repl@1.1.0
- @strudel/sampler@0.1.0
- @strudel/serial@1.1.0
- @strudel/soundfonts@1.1.0
- superdough@1.1.0
- @strudel/tidal@0.1.0
- @strudel/tonal@1.1.0
- @strudel/transpiler@1.1.0
- @strudel/web@1.1.0
- @strudel/webaudio@1.1.0
- @strudel/xen@1.1.0
**Full Changelog**: https://codeberg.org/uzu/strudel/compare/v1.0.0...v1.1.0
@@ -0,0 +1,186 @@
---
title: 'Release Notes v1.2.0'
description: ''
date: '2025-05-01'
tags: ['meta']
author: froos
---
## What's Changed
## highlights
- [stepwise functions](https://strudel.cc/learn/stepwise/) ([PR](https://github.com/tidalcycles/strudel/pull/1262))
- [midimaps](https://strudel.cc/learn/input-output/#midimaps) ([PR](https://github.com/tidalcycles/strudel/pull/1274))
- [spectrum](https://strudel.cc/learn/visual-feedback/#spectrum) ([PR](https://github.com/tidalcycles/strudel/pull/1213))
- [mqtt](https://strudel.cc/learn/input-output/#mqtt) ([PR](https://github.com/tidalcycles/strudel/pull/1224))
- pulse oscillator (todo: https://github.com/tidalcycles/strudel/issues/1336) ([PR](https://github.com/tidalcycles/strudel/pull/1304))
- theme improvements
## breaking changes
- [breaking change] Sample signals from query onset, rather than midpoint by @yaxu in https://github.com/tidalcycles/strudel/pull/1278
- change behaviour of polymeter, and remove polymeterSteps by @yaxu in https://github.com/tidalcycles/strudel/pull/1302
- Polish, rename, and document stepwise functions by @yaxu in https://github.com/tidalcycles/strudel/pull/1262
### superdough
- feat: Create Pulse Oscillator with variable PWM by @daslyfe in https://github.com/tidalcycles/strudel/pull/1304
- add num samples (edited numbers) by @yaxu in https://github.com/tidalcycles/strudel/pull/1309
- Add num samples from 0 up to 20 by @yaxu in https://github.com/tidalcycles/strudel/pull/1310
- feat: add max polyphony feature for superdough by @daslyfe in https://github.com/tidalcycles/strudel/pull/1317
### docs
- doc: visual functions + refactor onPaint by @felixroos in https://github.com/tidalcycles/strudel/pull/1125
- Labeled statements doc by @felixroos in https://github.com/tidalcycles/strudel/pull/1126
- Correct spelling mistakes by @EdwardBetts in https://github.com/tidalcycles/strudel/pull/1183
- remove redundant example for cat, update snapshot by @kdiab in https://github.com/tidalcycles/strudel/pull/1189
- chore: Edit run locally instructions in README.md by @ChinoUkaegbu in https://github.com/tidalcycles/strudel/pull/1206
- suggested changes to voicings.mdx by @bwagner in https://github.com/tidalcycles/strudel/pull/1231
- Documentation for all/each, and bugfix for each by @yaxu in https://github.com/tidalcycles/strudel/pull/1233
- Update documentation for param value modification by @gillespi314 in https://github.com/tidalcycles/strudel/pull/1238
- fix docs for beat function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1248
- understand voicings page by @felixroos in https://github.com/tidalcycles/strudel/pull/1230
- add reference package by @felixroos in https://github.com/tidalcycles/strudel/pull/1252
- Stepwise documentation tweaks, with mridangam samples by @yaxu in https://github.com/tidalcycles/strudel/pull/1275
- showcase tweaks by @yaxu in https://github.com/tidalcycles/strudel/pull/1291
- Signpost licenses for source code and samples a bit more, ref #1277 by @yaxu in https://github.com/tidalcycles/strudel/pull/1289
- Fix misplaced ending sentence by @makmanalp in https://github.com/tidalcycles/strudel/pull/1296
- Fix typo pattnr by @ReneNyffenegger in https://github.com/tidalcycles/strudel/pull/1316
- update docs to reflect import sounds tab change by @hpunq in https://github.com/tidalcycles/strudel/pull/1332
### ui improvements
- Udels (MultiFrame Strudel) Revisited by @daslyfe in https://github.com/tidalcycles/strudel/pull/1132
- Create audio target selector for OSC/Superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1160
- Add a search bar to the REPL Reference tab by @netux in https://github.com/tidalcycles/strudel/pull/1165
- Adding search bar (soundtab.jsx) by @Bubobubobubobubo in https://github.com/tidalcycles/strudel/pull/1185
- add 2 new ui settings by @felixroos in https://github.com/tidalcycles/strudel/pull/1200
- Theme glowup by @felixroos in https://github.com/tidalcycles/strudel/pull/1268
- Create Pattern Page Pagination by @daslyfe in https://github.com/tidalcycles/strudel/pull/1287
- feat: Theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1295
- feat: new themes + theme improvements by @daslyfe in https://github.com/tidalcycles/strudel/pull/1326
- Add new "import-sounds" tab with explanation on folder import by @hpunq in https://github.com/tidalcycles/strudel/pull/1329
- Add Icon to import sample button by @daslyfe in https://github.com/tidalcycles/strudel/pull/1331
- better spacing in zen mode by @felixroos in https://github.com/tidalcycles/strudel/pull/1147
- Screenreader improvements by @yaxu in https://github.com/tidalcycles/strudel/pull/1158
- colorize console + tweak header by @felixroos in https://github.com/tidalcycles/strudel/pull/1203
- Menu Panel Improvements! by @daslyfe in https://github.com/tidalcycles/strudel/pull/1193
- Make panel hover behavior optional by @daslyfe in https://github.com/tidalcycles/strudel/pull/1199
- REPL: solo and sync configuration by @bthj in https://github.com/tidalcycles/strudel/pull/1214
- enhancement: make error messages easier to read by @daslyfe in https://github.com/tidalcycles/strudel/pull/1315
### mqtt
- MQTT support by @yaxu in https://github.com/tidalcycles/strudel/pull/1224
- MQTT - if password isn't provided, prompt for one by @yaxu in https://github.com/tidalcycles/strudel/pull/1249
- MQTT - support adding hap duration and cps metadata to JSON messages by @yaxu in https://github.com/tidalcycles/strudel/pull/1279
- make mqtt topic patternable by @yaxu in https://github.com/tidalcycles/strudel/pull/1280
- Bugfix: update mqtt connections dictionary by @yaxu in https://github.com/tidalcycles/strudel/pull/1281
- mqtt bugfix - connection check by @yaxu in https://github.com/tidalcycles/strudel/pull/1282
### new functions
- Add scramble and shuffle by @yaxu in https://github.com/tidalcycles/strudel/pull/1167
- polyJoin by @yaxu in https://github.com/tidalcycles/strudel/pull/1168
- Add seqPLoop from Tidal by @yaxu in https://github.com/tidalcycles/strudel/pull/1182
- add filter + filterWhen + within by @felixroos in https://github.com/tidalcycles/strudel/pull/1039
- Add bite function by @yaxu in https://github.com/tidalcycles/strudel/pull/1187
- markcss by @felixroos in https://github.com/tidalcycles/strudel/pull/1202
- "beat" function for "step sequencer" style rhythm notation by @daslyfe in https://github.com/tidalcycles/strudel/pull/1237
- Add s_zip for 'cat'-ing patterns together step-by-step, bugfix `steps` by @yaxu in https://github.com/tidalcycles/strudel/pull/1208
- "stretch" function (phase vocoder) by @daslyfe in https://github.com/tidalcycles/strudel/pull/1130
- add basic spectrum function by @felixroos in https://github.com/tidalcycles/strudel/pull/1213
- Add onKey function for custom key commands for patterns by @daslyfe in https://github.com/tidalcycles/strudel/pull/1235
- Add binary and binaryN by @heerman in https://github.com/tidalcycles/strudel/pull/1226
- midimaps by @felixroos in https://github.com/tidalcycles/strudel/pull/1274
- small feat: Add alias for segment and ribbon by @daslyfe in https://github.com/tidalcycles/strudel/pull/1314
- feat: Create scrub function for scrubbing an audio file by @daslyfe in https://github.com/tidalcycles/strudel/pull/1321
- feat: Improve gain curve by @daslyfe in https://github.com/tidalcycles/strudel/pull/1318
- Chop chop by @yaxu in https://github.com/tidalcycles/strudel/pull/1078
### more
- Make `all()` post-stack again, and add `each()` for pre-stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1229
- Add stepBind, and some toplevel aliases for binds and withValue by @yaxu in https://github.com/tidalcycles/strudel/pull/1241
- Make cps patternable by @eefano in https://github.com/tidalcycles/strudel/pull/1001
- Allow wchooseCycles probabilities to be patterned by @yaxu in https://github.com/tidalcycles/strudel/pull/1292
- @strudel/sampler improvements by @felixroos in https://github.com/tidalcycles/strudel/pull/1288
### refactor
- expose comment commands by @felixroos in https://github.com/tidalcycles/strudel/pull/1136
- containerize/seperate out boolean checks for repl types/Repl logic into bespoke components. by @daslyfe in https://github.com/tidalcycles/strudel/pull/1163
- Improve + simplify neocyclist timing by @daslyfe in https://github.com/tidalcycles/strudel/pull/1164
- Make phaser control consistent with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1178
- Revert "Make phaser control consistent with superdirt" by @daslyfe in https://github.com/tidalcycles/strudel/pull/1179
- make phaser control match superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1180
- refactor sampler by @felixroos in https://github.com/tidalcycles/strudel/pull/1101
- update lockfile + minor versions by @felixroos in https://github.com/tidalcycles/strudel/pull/1198
- Preserve tactus for 'degrade' and friends, and tidy up 'pick' and friends by @yaxu in https://github.com/tidalcycles/strudel/pull/1205
- Apply `all` function to individual patterns rather than final stack by @yaxu in https://github.com/tidalcycles/strudel/pull/1209
- Revert "Fix sometimes" by @yaxu in https://github.com/tidalcycles/strudel/pull/1267
- patchday by @felixroos in https://github.com/tidalcycles/strudel/pull/1264
- Rename repeat back to extend by @yaxu in https://github.com/tidalcycles/strudel/pull/1285
- Send delta in OSC message in seconds, to match tidal/superdirt by @yaxu in https://github.com/tidalcycles/strudel/pull/1323
### fixes
- Fix clock worker dependency path in module builds by @matthewkaney in https://github.com/tidalcycles/strudel/pull/1129
- Fix bug in Fraction.lcm by @yaxu in https://github.com/tidalcycles/strudel/pull/1133
- Fix tactus marking in mininotation by @yaxu in https://github.com/tidalcycles/strudel/pull/1144
- Fix loopAt tactus by @yaxu in https://github.com/tidalcycles/strudel/pull/1145
- Fix OSC clock jitter by @daslyfe in https://github.com/tidalcycles/strudel/pull/1157
- [CORS HOTFIX] by @daslyfe in https://github.com/tidalcycles/strudel/pull/1162
- Fixes fit so it works after a chop or slice by @yaxu in https://github.com/tidalcycles/strudel/pull/1171
- fix sample speed when using splice and fit with superdirt by @daslyfe in https://github.com/tidalcycles/strudel/pull/1172
- handle midin device not found error by @felixroos in https://github.com/tidalcycles/strudel/pull/1146
- Fix serial timing by @yaxu in https://github.com/tidalcycles/strudel/pull/1188
- Fix regression for d1, p1, p(n) by @yaxu in https://github.com/tidalcycles/strudel/pull/1227
- Fix sometimes by @yaxu in https://github.com/tidalcycles/strudel/pull/1243
- Fix sf2 timing by @felixroos in https://github.com/tidalcycles/strudel/pull/1272
- Fix "squeezejoin" and functions using it, including "bite" by @yaxu in https://github.com/tidalcycles/strudel/pull/1286
- Fixes inverted triangle wave by renaming it to "itri", making non-inverted "tri" by @yaxu in https://github.com/tidalcycles/strudel/pull/1283
- Hotfix: prevent undefined pattern code from crashing strudel on load by @daslyfe in https://github.com/tidalcycles/strudel/pull/1297
- Fix test error #1297 by @nkymut in https://github.com/tidalcycles/strudel/pull/1298
- bugfix zoom stepcount by @yaxu in https://github.com/tidalcycles/strudel/pull/1301
- bugfix: Allow single param to be used in the as function by @daslyfe in https://github.com/tidalcycles/strudel/pull/1312
- fix: replace empty spaces in registered sound keys by @daslyfe in https://github.com/tidalcycles/strudel/pull/1319
- FIX: Multichannel Audio by @daslyfe in https://github.com/tidalcycles/strudel/pull/1322
- fix: udels header by @daslyfe in https://github.com/tidalcycles/strudel/pull/1325
- fix: disable astro toolbar by default by @daslyfe in https://github.com/tidalcycles/strudel/pull/1324
- FIX: sound import order by @daslyfe in https://github.com/tidalcycles/strudel/pull/1333`
## New Contributors
- @EdwardBetts made their first contribution in https://github.com/tidalcycles/strudel/pull/1183
- @netux made their first contribution in https://github.com/tidalcycles/strudel/pull/1165
- @kdiab made their first contribution in https://github.com/tidalcycles/strudel/pull/1189
**Full Changelog**: https://github.com/tidalcycles/strudel/compare/v1.1.0...v1.1.1
## packages
- @strudel/codemirror@1.2.0
- @strudel/core@1.2.0
- @strudel/csound@1.2.0
- @strudel/draw@1.2.0
- @strudel/gamepad@1.2.0
- @strudel/hydra@1.2.0
- @strudel/midi@1.2.0
- @strudel/mini@1.2.0
- @strudel/motion@1.2.0
- @strudel/mqtt@1.2.0
- @strudel/osc@1.2.0
- @strudel/reference@1.2.0
- @strudel/repl@1.2.0
- @strudel/sampler@0.2.0
- @strudel/serial@1.2.0
- @strudel/soundfonts@1.2.0
- superdough@1.2.0
- @strudel/tonal@1.2.0
- @strudel/transpiler@1.2.0
- @strudel/web@1.2.0
- @strudel/webaudio@1.2.0
- @strudel/xen@1.2.0
@@ -95,7 +95,7 @@ Diese Kombinationen von Buchstaben stehen für verschiedene Teile eines Schlagze
- `mt` = **m**iddle tom
- `ht` = **h**igh tom
- `rd` = **r**i**d**e cymbal
- `rd` = **cr**ash cymbal
- `cr` = **cr**ash cymbal
Probier verschiedene Sounds aus!
@@ -176,3 +176,16 @@ $ chord <Dm9!3 Db7> # voicing
/>
The `$` sign is an alias for `,` so it will create a stack behind the scenes.
## variables
using the `def` keyword, you can define variables:
<MiniRepl
client:idle
mondo
tune={`
$ def melody [0 1 2 3]
$ n melody # scale C:minor
`}
/>
+15
View File
@@ -163,6 +163,21 @@ The last section could be written as:
}
```
Please note that browsers will often cache `strudel.json` on first load, and keep using the cached
version even if the orginal has been updated. If this bites you (for example while developing a new
sample pack), you can force the browser to download a new copy by i.e. changing capitalization of one
character in the URL, or adding a URL attribute, such as:
```javascript
samples('https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/strudel.json?version=2');
```
that gets ignored by GitHub (but changes the URL, forcing the browser to reload every time we increase
the version number).
It is also possible, of course, to just remove it from cache (deleting cache in browser Privacy settings,
or from the dev console if you're technically minded, or by using a cache deleting extension).
## Github Shortcut
Because loading samples from github is common, there is a shortcut:
+2
View File
@@ -67,6 +67,8 @@ Or using 2 beats per cycle:
s("bd sd, hh*4")`}
/>
You can use the `setcps` method to set the global tempo in cycles per second. `setcpm(x)` is the same as `setcps(x / 60)`.
<Box>
To set a specific bpm, use `setcpm(bpm/bpc)`
@@ -21,7 +21,11 @@ export function Reference() {
return true;
}
return entry.name.includes(search) || (entry.synonyms?.some((s) => s.includes(search)) ?? false);
const lowCaseSearch = search.toLowerCase();
return (
entry.name.toLowerCase().includes(lowCaseSearch) ||
(entry.synonyms?.some((s) => s.includes(lowCaseSearch)) ?? false)
);
});
}, [search]);
@@ -109,6 +109,8 @@ export function SettingsTab({ started }) {
togglePanelTrigger,
maxPolyphony,
multiChannelOrbits,
isTabIndentationEnabled,
isMultiCursorEnabled,
} = useSettings();
const shouldAlwaysSync = isUdels();
const canChangeAudioDevice = AudioContext.prototype.setSinkId != null;
@@ -262,6 +264,16 @@ export function SettingsTab({ started }) {
onChange={(cbEvent) => settingsMap.setKey('isLineWrappingEnabled', cbEvent.target.checked)}
value={isLineWrappingEnabled}
/>
<Checkbox
label="Enable Tab indentation"
onChange={(cbEvent) => settingsMap.setKey('isTabIndentationEnabled', cbEvent.target.checked)}
value={isTabIndentationEnabled}
/>
<Checkbox
label="Enable Multi-Cursor (Cmd/Ctrl+Click)"
onChange={(cbEvent) => settingsMap.setKey('isMultiCursorEnabled', cbEvent.target.checked)}
value={isMultiCursorEnabled}
/>
<Checkbox
label="Enable flashing on evaluation"
onChange={(cbEvent) => settingsMap.setKey('isFlashEnabled', cbEvent.target.checked)}
@@ -20,7 +20,7 @@ export function WelcomeTab({ context }) {
</p>
<p>
{/* To learn more about what this all means, check out the{' '} */}
To get started, check out the
To get started, check out the{' '}
<a href={`${baseNoTrailing}/workshop/getting-started/`} target="_blank">
interactive tutorial
</a>
@@ -43,7 +43,7 @@ export function WelcomeTab({ context }) {
</a>
. You can find the source code at{' '}
<a href="https://codeberg.org/uzu/strudel" target="_blank">
github
codeberg
</a>
. You can also find <a href="https://github.com/felixroos/dough-samples/blob/main/README.md">licensing info</a>{' '}
for the default sound banks there. Please consider to{' '}
+2
View File
@@ -13,6 +13,7 @@ import {
resetGlobalEffects,
resetLoadedSounds,
initAudioOnFirstClick,
resetDefaults,
} from '@strudel/webaudio';
import { setVersionDefaultsFrom } from './util.mjs';
import { StrudelMirror, defaultSettings } from '@strudel/codemirror';
@@ -181,6 +182,7 @@ export function useReplContext() {
const resetEditor = async () => {
(await getModule('@strudel/tonal'))?.resetVoicings();
resetDefaults();
resetGlobalEffects();
clearCanvas();
clearHydra();
+4
View File
@@ -21,6 +21,8 @@ export const defaultSettings = {
isSyncEnabled: false,
isLineWrappingEnabled: false,
isPatternHighlightingEnabled: true,
isTabIndentationEnabled: false,
isMultiCursorEnabled: false,
theme: 'strudelTheme',
fontFamily: 'monospace',
fontSize: 18,
@@ -77,6 +79,8 @@ export function useSettings() {
isLineWrappingEnabled: parseBoolean(state.isLineWrappingEnabled),
isFlashEnabled: parseBoolean(state.isFlashEnabled),
isSyncEnabled: isUdels() ? true : parseBoolean(state.isSyncEnabled),
isTabIndentationEnabled: parseBoolean(state.isTabIndentationEnabled),
isMultiCursorEnabled: parseBoolean(state.isMultiCursorEnabled),
fontSize: Number(state.fontSize),
panelPosition: state.activeFooter !== '' && !isUdels() ? state.panelPosition : 'bottom', // <-- keep this 'bottom' where it is!
isPanelPinned: parseBoolean(state.isPanelPinned),