Compare commits

...

98 Commits

Author SHA1 Message Date
Felix Roos 051bdaccc7 Publish
- @strudel/codemirror@1.0.1
 - @strudel/core@1.0.1
 - @strudel/csound@1.0.1
 - @strudel/hydra@1.0.1
 - @strudel/midi@1.0.1
 - @strudel/mini@1.0.1
 - @strudel/osc@1.0.1
 - @strudel/repl@1.0.1
 - @strudel/serial@1.0.1
 - @strudel/soundfonts@1.0.1
 - superdough@1.0.1
 - @strudel/tonal@1.0.1
 - @strudel/transpiler@1.0.1
 - @strudel/web@1.0.1
 - @strudel/webaudio@1.0.1
 - @strudel/xen@1.0.1
2024-02-08 13:04:25 +01:00
Felix Roos 5dc04d9574 make sure to overwrite main field 2024-02-08 12:36:04 +01:00
Felix Roos 60129413d3 remove cjs builds
+ add type module everywhere
2024-02-08 12:19:11 +01:00
Felix Roos d2bf9370ea Update README.md
add link to usage example for repl package
2024-02-04 23:24:43 +01:00
Felix Roos fd11aa5eec Merge pull request #941 from mhetrick/patch-1
Minor documentation error: Update first-sounds.mdx
2024-02-04 23:15:37 +01:00
Michael Hetrick fb7c2b61d3 Update first-sounds.mdx
Update the tutorial text to reflect that the default cpm setting has changed from 60 to 30.
2024-01-26 07:13:09 -08:00
Felix Roos dd64bf0fc9 Merge pull request #938 from tidalcycles/pianoroll-sorting
fix: pianoroll sorting
2024-01-24 16:48:57 +01:00
Felix Roos 434eb3b256 fix: pianoroll sorting 2024-01-24 16:40:26 +01:00
Felix Roos 8fef75385a Update README.md 2024-01-23 01:35:28 +01:00
Felix Roos c66b9219a8 Update README.md 2024-01-23 01:31:11 +01:00
Felix Roos 2a1f8823e8 Merge pull request #935 from tidalcycles/v1-release-notes
V1 release notes
2024-01-23 00:04:03 +01:00
Felix Roos 3da65f90e3 shorter titles for release notes 2024-01-22 23:55:57 +01:00
Felix Roos a36cc24087 v1 release notes 2024-01-22 23:55:49 +01:00
Felix Roos 1829d8cadf Publish
- @strudel/codemirror@1.0.0
 - @strudel/core@1.0.0
 - @strudel/csound@1.0.0
 - @strudel/embed@1.0.0
 - @strudel/hydra@1.0.0
 - @strudel/midi@1.0.0
 - @strudel/mini@1.0.0
 - @strudel/osc@1.0.0
 - @strudel/repl@1.0.0
 - @strudel/serial@1.0.0
 - @strudel/soundfonts@1.0.0
 - superdough@1.0.0
 - @strudel/tonal@1.0.0
 - @strudel/transpiler@1.0.0
 - @strudel/web@1.0.0
 - @strudel/webaudio@1.0.0
 - @strudel/xen@1.0.0
