diff --git a/packages/core/index.mjs b/packages/core/index.mjs
index 30504a5b..78241f74 100644
--- a/packages/core/index.mjs
+++ b/packages/core/index.mjs
@@ -18,6 +18,7 @@ export * from './util.mjs';
export * from './speak.mjs';
export * from './evaluate.mjs';
export * from './repl.mjs';
+export * from './cyclist.mjs';
export * from './logger.mjs';
export * from './draw.mjs';
export * from './animate.mjs';
diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs
index de979258..abb9ef80 100644
--- a/packages/core/repl.mjs
+++ b/packages/core/repl.mjs
@@ -17,23 +17,15 @@ export function repl({
}) {
const scheduler = new Cyclist({
interval,
- onTrigger: async (hap, deadline, duration, cps) => {
- try {
- if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
- await defaultOutput(hap, deadline, duration, cps);
- }
- if (hap.context.onTrigger) {
- // call signature of output / onTrigger is different...
- await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps);
- }
- } catch (err) {
- logger(`[cyclist] error: ${err.message}`, 'error');
- }
- },
+ onTrigger: getTrigger({ defaultOutput, getTime }),
onError: onSchedulerError,
getTime,
onToggle,
});
+ const setPattern = (pattern, autostart = true) => {
+ pattern = editPattern?.(pattern) || pattern;
+ scheduler.setPattern(pattern, autostart);
+ };
const evaluate = async (code, autostart = true) => {
if (!code) {
throw new Error('no code to evaluate');
@@ -43,8 +35,7 @@ export function repl({
let { pattern } = await _evaluate(code, transpiler);
logger(`[eval] code updated`);
- pattern = editPattern?.(pattern) || pattern;
- scheduler.setPattern(pattern, autostart);
+ setPattern(pattern, autostart);
afterEval?.({ code, pattern });
return pattern;
} catch (err) {
@@ -61,5 +52,21 @@ export function repl({
setCps,
setcps: setCps,
});
- return { scheduler, evaluate, start, stop, pause, setCps };
+ return { scheduler, evaluate, start, stop, pause, setCps, setPattern };
}
+
+export const getTrigger =
+ ({ getTime, defaultOutput }) =>
+ async (hap, deadline, duration, cps) => {
+ try {
+ if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
+ await defaultOutput(hap, deadline, duration, cps);
+ }
+ if (hap.context.onTrigger) {
+ // call signature of output / onTrigger is different...
+ await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps);
+ }
+ } catch (err) {
+ logger(`[cyclist] error: ${err.message}`, 'error');
+ }
+ };
diff --git a/packages/mini/mini.mjs b/packages/mini/mini.mjs
index 648499e6..3f9228d9 100644
--- a/packages/mini/mini.mjs
+++ b/packages/mini/mini.mjs
@@ -190,3 +190,8 @@ export function minify(thing) {
}
return strudel.reify(thing);
}
+
+// calling this function will cause patterns to parse strings as mini notation by default
+export function miniAllStrings() {
+ strudel.setStringParser(mini);
+}
diff --git a/packages/web/README.md b/packages/web/README.md
index c70a5df7..53609c3e 100644
--- a/packages/web/README.md
+++ b/packages/web/README.md
@@ -4,16 +4,20 @@ This package provides an easy to use bundle of multiple strudel packages for the
## Usage
-```js
-import { repl } from '@strudel/web';
+Minimal example:
-const strudel = repl();
+```js
+import '@strudel/web';
document.getElementById('play').addEventListener('click',
- () => strudel.evaluate('note("c a f e").jux(rev)')
-);
+ () => note("c a f e").play()
+)
```
+As soon as you `import '@strudel/web'`, all strudel functions will be available in the global scope.
+In this case, we are using `note` to create a pattern.
+To actually play the pattern, you have to append `.play()` to the end.
+
Note: Due to the [Autoplay policy](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Best_practices#autoplay_policy), you can only play audio in a browser after a click event.
### Loading samples
@@ -21,15 +25,28 @@ Note: Due to the [Autoplay policy](https://developer.mozilla.org/en-US/docs/Web/
By default, no external samples are loaded, but you can add them like this:
```js
-import { repl, samples } from '@strudel/web';
+import { prebake } from '@strudel/web';
-const strudel = repl({
- prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
-});
+prebake(() => samples('github:tidalcycles/Dirt-Samples/master'))
document.getElementById('play').addEventListener('click',
- () => strudel.evaluate('s("bd,jvbass(3,8)").jux(rev)')
-);
+ () => s("bd sd").play()
+)
```
You can learn [more about the `samples` function here](https://strudel.tidalcycles.org/learn/samples#loading-custom-samples).
+
+### Evaluating Code
+
+Instead of creating patterns directly in JS, you might also want to take in user input and turn that into a pattern.
+This is called evaluation: Taking a piece of code and executing it on the fly.
+
+To do that, you can use the `evaluate` function:
+
+```js
+import '@strudel/web';
+
+document.getElementById('play').addEventListener('click',
+ () => evaluate('note("c a f e").jux(rev)')
+);
+```
diff --git a/packages/web/examples/repl-example/index.html b/packages/web/examples/repl-example/index.html
index a7954e64..853e02db 100644
--- a/packages/web/examples/repl-example/index.html
+++ b/packages/web/examples/repl-example/index.html
@@ -13,17 +13,16 @@