2024-01-22 22:46:35 +01:00
Felix Roos 02efc090ef hotfix: examples were still 1 cps based 2024-01-22 20:46:10 +01:00
Felix Roos b184348f55 hotfix: youtube embed styles were lost on prod 2024-01-22 20:38:34 +01:00
Felix Roos 06743cb072 Merge pull request #929 from tidalcycles/2-years
2 years blog post
2024-01-22 20:20:52 +01:00
Felix Roos 6fa66fb1d0 finish year 2 post 2024-01-22 20:19:01 +01:00
Felix Roos 23c0ab9648 offset blog post anchor links 2024-01-22 20:18:51 +01:00
Alex McLean 6422047cff make 0.5hz cps the default (#931)
* 0.5 default cps

* 1 -> 0.5 cps defaults

* start moving examples to 2Hz

* more 2Hz doc edits

* small tweaks

* format

* adapt cycles page

* adapt pitch page

* tonal page

* accumulation

* synth page

* adapt conditional-modifiers

* audio effects page

* adapt signals doc

* fix: errors for signals

* adapt signals page

* start time modifiers

* adapt time modifiers

* adapt factories

* hydra + pattern intro

* adapt mini notation page

* start recipes

* adapt recipes page

* use code_v1 table

* delete old dbdump + add new csv based tool

* fix: tests

* fix: cpm

* shuffle featured patterns

* fix: snapshot

---------

Co-authored-by: Felix Roos <flix91@gmail.com>
2024-01-22 19:02:34 +00:00
Jade (Rose) Rowland 46c2c72637 Merge pull request #934 from daslyfe/patterntab_fix
Fix pattern tab not showing patterns without created date
2024-01-21 18:52:01 -05:00
Jade (Rose) Rowland c088590244 remove console statement 2024-01-21 18:51:06 -05:00
Jade (Rose) Rowland 192ba69682 fixed if statement 2024-01-21 18:49:06 -05:00
Jade (Rose) Rowland 2cc428e968 Merge pull request #897 from daslyfe/pattern_selection
Add useful pattern selection behavior for performing.
2024-01-21 14:46:27 -05:00
Jade (Rose) Rowland 15c451a6d9 default pattern filtername 2024-01-21 14:35:17 -05:00
Jade (Rose) Rowland b46e8c07be reset/autoplay when window PARENT does not exist or does not contain oodles 2024-01-21 12:44:14 -05:00
Jade (Rose) Rowland 961e931c31 autoplay and reset cps on default 2024-01-21 12:12:33 -05:00
Jade (Rose) Rowland b1d49552ae title order 2024-01-21 11:27:48 -05:00
Jade (Rose) Rowland d31d154841 fix oven imports 2024-01-21 11:24:58 -05:00
Jade (Rose) Rowland d03892bbcf Merge branch 'tidalcycles:main' into pattern_selection 2024-01-21 11:19:06 -05:00
Felix Roos 0cf0c1c585 Merge pull request #933 from tidalcycles/refactor-cps-functions
Refactor cps functions
2024-01-21 01:30:27 +01:00
Felix Roos 0695b4bee9 clean + comment 2024-01-21 01:29:31 +01:00
Felix Roos 0cfec3a7bd show repls in community bakery 2024-01-21 01:21:21 +01:00
Felix Roos 6224cd40d4 mini repl max height option 2024-01-21 01:21:13 +01:00
Felix Roos 18ae82174d fix: "can't redefine non-configurable property" 2024-01-21 01:13:32 +01:00
Felix Roos aa1b9d11dc inject scheduler into Pattern methods right before eval 2024-01-21 00:59:31 +01:00
Felix Roos 0a82471112 implement loopAt with pat state 2024-01-21 00:45:40 +01:00
Felix Roos 8052e10f0c implement fit with pat state 2024-01-21 00:39:26 +01:00
Jade (Rose) Rowland 1146f6ba52 fix annoying div 2024-01-20 18:14:42 -05:00
Alex McLean 738cea0025 Make splice cps-aware (#932)
* make splice cps-aware

* format

* copypaste fix
2024-01-20 22:47:31 +00:00
Jade (Rose) Rowland 6c28398d20 fix scroll 2024-01-20 14:25:42 -05:00
Jade (Rose) Rowland 4fe75143d0 cleanup 2024-01-20 14:10:46 -05:00
Jade (Rose) Rowland 3cd59cdea5 cleaning up 2024-01-20 14:02:48 -05:00
Jade (Rose) Rowland 9dca7eb878 add pattern filter behaves like sounds tab 2024-01-20 13:59:32 -05:00
Jade (Rose) Rowland b45fd5ce3a fix invalid date 2024-01-20 13:00:33 -05:00
Felix Roos 229b1470f7 fix: localhost links 2024-01-20 10:59:34 +01:00
Jade (Rose) Rowland 0a349e1707 avoid json errors in firefox 2024-01-19 23:04:41 -05:00
Felix Roos d176e9ccf0 add stats 2024-01-19 21:51:52 +01:00
Felix Roos 710c3acb5d more writing 2024-01-19 21:21:33 +01:00
Felix Roos a7f5d0e0c1 Merge pull request #923 from tidalcycles/feed
community bakery
2024-01-19 18:50:57 +01:00
Felix Roos 9928526dda Merge pull request #924 from geikha/main
add pickF and pickmodF
2024-01-19 18:49:53 +01:00
Renzo Torr- 2f8111be0e update the .snap file 2024-01-19 14:47:03 -03:00
Renzo Torr- 68113937ff code format 2024-01-19 14:06:24 -03:00
Felix Roos c598fa026b write more 2024-01-19 15:49:16 +01:00
Alex McLean 491c99c348 Mini-notation additions towards tidal compatibility (#926)
- `.` feet now work, e.g. `"a b c . d e . f"` is the same as `"[a b c] [d e] [f]"`
- `_` elongation now works, e.g. `"a _ _ b"` is the same as `"a@3 b"` (`"a @ @ b"` also works, like in tidal)
- standalone `!` now works, e.g. `"a ! ! b"` is the same as `"a!3 b"`

Reworks #47 and #49
Ref #30
2024-01-19 14:10:47 +00:00
Felix Roos d49aa8242a begin 2 year post 2024-01-19 13:50:28 +01:00
Renzo Torr- 9ffbc06cf9 add pickF and pickmodF
allows to pick functions via a pattern of numbers, to apply to another pattern
2024-01-19 02:45:54 -03:00
Jade (Rose) Rowland af52ac30ba prettier 2024-01-19 00:28:55 -05:00
Jade (Rose) Rowland 7aea1b5fc8 fixed imports 2024-01-19 00:27:09 -05:00
Jade (Rose) Rowland 500ddf3946 Merge branch 'main' into pattern_selection 2024-01-19 00:23:06 -05:00
Jade (Rose) Rowland 3431eaf309 cleaning up 2024-01-19 00:20:10 -05:00
Jade (Rose) Rowland 9a13c58583 cleaning up 2024-01-19 00:14:08 -05:00
Jade (Rose) Rowland 77a48e8351 persistent pattern data 2024-01-18 22:30:53 -05:00
Jade (Rose) Rowland 6cb156d876 cleaning up 2024-01-18 20:01:54 -05:00
Felix Roos d8677c6261 hotfix: rss links 2024-01-18 23:40:22 +01:00
Felix Roos 6ef9ca18e9 Merge pull request #919 from tidalcycles/blog-improvements
Blog improvements
2024-01-18 23:34:10 +01:00
Felix Roos 6667738dc9 more rename 2024-01-18 21:34:20 +01:00
Felix Roos 4f7415b0ec rename 2024-01-18 21:31:21 +01:00
Felix Roos c6f3a8b7c7 more text 2024-01-18 18:30:57 +01:00
Felix Roos 4229d673c9 basic community oven 2024-01-18 18:21:56 +01:00
Alex McLean 98b7859605 pick, pickmod, inhabit, inhabitmod (#921)
* the args for `pick` are now reversed as standard (old behaviour still supported to avoid breaking change)
* `pick` is also now a pattern method
* `pick` now also accepts a lookup table for pick-by-name as an alternative to pick-by-index from a list
* `inhabit` added with same behaviour as `pick`, except cycles from source patterns are squeezed into events of inhabited patterns
* Also some general doc tidying, sorry for the noise..
* There is also `pickmod` and `inhabitmod`, for wrapping indexes around rather than clamping them
2024-01-18 17:08:29 +00:00
Alex McLean a8db707440 Revert "pick now accepts lookup tables, with alternate cycle squeezing behaviour as new inhabit function" (#920) 2024-01-18 17:04:26 +00:00
Alex McLean 873a412179 pick now accepts lookup tables, with alternate cycle squeezing behaviour as new inhabit function (#918)
- the args for `pick` are now reversed (breaking change!)
- `pick` is also now a method on the inhabited pattern
- `pick` now also accepts a lookup table
- `inhabit` added with same behaviour as `pick`, except cycles from source patterns are squeezed into events of inhabited patterns
- Also some general doc tidying, sorry for the noise..
- There is now also `pickmod` and `inhabitmod`, for wrapping indexes around rather than clamping them
2024-01-18 16:45:39 +00:00
Felix Roos 0778b4809e format 2024-01-18 13:47:34 +01:00
Felix Roos f85fb35c66 minirepl multi tune support + add other getting-started examples (more to come) 2024-01-18 13:46:35 +01:00
Felix Roos 5ada0daf40 add rss link to top + fix typo 2024-01-18 13:01:06 +01:00
Felix Roos 2ed5f5aa65 blog style fixes 2024-01-18 12:50:35 +01:00
Felix Roos ae5e6e3ab8 add rss.xml 2024-01-18 12:49:22 +01:00
Felix Roos 9ba7b9b4d4 Merge pull request #917 from tidalcycles/deprecate-old-package-names
rename @strudel.cycles/* packages to @strudel/*
2024-01-18 10:30:08 +01:00
Felix Roos a45f1fba45 update versions in example html files 2024-01-18 10:25:24 +01:00
Felix Roos e6b47d2cf2 fix link 2024-01-18 10:04:53 +01:00
Felix Roos b04a262433 Publish
- @strudel/codemirror@0.11.0
 - @strudel/core@0.11.0
 - @strudel/csound@0.11.0
 - @strudel/embed@0.11.0
 - @strudel/hydra@0.11.0
 - @strudel/midi@0.11.0
 - @strudel/mini@0.11.0
 - @strudel/osc@0.11.0
 - @strudel/repl@0.11.0
 - @strudel/serial@0.11.0
 - @strudel/soundfonts@0.11.0
 - @strudel/tonal@0.11.0
 - @strudel/transpiler@0.11.0
 - @strudel/web@0.11.0
 - @strudel/webaudio@0.11.0
 - @strudel/xen@0.11.0
2024-01-18 09:59:57 +01:00
Felix Roos 96bafa7f0b the big rename: @strudel.cycles/* -> @strudel/* 2024-01-18 09:54:37 +01:00
Jade (Rose) Rowland 7adfe6f2df fixing edge cases... 2024-01-17 09:45:00 -05:00
Jade (Rose) Rowland 45df7bfea3 making things consistent 2024-01-16 00:45:00 -05:00
Jade (Rose) Rowland 106772e480 Merge branch 'main' into pattern_selection 2024-01-15 18:37:18 -05:00
Felix Roos e7e60d3ed8 Merge branch 'main' into pattern_selection 2024-01-14 00:18:57 +01:00
Jade (Rose) Rowland 78f6fdf169 reset for example patterns 2024-01-08 10:49:26 -05:00
Jade (Rose) Rowland e01c6dc18d prettier 2024-01-08 00:25:58 -05:00
Jade (Rose) Rowland 51dd408733 all working 2024-01-08 00:15:07 -05:00
Jade (Rose) Rowland 1ff7548b52 refactoring 2024-01-07 22:48:07 -05:00
Jade (Rose) Rowland f7fe44063a handle deletion cases 2024-01-07 00:58:03 -05:00
Jade (Rose) Rowland 0355c358b8 fixed create and duplicate behavior 2024-01-06 23:49:37 -05:00
Jade (Rose) Rowland 4e0a60db00 example code logic 2024-01-06 22:10:14 -05:00
Jade (Rose) Rowland 3604d3940c mutate viewing pattern 2024-01-06 17:53:51 -05:00
Jade (Rose) Rowland 02b9bd82cf highlight viewing pattern 2024-01-06 17:33:24 -05:00
Jade (Rose) Rowland 1bc86c359e state 2024-01-03 01:04:39 -05:00
Jade (Rose) Rowland 1e2c26123b working 2024-01-03 00:35:47 -05:00
185 changed files with 6276 additions and 3586 deletions
+1 -1
View File
@@ -114,7 +114,7 @@ You can run the same check with `pnpm check`
## Package Workflow ## Package Workflow
The project is split into multiple [packages](https://github.com/tidalcycles/strudel/tree/main/packages) with independent versioning. The project is split into multiple [packages](https://github.com/tidalcycles/strudel/tree/main/packages) with independent versioning.
When you run `pnpm i` on the root folder, [pnpm workspaces](https://pnpm.io/workspaces) will install all dependencies of all subpackages. This will allow any js file to import `@strudel.cycles/<package-name>` to get the local version, When you run `pnpm i` on the root folder, [pnpm workspaces](https://pnpm.io/workspaces) will install all dependencies of all subpackages. This will allow any js file to import `@strudel/<package-name>` to get the local version,
allowing to develop multiple packages at the same time. allowing to develop multiple packages at the same time.
## Package Publishing ## Package Publishing
+2 -1
View File
@@ -2,12 +2,13 @@
[![Strudel test status](https://github.com/tidalcycles/strudel/actions/workflows/test.yml/badge.svg)](https://github.com/tidalcycles/strudel/actions) [![Strudel test status](https://github.com/tidalcycles/strudel/actions/workflows/test.yml/badge.svg)](https://github.com/tidalcycles/strudel/actions)
An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is slowly stabilising, but please continue to tread carefully. An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is a bit more stable now, but please continue to tread carefully.
- Try it here: <https://strudel.cc> - Try it here: <https://strudel.cc>
- Docs: <https://strudel.cc/learn> - Docs: <https://strudel.cc/learn>
- Technical Blog Post: <https://loophole-letters.vercel.app/strudel> - Technical Blog Post: <https://loophole-letters.vercel.app/strudel>
- 1 Year of Strudel Blog Post: <https://loophole-letters.vercel.app/strudel1year> - 1 Year of Strudel Blog Post: <https://loophole-letters.vercel.app/strudel1year>
- 2 Years of Strudel Blog Post: <https://strudel.cc/blog/#year-2>
## Running Locally ## Running Locally
+1 -1
View File
@@ -7,7 +7,7 @@
/> />
<div id="output"></div> <div id="output"></div>
<script type="module"> <script type="module">
const strudel = await import('https://cdn.skypack.dev/@strudel.cycles/core@0.6.8'); const strudel = await import('https://cdn.skypack.dev/@strudel/core@0.6.8');
Object.assign(window, strudel); // assign all strudel functions to global scope to use with eval Object.assign(window, strudel); // assign all strudel functions to global scope to use with eval
const input = document.getElementById('text'); const input = document.getElementById('text');
const getEvents = () => { const getEvents = () => {
+1 -1
View File
@@ -8,7 +8,7 @@
/> />
<canvas id="canvas"></canvas> <canvas id="canvas"></canvas>
<script type="module"> <script type="module">
const strudel = await import('https://cdn.skypack.dev/@strudel.cycles/core@0.6.8'); const strudel = await import('https://cdn.skypack.dev/@strudel/core@0.6.8');
// this adds all strudel functions to the global scope, to be used by eval // this adds all strudel functions to the global scope, to be used by eval
Object.assign(window, strudel); Object.assign(window, strudel);
// setup elements // setup elements
+17 -11
View File
@@ -16,34 +16,40 @@
</div> </div>
<div id="output"></div> <div id="output"></div>
<script type="module"> <script type="module">
import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel.cycles/core@0.6.8'; import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel/core@0.11.0';
import { mini } from 'https://cdn.skypack.dev/@strudel.cycles/mini@0.6.0'; import { mini } from 'https://cdn.skypack.dev/@strudel/mini@0.11.0';
import { transpiler } from 'https://cdn.skypack.dev/@strudel.cycles/transpiler@0.6.0'; import { transpiler } from 'https://cdn.skypack.dev/@strudel/transpiler@0.11.0';
import { import {
getAudioContext, getAudioContext,
webaudioOutput, webaudioOutput,
initAudioOnFirstClick, initAudioOnFirstClick,
} from 'https://cdn.skypack.dev/@strudel.cycles/webaudio@0.6.0'; registerSynthSounds,
} from 'https://cdn.skypack.dev/@strudel/webaudio@0.11.0';
initAudioOnFirstClick();
const ctx = getAudioContext(); const ctx = getAudioContext();
const input = document.getElementById('text'); const input = document.getElementById('text');
input.innerHTML = getTune(); input.innerHTML = getTune();
evalScope( const loadModules = evalScope(
controls, controls,
import('https://cdn.skypack.dev/@strudel.cycles/core@0.6.8'), import('https://cdn.skypack.dev/@strudel/core@0.11.0'),
import('https://cdn.skypack.dev/@strudel.cycles/mini@0.6.0'), import('https://cdn.skypack.dev/@strudel/mini@0.11.0'),
import('https://cdn.skypack.dev/@strudel.cycles/tonal@0.6.0'), import('https://cdn.skypack.dev/@strudel/tonal@0.11.0'),
import('https://cdn.skypack.dev/@strudel.cycles/webaudio@0.6.0'), import('https://cdn.skypack.dev/@strudel/webaudio@0.11.0'),
); );
const initAudio = Promise.all([initAudioOnFirstClick(), registerSynthSounds()]);
const { evaluate } = repl({ const { evaluate } = repl({
defaultOutput: webaudioOutput, defaultOutput: webaudioOutput,
getTime: () => ctx.currentTime, getTime: () => ctx.currentTime,
transpiler, transpiler,
}); });
document.getElementById('start').addEventListener('click', () => evaluate(input.value)); document.getElementById('start').addEventListener('click', async () => {
await loadModules;
await initAudio;
evaluate(input.value);
});
function getTune() { function getTune() {
return `await samples('github:tidalcycles/Dirt-Samples/master') return `await samples('github:tidalcycles/Dirt-Samples/master')
+1 -1
View File
@@ -1,4 +1,4 @@
<script src="https://unpkg.com/@strudel.cycles/embed@latest"></script> <script src="https://unpkg.com/@strudel/embed@0.11.0"></script>
<!-- <script src="./embed.js"></script> --> <!-- <script src="./embed.js"></script> -->
<strudel-repl> <strudel-repl>
<!-- <!--
+9 -9
View File
@@ -1,11 +1,11 @@
import { StrudelMirror } from '@strudel/codemirror'; import { StrudelMirror } from '@strudel/codemirror';
import { funk42 } from './tunes'; import { funk42 } from './tunes';
import { drawPianoroll, evalScope, controls } from '@strudel.cycles/core'; import { drawPianoroll, evalScope, controls } from '@strudel/core';
import './style.css'; import './style.css';
import { initAudioOnFirstClick } from '@strudel.cycles/webaudio'; import { initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel.cycles/transpiler'; import { transpiler } from '@strudel/transpiler';
import { getAudioContext, webaudioOutput, registerSynthSounds } from '@strudel.cycles/webaudio'; import { getAudioContext, webaudioOutput, registerSynthSounds } from '@strudel/webaudio';
import { registerSoundfonts } from '@strudel.cycles/soundfonts'; import { registerSoundfonts } from '@strudel/soundfonts';
// init canvas // init canvas
const canvas = document.getElementById('roll'); const canvas = document.getElementById('roll');
@@ -26,10 +26,10 @@ const editor = new StrudelMirror({
initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..) initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
const loadModules = evalScope( const loadModules = evalScope(
controls, controls,
import('@strudel.cycles/core'), import('@strudel/core'),
import('@strudel.cycles/mini'), import('@strudel/mini'),
import('@strudel.cycles/tonal'), import('@strudel/tonal'),
import('@strudel.cycles/webaudio'), import('@strudel/webaudio'),
); );
await Promise.all([loadModules, registerSynthSounds(), registerSoundfonts()]); await Promise.all([loadModules, registerSynthSounds(), registerSoundfonts()]);
}, },
+6 -6
View File
@@ -13,11 +13,11 @@
}, },
"dependencies": { "dependencies": {
"@strudel/codemirror": "workspace:*", "@strudel/codemirror": "workspace:*",
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel/mini": "workspace:*",
"@strudel.cycles/soundfonts": "workspace:*", "@strudel/soundfonts": "workspace:*",
"@strudel.cycles/tonal": "workspace:*", "@strudel/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*" "@strudel/webaudio": "workspace:*"
} }
} }
+7 -7
View File
@@ -1,6 +1,6 @@
import { controls, repl, evalScope } from '@strudel.cycles/core'; import { controls, repl, evalScope } from '@strudel/core';
import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel.cycles/webaudio'; import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel.cycles/transpiler'; import { transpiler } from '@strudel/transpiler';
import tune from './tune.mjs'; import tune from './tune.mjs';
const ctx = getAudioContext(); const ctx = getAudioContext();
@@ -10,10 +10,10 @@ initAudioOnFirstClick();
evalScope( evalScope(
controls, controls,
import('@strudel.cycles/core'), import('@strudel/core'),
import('@strudel.cycles/mini'), import('@strudel/mini'),
import('@strudel.cycles/webaudio'), import('@strudel/webaudio'),
import('@strudel.cycles/tonal'), import('@strudel/tonal'),
); );
const { evaluate } = repl({ const { evaluate } = repl({
+5 -5
View File
@@ -13,10 +13,10 @@
"vite": "^5.0.10" "vite": "^5.0.10"
}, },
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel/mini": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*", "@strudel/webaudio": "workspace:*",
"@strudel.cycles/tonal": "workspace:*" "@strudel/tonal": "workspace:*"
} }
} }
+7 -7
View File
@@ -1,5 +1,5 @@
{ {
"name": "@strudel.cycles/monorepo", "name": "@strudel/monorepo",
"version": "0.5.0", "version": "0.5.0",
"private": true, "private": true,
"description": "Port of tidalcycles to javascript", "description": "Port of tidalcycles to javascript",
@@ -45,12 +45,12 @@
}, },
"homepage": "https://strudel.cc", "homepage": "https://strudel.cc",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel/mini": "workspace:*",
"@strudel.cycles/tonal": "workspace:*", "@strudel/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*", "@strudel/webaudio": "workspace:*",
"@strudel.cycles/xen": "workspace:*" "@strudel/xen": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"dependency-tree": "^10.0.9", "dependency-tree": "^10.0.9",
+1 -1
View File
@@ -1,5 +1,5 @@
# Packages # Packages
Each folder represents one of the @strudel.cycles/* packages [published to npm](https://www.npmjs.com/org/strudel.cycles). 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://github.com/tidalcycles/strudel/wiki/Technical-Manual) or the individual READMEs. To understand how those pieces connect, refer to the [Technical Manual](https://github.com/tidalcycles/strudel/wiki/Technical-Manual) or the individual READMEs.
+1 -1
View File
@@ -12,7 +12,7 @@ import {
lineNumbers, lineNumbers,
drawSelection, drawSelection,
} from '@codemirror/view'; } from '@codemirror/view';
import { Pattern, Drawer, repl, cleanupDraw } from '@strudel.cycles/core'; import { Pattern, Drawer, repl, cleanupDraw } from '@strudel/core';
import { isAutoCompletionEnabled } from './autocomplete.mjs'; import { isAutoCompletionEnabled } from './autocomplete.mjs';
import { isTooltipEnabled } from './tooltip.mjs'; import { isTooltipEnabled } from './tooltip.mjs';
import { flash, isFlashEnabled } from './flash.mjs'; import { flash, isFlashEnabled } from './flash.mjs';
+3 -1
View File
@@ -57,6 +57,9 @@ const visibleMiniLocations = StateField.define({
// this is why we need to find a way to update the existing decorations, showing the ones that have an active range // this is why we need to find a way to update the existing decorations, showing the ones that have an active range
const haps = new Map(); const haps = new Map();
for (let hap of e.value.haps) { for (let hap of e.value.haps) {
if (!hap.context?.locations || !hap.whole) {
continue;
}
for (let { start, end } of hap.context.locations) { for (let { start, end } of hap.context.locations) {
let id = `${start}:${end}`; let id = `${start}:${end}`;
if (!haps.has(id) || haps.get(id).whole.begin.lt(hap.whole.begin)) { if (!haps.has(id) || haps.get(id).whole.begin.lt(hap.whole.begin)) {
@@ -64,7 +67,6 @@ const visibleMiniLocations = StateField.define({
} }
} }
} }
visible = { atTime: e.value.atTime, haps }; visible = { atTime: e.value.atTime, haps };
} }
} }
+3 -4
View File
@@ -1,11 +1,10 @@
{ {
"name": "@strudel/codemirror", "name": "@strudel/codemirror",
"version": "0.10.0", "version": "1.0.1",
"description": "Codemirror Extensions for Strudel", "description": "Codemirror Extensions for Strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -45,7 +44,7 @@
"@replit/codemirror-emacs": "^6.0.1", "@replit/codemirror-emacs": "^6.0.1",
"@replit/codemirror-vim": "^6.1.0", "@replit/codemirror-vim": "^6.1.0",
"@replit/codemirror-vscode-keymap": "^6.0.2", "@replit/codemirror-vscode-keymap": "^6.0.2",
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@uiw/codemirror-themes": "^4.21.21", "@uiw/codemirror-themes": "^4.21.21",
"@uiw/codemirror-themes-all": "^4.21.21", "@uiw/codemirror-themes-all": "^4.21.21",
"nanostores": "^0.9.5" "nanostores": "^0.9.5"
+1 -1
View File
@@ -1,4 +1,4 @@
import { ref, pure } from '@strudel.cycles/core'; import { ref, pure } from '@strudel/core';
import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view'; import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view';
import { StateEffect, StateField } from '@codemirror/state'; import { StateEffect, StateField } from '@codemirror/state';
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+4 -6
View File
@@ -1,19 +1,17 @@
# @strudel.cycles/core # @strudel/core
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/core](https://www.npmjs.com/package/@strudel/core).
This package contains the bare essence of strudel. This package contains the bare essence of strudel.
## Install ## Install
```sh ```sh
npm i @strudel.cycles/core --save npm i @strudel/core --save
``` ```
## Example ## Example
```js ```js
import { sequence } from '@strudel.cycles/core'; import { sequence } from '@strudel/core';
const pattern = sequence('a', ['b', 'c']); const pattern = sequence('a', ['b', 'c']);
@@ -35,7 +33,7 @@ b: 3/2 - 7/4
c: 7/4 - 2 c: 7/4 - 2
``` ```
- [play with @strudel.cycles/core on codesandbox](https://codesandbox.io/s/strudel-core-test-forked-9ywhv7?file=/src/index.js). - [play with @strudel/core on codesandbox](https://codesandbox.io/s/strudel-core-test-forked-9ywhv7?file=/src/index.js).
- [open color pattern example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/canvas.html) - [open color pattern example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/canvas.html)
- [open minimal repl example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/vanilla.html) - [open minimal repl example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/vanilla.html)
- [open minimal vite example](./examples/vite-vanilla-repl/) - [open minimal vite example](./examples/vite-vanilla-repl/)
+80 -76
View File
@@ -40,7 +40,7 @@ const generic_params = [
* @name n * @name n
* @param {number | Pattern} value sample index starting from 0 * @param {number | Pattern} value sample index starting from 0
* @example * @example
* s("bd sd,hh*3").n("<0 1>") * s("bd sd [~ bd] sd,hh*6").n("<0 1>")
*/ */
// also see https://github.com/tidalcycles/strudel/pull/63 // also see https://github.com/tidalcycles/strudel/pull/63
['n'], ['n'],
@@ -82,7 +82,7 @@ const generic_params = [
* @name gain * @name gain
* @param {number | Pattern} amount gain. * @param {number | Pattern} amount gain.
* @example * @example
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1") * s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
* *
*/ */
['gain'], ['gain'],
@@ -91,13 +91,13 @@ const generic_params = [
* *
* @name postgain * @name postgain
* @example * @example
* s("bd sd,hh*4") * s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02").postgain(1.5) * .compressor("-20:20:10:.002:.02").postgain(1.5)
* *
*/ */
['postgain'], ['postgain'],
/** /**
* Like {@link gain}, but linear. * Like `gain`, but linear.
* *
* @name amp * @name amp
* @param {number | Pattern} amount gain. * @param {number | Pattern} amount gain.
@@ -114,7 +114,7 @@ const generic_params = [
* @param {number | Pattern} attack time in seconds. * @param {number | Pattern} attack time in seconds.
* @synonyms att * @synonyms att
* @example * @example
* note("c3 e3").attack("<0 .1 .5>") * note("c3 e3 f3 g3").attack("<0 .1 .5>")
* *
*/ */
['attack', 'att'], ['attack', 'att'],
@@ -128,7 +128,7 @@ const generic_params = [
* @name fmh * @name fmh
* @param {number | Pattern} harmonicity * @param {number | Pattern} harmonicity
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmh("<1 2 1.5 1.61>") * .fmh("<1 2 1.5 1.61>")
* .scope() * .scope()
@@ -143,7 +143,7 @@ const generic_params = [
* @param {number | Pattern} brightness modulation index * @param {number | Pattern} brightness modulation index
* @synonyms fmi * @synonyms fmi
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm("<0 1 2 8 32>") * .fm("<0 1 2 8 32>")
* .scope() * .scope()
* *
@@ -156,7 +156,7 @@ const generic_params = [
* @name fmenv * @name fmenv
* @param {number | Pattern} type lin | exp * @param {number | Pattern} type lin | exp
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay(.2) * .fmdecay(.2)
* .fmsustain(0) * .fmsustain(0)
@@ -171,7 +171,7 @@ const generic_params = [
* @name fmattack * @name fmattack
* @param {number | Pattern} time attack time * @param {number | Pattern} time attack time
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmattack("<0 .05 .1 .2>") * .fmattack("<0 .05 .1 .2>")
* .scope() * .scope()
@@ -184,7 +184,7 @@ const generic_params = [
* @name fmdecay * @name fmdecay
* @param {number | Pattern} time decay time * @param {number | Pattern} time decay time
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay("<.01 .05 .1 .2>") * .fmdecay("<.01 .05 .1 .2>")
* .fmsustain(.4) * .fmsustain(.4)
@@ -198,7 +198,7 @@ const generic_params = [
* @name fmsustain * @name fmsustain
* @param {number | Pattern} level sustain level * @param {number | Pattern} level sustain level
* @example * @example
* note("c e g b") * note("c e g b g e")
* .fm(4) * .fm(4)
* .fmdecay(.1) * .fmdecay(.1)
* .fmsustain("<1 .75 .5 0>") * .fmsustain("<1 .75 .5 0>")
@@ -216,7 +216,7 @@ const generic_params = [
* @name bank * @name bank
* @param {string | Pattern} bank the name of the bank * @param {string | Pattern} bank the name of the bank
* @example * @example
* s("bd sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd") * s("bd sd [~ bd] sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd")
* *
*/ */
['bank'], ['bank'],
@@ -231,7 +231,7 @@ const generic_params = [
* @name decay * @name decay
* @param {number | Pattern} time decay time in seconds * @param {number | Pattern} time decay time in seconds
* @example * @example
* note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0) * note("c3 e3 f3 g3").decay("<.1 .2 .3 .4>").sustain(0)
* *
*/ */
['decay', 'dec'], ['decay', 'dec'],
@@ -242,7 +242,7 @@ const generic_params = [
* @param {number | Pattern} gain sustain level between 0 and 1 * @param {number | Pattern} gain sustain level between 0 and 1
* @synonyms sus * @synonyms sus
* @example * @example
* note("c3 e3").decay(.2).sustain("<0 .1 .4 .6 1>") * note("c3 e3 f3 g3").decay(.2).sustain("<0 .1 .4 .6 1>")
* *
*/ */
['sustain', 'sus'], ['sustain', 'sus'],
@@ -267,7 +267,7 @@ const generic_params = [
* @param {number | Pattern} frequency center frequency * @param {number | Pattern} frequency center frequency
* @synonyms bandf, bp * @synonyms bandf, bp
* @example * @example
* s("bd sd,hh*3").bpf("<1000 2000 4000 8000>") * s("bd sd [~ bd] sd,hh*6").bpf("<1000 2000 4000 8000>")
* *
*/ */
[['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'], [['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'],
@@ -279,7 +279,7 @@ const generic_params = [
* @param {number | Pattern} q q factor * @param {number | Pattern} q q factor
* @synonyms bandq * @synonyms bandq
* @example * @example
* s("bd sd").bpf(500).bpq("<0 1 2 3>") * s("bd sd [~ bd] sd").bpf(500).bpq("<0 1 2 3>")
* *
*/ */
// currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'bandq' https://github.com/tidalcycles/strudel/issues/496
@@ -293,7 +293,7 @@ const generic_params = [
* @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample * @param {number | Pattern} amount between 0 and 1, where 1 is the length of the sample
* @example * @example
* samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/') * samples({ rave: 'rave/AREUREADY.wav' }, 'github:tidalcycles/Dirt-Samples/master/')
* s("rave").begin("<0 .25 .5 .75>") * s("rave").begin("<0 .25 .5 .75>").fast(2)
* *
*/ */
['begin'], ['begin'],
@@ -304,7 +304,7 @@ const generic_params = [
* @name end * @name end
* @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc.. * @param {number | Pattern} length 1 = whole sample, .5 = half sample, .25 = quarter sample etc..
* @example * @example
* s("bd*2,oh*4").end("<.1 .2 .5 1>") * s("bd*2,oh*4").end("<.1 .2 .5 1>").fast(2)
* *
*/ */
['end'], ['end'],
@@ -376,7 +376,7 @@ const generic_params = [
* @name coarse * @name coarse
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on. * @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
* @example * @example
* s("bd sd,hh*4").coarse("<1 4 8 16 32>") * s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
* *
*/ */
['coarse'], ['coarse'],
@@ -463,7 +463,7 @@ const generic_params = [
* @name cut * @name cut
* @param {number | Pattern} group cut group number * @param {number | Pattern} group cut group number
* @example * @example
* s("rd*4").cut(1) * s("[oh hh]*4").cut(1)
* *
*/ */
['cut'], ['cut'],
@@ -476,9 +476,9 @@ const generic_params = [
* @param {number | Pattern} frequency audible between 0 and 20000 * @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms cutoff, ctf, lp * @synonyms cutoff, ctf, lp
* @example * @example
* s("bd sd,hh*3").lpf("<4000 2000 1000 500 200 100>") * s("bd sd [~ bd] sd,hh*6").lpf("<4000 2000 1000 500 200 100>")
* @example * @example
* s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30") * s("bd*16").lpf("1000:0 1000:10 1000:20 1000:30")
* *
*/ */
[['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'], [['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'],
@@ -489,7 +489,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
* @synonyms lpe * @synonyms lpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpa(.5) * .lpa(.5)
@@ -502,7 +502,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
* @synonyms hpe * @synonyms hpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpa(.5) * .hpa(.5)
@@ -515,7 +515,7 @@ const generic_params = [
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_ * @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
* @synonyms bpe * @synonyms bpe
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpa(.5) * .bpa(.5)
@@ -528,7 +528,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the filter envelope * @param {number | Pattern} attack time of the filter envelope
* @synonyms lpa * @synonyms lpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpa("<.5 .25 .1 .01>/4") * .lpa("<.5 .25 .1 .01>/4")
@@ -541,7 +541,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the highpass filter envelope * @param {number | Pattern} attack time of the highpass filter envelope
* @synonyms hpa * @synonyms hpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpa("<.5 .25 .1 .01>/4") * .hpa("<.5 .25 .1 .01>/4")
@@ -554,7 +554,7 @@ const generic_params = [
* @param {number | Pattern} attack time of the bandpass filter envelope * @param {number | Pattern} attack time of the bandpass filter envelope
* @synonyms bpa * @synonyms bpa
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpa("<.5 .25 .1 .01>/4") * .bpa("<.5 .25 .1 .01>/4")
@@ -567,7 +567,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the filter envelope * @param {number | Pattern} decay time of the filter envelope
* @synonyms lpd * @synonyms lpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpd("<.5 .25 .1 0>/4") * .lpd("<.5 .25 .1 0>/4")
@@ -581,7 +581,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the highpass filter envelope * @param {number | Pattern} decay time of the highpass filter envelope
* @synonyms hpd * @synonyms hpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpd("<.5 .25 .1 0>/4") * .hpd("<.5 .25 .1 0>/4")
@@ -595,7 +595,7 @@ const generic_params = [
* @param {number | Pattern} decay time of the bandpass filter envelope * @param {number | Pattern} decay time of the bandpass filter envelope
* @synonyms bpd * @synonyms bpd
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpd("<.5 .25 .1 0>/4") * .bpd("<.5 .25 .1 0>/4")
@@ -609,7 +609,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope * @param {number | Pattern} sustain amplitude of the lowpass filter envelope
* @synonyms lps * @synonyms lps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .lpd(.5) * .lpd(.5)
@@ -623,7 +623,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the highpass filter envelope * @param {number | Pattern} sustain amplitude of the highpass filter envelope
* @synonyms hps * @synonyms hps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .hpf(500) * .hpf(500)
* .hpd(.5) * .hpd(.5)
@@ -637,7 +637,7 @@ const generic_params = [
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope * @param {number | Pattern} sustain amplitude of the bandpass filter envelope
* @synonyms bps * @synonyms bps
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .bpf(500) * .bpf(500)
* .bpd(.5) * .bpd(.5)
@@ -651,7 +651,7 @@ const generic_params = [
* @param {number | Pattern} release time of the filter envelope * @param {number | Pattern} release time of the filter envelope
* @synonyms lpr * @synonyms lpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .lpf(500) * .lpf(500)
@@ -666,7 +666,7 @@ const generic_params = [
* @param {number | Pattern} release time of the highpass filter envelope * @param {number | Pattern} release time of the highpass filter envelope
* @synonyms hpr * @synonyms hpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .hpf(500) * .hpf(500)
@@ -681,7 +681,7 @@ const generic_params = [
* @param {number | Pattern} release time of the bandpass filter envelope * @param {number | Pattern} release time of the bandpass filter envelope
* @synonyms bpr * @synonyms bpr
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .clip(.5) * .clip(.5)
* .bpf(500) * .bpf(500)
@@ -695,11 +695,11 @@ const generic_params = [
* @name ftype * @name ftype
* @param {number | Pattern} type 12db (default) or 24db * @param {number | Pattern} type 12db (default) or 24db
* @example * @example
* note("<c2 e2 f2 g2>") * note("c2 e2 f2 g2")
* .sound('sawtooth') * .sound('sawtooth')
* .lpf(500) * .lpf(500)
* .bpenv(4) * .bpenv(4)
* .ftype("<12db 24db>") * .ftype("12db 24db")
*/ */
['ftype'], ['ftype'],
['fanchor'], ['fanchor'],
@@ -712,9 +712,9 @@ const generic_params = [
* @param {number | Pattern} frequency audible between 0 and 20000 * @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms hp, hcutoff * @synonyms hp, hcutoff
* @example * @example
* s("bd sd,hh*4").hpf("<4000 2000 1000 500 200 100>") * s("bd sd [~ bd] sd,hh*8").hpf("<4000 2000 1000 500 200 100>")
* @example * @example
* s("bd sd,hh*4").hpf("<2000 2000:25>") * s("bd sd [~ bd] sd,hh*8").hpf("<2000 2000:25>")
* *
*/ */
// currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'hcutoff' https://github.com/tidalcycles/strudel/issues/496
@@ -726,11 +726,11 @@ const generic_params = [
* @synonyms vibrato, v * @synonyms vibrato, v
* @param {number | Pattern} frequency of the vibrato in hertz * @param {number | Pattern} frequency of the vibrato in hertz
* @example * @example
* note("a") * note("a e")
* .vib("<.5 1 2 4 8 16>") * .vib("<.5 1 2 4 8 16>")
* @example * @example
* // change the modulation depth with ":" * // change the modulation depth with ":"
* note("a") * note("a e")
* .vib("<.5 1 2 4 8 16>:12") * .vib("<.5 1 2 4 8 16>:12")
*/ */
[['vib', 'vibmod'], 'vibrato', 'v'], [['vib', 'vibmod'], 'vibrato', 'v'],
@@ -750,11 +750,11 @@ const generic_params = [
* @synonyms vmod * @synonyms vmod
* @param {number | Pattern} depth of vibrato (in semitones) * @param {number | Pattern} depth of vibrato (in semitones)
* @example * @example
* note("a").vib(4) * note("a e").vib(4)
* .vibmod("<.25 .5 1 2 12>") * .vibmod("<.25 .5 1 2 12>")
* @example * @example
* // change the vibrato frequency with ":" * // change the vibrato frequency with ":"
* note("a") * note("a e")
* .vibmod("<.25 .5 1 2 12>:8") * .vibmod("<.25 .5 1 2 12>:8")
*/ */
[['vibmod', 'vib'], 'vmod'], [['vibmod', 'vib'], 'vmod'],
@@ -766,7 +766,7 @@ const generic_params = [
* @param {number | Pattern} q resonance factor between 0 and 50 * @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms hresonance * @synonyms hresonance
* @example * @example
* s("bd sd,hh*4").hpf(2000).hpq("<0 10 20 30>") * s("bd sd [~ bd] sd,hh*8").hpf(2000).hpq("<0 10 20 30>")
* *
*/ */
['hresonance', 'hpq'], ['hresonance', 'hpq'],
@@ -777,7 +777,7 @@ const generic_params = [
* @param {number | Pattern} q resonance factor between 0 and 50 * @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms resonance * @synonyms resonance
* @example * @example
* s("bd sd,hh*4").lpf(2000).lpq("<0 10 20 30>") * s("bd sd [~ bd] sd,hh*8").lpf(2000).lpq("<0 10 20 30>")
* *
*/ */
// currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496 // currently an alias of 'resonance' https://github.com/tidalcycles/strudel/issues/496
@@ -804,7 +804,7 @@ const generic_params = [
* @name delay * @name delay
* @param {number | Pattern} level between 0 and 1 * @param {number | Pattern} level between 0 and 1
* @example * @example
* s("bd").delay("<0 .25 .5 1>") * s("bd bd").delay("<0 .25 .5 1>")
* @example * @example
* s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7") * s("bd bd").delay("0.65:0.25:0.9 0.65:0.125:0.7")
* *
@@ -818,7 +818,7 @@ const generic_params = [
* @param {number | Pattern} feedback between 0 and 1 * @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb * @synonyms delayfb, dfb
* @example * @example
* s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>").slow(2) * s("bd").delay(.25).delayfeedback("<.25 .5 .75 1>")
* *
*/ */
['delayfeedback', 'delayfb', 'dfb'], ['delayfeedback', 'delayfb', 'dfb'],
@@ -829,7 +829,7 @@ const generic_params = [
* @param {number | Pattern} seconds between 0 and Infinity * @param {number | Pattern} seconds between 0 and Infinity
* @synonyms delayt, dt * @synonyms delayt, dt
* @example * @example
* s("bd").delay(.25).delaytime("<.125 .25 .5 1>").slow(2) * s("bd bd").delay(.25).delaytime("<.125 .25 .5 1>")
* *
*/ */
['delaytime', 'delayt', 'dt'], ['delaytime', 'delayt', 'dt'],
@@ -856,7 +856,7 @@ const generic_params = [
*/ */
['detune', 'det'], ['detune', 'det'],
/** /**
* Set dryness of reverb. See {@link room} and {@link size} for more information about reverb. * Set dryness of reverb. See `room` and `size` for more information about reverb.
* *
* @name dry * @name dry
* @param {number | Pattern} dry 0 = wet, 1 = dry * @param {number | Pattern} dry 0 = wet, 1 = dry
@@ -868,7 +868,7 @@ const generic_params = [
['dry'], ['dry'],
// TODO: does not seem to do anything // TODO: does not seem to do anything
/* /*
* Used when using {@link begin}/{@link end} or {@link chop}/{@link striate} and friends, to change the fade out time of the 'grain' envelope. * Used when using `begin`/`end` or `chop`/`striate` and friends, to change the fade out time of the 'grain' envelope.
* *
* @name fadeTime * @name fadeTime
* @param {number | Pattern} time between 0 and 1 * @param {number | Pattern} time between 0 and 1
@@ -899,7 +899,7 @@ const generic_params = [
* @synonyms patt * @synonyms patt
* @param {number | Pattern} time time in seconds * @param {number | Pattern} time time in seconds
* @example * @example
* note("<c eb g bb>").pattack("<0 .1 .25 .5>") * note("c eb g bb").pattack("0 .1 .25 .5").slow(2)
* *
*/ */
['pattack', 'patt'], ['pattack', 'patt'],
@@ -947,7 +947,7 @@ const generic_params = [
* @name pcurve * @name pcurve
* @param {number | Pattern} type 0 = linear, 1 = exponential * @param {number | Pattern} type 0 = linear, 1 = exponential
* @example * @example
* note("g1*2") * note("g1*4")
* .s("sine").pdec(.5) * .s("sine").pdec(.5)
* .penv(32) * .penv(32)
* .pcurve("<0 1>") * .pcurve("<0 1>")
@@ -963,7 +963,7 @@ const generic_params = [
* @name panchor * @name panchor
* @param {number | Pattern} anchor anchor offset * @param {number | Pattern} anchor anchor offset
* @example * @example
* note("c").penv(12).panchor("<0 .5 1 .5>") * note("c c4").penv(12).panchor("<0 .5 1 .5>")
* *
*/ */
['panchor'], ['panchor'],
@@ -1062,8 +1062,8 @@ const generic_params = [
* @param {number | Pattern} number * @param {number | Pattern} number
* @example * @example
* stack( * stack(
* s("hh*3").delay(.5).delaytime(.25).orbit(1), * s("hh*6").delay(.5).delaytime(.25).orbit(1),
* s("~ sd").delay(.5).delaytime(.125).orbit(2) * s("~ sd ~ sd").delay(.5).delaytime(.125).orbit(2)
* ) * )
*/ */
['orbit'], ['orbit'],
@@ -1076,6 +1076,8 @@ const generic_params = [
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel) * @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
* @example * @example
* s("[bd hh]*2").pan("<.5 1 .5 0>") * s("[bd hh]*2").pan("<.5 1 .5 0>")
* @example
* s("bd rim sd rim bd ~ cp rim").pan(sine.slow(2))
* *
*/ */
['pan'], ['pan'],
@@ -1133,9 +1135,9 @@ const generic_params = [
* @name room * @name room
* @param {number | Pattern} level between 0 and 1 * @param {number | Pattern} level between 0 and 1
* @example * @example
* s("bd sd").room("<0 .2 .4 .6 .8 1>") * s("bd sd [~ bd] sd").room("<0 .2 .4 .6 .8 1>")
* @example * @example
* s("bd sd").room("<0.9:1 0.9:4>") * s("bd sd [~ bd] sd").room("<0.9:1 0.9:4>")
* *
*/ */
[['room', 'size']], [['room', 'size']],
@@ -1147,9 +1149,9 @@ const generic_params = [
* @synonyms rlp * @synonyms rlp
* @param {number} frequency between 0 and 20000hz * @param {number} frequency between 0 and 20000hz
* @example * @example
* s("bd sd").room(0.5).rlp(10000) * s("bd sd [~ bd] sd").room(0.5).rlp(10000)
* @example * @example
* s("bd sd").room(0.5).rlp(5000) * s("bd sd [~ bd] sd").room(0.5).rlp(5000)
*/ */
['roomlp', 'rlp'], ['roomlp', 'rlp'],
/** /**
@@ -1160,9 +1162,9 @@ const generic_params = [
* @synonyms rdim * @synonyms rdim
* @param {number} frequency between 0 and 20000hz * @param {number} frequency between 0 and 20000hz
* @example * @example
* s("bd sd").room(0.5).rlp(10000).rdim(8000) * s("bd sd [~ bd] sd").room(0.5).rlp(10000).rdim(8000)
* @example * @example
* s("bd sd").room(0.5).rlp(5000).rdim(400) * s("bd sd [~ bd] sd").room(0.5).rlp(5000).rdim(400)
* *
*/ */
['roomdim', 'rdim'], ['roomdim', 'rdim'],
@@ -1174,9 +1176,9 @@ const generic_params = [
* @synonyms rfade * @synonyms rfade
* @param {number} seconds for the reverb to fade * @param {number} seconds for the reverb to fade
* @example * @example
* s("bd sd").room(0.5).rlp(10000).rfade(0.5) * s("bd sd [~ bd] sd").room(0.5).rlp(10000).rfade(0.5)
* @example * @example
* s("bd sd").room(0.5).rlp(5000).rfade(4) * s("bd sd [~ bd] sd").room(0.5).rlp(5000).rfade(4)
* *
*/ */
['roomfade', 'rfade'], ['roomfade', 'rfade'],
@@ -1186,25 +1188,25 @@ const generic_params = [
* @param {string | Pattern} sample to use as an impulse response * @param {string | Pattern} sample to use as an impulse response
* @synonyms ir * @synonyms ir
* @example * @example
* s("bd sd").room(.8).ir("<shaker_large:0 shaker_large:2>") * s("bd sd [~ bd] sd").room(.8).ir("<shaker_large:0 shaker_large:2>")
* *
*/ */
[['ir', 'i'], 'iresponse'], [['ir', 'i'], 'iresponse'],
/** /**
* Sets the room size of the reverb, see {@link room}. * Sets the room size of the reverb, see `room`.
* When this property is changed, the reverb will be recaculated, so only change this sparsely.. * When this property is changed, the reverb will be recaculated, so only change this sparsely..
* *
* @name roomsize * @name roomsize
* @param {number | Pattern} size between 0 and 10 * @param {number | Pattern} size between 0 and 10
* @synonyms rsize, sz, size * @synonyms rsize, sz, size
* @example * @example
* s("bd sd").room(.8).rsize(1) * s("bd sd [~ bd] sd").room(.8).rsize(1)
* @example * @example
* s("bd sd").room(.8).rsize(4) * s("bd sd [~ bd] sd").room(.8).rsize(4)
* *
*/ */
// TODO: find out why : // TODO: find out why :
// s("bd sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc() // s("bd sd [~ bd] sd").room(.8).roomsize("<0 .2 .4 .6 .8 [1,0]>").osc()
// .. does not work. Is it because room is only one effect? // .. does not work. Is it because room is only one effect?
['roomsize', 'size', 'sz', 'rsize'], ['roomsize', 'size', 'sz', 'rsize'],
// ['sagogo'], // ['sagogo'],
@@ -1217,7 +1219,7 @@ const generic_params = [
* @name shape * @name shape
* @param {number | Pattern} distortion between 0 and 1 * @param {number | Pattern} distortion between 0 and 1
* @example * @example
* s("bd sd,hh*4").shape("<0 .2 .4 .6 .8>") * s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
* *
*/ */
['shape'], ['shape'],
@@ -1227,7 +1229,7 @@ const generic_params = [
* *
* @name compressor * @name compressor
* @example * @example
* s("bd sd,hh*4") * s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02") * .compressor("-20:20:10:.002:.02")
* *
*/ */
@@ -1242,14 +1244,14 @@ const generic_params = [
* @name speed * @name speed
* @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards. * @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards.
* @example * @example
* s("bd").speed("<1 2 4 1 -2 -4>") * s("bd*6").speed("1 2 4 1 -2 -4")
* @example * @example
* speed("1 1.5*2 [2 1.1]").s("piano").clip(1) * speed("1 1.5*2 [2 1.1]").s("piano").clip(1)
* *
*/ */
['speed'], ['speed'],
/** /**
* Used in conjunction with {@link speed}, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`. * Used in conjunction with `speed`, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.
* *
* @name unit * @name unit
* @param {number | string | Pattern} unit see description above * @param {number | string | Pattern} unit see description above
@@ -1287,8 +1289,10 @@ const generic_params = [
* @name vowel * @name vowel
* @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ. * @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ.
* @example * @example
* note("c2 <eb2 <g2 g1>>").s('sawtooth') * note("[c2 <eb2 <g2 g1>>]*2").s('sawtooth')
* .vowel("<a e i <o u>>") * .vowel("<a e i <o u>>")
* @example
* s("bd sd mt ht bd [~ cp] ht lt").vowel("[a|e|i|o|u]")
* *
*/ */
['vowel'], ['vowel'],
@@ -1463,7 +1467,7 @@ controls.createParams = (...names) =>
* @param {number | Pattern} gain sustain level (0 to 1) * @param {number | Pattern} gain sustain level (0 to 1)
* @param {number | Pattern} time release time in seconds * @param {number | Pattern} time release time in seconds
* @example * @example
* note("<c3 bb2 f3 eb3>").sound("sawtooth").lpf(600).adsr(".1:.1:.5:.2") * note("[c3 bb2 f3 eb3]*2").sound("sawtooth").lpf(600).adsr(".1:.1:.5:.2")
*/ */
controls.adsr = register('adsr', (adsr, pat) => { controls.adsr = register('adsr', (adsr, pat) => {
adsr = !Array.isArray(adsr) ? [adsr] : adsr; adsr = !Array.isArray(adsr) ? [adsr] : adsr;
+3 -3
View File
@@ -10,7 +10,7 @@ import { logger } from './logger.mjs';
export class Cyclist { export class Cyclist {
constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) { constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) {
this.started = false; this.started = false;
this.cps = 1; this.cps = 0.5;
this.num_ticks_since_cps_change = 0; this.num_ticks_since_cps_change = 0;
this.lastTick = 0; // absolute time when last tick (clock callback) happened this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.lastBegin = 0; // query begin of last tick this.lastBegin = 0; // query begin of last tick
@@ -41,7 +41,7 @@ export class Cyclist {
this.lastEnd = end; this.lastEnd = end;
// query the pattern for events // query the pattern for events
const haps = this.pattern.queryArc(begin, end); const haps = this.pattern.queryArc(begin, end, { _cps: this.cps });
const tickdeadline = phase - time; // time left until the phase is a whole number const tickdeadline = phase - time; // time left until the phase is a whole number
this.lastTick = time + tickdeadline; this.lastTick = time + tickdeadline;
@@ -96,7 +96,7 @@ export class Cyclist {
this.start(); this.start();
} }
} }
setCps(cps = 1) { setCps(cps = 0.5) {
if (this.cps === cps) { if (this.cps === cps) {
return; return;
} }
+1 -1
View File
@@ -134,7 +134,7 @@ export class Drawer {
this.lastFrame = phase; this.lastFrame = phase;
this.visibleHaps = (this.visibleHaps || []) this.visibleHaps = (this.visibleHaps || [])
// filter out haps that are too far in the past (think left edge of screen for pianoroll) // filter out haps that are too far in the past (think left edge of screen for pianoroll)
.filter((h) => h.whole.end >= phase - lookbehind - lookahead) .filter((h) => h.whole?.end >= phase - lookbehind - lookahead)
// add new haps with onset (think right edge bars scrolling in) // add new haps with onset (think right edge bars scrolling in)
.concat(haps.filter((h) => h.hasOnset())); .concat(haps.filter((h) => h.hasOnset()));
const time = phase - lookahead; const time = phase - lookahead;
+1 -1
View File
@@ -148,7 +148,7 @@ export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], fun
* @param {number} pulses the number of onsets / beats * @param {number} pulses the number of onsets / beats
* @param {number} steps the number of steps to fill * @param {number} steps the number of steps to fill
* @example * @example
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8) * note("c3").euclidLegato(3,8)
*/ */
const _euclidLegato = function (pulses, steps, rotation, pat) { const _euclidLegato = function (pulses, steps, rotation, pat) {
+3 -3
View File
@@ -30,12 +30,12 @@ export { default as drawLine } from './drawLine.mjs';
// below won't work with runtime.mjs (json import fails) // below won't work with runtime.mjs (json import fails)
/* import * as p from './package.json'; /* import * as p from './package.json';
export const version = p.version; */ export const version = p.version; */
logger('🌀 @strudel.cycles/core loaded 🌀'); logger('🌀 @strudel/core loaded 🌀');
if (globalThis._strudelLoaded) { if (globalThis._strudelLoaded) {
console.warn( console.warn(
`@strudel.cycles/core was loaded more than once... `@strudel/core was loaded more than once...
This might happen when you have multiple versions of strudel installed. This might happen when you have multiple versions of strudel installed.
Please check with "npm ls @strudel.cycles/core".`, Please check with "npm ls @strudel/core".`,
); );
} }
globalThis._strudelLoaded = true; globalThis._strudelLoaded = true;
+3 -4
View File
@@ -1,12 +1,11 @@
{ {
"name": "@strudel.cycles/core", "name": "@strudel/core",
"version": "0.10.0", "version": "1.0.1",
"description": "Port of Tidal Cycles to JavaScript", "description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run",
+122 -101
View File
@@ -26,7 +26,7 @@ export class Pattern {
/** /**
* Create a pattern. As an end user, you will most likely not create a Pattern directly. * Create a pattern. As an end user, you will most likely not create a Pattern directly.
* *
* @param {function} query - The function that maps a {@link State} to an array of {@link Hap}. * @param {function} query - The function that maps a `State` to an array of `Hap`.
* @noAutocomplete * @noAutocomplete
*/ */
constructor(query) { constructor(query) {
@@ -39,7 +39,7 @@ export class Pattern {
/** /**
* Returns a new pattern, with the function applied to the value of * Returns a new pattern, with the function applied to the value of
* each hap. It has the alias {@link Pattern#fmap}. * each hap. It has the alias `fmap`.
* @synonyms fmap * @synonyms fmap
* @param {Function} func to to apply to the value * @param {Function} func to to apply to the value
* @returns Pattern * @returns Pattern
@@ -51,7 +51,7 @@ export class Pattern {
} }
/** /**
* see {@link Pattern#withValue} * see `withValue`
* @noAutocomplete * @noAutocomplete
*/ */
fmap(func) { fmap(func) {
@@ -115,7 +115,7 @@ export class Pattern {
} }
/** /**
* As with {@link Pattern#appBoth}, but the `whole` timespan is not the intersection, * As with `appBoth`, but the `whole` timespan is not the intersection,
* but the timespan from the function of patterns that this method is called * but the timespan from the function of patterns that this method is called
* on. In practice, this means that the pattern structure, including onsets, * on. In practice, this means that the pattern structure, including onsets,
* are preserved from the pattern of functions (often referred to as the left * are preserved from the pattern of functions (often referred to as the left
@@ -148,7 +148,7 @@ export class Pattern {
} }
/** /**
* As with {@link Pattern#appLeft}, but `whole` timespans are instead taken from the * As with `appLeft`, but `whole` timespans are instead taken from the
* pattern of values, i.e. structure is preserved from the right hand/outer * pattern of values, i.e. structure is preserved from the right hand/outer
* pattern. * pattern.
* @param {Pattern} pat_val * @param {Pattern} pat_val
@@ -340,9 +340,9 @@ export class Pattern {
* silence * silence
* @noAutocomplete * @noAutocomplete
*/ */
queryArc(begin, end) { queryArc(begin, end, controls = {}) {
try { try {
return this.query(new State(new TimeSpan(begin, end))); return this.query(new State(new TimeSpan(begin, end), controls));
} catch (err) { } catch (err) {
logger(`[query]: ${err.message}`, 'error'); logger(`[query]: ${err.message}`, 'error');
return []; return [];
@@ -387,7 +387,7 @@ export class Pattern {
} }
/** /**
* As with {@link Pattern#withQuerySpan}, but the function is applied to both the * As with `withQuerySpan`, but the function is applied to both the
* begin and end time of the query timespan. * begin and end time of the query timespan.
* @param {Function} func the function to apply * @param {Function} func the function to apply
* @returns Pattern * @returns Pattern
@@ -398,7 +398,7 @@ export class Pattern {
} }
/** /**
* Similar to {@link Pattern#withQuerySpan}, but the function is applied to the timespans * Similar to `withQuerySpan`, but the function is applied to the timespans
* of all haps returned by pattern queries (both `part` timespans, and where * of all haps returned by pattern queries (both `part` timespans, and where
* present, `whole` timespans). * present, `whole` timespans).
* @param {Function} func * @param {Function} func
@@ -410,7 +410,7 @@ export class Pattern {
} }
/** /**
* As with {@link Pattern#withHapSpan}, but the function is applied to both the * As with `withHapSpan`, but the function is applied to both the
* begin and end time of the hap timespans. * begin and end time of the hap timespans.
* @param {Function} func the function to apply * @param {Function} func the function to apply
* @returns Pattern * @returns Pattern
@@ -427,11 +427,11 @@ export class Pattern {
* @noAutocomplete * @noAutocomplete
*/ */
withHaps(func) { withHaps(func) {
return new Pattern((state) => func(this.query(state))); return new Pattern((state) => func(this.query(state), state));
} }
/** /**
* As with {@link Pattern#withHaps}, but applies the function to every hap, rather than every list of haps. * As with `withHaps`, but applies the function to every hap, rather than every list of haps.
* @param {Function} func * @param {Function} func
* @returns Pattern * @returns Pattern
* @noAutocomplete * @noAutocomplete
@@ -499,7 +499,7 @@ export class Pattern {
} }
/** /**
* As with {@link Pattern#filterHaps}, but the function is applied to values * As with `filterHaps`, but the function is applied to values
* inside haps. * inside haps.
* @param {Function} value_test * @param {Function} value_test
* @returns Pattern * @returns Pattern
@@ -621,7 +621,7 @@ export class Pattern {
} }
/** /**
* More human-readable version of the {@link Pattern#firstCycleValues} accessor. * More human-readable version of the `firstCycleValues` accessor.
* @noAutocomplete * @noAutocomplete
*/ */
get showFirstCycle() { get showFirstCycle() {
@@ -691,13 +691,13 @@ export class Pattern {
// Methods without corresponding toplevel functions // Methods without corresponding toplevel functions
/** /**
* Layers the result of the given function(s). Like {@link Pattern.superimpose}, but without the original pattern: * Layers the result of the given function(s). Like `superimpose`, but without the original pattern:
* @name layer * @name layer
* @memberof Pattern * @memberof Pattern
* @synonyms apply * @synonyms apply
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8"
* .layer(x=>x.add("0,2")) * .layer(x=>x.add("0,2"))
* .scale('C minor').note() * .scale('C minor').note()
*/ */
@@ -711,7 +711,7 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*4" * "<0 2 4 6 ~ 4 ~ 2 0!3 ~!5>*8"
* .superimpose(x=>x.add(2)) * .superimpose(x=>x.add(2))
* .scale('C minor').note() * .scale('C minor').note()
*/ */
@@ -727,8 +727,8 @@ export class Pattern {
* @name stack * @name stack
* @memberof Pattern * @memberof Pattern
* @example * @example
* s("hh*2").stack( * s("hh*4").stack(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
stack(...pats) { stack(...pats) {
@@ -745,8 +745,8 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @synonyms sequence, fastcat * @synonyms sequence, fastcat
* @example * @example
* s("hh*2").seq( * s("hh*4").seq(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
seq(...pats) { seq(...pats) {
@@ -759,8 +759,8 @@ export class Pattern {
* @memberof Pattern * @memberof Pattern
* @synonyms slowcat * @synonyms slowcat
* @example * @example
* s("hh*2").cat( * s("hh*4").cat(
* note("c2(3,8)") * note("c4(5,8)")
* ) * )
*/ */
cat(...pats) { cat(...pats) {
@@ -858,7 +858,7 @@ Pattern.prototype.arpWith = function (func) {
* Selects indices in in stacked notes. * Selects indices in in stacked notes.
* @example * @example
* note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>") * note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>")
* .arp("0 [0,2] 1 [0,2]").slow(2) * .arp("0 [0,2] 1 [0,2]")
* */ * */
Pattern.prototype.arp = function (pat) { Pattern.prototype.arp = function (pat) {
return this.arpWith((haps) => pat.fmap((i) => haps[i % haps.length])); return this.arpWith((haps) => pat.fmap((i) => haps[i % haps.length]));
@@ -929,14 +929,14 @@ function _composeOp(a, b, func) {
* @memberof Pattern * @memberof Pattern
* @example * @example
* // Here, the triad 0, 2, 4 is shifted by different amounts * // Here, the triad 0, 2, 4 is shifted by different amounts
* "0 2 4".add("<0 3 4 0>").scale('C major').note() * n("0 2 4".add("<0 3 4 0>")).scale("C:major")
* // Without add, the equivalent would be: * // Without add, the equivalent would be:
* // "<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>".scale('C major').note() * // n("<[0 2 4] [3 5 7] [4 6 8] [0 2 4]>").scale("C:major")
* @example * @example
* // You can also use add with notes: * // You can also use add with notes:
* "c3 e3 g3".add("<0 5 7 0>").note() * note("c3 e3 g3".add("<0 5 7 0>"))
* // Behind the scenes, the notes are converted to midi numbers: * // Behind the scenes, the notes are converted to midi numbers:
* // "48 52 55".add("<0 5 7 0>").note() * // note("48 52 55".add("<0 5 7 0>"))
*/ */
add: [numeralArgs((a, b) => a + b)], // support string concatenation add: [numeralArgs((a, b) => a + b)], // support string concatenation
/** /**
@@ -945,7 +945,7 @@ function _composeOp(a, b, func) {
* @name sub * @name sub
* @memberof Pattern * @memberof Pattern
* @example * @example
* "0 2 4".sub("<0 1 2 3>").scale('C4 minor').note() * n("0 2 4".sub("<0 1 2 3>")).scale("C4:minor")
* // See add for more information. * // See add for more information.
*/ */
sub: [numeralArgs((a, b) => a - b)], sub: [numeralArgs((a, b) => a - b)],
@@ -955,7 +955,7 @@ function _composeOp(a, b, func) {
* @name mul * @name mul
* @memberof Pattern * @memberof Pattern
* @example * @example
* "1 1.5 [1.66, <2 2.33>]".mul(150).freq() * "<1 1.5 [1.66, <2 2.33>]>*4".mul(150).freq()
*/ */
mul: [numeralArgs((a, b) => a * b)], mul: [numeralArgs((a, b) => a * b)],
/** /**
@@ -1049,9 +1049,9 @@ function _composeOp(a, b, func) {
* Applies the given structure to the pattern: * Applies the given structure to the pattern:
* *
* @example * @example
* note("c3,eb3,g3") * note("c,eb,g")
* .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~") * .struct("x ~ x ~ ~ x ~ x ~ ~ ~ x ~ x ~ ~")
* .slow(4) * .slow(2)
*/ */
Pattern.prototype.struct = function (...args) { Pattern.prototype.struct = function (...args) {
return this.keepif.out(...args); return this.keepif.out(...args);
@@ -1063,7 +1063,7 @@ function _composeOp(a, b, func) {
* Returns silence when mask is 0 or "~" * Returns silence when mask is 0 or "~"
* *
* @example * @example
* note("c [eb,g] d [eb,g]").mask("<1 [0 1]>").slow(2) * note("c [eb,g] d [eb,g]").mask("<1 [0 1]>")
*/ */
Pattern.prototype.mask = function (...args) { Pattern.prototype.mask = function (...args) {
return this.keepif.in(...args); return this.keepif.in(...args);
@@ -1075,7 +1075,7 @@ function _composeOp(a, b, func) {
* Resets the pattern to the start of the cycle for each onset of the reset pattern. * Resets the pattern to the start of the cycle for each onset of the reset pattern.
* *
* @example * @example
* s("<bd lt> sd, hh*4").reset("<x@3 x(3,8)>") * s("[<bd lt> sd]*2, hh*8").reset("<x@3 x(5,8)>")
*/ */
Pattern.prototype.reset = function (...args) { Pattern.prototype.reset = function (...args) {
return this.keepif.trig(...args); return this.keepif.trig(...args);
@@ -1088,7 +1088,7 @@ function _composeOp(a, b, func) {
* While reset will only reset the current cycle, restart will start from cycle 0. * While reset will only reset the current cycle, restart will start from cycle 0.
* *
* @example * @example
* s("<bd lt> sd, hh*4").restart("<x@3 x(3,8)>") * s("[<bd lt> sd]*2, hh*8").restart("<x@3 x(5,8)>")
*/ */
Pattern.prototype.restart = function (...args) { Pattern.prototype.restart = function (...args) {
return this.keepif.trigzero(...args); return this.keepif.trigzero(...args);
@@ -1154,8 +1154,8 @@ export function isPattern(thing) {
/* if (!thing instanceof Pattern) { /* if (!thing instanceof Pattern) {
console.warn( console.warn(
`Found Pattern that fails "instanceof Pattern" check. `Found Pattern that fails "instanceof Pattern" check.
This may happen if you are using multiple versions of @strudel.cycles/core. This may happen if you are using multiple versions of @strudel/core.
Please check by running "npm ls @strudel.cycles/core".`, Please check by running "npm ls @strudel/core".`,
); );
console.log(thing); console.log(thing);
} */ } */
@@ -1178,7 +1178,8 @@ export function reify(thing) {
* @return {Pattern} * @return {Pattern}
* @synonyms polyrhythm, pr * @synonyms polyrhythm, pr
* @example * @example
* stack("g3", "b3", ["e4", "d4"]).note() // "g3,b3,[e4,d4]".note() * stack("g3", "b3", ["e4", "d4"]).note()
* // "g3,b3,[e4,d4]".note()
*/ */
export function stack(...pats) { export function stack(...pats) {
// Array test here is to avoid infinite recursions.. // Array test here is to avoid infinite recursions..
@@ -1189,7 +1190,7 @@ export function stack(...pats) {
/** Concatenation: combines a list of patterns, switching between them successively, one per cycle: /** Concatenation: combines a list of patterns, switching between them successively, one per cycle:
* *
* synonyms: {@link cat} * synonyms: `cat`
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
@@ -1237,17 +1238,19 @@ export function slowcatPrime(...pats) {
* @synonyms slowcat * @synonyms slowcat
* @return {Pattern} * @return {Pattern}
* @example * @example
* cat("e5", "b4", ["d5", "c5"]).note() // "<e5 b4 [d5 c5]>".note() * cat("e5", "b4", ["d5", "c5"]).note()
* // "<e5 b4 [d5 c5]>".note()
* *
*/ */
export function cat(...pats) { export function cat(...pats) {
return slowcat(...pats); return slowcat(...pats);
} }
/** Like {@link Pattern.seq}, but each step has a length, relative to the whole. /** Like `seq`, but each step has a length, relative to the whole.
* @return {Pattern} * @return {Pattern}
* @example * @example
* timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note() * timeCat([3,"e3"],[1, "g3"]).note()
* // "e3@3 g3".note()
*/ */
export function timeCat(...timepats) { export function timeCat(...timepats) {
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0));
@@ -1267,7 +1270,10 @@ export function timeCat(...timepats) {
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* arrange([4, "<c a f e>(3,8)"],[2, "<g a>(5,8)"]).note() * arrange(
* [4, "<c a f e>(3,8)"],
* [2, "<g a>(5,8)"]
* ).note()
*/ */
export function arrange(...sections) { export function arrange(...sections) {
const total = sections.reduce((sum, [cycles]) => sum + cycles, 0); const total = sections.reduce((sum, [cycles]) => sum + cycles, 0);
@@ -1279,7 +1285,7 @@ export function fastcat(...pats) {
return slowcat(...pats)._fast(pats.length); return slowcat(...pats)._fast(pats.length);
} }
/** See {@link fastcat} */ /** See `fastcat` */
export function sequence(...pats) { export function sequence(...pats) {
return fastcat(...pats); return fastcat(...pats);
} }
@@ -1287,7 +1293,8 @@ export function sequence(...pats) {
/** Like **cat**, but the items are crammed into one cycle. /** Like **cat**, but the items are crammed into one cycle.
* @synonyms fastcat, sequence * @synonyms fastcat, sequence
* @example * @example
* seq("e5", "b4", ["d5", "c5"]).note() // "e5 b4 [d5 c5]".note() * seq("e5", "b4", ["d5", "c5"]).note()
* // "e5 b4 [d5 c5]".note()
* *
*/ */
export function seq(...pats) { export function seq(...pats) {
@@ -1313,9 +1320,9 @@ function _sequenceCount(x) {
* @param {number} steps how many items are placed in one cycle * @param {number} steps how many items are placed in one cycle
* @param {any[]} sequences one or more arrays of Patterns / values * @param {any[]} sequences one or more arrays of Patterns / values
* @example * @example
* polymeterSteps(2, ["c", "d", "e", "f", "g", "f", "e", "d"]) * polymeterSteps(4, ["c", "d", "e"])
* .note().stack(s("bd")) // 1 cycle = 1 bd = 2 notes * .note().stack(s("bd"))
* // note("{c d e f g f e d}%2").stack(s("bd")) * // note("{c d e}%4").stack(s("bd"))
*/ */
export function polymeterSteps(steps, ...args) { export function polymeterSteps(steps, ...args) {
const seqs = args.map((a) => _sequenceCount(a)); const seqs = args.map((a) => _sequenceCount(a));
@@ -1463,7 +1470,7 @@ export function register(name, func, patternify = true) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0.5 1.5 2.5".round().scale('C major').note() * n("0.5 1.5 2.5".round()).scale("C:major")
*/ */
export const round = register('round', function (pat) { export const round = register('round', function (pat) {
return pat.asNumber().fmap((v) => Math.round(v)); return pat.asNumber().fmap((v) => Math.round(v));
@@ -1477,7 +1484,7 @@ export const round = register('round', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "42 42.1 42.5 43".floor().note() * note("42 42.1 42.5 43".floor())
*/ */
export const floor = register('floor', function (pat) { export const floor = register('floor', function (pat) {
return pat.asNumber().fmap((v) => Math.floor(v)); return pat.asNumber().fmap((v) => Math.floor(v));
@@ -1491,7 +1498,7 @@ export const floor = register('floor', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "42 42.1 42.5 43".ceil().note() * note("42 42.1 42.5 43".ceil())
*/ */
export const ceil = register('ceil', function (pat) { export const ceil = register('ceil', function (pat) {
return pat.asNumber().fmap((v) => Math.ceil(v)); return pat.asNumber().fmap((v) => Math.ceil(v));
@@ -1524,7 +1531,8 @@ export const fromBipolar = register('fromBipolar', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine.range(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine.range(500,4000))
*/ */
export const range = register('range', function (min, max, pat) { export const range = register('range', function (min, max, pat) {
return pat.mul(max - min).add(min); return pat.mul(max - min).add(min);
@@ -1538,7 +1546,8 @@ export const range = register('range', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine.rangex(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine.rangex(500,4000))
*/ */
export const rangex = register('rangex', function (min, max, pat) { export const rangex = register('rangex', function (min, max, pat) {
return pat._range(Math.log(min), Math.log(max)).fmap(Math.exp); return pat._range(Math.log(min), Math.log(max)).fmap(Math.exp);
@@ -1551,7 +1560,8 @@ export const rangex = register('rangex', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("bd sd,hh*4").cutoff(sine2.range2(500,2000).slow(4)) * s("[bd sd]*2,hh*8")
* .cutoff(sine2.range2(500,4000))
*/ */
export const range2 = register('range2', function (min, max, pat) { export const range2 = register('range2', function (min, max, pat) {
return pat.fromBipolar()._range(min, max); return pat.fromBipolar()._range(min, max);
@@ -1564,7 +1574,8 @@ export const range2 = register('range2', function (min, max, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* ratio("1, 5:4, 3:2").mul(110).freq().s("piano").slow(2) * ratio("1, 5:4, 3:2").mul(110)
* .freq().s("piano")
*/ */
export const ratio = register('ratio', (pat) => export const ratio = register('ratio', (pat) =>
pat.fmap((v) => { pat.fmap((v) => {
@@ -1636,7 +1647,7 @@ export const { fastGap, fastgap } = register(['fastGap', 'fastgap'], function (f
}); });
/** /**
* Similar to compress, but doesn't leave gaps, and the 'focus' can be bigger than a cycle * Similar to `compress`, but doesn't leave gaps, and the 'focus' can be bigger than a cycle
* @example * @example
* s("bd hh sd hh").focus(1/4, 3/4) * s("bd hh sd hh").focus(1/4, 3/4)
*/ */
@@ -1667,7 +1678,7 @@ export const ply = register('ply', function (factor, pat) {
* @param {number | Pattern} factor speed up factor * @param {number | Pattern} factor speed up factor
* @returns Pattern * @returns Pattern
* @example * @example
* s("<bd sd> hh").fast(2) // s("[<bd sd> hh]*2") * s("bd hh sd hh").fast(2) // s("[bd hh sd hh]*2")
*/ */
export const { fast, density } = register(['fast', 'density'], function (factor, pat) { export const { fast, density } = register(['fast', 'density'], function (factor, pat) {
if (factor === 0) { if (factor === 0) {
@@ -1696,7 +1707,7 @@ export const hurry = register('hurry', function (r, pat) {
* @param {number | Pattern} factor slow down factor * @param {number | Pattern} factor slow down factor
* @returns Pattern * @returns Pattern
* @example * @example
* s("<bd sd> hh").slow(2) // s("[<bd sd> hh]/2") * s("bd hh sd hh").slow(2) // s("[bd hh sd hh]/2")
*/ */
export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) { export const { slow, sparsity } = register(['slow', 'sparsity'], function (factor, pat) {
if (factor === 0) { if (factor === 0) {
@@ -1753,7 +1764,7 @@ export const lastOf = register('lastOf', function (n, func, pat) {
*/ */
/** /**
* An alias for {@link firstOf} * An alias for `firstOf`
* @name every * @name every
* @memberof Pattern * @memberof Pattern
* @param {number} n how many cycles * @param {number} n how many cycles
@@ -1785,9 +1796,9 @@ export const apply = register('apply', function (func, pat) {
* @example * @example
* s("<bd sd>,hh*2").cpm(90) // = 90 bpm * s("<bd sd>,hh*2").cpm(90) // = 90 bpm
*/ */
// TODO - global clock // this is redefined in repl.mjs, using the current cps as divisor
export const cpm = register('cpm', function (cpm, pat) { export const cpm = register('cpm', function (cpm, pat) {
return pat._fast(cpm / 60); return pat._fast(cpm / 60 / 1);
}); });
/** /**
@@ -1860,7 +1871,7 @@ export const linger = register('linger', function (t, pat) {
* Samples the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one. * Samples the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one.
* @param {number} segments number of segments per cycle * @param {number} segments number of segments per cycle
* @example * @example
* note(saw.range(0,12).segment(24)).add(40) * note(saw.range(40,52).segment(24))
*/ */
export const segment = register('segment', function (rate, pat) { export const segment = register('segment', function (rate, pat) {
return pat.struct(pure(true)._fast(rate)); return pat.struct(pure(true)._fast(rate));
@@ -1886,7 +1897,7 @@ export const { invert, inv } = register(['invert', 'inv'], function (pat) {
* @param {function} func * @param {function} func
* @returns Pattern * @returns Pattern
* @example * @example
* "c3 eb3 g3".when("<0 1>/2", x=>x.sub(5)).note() * "c3 eb3 g3".when("<0 1>/2", x=>x.sub("5")).note()
*/ */
export const when = register('when', function (on, func, pat) { export const when = register('when', function (on, func, pat) {
return on ? func(pat) : pat; return on ? func(pat) : pat;
@@ -1923,7 +1934,7 @@ export const brak = register('brak', function (pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* note("c3 d3 e3 g3").rev() * note("c d e g").rev()
*/ */
export const rev = register('rev', function (pat) { export const rev = register('rev', function (pat) {
const query = function (state) { const query = function (state) {
@@ -1993,7 +2004,7 @@ export const palindrome = register('palindrome', function (pat) {
* @name juxBy * @name juxBy
* @synonyms juxby * @synonyms juxby
* @example * @example
* s("lt ht mt ht hh").juxBy("<0 .5 1>/2", rev) * s("bd lt [~ ht] mt cp ~ bd hh").juxBy("<0 .5 1>/2", rev)
*/ */
export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func, pat) { export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func, pat) {
by /= 2; by /= 2;
@@ -2012,7 +2023,11 @@ export const { juxBy, juxby } = register(['juxBy', 'juxby'], function (by, func,
/** /**
* The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. * The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel.
* @example * @example
* s("lt ht mt ht hh").jux(rev) * s("bd lt [~ ht] mt cp ~ bd hh").jux(rev)
* @example
* s("bd lt [~ ht] mt cp ~ bd hh").jux(press)
* @example
* s("bd lt [~ ht] mt cp ~ bd hh").jux(iter(4))
*/ */
export const jux = register('jux', function (func, pat) { export const jux = register('jux', function (func, pat) {
return pat._juxBy(1, func, pat); return pat._juxBy(1, func, pat);
@@ -2028,7 +2043,7 @@ export const jux = register('jux', function (func, pat) {
* @example * @example
* "<0 [2 4]>" * "<0 [2 4]>"
* .echoWith(4, 1/8, (p,n) => p.add(n*2)) * .echoWith(4, 1/8, (p,n) => p.add(n*2))
* .scale('C minor').note().clip(.2) * .scale("C:minor").note()
*/ */
export const { echoWith, echowith, stutWith, stutwith } = register( export const { echoWith, echowith, stutWith, stutwith } = register(
['echoWith', 'echowith', 'stutWith', 'stutwith'], ['echoWith', 'echowith', 'stutWith', 'stutwith'],
@@ -2121,7 +2136,8 @@ const { repeatCycles } = register('repeatCycles', _repeatCycles);
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0 1 2 3".chunk(4, x=>x.add(7)).scale('A minor').note() * "0 1 2 3".chunk(4, x=>x.add(7))
* .scale("A:minor").note()
*/ */
const _chunk = function (n, func, pat, back = false, fast = false) { const _chunk = function (n, func, pat, back = false, fast = false) {
const binary = Array(n - 1).fill(false); const binary = Array(n - 1).fill(false);
@@ -2146,7 +2162,8 @@ const { chunk, slowchunk, slowChunk } = register(['chunk', 'slowchunk', 'slowChu
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "0 1 2 3".chunkBack(4, x=>x.add(7)).scale('A minor').note() * "0 1 2 3".chunkBack(4, x=>x.add(7))
* .scale("A:minor").note()
*/ */
export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], function (n, func, pat) { export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], function (n, func, pat) {
return _chunk(n, func, pat, true); return _chunk(n, func, pat, true);
@@ -2160,10 +2177,11 @@ export const { chunkBack, chunkback } = register(['chunkBack', 'chunkback'], fun
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* "<0 8> 1 2 3 4 5 6 7".fastChunk(4, x => x.color('red')).slow(4).scale("C2:major").note() * "<0 8> 1 2 3 4 5 6 7"
.s("folkharp") * .fastChunk(4, x => x.color('red')).slow(2)
* .scale("C2:major").note()
*/ */
const { fastchunk, fastChunk } = register(['fastchunk', 'fastChunk'], function (n, func, pat) { export const { fastchunk, fastChunk } = register(['fastchunk', 'fastChunk'], function (n, func, pat) {
return _chunk(n, func, pat, false, true); return _chunk(n, func, pat, false, true);
}); });
@@ -2178,6 +2196,8 @@ export const bypass = register('bypass', function (on, pat) {
* @param {number} offset start point of loop in cycles * @param {number} offset start point of loop in cycles
* @param {number} cycles loop length in cycles * @param {number} cycles loop length in cycles
* @example * @example
* note("<c d e f>").ribbon(1, 2).fast(2)
* @example
* // Looping a portion of randomness * // Looping a portion of randomness
* note(irand(8).segment(4).scale('C3 minor')).ribbon(1337, 2) * note(irand(8).segment(4).scale('C3 minor')).ribbon(1337, 2)
*/ */
@@ -2251,7 +2271,7 @@ export const legato = register('legato', function (value, pat) {
* s("rhodes") * s("rhodes")
* .chop(4) * .chop(4)
* .rev() // reverse order of chops * .rev() // reverse order of chops
* .loopAt(4) // fit sample into 4 cycles * .loopAt(2) // fit sample into 2 cycles
* *
*/ */
export const chop = register('chop', function (n, pat) { export const chop = register('chop', function (n, pat) {
@@ -2269,7 +2289,7 @@ export const chop = register('chop', function (n, pat) {
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("numbers:0 numbers:1 numbers:2").striate(6).slow(6) * s("numbers:0 numbers:1 numbers:2").striate(6).slow(3)
*/ */
export const striate = register('striate', function (n, pat) { export const striate = register('striate', function (n, pat) {
const slices = Array.from({ length: n }, (x, i) => i); const slices = Array.from({ length: n }, (x, i) => i);
@@ -2285,10 +2305,10 @@ export const striate = register('striate', function (n, pat) {
* @returns Pattern * @returns Pattern
* @example * @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes").loopAt(4) * s("rhodes").loopAt(2)
*/ */
// TODO - global cps clock // TODO - global cps clock
const _loopAt = function (factor, pat, cps = 1) { const _loopAt = function (factor, pat, cps = 0.5) {
return pat return pat
.speed((1 / factor) * cps) .speed((1 / factor) * cps)
.unit('c') .unit('c')
@@ -2303,10 +2323,10 @@ const _loopAt = function (factor, pat, cps = 1) {
* @returns Pattern * @returns Pattern
* @example * @example
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(1.5) * s("breaks165").slice(8, "0 1 <2 2*2> 3 [4 0] 5 6 7".every(3, rev)).slow(0.75)
* @example * @example
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks125/2").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>") * s("breaks125").fit().slice([0,.25,.5,.75], "0 1 1 <2 3>")
*/ */
export const slice = register( export const slice = register(
@@ -2334,50 +2354,51 @@ export const slice = register(
* await samples('github:tidalcycles/Dirt-Samples/master') * await samples('github:tidalcycles/Dirt-Samples/master')
* s("breaks165") * s("breaks165")
* .splice(8, "0 1 [2 3 0]@2 3 0@2 7") * .splice(8, "0 1 [2 3 0]@2 3 0@2 7")
* .hurry(0.65)
*/ */
export const splice = register( export const splice = register(
'splice', 'splice',
function (npat, ipat, opat) { function (npat, ipat, opat) {
const sliced = slice(npat, ipat, opat); const sliced = slice(npat, ipat, opat);
return sliced.withHap(function (hap) { return new Pattern((state) => {
return hap.withValue((v) => ({ // TODO - default cps to 0.5
...{ const cps = state.controls._cps || 1;
speed: (1 / v._slices / hap.whole.duration) * (v.speed || 1), const haps = sliced.query(state);
unit: 'c', return haps.map((hap) =>
}, hap.withValue((v) => ({
...v, ...{
})); speed: (cps / v._slices / hap.whole.duration) * (v.speed || 1),
unit: 'c',
},
...v,
})),
);
}); });
}, },
false, // turns off auto-patternification false, // turns off auto-patternification
); );
// this function will be redefined in repl.mjs to use the correct cps value.
// It is still here to work in cases where repl.mjs is not used
export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) { export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (factor, pat) {
return _loopAt(factor, pat, 1); return new Pattern((state) => _loopAt(factor, pat, state.controls._cps).query(state));
}); });
// the fit function will be redefined in repl.mjs to use the correct cps value.
// It is still here to work in cases where repl.mjs is not used
/** /**
* Makes the sample fit its event duration. Good for rhythmical loops like drum breaks. * Makes the sample fit its event duration. Good for rhythmical loops like drum breaks.
* Similar to loopAt. * Similar to `loopAt`.
* @name fit * @name fit
* @example * @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' }) * samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes/4").fit() * s("rhodes/2").fit()
*/ */
export const fit = register('fit', (pat) => export const fit = register('fit', (pat) =>
pat.withHap((hap) => pat.withHaps((haps, state) =>
hap.withValue((v) => ({ haps.map((hap) =>
...v, hap.withValue((v) => ({
speed: 1 / hap.whole.duration, ...v,
unit: 'c', speed: (state.controls._cps || 1) / hap.whole.duration,
})), unit: 'c',
})),
),
), ),
); );
+7 -2
View File
@@ -160,8 +160,13 @@ export function pianoroll({
maxMidi = max; maxMidi = max;
valueExtent = maxMidi - minMidi + 1; valueExtent = maxMidi - minMidi + 1;
} }
// foldValues = values.sort((a, b) => a - b); foldValues = values.sort((a, b) =>
foldValues = values.sort((a, b) => String(a).localeCompare(String(b))); typeof a === 'number' && typeof b === 'number'
? a - b
: typeof a === 'number'
? 1
: String(a).localeCompare(String(b)),
);
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent; barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
ctx.fillStyle = background; ctx.fillStyle = background;
ctx.globalAlpha = 1; // reset! ctx.globalAlpha = 1; // reset!
+55 -63
View File
@@ -61,12 +61,67 @@ export function repl({
scheduler.setPattern(pattern, autostart); scheduler.setPattern(pattern, autostart);
}; };
setTime(() => scheduler.now()); // TODO: refactor? setTime(() => scheduler.now()); // TODO: refactor?
const stop = () => scheduler.stop();
const start = () => scheduler.start();
const pause = () => scheduler.pause();
const toggle = () => scheduler.toggle();
const setCps = (cps) => scheduler.setCps(cps);
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
const all = function (transform) {
allTransform = transform;
return silence;
};
// set pattern methods that use this repl via closure
const injectPatternMethods = () => {
Pattern.prototype.p = function (id) {
pPatterns[id] = this;
return this;
};
Pattern.prototype.q = function (id) {
return silence;
};
try {
for (let i = 1; i < 10; ++i) {
Object.defineProperty(Pattern.prototype, `d${i}`, {
get() {
return this.p(i);
},
configurable: true,
});
Object.defineProperty(Pattern.prototype, `p${i}`, {
get() {
return this.p(i);
},
configurable: true,
});
Pattern.prototype[`q${i}`] = silence;
}
} catch (err) {
console.warn('injectPatternMethods: error:', err);
}
const cpm = register('cpm', function (cpm, pat) {
return pat._fast(cpm / 60 / scheduler.cps);
});
evalScope({
all,
hush,
cpm,
setCps,
setcps: setCps,
setCpm,
setcpm: setCpm,
});
};
const evaluate = async (code, autostart = true, shouldHush = true) => { const evaluate = async (code, autostart = true, shouldHush = true) => {
if (!code) { if (!code) {
throw new Error('no code to evaluate'); throw new Error('no code to evaluate');
} }
try { try {
updateState({ code, pending: true }); updateState({ code, pending: true });
injectPatternMethods();
await beforeEval?.({ code }); await beforeEval?.({ code });
shouldHush && hush(); shouldHush && hush();
let { pattern, meta } = await _evaluate(code, transpiler); let { pattern, meta } = await _evaluate(code, transpiler);
@@ -94,74 +149,11 @@ export function repl({
afterEval?.({ code, pattern, meta }); afterEval?.({ code, pattern, meta });
return pattern; return pattern;
} catch (err) { } catch (err) {
// console.warn(`[repl] eval error: ${err.message}`);
logger(`[eval] error: ${err.message}`, 'error'); logger(`[eval] error: ${err.message}`, 'error');
updateState({ evalError: err, pending: false }); updateState({ evalError: err, pending: false });
onEvalError?.(err); onEvalError?.(err);
} }
}; };
const stop = () => scheduler.stop();
const start = () => scheduler.start();
const pause = () => scheduler.pause();
const toggle = () => scheduler.toggle();
const setCps = (cps) => scheduler.setCps(cps);
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
// the following functions use the cps value, which is why they are defined here..
const loopAt = register('loopAt', (cycles, pat) => {
return pat.loopAtCps(cycles, scheduler.cps);
});
Pattern.prototype.p = function (id) {
pPatterns[id] = this;
return this;
};
Pattern.prototype.q = function (id) {
return silence;
};
const all = function (transform) {
allTransform = transform;
return silence;
};
try {
for (let i = 1; i < 10; ++i) {
Object.defineProperty(Pattern.prototype, `d${i}`, {
get() {
return this.p(i);
},
});
Object.defineProperty(Pattern.prototype, `p${i}`, {
get() {
return this.p(i);
},
});
Pattern.prototype[`q${i}`] = silence;
}
} catch (err) {
// already defined..
}
const fit = register('fit', (pat) =>
pat.withHap((hap) =>
hap.withValue((v) => ({
...v,
speed: scheduler.cps / hap.whole.duration, // overwrite speed completely?
unit: 'c',
})),
),
);
evalScope({
loopAt,
fit,
all,
hush,
setCps,
setcps: setCps,
setCpm,
setcpm: setCpm,
});
const setCode = (code) => updateState({ code }); const setCode = (code) => updateState({ code });
return { scheduler, evaluate, start, stop, pause, setCps, setPattern, setCode, toggle, state }; return { scheduler, evaluate, start, stop, pause, setCps, setPattern, setCode, toggle, state };
} }
+131 -36
View File
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
import { Hap } from './hap.mjs'; import { Hap } from './hap.mjs';
import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs'; import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs';
import Fraction from './fraction.mjs'; import Fraction from './fraction.mjs';
import { id, _mod, clamp } from './util.mjs'; import { id, _mod, clamp, objectMap } from './util.mjs';
export function steady(value) { export function steady(value) {
// A continuous value // A continuous value
@@ -27,9 +27,11 @@ export const isaw2 = isaw.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* "c3 [eb3,g3] g2 [g3,bb3]".note().clip(saw.slow(4)) * note("<c3 [eb3,g3] g2 [g3,bb3]>*8")
* .clip(saw.slow(2))
* @example * @example
* saw.range(0,8).segment(8).scale('C major').slow(4).note() * n(saw.range(0,8).segment(8))
* .scale('C major')
* *
*/ */
export const saw = signal((t) => t % 1); export const saw = signal((t) => t % 1);
@@ -42,7 +44,8 @@ export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t));
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* sine.segment(16).range(0,15).slow(2).scale('C minor').note() * n(sine.segment(16).range(0,15))
* .scale("C:minor")
* *
*/ */
export const sine = sine2.fromBipolar(); export const sine = sine2.fromBipolar();
@@ -52,7 +55,8 @@ export const sine = sine2.fromBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* stack(sine,cosine).segment(16).range(0,15).slow(2).scale('C minor').note() * n(stack(sine,cosine).segment(16).range(0,15))
* .scale("C:minor")
* *
*/ */
export const cosine = sine._early(Fraction(1).div(4)); export const cosine = sine._early(Fraction(1).div(4));
@@ -63,7 +67,7 @@ export const cosine2 = sine2._early(Fraction(1).div(4));
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* square.segment(2).range(0,7).scale('C minor').note() * n(square.segment(4).range(0,7)).scale("C:minor")
* *
*/ */
export const square = signal((t) => Math.floor((t * 2) % 2)); export const square = signal((t) => Math.floor((t * 2) % 2));
@@ -74,7 +78,7 @@ export const square2 = square.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* tri.segment(8).range(0,7).scale('C minor').note() * n(tri.segment(8).range(0,7)).scale("C:minor")
* *
*/ */
export const tri = fastcat(isaw, saw); export const tri = fastcat(isaw, saw);
@@ -118,8 +122,8 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n);
/** /**
* A discrete pattern of numbers from 0 to n-1 * A discrete pattern of numbers from 0 to n-1
* @example * @example
* run(4).scale('C4 major').note() * n(run(4)).scale("C4:pentatonic")
* // "0 1 2 3".scale('C4 major').note() * // n("0 1 2 3").scale("C4:pentatonic")
*/ */
export const run = (n) => saw.range(0, n).floor().segment(n); export const run = (n) => saw.range(0, n).floor().segment(n);
@@ -129,7 +133,7 @@ export const run = (n) => saw.range(0, n).floor().segment(n);
* @name rand * @name rand
* @example * @example
* // randomly change the cutoff * // randomly change the cutoff
* s("bd sd,hh*4").cutoff(rand.range(500,2000)) * s("bd*4,hh*8").cutoff(rand.range(500,8000))
* *
*/ */
export const rand = signal(timeToRand); export const rand = signal(timeToRand);
@@ -151,36 +155,127 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
* @param {number} n max value (exclusive) * @param {number} n max value (exclusive)
* @example * @example
* // randomly select scale notes from 0 - 7 (= C to C) * // randomly select scale notes from 0 - 7 (= C to C)
* irand(8).struct("x(3,8)").scale('C minor').note() * n(irand(8)).struct("x x*2 x x*3").scale("C:minor")
* *
*/ */
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
/** const _pick = function (lookup, pat, modulo = true) {
* pick from the list of values (or patterns of values) via the index using the given const array = Array.isArray(lookup);
* pattern of integers const len = Object.keys(lookup).length;
lookup = objectMap(lookup, reify);
if (len === 0) {
return silence;
}
return pat.fmap((i) => {
let key = i;
if (array) {
key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1);
}
return lookup[key];
});
};
/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
* Similar to `inhabit`, but maintains the structure of the original patterns.
* @param {Pattern} pat * @param {Pattern} pat
* @param {*} xs * @param {*} xs
* @returns {Pattern} * @returns {Pattern}
* @example * @example
* note(pick("<0 1 [2!2] 3>", ["g a", "e f", "f g f g" , "g a c d"])) * note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"]))
* @example
* sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"]))
* @example
* sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"]))
* @example
* s("<a!2 [a,b] b>".pick({a: "bd(3,8)", b: "sd sd"}))
*/ */
export const pick = (pat, xs) => { export const pick = function (lookup, pat) {
xs = xs.map(reify); // backward compatibility - the args used to be flipped
if (xs.length == 0) { if (Array.isArray(pat)) {
return silence; [pat, lookup] = [lookup, pat];
} }
return pat return __pick(lookup, pat);
.fmap((i) => {
const key = clamp(Math.round(i), 0, xs.length - 1);
return xs[key];
})
.innerJoin();
}; };
const __pick = register('pick', function (lookup, pat) {
return _pick(lookup, pat, false).innerJoin();
});
/** * The same as `pick`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* For example, if you pick the fifth pattern of a list of three, you'll get the
* second one.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickmod = register('pickmod', function (lookup, pat) {
return _pick(lookup, pat, true).innerJoin();
});
/** * pickF lets you use a pattern of numbers to pick which function to apply to another pattern.
* @param {Pattern} pat
* @param {Pattern} lookup a pattern of indices
* @param {function[]} funcs the array of functions from which to pull
* @returns {Pattern}
* @example
* s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)])
* @example
* note("<c2 d2>(3,8)").s("square")
* .pickF("<0 2> 1", [jux(rev),fast(2),x=>x.lpf(800)])
*/
export const pickF = register('pickF', function (lookup, funcs, pat) {
return pat.apply(pick(lookup, funcs));
});
/** * The same as `pickF`, but if you pick a number greater than the size of the functions list,
* it wraps around, rather than sticking at the maximum value.
* @param {Pattern} pat
* @param {Pattern} lookup a pattern of indices
* @param {function[]} funcs the array of functions from which to pull
* @returns {Pattern}
*/
export const pickmodF = register('pickmodF', function (lookup, funcs, pat) {
return pat.apply(pickmod(lookup, funcs));
});
/** /**
* pick from the list of values (or patterns of values) via the index using the given /** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
* Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
* @example
* "<a b [a,b]>".inhabit({a: s("bd(3,8)"),
b: s("cp sd")
})
* @example
* s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4)
*/
export const inhabit = register('inhabit', function (lookup, pat) {
return _pick(lookup, pat, true).squeezeJoin();
});
/** * The same as `inhabit`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* For example, if you pick the fifth pattern of a list of three, you'll get the
* second one.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const inhabitmod = register('inhabit', function (lookup, pat) {
return _pick(lookup, pat, false).squeezeJoin();
});
/**
* Pick from the list of values (or patterns of values) via the index using the given
* pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event * pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event
* @param {Pattern} pat * @param {Pattern} pat
* @param {*} xs * @param {*} xs
@@ -269,9 +364,9 @@ Pattern.prototype.choose2 = function (...xs) {
* Picks one of the elements at random each cycle. * Picks one of the elements at random each cycle.
* @returns {Pattern} * @returns {Pattern}
* @example * @example
* chooseCycles("bd", "hh", "sd").s().fast(4) * chooseCycles("bd", "hh", "sd").s().fast(8)
* @example * @example
* "bd | hh | sd".s().fast(4) * s("bd | hh | sd").fast(8)
*/ */
export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs); export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs);
@@ -314,7 +409,7 @@ export const perlinWith = (pat) => {
* @name perlin * @name perlin
* @example * @example
* // randomly change the cutoff * // randomly change the cutoff
* s("bd sd,hh*4").cutoff(perlin.range(500,2000)) * s("bd*4,hh*8").cutoff(perlin.range(500,8000))
* *
*/ */
export const perlin = perlinWith(time.fmap((v) => Number(v))); export const perlin = perlinWith(time.fmap((v) => Number(v)));
@@ -356,7 +451,7 @@ export const degradeBy = register('degradeBy', function (x, pat) {
export const degrade = register('degrade', (pat) => pat._degradeBy(0.5)); export const degrade = register('degrade', (pat) => pat._degradeBy(0.5));
/** /**
* Inverse of {@link Pattern#degradeBy}: Randomly removes events from the pattern by a given amount. * Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount.
* 0 = 100% chance of removal * 0 = 100% chance of removal
* 1 = 0% chance of removal * 1 = 0% chance of removal
* Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example). * Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example).
@@ -380,7 +475,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5));
/** /**
* *
* Randomly applies the given function by the given probability. * Randomly applies the given function by the given probability.
* Similar to {@link Pattern#someCyclesBy} * Similar to `someCyclesBy`
* *
* @name sometimesBy * @name sometimesBy
* @memberof Pattern * @memberof Pattern
@@ -388,7 +483,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5));
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").sometimesBy(.4, x=>x.speed("0.5")) * s("hh*8").sometimesBy(.4, x=>x.speed("0.5"))
*/ */
export const sometimesBy = register('sometimesBy', function (patx, func, pat) { export const sometimesBy = register('sometimesBy', function (patx, func, pat) {
@@ -406,7 +501,7 @@ export const sometimesBy = register('sometimesBy', function (patx, func, pat) {
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh*4").sometimes(x=>x.speed("0.5")) * s("hh*8").sometimes(x=>x.speed("0.5"))
*/ */
export const sometimes = register('sometimes', function (func, pat) { export const sometimes = register('sometimes', function (func, pat) {
return pat._sometimesBy(0.5, func); return pat._sometimesBy(0.5, func);
@@ -415,7 +510,7 @@ export const sometimes = register('sometimes', function (func, pat) {
/** /**
* *
* Randomly applies the given function by the given probability on a cycle by cycle basis. * Randomly applies the given function by the given probability on a cycle by cycle basis.
* Similar to {@link Pattern#sometimesBy} * Similar to `sometimesBy`
* *
* @name someCyclesBy * @name someCyclesBy
* @memberof Pattern * @memberof Pattern
@@ -423,7 +518,7 @@ export const sometimes = register('sometimes', function (func, pat) {
* @param {function} function - the transformation to apply * @param {function} function - the transformation to apply
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").someCyclesBy(.3, x=>x.speed("0.5")) * s("bd,hh*8").someCyclesBy(.3, x=>x.speed("0.5"))
*/ */
export const someCyclesBy = register('someCyclesBy', function (patx, func, pat) { export const someCyclesBy = register('someCyclesBy', function (patx, func, pat) {
@@ -445,7 +540,7 @@ export const someCyclesBy = register('someCyclesBy', function (patx, func, pat)
* @memberof Pattern * @memberof Pattern
* @returns Pattern * @returns Pattern
* @example * @example
* s("hh(3,8)").someCycles(x=>x.speed("0.5")) * s("bd,hh*8").someCycles(x=>x.speed("0.5"))
*/ */
export const someCycles = register('someCycles', function (func, pat) { export const someCycles = register('someCycles', function (func, pat) {
return pat._someCyclesBy(0.5, func); return pat._someCyclesBy(0.5, func);
+60
View File
@@ -46,6 +46,7 @@ import {
rev, rev,
time, time,
run, run,
pick,
} from '../index.mjs'; } from '../index.mjs';
import { steady } from '../signal.mjs'; import { steady } from '../signal.mjs';
@@ -1057,4 +1058,63 @@ describe('Pattern', () => {
expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]); expect(slowcat(0, 1).repeatCycles(2).fast(6).firstCycleValues).toStrictEqual([0, 0, 1, 1, 0, 0]);
}); });
}); });
describe('inhabit', () => {
it('Can pattern named patterns', () => {
expect(
sameFirst(
sequence('a', 'b', stack('a', 'b')).inhabit({ a: sequence(1, 2), b: sequence(10, 20, 30) }),
sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])),
),
);
});
it('Can pattern indexed patterns', () => {
expect(
sameFirst(
sequence('0', '1', stack('0', '1')).inhabit([sequence(1, 2), sequence(10, 20, 30)]),
sequence([1, 2], [10, 20, 30], stack([1, 2], [10, 20, 30])),
),
);
});
});
describe('pick', () => {
it('Can pattern named patterns', () => {
expect(
sameFirst(
sequence('a', 'b', 'a', stack('a', 'b')).pick({ a: sequence(1, 2, 3, 4), b: sequence(10, 20, 30, 40) }),
sequence(1, 20, 3, stack(4, 40)),
),
);
});
it('Can pattern indexed patterns', () => {
expect(
sameFirst(
sequence(0, 1, 0, stack(0, 1)).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]),
sequence(1, 20, 3, stack(4, 40)),
),
);
});
it('Clamps indexes', () => {
expect(
sameFirst(sequence(0, 1, 2, 3).pick([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]), sequence(1, 20, 30, 40)),
);
});
it('Is backwards compatible', () => {
expect(
sameFirst(
pick([sequence('a', 'b'), sequence('c', 'd')], sequence(0, 1)),
pick(sequence(0, 1), [sequence('a', 'b'), sequence('c', 'd')]),
),
);
});
});
describe('pickmod', () => {
it('Wraps indexes', () => {
expect(
sameFirst(
sequence(0, 1, 2, 3).pickmod([sequence(1, 2, 3, 4), sequence(10, 20, 30, 40)]),
sequence(1, 20, 3, 40),
),
);
});
});
}); });
+7
View File
@@ -316,3 +316,10 @@ export function hash2code(hash) {
return base64ToUnicode(decodeURIComponent(hash)); return base64ToUnicode(decodeURIComponent(hash));
//return atob(decodeURIComponent(codeParam || '')); //return atob(decodeURIComponent(codeParam || ''));
} }
export function objectMap(obj, fn) {
if (Array.isArray(obj)) {
return obj.map(fn);
}
return Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, fn(v, k, i)]));
}
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -3
View File
@@ -1,3 +1 @@
# @strudel.cycles/csound # @strudel/csound
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/csound](https://www.npmjs.com/package/@strudel/csound).
+2 -2
View File
@@ -1,5 +1,5 @@
import { getFrequency, logger, register } from '@strudel.cycles/core'; import { getFrequency, logger, register } from '@strudel/core';
import { getAudioContext } from '@strudel.cycles/webaudio'; import { getAudioContext } from '@strudel/webaudio';
import csd from './project.csd?raw'; import csd from './project.csd?raw';
// import livecodeOrc from './livecode.orc?raw'; // import livecodeOrc from './livecode.orc?raw';
import presetsOrc from './presets.orc?raw'; import presetsOrc from './presets.orc?raw';
+6 -6
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/csound", "name": "@strudel/csound",
"version": "0.10.0", "version": "1.0.1",
"description": "csound bindings for strudel", "description": "csound bindings for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -33,8 +33,8 @@
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@csound/browser": "6.18.7", "@csound/browser": "6.18.7",
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*" "@strudel/webaudio": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^5.0.10" "vite": "^5.0.10"
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -1
View File
@@ -1,5 +1,5 @@
import { Invoke } from './utils.mjs'; import { Invoke } from './utils.mjs';
import { Pattern, noteToMidi } from '@strudel.cycles/core'; import { Pattern, noteToMidi } from '@strudel/core';
const ON_MESSAGE = 0x90; const ON_MESSAGE = 0x90;
const OFF_MESSAGE = 0x80; const OFF_MESSAGE = 0x80;
+1 -1
View File
@@ -1,4 +1,4 @@
import { parseNumeral, Pattern } from '@strudel.cycles/core'; import { parseNumeral, Pattern } from '@strudel/core';
import { Invoke } from './utils.mjs'; import { Invoke } from './utils.mjs';
Pattern.prototype.osc = function () { Pattern.prototype.osc = function () {
+1 -1
View File
@@ -22,7 +22,7 @@
"url": "https://github.com/tidalcycles/strudel/issues" "url": "https://github.com/tidalcycles/strudel/issues"
}, },
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@tauri-apps/api": "^1.5.3" "@tauri-apps/api": "^1.5.3"
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme" "homepage": "https://github.com/tidalcycles/strudel#readme"
+3 -5
View File
@@ -1,15 +1,13 @@
# @strudel.cycles/embed # @strudel/embed
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/embed](https://www.npmjs.com/package/@strudel/embed).
This package contains a embeddable web component for the Strudel REPL. This package contains a embeddable web component for the Strudel REPL.
## Usage ## Usage
Either install with `npm i @strudel.cycles/embed` or just use a cdn to import the script: Either install with `npm i @strudel/embed` or just use a cdn to import the script:
```html ```html
<script src="https://unpkg.com/@strudel.cycles/embed@latest"></script> <script src="https://unpkg.com/@strudel/embed@latest"></script>
<strudel-repl> <strudel-repl>
<!-- <!--
note(`[[e5 [b4 c5] d5 [c5 b4]] note(`[[e5 [b4 c5] d5 [c5 b4]]
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/embed", "name": "@strudel/embed",
"version": "0.10.0", "version": "1.0.0",
"description": "Embeddable Web Component to load a Strudel REPL into an iframe", "description": "Embeddable Web Component to load a Strudel REPL into an iframe",
"main": "embed.js", "main": "embed.js",
"type": "module", "type": "module",
+1 -1
View File
@@ -27,7 +27,7 @@ npm i @strudel/hydra
Then add the import to your evalScope: Then add the import to your evalScope:
```js ```js
import { evalScope } from '@strudel.cycles/core'; import { evalScope } from '@strudel/core';
evalScope( evalScope(
import('@strudel/hydra') import('@strudel/hydra')
+1 -1
View File
@@ -1,4 +1,4 @@
import { getDrawContext } from '@strudel.cycles/core'; import { getDrawContext } from '@strudel/core';
let latestOptions; let latestOptions;
+4 -4
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel/hydra", "name": "@strudel/hydra",
"version": "0.10.0", "version": "1.0.1",
"description": "Hydra integration for strudel", "description": "Hydra integration for strudel",
"main": "hydra.mjs", "main": "hydra.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"server": "node server.js", "server": "node server.js",
@@ -33,7 +33,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"hydra-synth": "^1.3.29" "hydra-synth": "^1.3.29"
}, },
"devDependencies": { "devDependencies": {
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'hydra.mjs'), entry: resolve(__dirname, 'hydra.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+2 -4
View File
@@ -1,11 +1,9 @@
# @strudel.cycles/midi # @strudel/midi
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/midi](https://www.npmjs.com/package/@strudel/midi).
This package adds midi functionality to strudel Patterns. This package adds midi functionality to strudel Patterns.
## Install ## Install
```sh ```sh
npm i @strudel.cycles/midi --save npm i @strudel/midi --save
``` ```
+2 -2
View File
@@ -5,8 +5,8 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import * as _WebMidi from 'webmidi'; import * as _WebMidi from 'webmidi';
import { Pattern, isPattern, logger, ref } from '@strudel.cycles/core'; import { Pattern, isPattern, logger, ref } from '@strudel/core';
import { noteToMidi } from '@strudel.cycles/core'; import { noteToMidi } from '@strudel/core';
import { Note } from 'webmidi'; import { Note } from 'webmidi';
// if you use WebMidi from outside of this package, make sure to import that instance: // if you use WebMidi from outside of this package, make sure to import that instance:
export const { WebMidi } = _WebMidi; export const { WebMidi } = _WebMidi;
+6 -6
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/midi", "name": "@strudel/midi",
"version": "0.10.0", "version": "1.0.1",
"description": "Midi API for strudel", "description": "Midi API for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -29,8 +29,8 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*", "@strudel/webaudio": "workspace:*",
"webmidi": "^3.1.8" "webmidi": "^3.1.8"
}, },
"devDependencies": { "devDependencies": {
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+4 -6
View File
@@ -1,19 +1,17 @@
# @strudel.cycles/mini # @strudel/mini
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/mini](https://www.npmjs.com/package/@strudel/mini).
This package contains the mini notation parser and pattern generator. This package contains the mini notation parser and pattern generator.
## Install ## Install
```sh ```sh
npm i @strudel.cycles/mini --save npm i @strudel/mini --save
``` ```
## Example ## Example
```js ```js
import { mini } from '@strudel.cycles/mini'; import { mini } from '@strudel/mini';
const pattern = mini('a [b c*2]'); const pattern = mini('a [b c*2]');
@@ -30,7 +28,7 @@ yields:
(7/8 -> 1/1, 7/8 -> 1/1, c) (7/8 -> 1/1, 7/8 -> 1/1, c)
``` ```
[Play with @strudel.cycles/mini codesandbox](https://codesandbox.io/s/strudel-mini-example-oe9wcu?file=/src/index.js) [Play with @strudel/mini codesandbox](https://codesandbox.io/s/strudel-mini-example-oe9wcu?file=/src/index.js)
## Mini Notation API ## Mini Notation API
+193 -96
View File
@@ -288,48 +288,50 @@ function peg$parse(input, options) {
var peg$f0 = function() { return parseFloat(text()); }; var peg$f0 = function() { return parseFloat(text()); };
var peg$f1 = function() { return parseInt(text()); }; var peg$f1 = function() { return parseInt(text()); };
var peg$f2 = function(chars) { return new AtomStub(chars.join("")) }; var peg$f2 = function(chars) { const s = chars.join(""); return (s === ".") || (s === "_") };
var peg$f3 = function(s) { return s }; var peg$f3 = function(chars) { return new AtomStub(chars.join("")) };
var peg$f4 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; }; var peg$f4 = function(s) { return s };
var peg$f5 = function(a) { return a }; var peg$f5 = function(s, stepsPerCycle) { s.arguments_.stepsPerCycle = stepsPerCycle ; return s; };
var peg$f6 = function(s) { s.arguments_.alignment = 'polymeter_slowcat'; return s; }; var peg$f6 = function(a) { return a };
var peg$f7 = function(a) { return x => x.options_['weight'] = a }; var peg$f7 = function(s) { s.arguments_.alignment = 'polymeter_slowcat'; return s; };
var peg$f8 = function(a) { return x => x.options_['reps'] = a }; var peg$f8 = function(a) { return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 };
var peg$f9 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }; var peg$f9 = function(a) { return x => x.options_['reps'] = (x.options_['reps'] ?? 1) + (a ?? 2) - 1 };
var peg$f10 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) }; var peg$f10 = function(p, s, r) { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) };
var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) }; var peg$f11 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'slow' }}) };
var peg$f12 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) }; var peg$f12 = function(a) { return x => x.options_['ops'].push({ type_: "stretch", arguments_ :{ amount:a, type: 'fast' }}) };
var peg$f13 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) }; var peg$f13 = function(a) { return x => x.options_['ops'].push({ type_: "degradeBy", arguments_ :{ amount:a, seed: seed++ } }) };
var peg$f14 = function(s) { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) }; var peg$f14 = function(s) { return x => x.options_['ops'].push({ type_: "tail", arguments_ :{ element:s } }) };
var peg$f15 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1}); var peg$f15 = function(s) { return x => x.options_['ops'].push({ type_: "range", arguments_ :{ element:s } }) };
var peg$f16 = function(s, ops) { const result = new ElementStub(s, {ops: [], weight: 1, reps: 1});
for (const op of ops) { for (const op of ops) {
op(result); op(result);
} }
return result; return result;
}; };
var peg$f16 = function(s) { return new PatternStub(s, 'fastcat'); }; var peg$f17 = function(s) { return new PatternStub(s, 'fastcat'); };
var peg$f17 = function(tail) { return { alignment: 'stack', list: tail }; }; var peg$f18 = function(tail) { return { alignment: 'stack', list: tail }; };
var peg$f18 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; }; var peg$f19 = function(tail) { return { alignment: 'rand', list: tail, seed: seed++ }; };
var peg$f19 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }; var peg$f20 = function(tail) { return { alignment: 'feet', list: tail, seed: seed++ }; };
var peg$f20 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); }; var peg$f21 = function(head, tail) { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } };
var peg$f21 = function(sc) { return sc; }; var peg$f22 = function(head, tail) { return new PatternStub(tail ? [head, ...tail.list] : [head], 'polymeter'); };
var peg$f22 = function(s) { return { name: "struct", args: { mini:s }}}; var peg$f23 = function(sc) { return sc; };
var peg$f23 = function(s) { return { name: "target", args : { name:s}}}; var peg$f24 = function(s) { return { name: "struct", args: { mini:s }}};
var peg$f24 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}}; var peg$f25 = function(s) { return { name: "target", args : { name:s}}};
var peg$f25 = function(a) { return { name: "stretch", args :{ amount: a}}}; var peg$f26 = function(p, s, r) { return { name: "bjorklund", args :{ pulse: p, step:parseInt(s) }}};
var peg$f26 = function(a) { return { name: "shift", args :{ amount: "-"+a}}}; var peg$f27 = function(a) { return { name: "stretch", args :{ amount: a}}};
var peg$f27 = function(a) { return { name: "shift", args :{ amount: a}}}; var peg$f28 = function(a) { return { name: "shift", args :{ amount: "-"+a}}};
var peg$f28 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}}; var peg$f29 = function(a) { return { name: "shift", args :{ amount: a}}};
var peg$f29 = function(s) { return { name: "scale", args :{ scale: s.join("")}}}; var peg$f30 = function(a) { return { name: "stretch", args :{ amount: "1/"+a}}};
var peg$f30 = function(s, v) { return v}; var peg$f31 = function(s) { return { name: "scale", args :{ scale: s.join("")}}};
var peg$f31 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); }; var peg$f32 = function(s, v) { return v};
var peg$f32 = function(sg) {return sg}; var peg$f33 = function(s, ss) { ss.unshift(s); return new PatternStub(ss, 'slowcat'); };
var peg$f33 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)}; var peg$f34 = function(sg) {return sg};
var peg$f34 = function(sc) { return sc }; var peg$f35 = function(o, soc) { return new OperatorStub(o.name,o.args,soc)};
var peg$f35 = function(c) { return c }; var peg$f36 = function(sc) { return sc };
var peg$f36 = function(v) { return new CommandStub("setcps", { value: v})}; var peg$f37 = function(c) { return c };
var peg$f37 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})}; var peg$f38 = function(v) { return new CommandStub("setcps", { value: v})};
var peg$f38 = function() { return new CommandStub("hush")}; var peg$f39 = function(v) { return new CommandStub("setcps", { value: (v/120/2)})};
var peg$f40 = function() { return new CommandStub("hush")};
var peg$currPos = 0; var peg$currPos = 0;
var peg$savedPos = 0; var peg$savedPos = 0;
var peg$posDetailsCache = [{ line: 1, column: 1 }]; var peg$posDetailsCache = [{ line: 1, column: 1 }];
@@ -821,6 +823,30 @@ function peg$parse(input, options) {
return s0; return s0;
} }
function peg$parsedot() {
var s0, s1, s2, s3;
s0 = peg$currPos;
s1 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 46) {
s2 = peg$c0;
peg$currPos++;
} else {
s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e1); }
}
if (s2 !== peg$FAILED) {
s3 = peg$parsews();
s1 = [s1, s2, s3];
s0 = s1;
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
return s0;
}
function peg$parsequote() { function peg$parsequote() {
var s0; var s0;
@@ -913,7 +939,7 @@ function peg$parse(input, options) {
} }
function peg$parsestep() { function peg$parsestep() {
var s0, s1, s2, s3; var s0, s1, s2, s3, s4;
s0 = peg$currPos; s0 = peg$currPos;
s1 = peg$parsews(); s1 = peg$parsews();
@@ -929,8 +955,20 @@ function peg$parse(input, options) {
} }
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
s3 = peg$parsews(); s3 = peg$parsews();
peg$savedPos = s0; peg$savedPos = peg$currPos;
s0 = peg$f2(s2); s4 = peg$f2(s2);
if (s4) {
s4 = peg$FAILED;
} else {
s4 = undefined;
}
if (s4 !== peg$FAILED) {
peg$savedPos = s0;
s0 = peg$f3(s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
}
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -966,7 +1004,7 @@ function peg$parse(input, options) {
if (s6 !== peg$FAILED) { if (s6 !== peg$FAILED) {
s7 = peg$parsews(); s7 = peg$parsews();
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f3(s4); s0 = peg$f4(s4);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1014,7 +1052,7 @@ function peg$parse(input, options) {
} }
s8 = peg$parsews(); s8 = peg$parsews();
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f4(s4, s7); s0 = peg$f5(s4, s7);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1046,7 +1084,7 @@ function peg$parse(input, options) {
s2 = peg$parseslice(); s2 = peg$parseslice();
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f5(s2); s0 = peg$f6(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1086,7 +1124,7 @@ function peg$parse(input, options) {
if (s6 !== peg$FAILED) { if (s6 !== peg$FAILED) {
s7 = peg$parsews(); s7 = peg$parsews();
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f6(s4); s0 = peg$f7(s4);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1150,25 +1188,33 @@ function peg$parse(input, options) {
} }
function peg$parseop_weight() { function peg$parseop_weight() {
var s0, s1, s2; var s0, s1, s2, s3;
s0 = peg$currPos; s0 = peg$currPos;
s1 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 64) { if (input.charCodeAt(peg$currPos) === 64) {
s1 = peg$c18; s2 = peg$c18;
peg$currPos++; peg$currPos++;
} else { } else {
s1 = peg$FAILED; s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e26); } if (peg$silentFails === 0) { peg$fail(peg$e26); }
} }
if (s1 !== peg$FAILED) { if (s2 === peg$FAILED) {
s2 = peg$parsenumber(); if (input.charCodeAt(peg$currPos) === 95) {
if (s2 !== peg$FAILED) { s2 = peg$c10;
peg$savedPos = s0; peg$currPos++;
s0 = peg$f7(s2);
} else { } else {
peg$currPos = s0; s2 = peg$FAILED;
s0 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e18); }
} }
}
if (s2 !== peg$FAILED) {
s3 = peg$parsenumber();
if (s3 === peg$FAILED) {
s3 = null;
}
peg$savedPos = s0;
s0 = peg$f8(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1178,25 +1224,24 @@ function peg$parse(input, options) {
} }
function peg$parseop_replicate() { function peg$parseop_replicate() {
var s0, s1, s2; var s0, s1, s2, s3;
s0 = peg$currPos; s0 = peg$currPos;
s1 = peg$parsews();
if (input.charCodeAt(peg$currPos) === 33) { if (input.charCodeAt(peg$currPos) === 33) {
s1 = peg$c19; s2 = peg$c19;
peg$currPos++; peg$currPos++;
} else { } else {
s1 = peg$FAILED; s2 = peg$FAILED;
if (peg$silentFails === 0) { peg$fail(peg$e27); } if (peg$silentFails === 0) { peg$fail(peg$e27); }
} }
if (s1 !== peg$FAILED) { if (s2 !== peg$FAILED) {
s2 = peg$parsenumber(); s3 = peg$parsenumber();
if (s2 !== peg$FAILED) { if (s3 === peg$FAILED) {
peg$savedPos = s0; s3 = null;
s0 = peg$f8(s2);
} else {
peg$currPos = s0;
s0 = peg$FAILED;
} }
peg$savedPos = s0;
s0 = peg$f9(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1246,7 +1291,7 @@ function peg$parse(input, options) {
} }
if (s13 !== peg$FAILED) { if (s13 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f9(s3, s7, s11); s0 = peg$f10(s3, s7, s11);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1286,7 +1331,7 @@ function peg$parse(input, options) {
s2 = peg$parseslice(); s2 = peg$parseslice();
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f10(s2); s0 = peg$f11(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1314,7 +1359,7 @@ function peg$parse(input, options) {
s2 = peg$parseslice(); s2 = peg$parseslice();
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f11(s2); s0 = peg$f12(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1344,7 +1389,7 @@ function peg$parse(input, options) {
s2 = null; s2 = null;
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f12(s2); s0 = peg$f13(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1368,7 +1413,7 @@ function peg$parse(input, options) {
s2 = peg$parseslice(); s2 = peg$parseslice();
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f13(s2); s0 = peg$f14(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1396,7 +1441,7 @@ function peg$parse(input, options) {
s2 = peg$parseslice(); s2 = peg$parseslice();
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f14(s2); s0 = peg$f15(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1422,7 +1467,7 @@ function peg$parse(input, options) {
s3 = peg$parseslice_op(); s3 = peg$parseslice_op();
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f15(s1, s2); s0 = peg$f16(s1, s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1447,7 +1492,7 @@ function peg$parse(input, options) {
} }
if (s1 !== peg$FAILED) { if (s1 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s1 = peg$f16(s1); s1 = peg$f17(s1);
} }
s0 = s1; s0 = s1;
@@ -1496,7 +1541,7 @@ function peg$parse(input, options) {
} }
if (s1 !== peg$FAILED) { if (s1 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s1 = peg$f17(s1); s1 = peg$f18(s1);
} }
s0 = s1; s0 = s1;
@@ -1545,7 +1590,56 @@ function peg$parse(input, options) {
} }
if (s1 !== peg$FAILED) { if (s1 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s1 = peg$f18(s1); s1 = peg$f19(s1);
}
s0 = s1;
return s0;
}
function peg$parsedot_tail() {
var s0, s1, s2, s3, s4;
s0 = peg$currPos;
s1 = [];
s2 = peg$currPos;
s3 = peg$parsedot();
if (s3 !== peg$FAILED) {
s4 = peg$parsesequence();
if (s4 !== peg$FAILED) {
s2 = s4;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
if (s2 !== peg$FAILED) {
while (s2 !== peg$FAILED) {
s1.push(s2);
s2 = peg$currPos;
s3 = peg$parsedot();
if (s3 !== peg$FAILED) {
s4 = peg$parsesequence();
if (s4 !== peg$FAILED) {
s2 = s4;
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
} else {
peg$currPos = s2;
s2 = peg$FAILED;
}
}
} else {
s1 = peg$FAILED;
}
if (s1 !== peg$FAILED) {
peg$savedPos = s0;
s1 = peg$f20(s1);
} }
s0 = s1; s0 = s1;
@@ -1561,12 +1655,15 @@ function peg$parse(input, options) {
s2 = peg$parsestack_tail(); s2 = peg$parsestack_tail();
if (s2 === peg$FAILED) { if (s2 === peg$FAILED) {
s2 = peg$parsechoose_tail(); s2 = peg$parsechoose_tail();
if (s2 === peg$FAILED) {
s2 = peg$parsedot_tail();
}
} }
if (s2 === peg$FAILED) { if (s2 === peg$FAILED) {
s2 = null; s2 = null;
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f19(s1, s2); s0 = peg$f21(s1, s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1586,7 +1683,7 @@ function peg$parse(input, options) {
s2 = null; s2 = null;
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f20(s1, s2); s0 = peg$f22(s1, s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1609,7 +1706,7 @@ function peg$parse(input, options) {
s6 = peg$parsequote(); s6 = peg$parsequote();
if (s6 !== peg$FAILED) { if (s6 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f21(s4); s0 = peg$f23(s4);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1671,7 +1768,7 @@ function peg$parse(input, options) {
s3 = peg$parsemini_or_operator(); s3 = peg$parsemini_or_operator();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f22(s3); s0 = peg$f24(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1704,7 +1801,7 @@ function peg$parse(input, options) {
s5 = peg$parsequote(); s5 = peg$parsequote();
if (s5 !== peg$FAILED) { if (s5 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f23(s4); s0 = peg$f25(s4);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1749,7 +1846,7 @@ function peg$parse(input, options) {
s7 = null; s7 = null;
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f24(s3, s5, s7); s0 = peg$f26(s3, s5, s7);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1782,7 +1879,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f25(s3); s0 = peg$f27(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1811,7 +1908,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f26(s3); s0 = peg$f28(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1840,7 +1937,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f27(s3); s0 = peg$f29(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1869,7 +1966,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f28(s3); s0 = peg$f30(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -1911,7 +2008,7 @@ function peg$parse(input, options) {
s5 = peg$parsequote(); s5 = peg$parsequote();
if (s5 !== peg$FAILED) { if (s5 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f29(s4); s0 = peg$f31(s4);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2003,7 +2100,7 @@ function peg$parse(input, options) {
s9 = peg$parsemini_or_operator(); s9 = peg$parsemini_or_operator();
if (s9 !== peg$FAILED) { if (s9 !== peg$FAILED) {
peg$savedPos = s7; peg$savedPos = s7;
s7 = peg$f30(s5, s9); s7 = peg$f32(s5, s9);
} else { } else {
peg$currPos = s7; peg$currPos = s7;
s7 = peg$FAILED; s7 = peg$FAILED;
@@ -2020,7 +2117,7 @@ function peg$parse(input, options) {
s9 = peg$parsemini_or_operator(); s9 = peg$parsemini_or_operator();
if (s9 !== peg$FAILED) { if (s9 !== peg$FAILED) {
peg$savedPos = s7; peg$savedPos = s7;
s7 = peg$f30(s5, s9); s7 = peg$f32(s5, s9);
} else { } else {
peg$currPos = s7; peg$currPos = s7;
s7 = peg$FAILED; s7 = peg$FAILED;
@@ -2040,7 +2137,7 @@ function peg$parse(input, options) {
} }
if (s8 !== peg$FAILED) { if (s8 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f31(s5, s6); s0 = peg$f33(s5, s6);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2086,7 +2183,7 @@ function peg$parse(input, options) {
s4 = peg$parsecomment(); s4 = peg$parsecomment();
} }
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f32(s1); s0 = peg$f34(s1);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2108,7 +2205,7 @@ function peg$parse(input, options) {
s5 = peg$parsemini_or_operator(); s5 = peg$parsemini_or_operator();
if (s5 !== peg$FAILED) { if (s5 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f33(s1, s5); s0 = peg$f35(s1, s5);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2133,7 +2230,7 @@ function peg$parse(input, options) {
s1 = peg$parsemini_or_operator(); s1 = peg$parsemini_or_operator();
if (s1 !== peg$FAILED) { if (s1 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s1 = peg$f34(s1); s1 = peg$f36(s1);
} }
s0 = s1; s0 = s1;
if (s0 === peg$FAILED) { if (s0 === peg$FAILED) {
@@ -2166,7 +2263,7 @@ function peg$parse(input, options) {
if (s2 !== peg$FAILED) { if (s2 !== peg$FAILED) {
s3 = peg$parsews(); s3 = peg$parsews();
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f35(s2); s0 = peg$f37(s2);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2191,7 +2288,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f36(s3); s0 = peg$f38(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2220,7 +2317,7 @@ function peg$parse(input, options) {
s3 = peg$parsenumber(); s3 = peg$parsenumber();
if (s3 !== peg$FAILED) { if (s3 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s0 = peg$f37(s3); s0 = peg$f39(s3);
} else { } else {
peg$currPos = s0; peg$currPos = s0;
s0 = peg$FAILED; s0 = peg$FAILED;
@@ -2246,7 +2343,7 @@ function peg$parse(input, options) {
} }
if (s1 !== peg$FAILED) { if (s1 !== peg$FAILED) {
peg$savedPos = s0; peg$savedPos = s0;
s1 = peg$f38(); s1 = peg$f40();
} }
s0 = s1; s0 = s1;
+13 -7
View File
@@ -98,6 +98,7 @@ DIGIT = [0-9]
ws "whitespace" = [ \n\r\t\u00A0]* ws "whitespace" = [ \n\r\t\u00A0]*
comma = ws "," ws comma = ws "," ws
pipe = ws "|" ws pipe = ws "|" ws
dot = ws "." ws
quote = '"' / "'" quote = '"' / "'"
// ------------------ steps and cycles --------------------------- // ------------------ steps and cycles ---------------------------
@@ -105,7 +106,8 @@ quote = '"' / "'"
// single step definition (e.g bd) // single step definition (e.g bd)
step_char "a letter, a number, \"-\", \"#\", \".\", \"^\", \"_\"" = step_char "a letter, a number, \"-\", \"#\", \".\", \"^\", \"_\"" =
unicode_letter / [0-9~] / "-" / "#" / "." / "^" / "_" unicode_letter / [0-9~] / "-" / "#" / "." / "^" / "_"
step = ws chars:step_char+ ws { return new AtomStub(chars.join("")) }
step = ws chars:step_char+ ws !{ const s = chars.join(""); return (s === ".") || (s === "_") } { return new AtomStub(chars.join("")) }
// define a sub cycle e.g. [1 2, 3 [4]] // define a sub cycle e.g. [1 2, 3 [4]]
sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s } sub_cycle = ws "[" ws s:stack_or_choose ws "]" ws { return s }
@@ -129,11 +131,11 @@ slice = step / sub_cycle / polymeter / slow_sequence
// at this point, we assume we can represent them as regular sequence operators // at this point, we assume we can represent them as regular sequence operators
slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail / op_range slice_op = op_weight / op_bjorklund / op_slow / op_fast / op_replicate / op_degrade / op_tail / op_range
op_weight = "@" a:number op_weight = ws ("@" / "_") a:number?
{ return x => x.options_['weight'] = a } { return x => x.options_['weight'] = (x.options_['weight'] ?? 1) + (a ?? 2) - 1 }
op_replicate = "!"a:number op_replicate = ws "!" a:number?
{ return x => x.options_['reps'] = a } { return x => x.options_['reps'] = (x.options_['reps'] ?? 1) + (a ?? 2) - 1 }
op_bjorklund = "(" ws p:slice_with_ops ws comma ws s:slice_with_ops ws comma? ws r:slice_with_ops? ws ")" op_bjorklund = "(" ws p:slice_with_ops ws comma ws s:slice_with_ops ws comma? ws r:slice_with_ops? ws ")"
{ return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) } { return x => x.options_['ops'].push({ type_: "bjorklund", arguments_ :{ pulse: p, step:s, rotation:r }}) }
@@ -175,9 +177,13 @@ stack_tail = tail:(comma @sequence)+
choose_tail = tail:(pipe @sequence)+ choose_tail = tail:(pipe @sequence)+
{ return { alignment: 'rand', list: tail, seed: seed++ }; } { return { alignment: 'rand', list: tail, seed: seed++ }; }
// a foot separates subsequences, as an alternative to wrapping them in []
dot_tail = tail:(dot @sequence)+
{ return { alignment: 'feet', list: tail, seed: seed++ }; }
// if the stack contains only one element, we don't create a stack but return the // if the stack contains only one element, we don't create a stack but return the
// underlying element // underlying element
stack_or_choose = head:sequence tail:(stack_tail / choose_tail)? stack_or_choose = head:sequence tail:(stack_tail / choose_tail / dot_tail)?
{ if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } } { if (tail && tail.list.length > 0) { return new PatternStub([head, ...tail.list], tail.alignment, tail.seed); } else { return head; } }
polymeter_stack = head:sequence tail:stack_tail? polymeter_stack = head:sequence tail:stack_tail?
@@ -287,4 +293,4 @@ Lt = [\u01C5\u01C8\u01CB\u01F2\u1F88-\u1F8F\u1F98-\u1F9F\u1FA8-\u1FAF\u1FBC\u1FC
Lu = [\u0041-\u005A\u00C0-\u00D6\u00D8-\u00DE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178-\u0179\u017B\u017D\u0181-\u0182\u0184\u0186-\u0187\u0189-\u018B\u018E-\u0191\u0193-\u0194\u0196-\u0198\u019C-\u019D\u019F-\u01A0\u01A2\u01A4\u01A6-\u01A7\u01A9\u01AC\u01AE-\u01AF\u01B1-\u01B3\u01B5\u01B7-\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A-\u023B\u023D-\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E-\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9-\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0-\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1C90-\u1CBA\u1CBD-\u1CBF\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E-\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D-\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AE\uA7B0-\uA7B4\uA7B6\uA7B8\uFF21-\uFF3A] Lu = [\u0041-\u005A\u00C0-\u00D6\u00D8-\u00DE\u0100\u0102\u0104\u0106\u0108\u010A\u010C\u010E\u0110\u0112\u0114\u0116\u0118\u011A\u011C\u011E\u0120\u0122\u0124\u0126\u0128\u012A\u012C\u012E\u0130\u0132\u0134\u0136\u0139\u013B\u013D\u013F\u0141\u0143\u0145\u0147\u014A\u014C\u014E\u0150\u0152\u0154\u0156\u0158\u015A\u015C\u015E\u0160\u0162\u0164\u0166\u0168\u016A\u016C\u016E\u0170\u0172\u0174\u0176\u0178-\u0179\u017B\u017D\u0181-\u0182\u0184\u0186-\u0187\u0189-\u018B\u018E-\u0191\u0193-\u0194\u0196-\u0198\u019C-\u019D\u019F-\u01A0\u01A2\u01A4\u01A6-\u01A7\u01A9\u01AC\u01AE-\u01AF\u01B1-\u01B3\u01B5\u01B7-\u01B8\u01BC\u01C4\u01C7\u01CA\u01CD\u01CF\u01D1\u01D3\u01D5\u01D7\u01D9\u01DB\u01DE\u01E0\u01E2\u01E4\u01E6\u01E8\u01EA\u01EC\u01EE\u01F1\u01F4\u01F6-\u01F8\u01FA\u01FC\u01FE\u0200\u0202\u0204\u0206\u0208\u020A\u020C\u020E\u0210\u0212\u0214\u0216\u0218\u021A\u021C\u021E\u0220\u0222\u0224\u0226\u0228\u022A\u022C\u022E\u0230\u0232\u023A-\u023B\u023D-\u023E\u0241\u0243-\u0246\u0248\u024A\u024C\u024E\u0370\u0372\u0376\u037F\u0386\u0388-\u038A\u038C\u038E-\u038F\u0391-\u03A1\u03A3-\u03AB\u03CF\u03D2-\u03D4\u03D8\u03DA\u03DC\u03DE\u03E0\u03E2\u03E4\u03E6\u03E8\u03EA\u03EC\u03EE\u03F4\u03F7\u03F9-\u03FA\u03FD-\u042F\u0460\u0462\u0464\u0466\u0468\u046A\u046C\u046E\u0470\u0472\u0474\u0476\u0478\u047A\u047C\u047E\u0480\u048A\u048C\u048E\u0490\u0492\u0494\u0496\u0498\u049A\u049C\u049E\u04A0\u04A2\u04A4\u04A6\u04A8\u04AA\u04AC\u04AE\u04B0\u04B2\u04B4\u04B6\u04B8\u04BA\u04BC\u04BE\u04C0-\u04C1\u04C3\u04C5\u04C7\u04C9\u04CB\u04CD\u04D0\u04D2\u04D4\u04D6\u04D8\u04DA\u04DC\u04DE\u04E0\u04E2\u04E4\u04E6\u04E8\u04EA\u04EC\u04EE\u04F0\u04F2\u04F4\u04F6\u04F8\u04FA\u04FC\u04FE\u0500\u0502\u0504\u0506\u0508\u050A\u050C\u050E\u0510\u0512\u0514\u0516\u0518\u051A\u051C\u051E\u0520\u0522\u0524\u0526\u0528\u052A\u052C\u052E\u0531-\u0556\u10A0-\u10C5\u10C7\u10CD\u13A0-\u13F5\u1C90-\u1CBA\u1CBD-\u1CBF\u1E00\u1E02\u1E04\u1E06\u1E08\u1E0A\u1E0C\u1E0E\u1E10\u1E12\u1E14\u1E16\u1E18\u1E1A\u1E1C\u1E1E\u1E20\u1E22\u1E24\u1E26\u1E28\u1E2A\u1E2C\u1E2E\u1E30\u1E32\u1E34\u1E36\u1E38\u1E3A\u1E3C\u1E3E\u1E40\u1E42\u1E44\u1E46\u1E48\u1E4A\u1E4C\u1E4E\u1E50\u1E52\u1E54\u1E56\u1E58\u1E5A\u1E5C\u1E5E\u1E60\u1E62\u1E64\u1E66\u1E68\u1E6A\u1E6C\u1E6E\u1E70\u1E72\u1E74\u1E76\u1E78\u1E7A\u1E7C\u1E7E\u1E80\u1E82\u1E84\u1E86\u1E88\u1E8A\u1E8C\u1E8E\u1E90\u1E92\u1E94\u1E9E\u1EA0\u1EA2\u1EA4\u1EA6\u1EA8\u1EAA\u1EAC\u1EAE\u1EB0\u1EB2\u1EB4\u1EB6\u1EB8\u1EBA\u1EBC\u1EBE\u1EC0\u1EC2\u1EC4\u1EC6\u1EC8\u1ECA\u1ECC\u1ECE\u1ED0\u1ED2\u1ED4\u1ED6\u1ED8\u1EDA\u1EDC\u1EDE\u1EE0\u1EE2\u1EE4\u1EE6\u1EE8\u1EEA\u1EEC\u1EEE\u1EF0\u1EF2\u1EF4\u1EF6\u1EF8\u1EFA\u1EFC\u1EFE\u1F08-\u1F0F\u1F18-\u1F1D\u1F28-\u1F2F\u1F38-\u1F3F\u1F48-\u1F4D\u1F59\u1F5B\u1F5D\u1F5F\u1F68-\u1F6F\u1FB8-\u1FBB\u1FC8-\u1FCB\u1FD8-\u1FDB\u1FE8-\u1FEC\u1FF8-\u1FFB\u2102\u2107\u210B-\u210D\u2110-\u2112\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u2130-\u2133\u213E-\u213F\u2145\u2183\u2C00-\u2C2E\u2C60\u2C62-\u2C64\u2C67\u2C69\u2C6B\u2C6D-\u2C70\u2C72\u2C75\u2C7E-\u2C80\u2C82\u2C84\u2C86\u2C88\u2C8A\u2C8C\u2C8E\u2C90\u2C92\u2C94\u2C96\u2C98\u2C9A\u2C9C\u2C9E\u2CA0\u2CA2\u2CA4\u2CA6\u2CA8\u2CAA\u2CAC\u2CAE\u2CB0\u2CB2\u2CB4\u2CB6\u2CB8\u2CBA\u2CBC\u2CBE\u2CC0\u2CC2\u2CC4\u2CC6\u2CC8\u2CCA\u2CCC\u2CCE\u2CD0\u2CD2\u2CD4\u2CD6\u2CD8\u2CDA\u2CDC\u2CDE\u2CE0\u2CE2\u2CEB\u2CED\u2CF2\uA640\uA642\uA644\uA646\uA648\uA64A\uA64C\uA64E\uA650\uA652\uA654\uA656\uA658\uA65A\uA65C\uA65E\uA660\uA662\uA664\uA666\uA668\uA66A\uA66C\uA680\uA682\uA684\uA686\uA688\uA68A\uA68C\uA68E\uA690\uA692\uA694\uA696\uA698\uA69A\uA722\uA724\uA726\uA728\uA72A\uA72C\uA72E\uA732\uA734\uA736\uA738\uA73A\uA73C\uA73E\uA740\uA742\uA744\uA746\uA748\uA74A\uA74C\uA74E\uA750\uA752\uA754\uA756\uA758\uA75A\uA75C\uA75E\uA760\uA762\uA764\uA766\uA768\uA76A\uA76C\uA76E\uA779\uA77B\uA77D-\uA77E\uA780\uA782\uA784\uA786\uA78B\uA78D\uA790\uA792\uA796\uA798\uA79A\uA79C\uA79E\uA7A0\uA7A2\uA7A4\uA7A6\uA7A8\uA7AA-\uA7AE\uA7B0-\uA7B4\uA7B6\uA7B8\uFF21-\uFF3A]
// Number, Letter // Number, Letter
Nl = [\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF] Nl = [\u16EE-\u16F0\u2160-\u2182\u2185-\u2188\u3007\u3021-\u3029\u3038-\u303A\uA6E6-\uA6EF]
+4 -1
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import * as krill from './krill-parser.js'; import * as krill from './krill-parser.js';
import * as strudel from '@strudel.cycles/core'; import * as strudel from '@strudel/core';
const randOffset = 0.0003; const randOffset = 0.0003;
@@ -107,6 +107,9 @@ export function patternifyAST(ast, code, onEnter, offset = 0) {
if (alignment === 'rand') { if (alignment === 'rand') {
return strudel.chooseInWith(strudel.rand.early(randOffset * ast.arguments_.seed).segment(1), children); return strudel.chooseInWith(strudel.rand.early(randOffset * ast.arguments_.seed).segment(1), children);
} }
if (alignment === 'feet') {
return strudel.fastcat(...children);
}
const weightedChildren = ast.source_.some((child) => !!child.options_?.weight); const weightedChildren = ast.source_.some((child) => !!child.options_?.weight);
if (weightedChildren) { if (weightedChildren) {
const weightSum = ast.source_.reduce((sum, child) => sum + (child.options_?.weight || 1), 0); const weightSum = ast.source_.reduce((sum, child) => sum + (child.options_?.weight || 1), 0);
+4 -5
View File
@@ -1,12 +1,11 @@
{ {
"name": "@strudel.cycles/mini", "name": "@strudel/mini",
"version": "0.10.0", "version": "1.0.1",
"description": "Mini notation for strudel", "description": "Mini notation for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run",
@@ -32,7 +31,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*" "@strudel/core": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"peggy": "^3.0.2", "peggy": "^3.0.2",
+15 -1
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import { getLeafLocation, getLeafLocations, mini, mini2ast } from '../mini.mjs'; import { getLeafLocation, getLeafLocations, mini, mini2ast } from '../mini.mjs';
import '@strudel.cycles/core/euclid.mjs'; import '@strudel/core/euclid.mjs';
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
describe('mini', () => { describe('mini', () => {
@@ -73,6 +73,10 @@ describe('mini', () => {
expect(minS('a!3 b')).toEqual(['a: 0 - 1/4', 'a: 1/4 - 1/2', 'a: 1/2 - 3/4', 'b: 3/4 - 1']); expect(minS('a!3 b')).toEqual(['a: 0 - 1/4', 'a: 1/4 - 1/2', 'a: 1/2 - 3/4', 'b: 3/4 - 1']);
expect(minS('[<a b c>]!3 d')).toEqual(minS('<a b c> <a b c> <a b c> d')); expect(minS('[<a b c>]!3 d')).toEqual(minS('<a b c> <a b c> <a b c> d'));
}); });
it('supports replication via repeated !', () => {
expect(minS('a ! ! b')).toEqual(['a: 0 - 1/4', 'a: 1/4 - 1/2', 'a: 1/2 - 3/4', 'b: 3/4 - 1']);
expect(minS('[<a b c>]!! d')).toEqual(minS('<a b c> <a b c> <a b c> d'));
});
it('supports euclidean rhythms', () => { it('supports euclidean rhythms', () => {
expect(minS('a(3, 8)')).toEqual(['a: 0 - 1/8', 'a: 3/8 - 1/2', 'a: 3/4 - 7/8']); expect(minS('a(3, 8)')).toEqual(['a: 0 - 1/8', 'a: 3/8 - 1/2', 'a: 3/4 - 7/8']);
}); });
@@ -190,6 +194,16 @@ describe('mini', () => {
it('supports patterned ranges', () => { it('supports patterned ranges', () => {
expect(minS('[<0 1> .. <2 4>]*2')).toEqual(minS('[0 1 2] [1 2 3 4]')); expect(minS('[<0 1> .. <2 4>]*2')).toEqual(minS('[0 1 2] [1 2 3 4]'));
}); });
it('supports the . operator', () => {
expect(minS('a . b c')).toEqual(minS('a [b c]'));
expect(minS('a . b c . [d e f . g h]')).toEqual(minS('a [b c] [[d e f] [g h]]'));
});
it('supports the _ operator', () => {
expect(minS('a _ b _ _')).toEqual(minS('a@2 b@3'));
});
it('_ and @ are almost interchangeable', () => {
expect(minS('a @ b @ @')).toEqual(minS('a _2 b _3'));
});
}); });
describe('getLeafLocation', () => { describe('getLeafLocation', () => {
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -3
View File
@@ -1,6 +1,4 @@
# @strudel.cycles/osc # @strudel/osc
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/osc](https://www.npmjs.com/package/@strudel/osc).
OSC output for strudel patterns! Currently only tested with super collider / super dirt. OSC output for strudel patterns! Currently only tested with super collider / super dirt.
+1 -1
View File
@@ -6,7 +6,7 @@ This program is free software: you can redistribute it and/or modify it under th
import OSC from 'osc-js'; import OSC from 'osc-js';
import { logger, parseNumeral, Pattern } from '@strudel.cycles/core'; import { logger, parseNumeral, Pattern } from '@strudel/core';
let connection; // Promise<OSC> let connection; // Promise<OSC>
function connect() { function connect() {
+5 -5
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/osc", "name": "@strudel/osc",
"version": "0.10.0", "version": "1.0.1",
"description": "OSC messaging for strudel", "description": "OSC messaging for strudel",
"main": "osc.mjs", "main": "osc.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"server": "node server.js", "server": "node server.js",
@@ -36,7 +36,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"osc-js": "^2.4.0" "osc-js": "^2.4.0"
}, },
"devDependencies": { "devDependencies": {
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'osc.mjs'), entry: resolve(__dirname, 'osc.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+2
View File
@@ -1,3 +1,5 @@
# @strudel/repl # @strudel/repl
The Strudel REPL as a web component. The Strudel REPL as a web component.
[Usage example](https://github.com/tidalcycles/strudel/blob/main/examples/buildless/web-component-no-iframe.html)
+10 -11
View File
@@ -1,11 +1,10 @@
{ {
"name": "@strudel/repl", "name": "@strudel/repl",
"version": "0.10.0", "version": "1.0.1",
"description": "Strudel REPL as a Web Component", "description": "Strudel REPL as a Web Component",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -33,15 +32,15 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/midi": "workspace:*",
"@strudel.cycles/mini": "workspace:*",
"@strudel.cycles/soundfonts": "workspace:*",
"@strudel.cycles/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*",
"@strudel/codemirror": "workspace:*", "@strudel/codemirror": "workspace:*",
"@strudel/hydra": "workspace:*" "@strudel/core": "workspace:*",
"@strudel/hydra": "workspace:*",
"@strudel/midi": "workspace:*",
"@strudel/mini": "workspace:*",
"@strudel/soundfonts": "workspace:*",
"@strudel/tonal": "workspace:*",
"@strudel/transpiler": "workspace:*",
"@strudel/webaudio": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-replace": "^5.0.5",
+16 -16
View File
@@ -1,22 +1,22 @@
import { controls, noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel.cycles/core'; import { controls, noteToMidi, valueToMidi, Pattern, evalScope } from '@strudel/core';
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel.cycles/webaudio'; import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel/webaudio';
import * as core from '@strudel.cycles/core'; import * as core from '@strudel/core';
export async function prebake() { export async function prebake() {
const modulesLoading = evalScope( const modulesLoading = evalScope(
// import('@strudel.cycles/core'), // import('@strudel/core'),
core, core,
import('@strudel.cycles/mini'), import('@strudel/mini'),
import('@strudel.cycles/tonal'), import('@strudel/tonal'),
import('@strudel.cycles/webaudio'), import('@strudel/webaudio'),
import('@strudel/codemirror'), import('@strudel/codemirror'),
import('@strudel/hydra'), import('@strudel/hydra'),
import('@strudel.cycles/soundfonts'), import('@strudel/soundfonts'),
import('@strudel.cycles/midi'), import('@strudel/midi'),
// import('@strudel.cycles/xen'), // import('@strudel/xen'),
// import('@strudel.cycles/serial'), // import('@strudel/serial'),
// import('@strudel.cycles/csound'), // import('@strudel/csound'),
// import('@strudel.cycles/osc'), // import('@strudel/osc'),
controls, // sadly, this cannot be exported from core directly (yet) controls, // sadly, this cannot be exported from core directly (yet)
); );
// load samples // load samples
@@ -26,10 +26,10 @@ export async function prebake() {
registerSynthSounds(), registerSynthSounds(),
registerZZFXSounds(), registerZZFXSounds(),
//registerSoundfonts(), //registerSoundfonts(),
// need dynamic import here, because importing @strudel.cycles/soundfonts fails on server: // need dynamic import here, because importing @strudel/soundfonts fails on server:
// => getting "window is not defined", as soon as "@strudel.cycles/soundfonts" is imported statically // => getting "window is not defined", as soon as "@strudel/soundfonts" is imported statically
// seems to be a problem with soundfont2 // seems to be a problem with soundfont2
import('@strudel.cycles/soundfonts').then(({ registerSoundfonts }) => registerSoundfonts()), import('@strudel/soundfonts').then(({ registerSoundfonts }) => registerSoundfonts()),
samples(`${ds}/tidal-drum-machines.json`), samples(`${ds}/tidal-drum-machines.json`),
samples(`${ds}/piano.json`), samples(`${ds}/piano.json`),
samples(`${ds}/Dirt-Samples.json`), samples(`${ds}/Dirt-Samples.json`),
+3 -3
View File
@@ -1,6 +1,6 @@
import { getDrawContext, silence } from '@strudel.cycles/core'; import { getDrawContext, silence } from '@strudel/core';
import { transpiler } from '@strudel.cycles/transpiler'; import { transpiler } from '@strudel/transpiler';
import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio'; import { getAudioContext, webaudioOutput } from '@strudel/webaudio';
import { StrudelMirror, codemirrorSettings } from '@strudel/codemirror'; import { StrudelMirror, codemirrorSettings } from '@strudel/codemirror';
import { prebake } from './prebake.mjs'; import { prebake } from './prebake.mjs';
+1 -3
View File
@@ -1,5 +1,3 @@
# @strudel.cycles/serial # @strudel/serial
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/serial](https://www.npmjs.com/package/@strudel/serial).
This package adds webserial functionality to strudel Patterns, for e.g. sending messages to arduino microcontrollers. This package adds webserial functionality to strudel Patterns, for e.g. sending messages to arduino microcontrollers.
+5 -5
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/serial", "name": "@strudel/serial",
"version": "0.10.0", "version": "1.0.1",
"description": "Webserial API for strudel", "description": "Webserial API for strudel",
"main": "serial.mjs", "main": "serial.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -29,7 +29,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*" "@strudel/core": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^5.0.10" "vite": "^5.0.10"
+1 -1
View File
@@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Pattern, isPattern } from '@strudel.cycles/core'; import { Pattern, isPattern } from '@strudel/core';
var writeMessagers = {}; var writeMessagers = {};
var choosing = false; var choosing = false;
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'serial.mjs'), entry: resolve(__dirname, 'serial.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -3
View File
@@ -1,3 +1 @@
# @strudel.cycles/soundfonts # @strudel/soundfonts
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/soundfonts](https://www.npmjs.com/package/@strudel/soundfonts).
+2 -2
View File
@@ -1,4 +1,4 @@
import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel.cycles/core'; import { noteToMidi, freqToMidi, getSoundIndex } from '@strudel/core';
import { import {
getAudioContext, getAudioContext,
registerSound, registerSound,
@@ -6,7 +6,7 @@ import {
getADSRValues, getADSRValues,
getPitchEnvelope, getPitchEnvelope,
getVibratoOscillator, getVibratoOscillator,
} from '@strudel.cycles/webaudio'; } from '@strudel/webaudio';
import gm from './gm.mjs'; import gm from './gm.mjs';
let loadCache = {}; let loadCache = {};
+5 -6
View File
@@ -1,11 +1,10 @@
{ {
"name": "@strudel.cycles/soundfonts", "name": "@strudel/soundfonts",
"version": "0.10.0", "version": "1.0.1",
"description": "Soundsfont support for strudel", "description": "Soundsfont support for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -30,8 +29,8 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*", "@strudel/webaudio": "workspace:*",
"sfumato": "^0.1.2", "sfumato": "^0.1.2",
"soundfont2": "^0.4.0" "soundfont2": "^0.4.0"
}, },
+2 -2
View File
@@ -1,5 +1,5 @@
import { Pattern, getPlayableNoteValue, noteToMidi } from '@strudel.cycles/core'; import { Pattern, getPlayableNoteValue, noteToMidi } from '@strudel/core';
import { getAudioContext, registerSound } from '@strudel.cycles/webaudio'; import { getAudioContext, registerSound } from '@strudel/webaudio';
import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato'; import { loadSoundfont as _loadSoundfont, startPresetNote } from 'sfumato';
Pattern.prototype.soundfont = function (sf, n = 0) { Pattern.prototype.soundfont = function (sf, n = 0) {
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+2 -3
View File
@@ -1,12 +1,11 @@
{ {
"name": "superdough", "name": "superdough",
"version": "0.10.0", "version": "1.0.1",
"description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.", "description": "simple web audio synth and sampler intended for live coding. inspired by superdirt and webdirt.",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.cjs", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"directories": { "directories": {
"example": "examples" "example": "examples"
+1 -1
View File
@@ -8,7 +8,7 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.cjs' })[ext], fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.cjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
+5 -7
View File
@@ -1,20 +1,18 @@
# @strudel.cycles/tonal # @strudel/tonal
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/tonal](https://www.npmjs.com/package/@strudel/tonal).
This package adds tonal / harmonic functions to strudel Patterns. This package adds tonal / harmonic functions to strudel Patterns.
## Install ## Install
```sh ```sh
npm i @strudel.cycles/tonal --save npm i @strudel/tonal --save
``` ```
## Example ## Example
```js ```js
import { sequence } from '@strudel.cycles/core'; import { sequence } from '@strudel/core';
import '@strudel.cycles/tonal'; import '@strudel/tonal';
const pattern = sequence(0, [1, 2]).scale('C major'); const pattern = sequence(0, [1, 2]).scale('C major');
@@ -29,7 +27,7 @@ yields:
(3/4 -> 1/1, 3/4 -> 1/1, E3) (3/4 -> 1/1, 3/4 -> 1/1, E3)
``` ```
[play with @strudel.cycles/tonal codesandbox](https://codesandbox.io/s/strudel-tonal-example-rgc5if?file=/src/index.js) [play with @strudel/tonal codesandbox](https://codesandbox.io/s/strudel-tonal-example-rgc5if?file=/src/index.js)
## Tonal API ## Tonal API
+4 -5
View File
@@ -1,11 +1,10 @@
{ {
"name": "@strudel.cycles/tonal", "name": "@strudel/tonal",
"version": "0.10.0", "version": "1.0.1",
"description": "Tonal functions for strudel", "description": "Tonal functions for strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -31,7 +30,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@tonaljs/tonal": "^4.7.2", "@tonaljs/tonal": "^4.7.2",
"chord-voicings": "^0.0.1", "chord-voicings": "^0.0.1",
"webmidi": "^3.1.8" "webmidi": "^3.1.8"
+1 -1
View File
@@ -7,7 +7,7 @@ This program is free software: you can redistribute it and/or modify it under th
// import { strict as assert } from 'assert'; // import { strict as assert } from 'assert';
import '../tonal.mjs'; // need to import this to add prototypes import '../tonal.mjs'; // need to import this to add prototypes
import { pure, controls, seq } from '@strudel.cycles/core'; import { pure, controls, seq } from '@strudel/core';
import { describe, it, expect } from 'vitest'; import { describe, it, expect } from 'vitest';
import { mini } from '../../mini/mini.mjs'; import { mini } from '../../mini/mini.mjs';
const { n } = controls; const { n } = controls;
+3 -3
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import { Note, Interval, Scale } from '@tonaljs/tonal'; import { Note, Interval, Scale } from '@tonaljs/tonal';
import { register, _mod, silence, logger, pure, isNote } from '@strudel.cycles/core'; import { register, _mod, silence, logger, pure, isNote } from '@strudel/core';
import { stepInNamedScale } from './tonleiter.mjs'; import { stepInNamedScale } from './tonleiter.mjs';
const octavesInterval = (octaves) => (octaves <= 0 ? -1 : 1) + octaves * 7 + 'P'; const octavesInterval = (octaves) => (octaves <= 0 ? -1 : 1) + octaves * 7 + 'P';
@@ -157,9 +157,9 @@ export const scaleTranspose = register('scaleTranspose', function (offset /* : n
* .scale("C:<major minor>/2") * .scale("C:<major minor>/2")
* .s("piano") * .s("piano")
* @example * @example
* n(rand.range(0,12).segment(8).round()) * n(rand.range(0,12).segment(8))
* .scale("C:ritusen") * .scale("C:ritusen")
* .s("folkharp") * .s("piano")
*/ */
export const scale = register('scale', function (scale, pat) { export const scale = register('scale', function (scale, pat) {
+1 -1
View File
@@ -1,4 +1,4 @@
import { isNote, isNoteWithOctave, _mod, noteToMidi, tokenizeNote } from '@strudel.cycles/core'; import { isNote, isNoteWithOctave, _mod, noteToMidi, tokenizeNote } from '@strudel/core';
import { Interval, Scale } from '@tonaljs/tonal'; import { Interval, Scale } from '@tonaljs/tonal';
// https://codesandbox.io/s/stateless-voicings-g2tmz0?file=/src/lib.js:0-2515 // https://codesandbox.io/s/stateless-voicings-g2tmz0?file=/src/lib.js:0-2515
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -1
View File
@@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { stack, register, silence, logger } from '@strudel.cycles/core'; import { stack, register, silence, logger } from '@strudel/core';
import { renderVoicing } from './tonleiter.mjs'; import { renderVoicing } from './tonleiter.mjs';
import _voicings from 'chord-voicings'; import _voicings from 'chord-voicings';
import { complex, simple } from './ireal.mjs'; import { complex, simple } from './ireal.mjs';
+4 -6
View File
@@ -1,6 +1,4 @@
# @strudel.cycles/transpiler # @strudel/transpiler
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/transpiler](https://www.npmjs.com/package/@strudel/transpiler).
This package contains a JS code transpiler with the following features: This package contains a JS code transpiler with the following features:
@@ -11,14 +9,14 @@ This package contains a JS code transpiler with the following features:
## Install ## Install
```sh ```sh
npm i @strudel.cycles/transpiler npm i @strudel/transpiler
``` ```
## Use ## Use
```js ```js
import { transpiler } from '@strudel.cycles/core'; import { transpiler } from '@strudel/core';
import { evaluate } from '@strudel.cycles/core'; import { evaluate } from '@strudel/core';
transpiler('note("c3 [e3,g3]")', { wrapAsync: false, addReturn: false, simpleLocs: true }); transpiler('note("c3 [e3,g3]")', { wrapAsync: false, addReturn: false, simpleLocs: true });
/* mini('c3 [e3,g3]').withMiniLocation(7,17) */ /* mini('c3 [e3,g3]').withMiniLocation(7,17) */
+1 -1
View File
@@ -1,4 +1,4 @@
import { evaluate as _evaluate } from '@strudel.cycles/core'; import { evaluate as _evaluate } from '@strudel/core';
import { transpiler } from './transpiler.mjs'; import { transpiler } from './transpiler.mjs';
export * from './transpiler.mjs'; export * from './transpiler.mjs';
+6 -6
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/transpiler", "name": "@strudel/transpiler",
"version": "0.10.0", "version": "1.0.1",
"description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.", "description": "Transpiler for strudel user code. Converts syntactically correct but semantically meaningless JS into evaluatable strudel code.",
"main": "index.mjs", "main": "index.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -30,8 +30,8 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel/mini": "workspace:*",
"acorn": "^8.11.3", "acorn": "^8.11.3",
"escodegen": "^2.1.0", "escodegen": "^2.1.0",
"estree-walker": "^3.0.1" "estree-walker": "^3.0.1"
+2 -2
View File
@@ -1,8 +1,8 @@
import escodegen from 'escodegen'; import escodegen from 'escodegen';
import { parse } from 'acorn'; import { parse } from 'acorn';
import { walk } from 'estree-walker'; import { walk } from 'estree-walker';
import { isNoteWithOctave } from '@strudel.cycles/core'; import { isNoteWithOctave } from '@strudel/core';
import { getLeafLocations } from '@strudel.cycles/mini'; import { getLeafLocations } from '@strudel/mini';
export function transpiler(input, options = {}) { export function transpiler(input, options = {}) {
const { wrapAsync = false, addReturn = true, emitMiniLocations = true, emitWidgets = true } = options; const { wrapAsync = false, addReturn = true, emitMiniLocations = true, emitWidgets = true } = options;
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+7 -8
View File
@@ -1,11 +1,10 @@
{ {
"name": "@strudel/web", "name": "@strudel/web",
"version": "0.10.0", "version": "1.0.1",
"description": "Easy to setup, opiniated bundle of Strudel for the browser.", "description": "Easy to setup, opiniated bundle of Strudel for the browser.",
"main": "web.mjs", "main": "web.mjs",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -33,11 +32,11 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*", "@strudel/mini": "workspace:*",
"@strudel.cycles/tonal": "workspace:*", "@strudel/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*" "@strudel/webaudio": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^5.0.10" "vite": "^5.0.10"
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'web.mjs'), entry: resolve(__dirname, 'web.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+16 -16
View File
@@ -1,25 +1,25 @@
export * from '@strudel.cycles/core'; export * from '@strudel/core';
export * from '@strudel.cycles/webaudio'; export * from '@strudel/webaudio';
//export * from '@strudel.cycles/soundfonts'; //export * from '@strudel/soundfonts';
export * from '@strudel.cycles/transpiler'; export * from '@strudel/transpiler';
export * from '@strudel.cycles/mini'; export * from '@strudel/mini';
export * from '@strudel.cycles/tonal'; export * from '@strudel/tonal';
export * from '@strudel.cycles/webaudio'; export * from '@strudel/webaudio';
import { Pattern, evalScope, controls } from '@strudel.cycles/core'; import { Pattern, evalScope, controls } from '@strudel/core';
import { initAudioOnFirstClick, registerSynthSounds, webaudioScheduler } from '@strudel.cycles/webaudio'; import { initAudioOnFirstClick, registerSynthSounds, webaudioScheduler } from '@strudel/webaudio';
// import { registerSoundfonts } from '@strudel.cycles/soundfonts'; // import { registerSoundfonts } from '@strudel/soundfonts';
import { evaluate as _evaluate } from '@strudel.cycles/transpiler'; import { evaluate as _evaluate } from '@strudel/transpiler';
import { miniAllStrings } from '@strudel.cycles/mini'; import { miniAllStrings } from '@strudel/mini';
// init logic // init logic
export async function defaultPrebake() { export async function defaultPrebake() {
const loadModules = evalScope( const loadModules = evalScope(
evalScope, evalScope,
controls, controls,
import('@strudel.cycles/core'), import('@strudel/core'),
import('@strudel.cycles/mini'), import('@strudel/mini'),
import('@strudel.cycles/tonal'), import('@strudel/tonal'),
import('@strudel.cycles/webaudio'), import('@strudel/webaudio'),
{ hush, evaluate }, { hush, evaluate },
); );
await Promise.all([loadModules, registerSynthSounds() /* , registerSoundfonts() */]); await Promise.all([loadModules, registerSynthSounds() /* , registerSoundfonts() */]);
+4 -6
View File
@@ -1,6 +1,4 @@
# @strudel.cycles/webaudio # @strudel/webaudio
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/webaudio](https://www.npmjs.com/package/@strudel/webaudio).
This package contains helpers to make music with strudel and the Web Audio API. This package contains helpers to make music with strudel and the Web Audio API.
It is a thin binding to [superdough](https://www.npmjs.com/package/superdough). It is a thin binding to [superdough](https://www.npmjs.com/package/superdough).
@@ -8,14 +6,14 @@ It is a thin binding to [superdough](https://www.npmjs.com/package/superdough).
## Install ## Install
```sh ```sh
npm i @strudel.cycles/webaudio --save npm i @strudel/webaudio --save
``` ```
## Example ## Example
```js ```js
import { repl, controls } from "@strudel.cycles/core"; import { repl, controls } from "@strudel/core";
import { initAudioOnFirstClick, getAudioContext, webaudioOutput } from "@strudel.cycles/webaudio"; import { initAudioOnFirstClick, getAudioContext, webaudioOutput } from "@strudel/webaudio";
const { note } = controls; const { note } = controls;
initAudioOnFirstClick(); initAudioOnFirstClick();
+4 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/webaudio", "name": "@strudel/webaudio",
"version": "0.10.0", "version": "1.0.1",
"description": "Web Audio helpers for Strudel", "description": "Web Audio helpers for Strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
@@ -8,8 +8,7 @@
"example": "examples" "example": "examples"
}, },
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"example": "npx parcel examples/repl.html", "example": "npx parcel examples/repl.html",
@@ -34,7 +33,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*", "@strudel/core": "workspace:*",
"superdough": "workspace:*" "superdough": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
+1 -1
View File
@@ -1,4 +1,4 @@
import { Pattern, getDrawContext, clamp } from '@strudel.cycles/core'; import { Pattern, getDrawContext, clamp } from '@strudel/core';
import { analyser, getAnalyzerData } from 'superdough'; import { analyser, getAnalyzerData } from 'superdough';
export function drawTimeScope( export function drawTimeScope(
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -1
View File
@@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import * as strudel from '@strudel.cycles/core'; import * as strudel from '@strudel/core';
import { superdough, getAudioContext, setLogger, doughTrigger } from 'superdough'; import { superdough, getAudioContext, setLogger, doughTrigger } from 'superdough';
const { Pattern, logger } = strudel; const { Pattern, logger } = strudel;
+2 -4
View File
@@ -1,11 +1,9 @@
# @strudel.cycles/xen # @strudel/xen
**DEPRECATION NOTE**: This package is old and won't get any updates! The newer version goes by the name of [@strudel/xen](https://www.npmjs.com/package/@strudel/xen).
This package adds xenharmonic / microtonal functions to strudel Patterns. Further documentation + examples will follow. This package adds xenharmonic / microtonal functions to strudel Patterns. Further documentation + examples will follow.
## Install ## Install
```sh ```sh
npm i @strudel.cycles/xen --save npm i @strudel/xen --save
``` ```
+5 -5
View File
@@ -1,11 +1,11 @@
{ {
"name": "@strudel.cycles/xen", "name": "@strudel/xen",
"version": "0.10.0", "version": "1.0.1",
"description": "Xenharmonic API for strudel", "description": "Xenharmonic API for strudel",
"main": "index.mjs", "main": "index.mjs",
"type": "module",
"publishConfig": { "publishConfig": {
"main": "dist/index.js", "main": "dist/index.mjs"
"module": "dist/index.mjs"
}, },
"scripts": { "scripts": {
"build": "vite build", "build": "vite build",
@@ -30,7 +30,7 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@strudel.cycles/core": "workspace:*" "@strudel/core": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^5.0.10", "vite": "^5.0.10",
+1 -1
View File
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/ */
import Tune from './tunejs.js'; import Tune from './tunejs.js';
import { register } from '@strudel.cycles/core'; import { register } from '@strudel/core';
export const tune = register('tune', (scale, pat) => { export const tune = register('tune', (scale, pat) => {
const tune = new Tune(); const tune = new Tune();
+2 -2
View File
@@ -8,8 +8,8 @@ export default defineConfig({
build: { build: {
lib: { lib: {
entry: resolve(__dirname, 'index.mjs'), entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'], formats: ['es'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext], fileName: (ext) => ({ es: 'index.mjs' })[ext],
}, },
rollupOptions: { rollupOptions: {
external: [...Object.keys(dependencies)], external: [...Object.keys(dependencies)],
+1 -1
View File
@@ -4,7 +4,7 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { register, _mod, parseNumeral } from '@strudel.cycles/core'; import { register, _mod, parseNumeral } from '@strudel/core';
export function edo(name) { export function edo(name) {
if (!/^[1-9]+[0-9]*edo$/.test(name)) { if (!/^[1-9]+[0-9]*edo$/.test(name)) {
+162 -109
View File
@@ -8,22 +8,22 @@ importers:
.: .:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:packages/core version: link:packages/core
'@strudel.cycles/mini': '@strudel/mini':
specifier: workspace:* specifier: workspace:*
version: link:packages/mini version: link:packages/mini
'@strudel.cycles/tonal': '@strudel/tonal':
specifier: workspace:* specifier: workspace:*
version: link:packages/tonal version: link:packages/tonal
'@strudel.cycles/transpiler': '@strudel/transpiler':
specifier: workspace:* specifier: workspace:*
version: link:packages/transpiler version: link:packages/transpiler
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:packages/webaudio version: link:packages/webaudio
'@strudel.cycles/xen': '@strudel/xen':
specifier: workspace:* specifier: workspace:*
version: link:packages/xen version: link:packages/xen
devDependencies: devDependencies:
@@ -72,27 +72,27 @@ importers:
examples/codemirror-repl: examples/codemirror-repl:
dependencies: dependencies:
'@strudel.cycles/core':
specifier: workspace:*
version: link:../../packages/core
'@strudel.cycles/mini':
specifier: workspace:*
version: link:../../packages/mini
'@strudel.cycles/soundfonts':
specifier: workspace:*
version: link:../../packages/soundfonts
'@strudel.cycles/tonal':
specifier: workspace:*
version: link:../../packages/tonal
'@strudel.cycles/transpiler':
specifier: workspace:*
version: link:../../packages/transpiler
'@strudel.cycles/webaudio':
specifier: workspace:*
version: link:../../packages/webaudio
'@strudel/codemirror': '@strudel/codemirror':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/codemirror version: link:../../packages/codemirror
'@strudel/core':
specifier: workspace:*
version: link:../../packages/core
'@strudel/mini':
specifier: workspace:*
version: link:../../packages/mini
'@strudel/soundfonts':
specifier: workspace:*
version: link:../../packages/soundfonts
'@strudel/tonal':
specifier: workspace:*
version: link:../../packages/tonal
'@strudel/transpiler':
specifier: workspace:*
version: link:../../packages/transpiler
'@strudel/webaudio':
specifier: workspace:*
version: link:../../packages/webaudio
devDependencies: devDependencies:
vite: vite:
specifier: ^5.0.10 specifier: ^5.0.10
@@ -110,19 +110,19 @@ importers:
examples/minimal-repl: examples/minimal-repl:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/core version: link:../../packages/core
'@strudel.cycles/mini': '@strudel/mini':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/mini version: link:../../packages/mini
'@strudel.cycles/tonal': '@strudel/tonal':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/tonal version: link:../../packages/tonal
'@strudel.cycles/transpiler': '@strudel/transpiler':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/transpiler version: link:../../packages/transpiler
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/webaudio version: link:../../packages/webaudio
devDependencies: devDependencies:
@@ -178,7 +178,7 @@ importers:
'@replit/codemirror-vscode-keymap': '@replit/codemirror-vscode-keymap':
specifier: ^6.0.2 specifier: ^6.0.2
version: 6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0) version: 6.0.2(@codemirror/autocomplete@6.11.1)(@codemirror/commands@6.3.3)(@codemirror/language@6.10.0)(@codemirror/lint@6.4.2)(@codemirror/search@6.5.5)(@codemirror/state@6.4.0)(@codemirror/view@6.23.0)
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@uiw/codemirror-themes': '@uiw/codemirror-themes':
@@ -213,10 +213,10 @@ importers:
'@csound/browser': '@csound/browser':
specifier: 6.18.7 specifier: 6.18.7
version: 6.18.7(eslint@8.56.0) version: 6.18.7(eslint@8.56.0)
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:../webaudio version: link:../webaudio
devDependencies: devDependencies:
@@ -226,7 +226,7 @@ importers:
packages/desktopbridge: packages/desktopbridge:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@tauri-apps/api': '@tauri-apps/api':
@@ -237,7 +237,7 @@ importers:
packages/hydra: packages/hydra:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
hydra-synth: hydra-synth:
@@ -253,10 +253,10 @@ importers:
packages/midi: packages/midi:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:../webaudio version: link:../webaudio
webmidi: webmidi:
@@ -269,7 +269,7 @@ importers:
packages/mini: packages/mini:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
devDependencies: devDependencies:
@@ -285,7 +285,7 @@ importers:
packages/osc: packages/osc:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
osc-js: osc-js:
@@ -301,33 +301,33 @@ importers:
packages/repl: packages/repl:
dependencies: dependencies:
'@strudel.cycles/core':
specifier: workspace:*
version: link:../core
'@strudel.cycles/midi':
specifier: workspace:*
version: link:../midi
'@strudel.cycles/mini':
specifier: workspace:*
version: link:../mini
'@strudel.cycles/soundfonts':
specifier: workspace:*
version: link:../soundfonts
'@strudel.cycles/tonal':
specifier: workspace:*
version: link:../tonal
'@strudel.cycles/transpiler':
specifier: workspace:*
version: link:../transpiler
'@strudel.cycles/webaudio':
specifier: workspace:*
version: link:../webaudio
'@strudel/codemirror': '@strudel/codemirror':
specifier: workspace:* specifier: workspace:*
version: link:../codemirror version: link:../codemirror
'@strudel/core':
specifier: workspace:*
version: link:../core
'@strudel/hydra': '@strudel/hydra':
specifier: workspace:* specifier: workspace:*
version: link:../hydra version: link:../hydra
'@strudel/midi':
specifier: workspace:*
version: link:../midi
'@strudel/mini':
specifier: workspace:*
version: link:../mini
'@strudel/soundfonts':
specifier: workspace:*
version: link:../soundfonts
'@strudel/tonal':
specifier: workspace:*
version: link:../tonal
'@strudel/transpiler':
specifier: workspace:*
version: link:../transpiler
'@strudel/webaudio':
specifier: workspace:*
version: link:../webaudio
devDependencies: devDependencies:
'@rollup/plugin-replace': '@rollup/plugin-replace':
specifier: ^5.0.5 specifier: ^5.0.5
@@ -341,7 +341,7 @@ importers:
packages/serial: packages/serial:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
devDependencies: devDependencies:
@@ -351,10 +351,10 @@ importers:
packages/soundfonts: packages/soundfonts:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:../webaudio version: link:../webaudio
sfumato: sfumato:
@@ -383,7 +383,7 @@ importers:
packages/tonal: packages/tonal:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@tonaljs/tonal': '@tonaljs/tonal':
@@ -405,10 +405,10 @@ importers:
packages/transpiler: packages/transpiler:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@strudel.cycles/mini': '@strudel/mini':
specifier: workspace:* specifier: workspace:*
version: link:../mini version: link:../mini
acorn: acorn:
@@ -430,19 +430,19 @@ importers:
packages/web: packages/web:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@strudel.cycles/mini': '@strudel/mini':
specifier: workspace:* specifier: workspace:*
version: link:../mini version: link:../mini
'@strudel.cycles/tonal': '@strudel/tonal':
specifier: workspace:* specifier: workspace:*
version: link:../tonal version: link:../tonal
'@strudel.cycles/transpiler': '@strudel/transpiler':
specifier: workspace:* specifier: workspace:*
version: link:../transpiler version: link:../transpiler
'@strudel.cycles/webaudio': '@strudel/webaudio':
specifier: workspace:* specifier: workspace:*
version: link:../webaudio version: link:../webaudio
devDependencies: devDependencies:
@@ -452,7 +452,7 @@ importers:
packages/webaudio: packages/webaudio:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
superdough: superdough:
@@ -465,7 +465,7 @@ importers:
packages/xen: packages/xen:
dependencies: dependencies:
'@strudel.cycles/core': '@strudel/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
devDependencies: devDependencies:
@@ -476,20 +476,29 @@ importers:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.1.0(@vitest/ui@1.1.0) version: 1.1.0(@vitest/ui@1.1.0)
tools/dbpatch:
dependencies:
csv:
specifier: ^6.3.6
version: 6.3.6
website: website:
dependencies: dependencies:
'@algolia/client-search': '@algolia/client-search':
specifier: ^4.22.0 specifier: ^4.22.0
version: 4.22.0 version: 4.22.0
'@astro-community/astro-embed-youtube': '@astro-community/astro-embed-youtube':
specifier: ^0.4.3 specifier: ^0.4.4
version: 0.4.3(astro@4.0.8) version: 0.4.4(astro@4.0.8)
'@astrojs/mdx': '@astrojs/mdx':
specifier: ^2.0.3 specifier: ^2.0.3
version: 2.0.3(astro@4.0.8) version: 2.0.3(astro@4.0.8)
'@astrojs/react': '@astrojs/react':
specifier: ^3.0.9 specifier: ^3.0.9
version: 3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.11) version: 3.0.9(@types/react-dom@18.2.18)(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)(vite@5.0.11)
'@astrojs/rss':
specifier: ^4.0.2
version: 4.0.2
'@astrojs/tailwind': '@astrojs/tailwind':
specifier: ^5.1.0 specifier: ^5.1.0
version: 5.1.0(astro@4.0.8)(tailwindcss@3.4.0) version: 5.1.0(astro@4.0.8)(tailwindcss@3.4.0)
@@ -511,51 +520,51 @@ importers:
'@nanostores/react': '@nanostores/react':
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1(nanostores@0.9.5)(react@18.2.0) version: 0.7.1(nanostores@0.9.5)(react@18.2.0)
'@strudel.cycles/core':
specifier: workspace:*
version: link:../packages/core
'@strudel.cycles/csound':
specifier: workspace:*
version: link:../packages/csound
'@strudel.cycles/midi':
specifier: workspace:*
version: link:../packages/midi
'@strudel.cycles/mini':
specifier: workspace:*
version: link:../packages/mini
'@strudel.cycles/osc':
specifier: workspace:*
version: link:../packages/osc
'@strudel.cycles/serial':
specifier: workspace:*
version: link:../packages/serial
'@strudel.cycles/soundfonts':
specifier: workspace:*
version: link:../packages/soundfonts
'@strudel.cycles/tonal':
specifier: workspace:*
version: link:../packages/tonal
'@strudel.cycles/transpiler':
specifier: workspace:*
version: link:../packages/transpiler
'@strudel.cycles/webaudio':
specifier: workspace:*
version: link:../packages/webaudio
'@strudel.cycles/xen':
specifier: workspace:*
version: link:../packages/xen
'@strudel/codemirror': '@strudel/codemirror':
specifier: workspace:* specifier: workspace:*
version: link:../packages/codemirror version: link:../packages/codemirror
'@strudel/core':
specifier: workspace:*
version: link:../packages/core
'@strudel/csound':
specifier: workspace:*
version: link:../packages/csound
'@strudel/desktopbridge': '@strudel/desktopbridge':
specifier: workspace:* specifier: workspace:*
version: link:../packages/desktopbridge version: link:../packages/desktopbridge
'@strudel/hydra': '@strudel/hydra':
specifier: workspace:* specifier: workspace:*
version: link:../packages/hydra version: link:../packages/hydra
'@strudel/midi':
specifier: workspace:*
version: link:../packages/midi
'@strudel/mini':
specifier: workspace:*
version: link:../packages/mini
'@strudel/osc':
specifier: workspace:*
version: link:../packages/osc
'@strudel/repl': '@strudel/repl':
specifier: workspace:* specifier: workspace:*
version: link:../packages/repl version: link:../packages/repl
'@strudel/serial':
specifier: workspace:*
version: link:../packages/serial
'@strudel/soundfonts':
specifier: workspace:*
version: link:../packages/soundfonts
'@strudel/tonal':
specifier: workspace:*
version: link:../packages/tonal
'@strudel/transpiler':
specifier: workspace:*
version: link:../packages/transpiler
'@strudel/webaudio':
specifier: workspace:*
version: link:../packages/webaudio
'@strudel/xen':
specifier: workspace:*
version: link:../packages/xen
'@supabase/supabase-js': '@supabase/supabase-js':
specifier: ^2.39.1 specifier: ^2.39.1
version: 2.39.1 version: 2.39.1
@@ -803,8 +812,8 @@ packages:
leven: 3.1.0 leven: 3.1.0
dev: true dev: true
/@astro-community/astro-embed-youtube@0.4.3(astro@4.0.8): /@astro-community/astro-embed-youtube@0.4.4(astro@4.0.8):
resolution: {integrity: sha512-zXtPmR9yxrTo6cuLhH8v+r62bsXbsLJgsU2FiZalPr4bXJxAUQEIlG46S/qK0AEXi9uNShKqy4+zBaJ98xTVEg==} resolution: {integrity: sha512-fYlycLrJFNnibZ9VHPSJO766kO2IgqYQU4mBd4iaDMaicL0gGX9cVZ80QdnpzGrI6w0XOJOY7prx86eWEVBy8w==}
peerDependencies: peerDependencies:
astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta astro: ^2.0.0 || ^3.0.0-beta || ^4.0.0-beta
dependencies: dependencies:
@@ -890,6 +899,13 @@ packages:
- vite - vite
dev: false dev: false
/@astrojs/rss@4.0.2:
resolution: {integrity: sha512-Hb9GKAyvsn5EUjZtB6SniesBScMQe7SQinEHLY5EFa74QEvgcWaXTmA0Mb0P3vqDSN3d/NTYbGivprrSAawfnA==}
dependencies:
fast-xml-parser: 4.3.3
kleur: 4.1.5
dev: false
/@astrojs/tailwind@5.1.0(astro@4.0.8)(tailwindcss@3.4.0): /@astrojs/tailwind@5.1.0(astro@4.0.8)(tailwindcss@3.4.0):
resolution: {integrity: sha512-BJoCDKuWhU9FT2qYg+fr6Nfb3qP4ShtyjXGHKA/4mHN94z7BGcmauQK23iy+YH5qWvTnhqkd6mQPQ1yTZTe9Ig==} resolution: {integrity: sha512-BJoCDKuWhU9FT2qYg+fr6Nfb3qP4ShtyjXGHKA/4mHN94z7BGcmauQK23iy+YH5qWvTnhqkd6mQPQ1yTZTe9Ig==}
peerDependencies: peerDependencies:
@@ -6213,6 +6229,28 @@ packages:
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
dev: false dev: false
/csv-generate@4.3.1:
resolution: {integrity: sha512-7YeeJq+44/I/O5N2sr2qBMcHZXhpfe38eh7DOFxyMtYO+Pir7kIfgFkW5MPksqKqqR6+/wX7UGoZm1Ot11151w==}
dev: false
/csv-parse@5.5.3:
resolution: {integrity: sha512-v0KW6C0qlZzoGjk6u5tLmVfyZxNgPGXZsWTXshpAgKVGmGXzaVWGdlCFxNx5iuzcXT/oJN1HHM9DZKwtAtYa+A==}
dev: false
/csv-stringify@6.4.5:
resolution: {integrity: sha512-SPu1Vnh8U5EnzpNOi1NDBL5jU5Rx7DVHr15DNg9LXDTAbQlAVAmEbVt16wZvEW9Fu9Qt4Ji8kmeCJ2B1+4rFTQ==}
dev: false
/csv@6.3.6:
resolution: {integrity: sha512-jsEsX2HhGp7xiwrJu5srQavKsh+HUJcCi78Ar3m4jlmFKRoTkkMy7ZZPP+LnQChmaztW+uj44oyfMb59daAs/Q==}
engines: {node: '>= 0.1.90'}
dependencies:
csv-generate: 4.3.1
csv-parse: 5.5.3
csv-stringify: 6.4.5
stream-transform: 3.3.0
dev: false
/dargs@7.0.0: /dargs@7.0.0:
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -7182,6 +7220,13 @@ packages:
/fast-levenshtein@2.0.6: /fast-levenshtein@2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
/fast-xml-parser@4.3.3:
resolution: {integrity: sha512-coV/D1MhrShMvU6D0I+VAK3umz6hUaxxhL0yp/9RjfiYUfAv14rDhGQL+PLForhMdr0wq3PiV07WtkkNjJjNHg==}
hasBin: true
dependencies:
strnum: 1.0.5
dev: false
/fastq@1.15.0: /fastq@1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies: dependencies:
@@ -12457,6 +12502,10 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/stream-transform@3.3.0:
resolution: {integrity: sha512-pG1NeDdmErNYKtvTpFayrEueAmL0xVU5wd22V7InGnatl4Ocq3HY7dcXIKj629kXvYQvglCC7CeDIGAlx1RNGA==}
dev: false
/stream-via@1.0.4: /stream-via@1.0.4:
resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==} resolution: {integrity: sha512-DBp0lSvX5G9KGRDTkR/R+a29H+Wk2xItOF+MpZLLNDWbEV9tGPnqLPxHEYjmiz8xGtJHRIqmI+hCjmNzqoA4nQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -12637,6 +12686,10 @@ packages:
acorn: 8.11.3 acorn: 8.11.3
dev: true dev: true
/strnum@1.0.5:
resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==}
dev: false
/strong-log-transformer@2.1.0: /strong-log-transformer@2.1.0:
resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==} resolution: {integrity: sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==}
engines: {node: '>=4'} engines: {node: '>=4'}

Some files were not shown because too many files have changed in this diff Show More