mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 13:48:34 +00:00
Merge pull request #263 from tidalcycles/fix-tutorial-bugs
fix tutorial bugs
This commit is contained in:
commit
547d925065
@ -10,7 +10,7 @@
|
||||
"test-coverage": "vitest --coverage",
|
||||
"bootstrap": "lerna bootstrap",
|
||||
"setup": "npm i && npm run bootstrap && cd repl && npm i && cd ../tutorial && npm i",
|
||||
"snapshot": "cd repl && npm run snapshot",
|
||||
"snapshot": "vitest run -u --silent",
|
||||
"repl": "cd repl && npm run dev",
|
||||
"osc": "cd packages/osc && npm run server",
|
||||
"build": "rm -rf out && cd repl && npm run build && cd ../tutorial && npm run build",
|
||||
|
||||
@ -1050,7 +1050,7 @@ export class Pattern {
|
||||
* @param {function} func function to apply
|
||||
* @returns Pattern
|
||||
* @example
|
||||
* note("c3 d3 e3 g3").every(4, x=>x.rev())
|
||||
* note("c3 d3 e3 g3").each(4, x=>x.rev())
|
||||
*/
|
||||
each(n, func) {
|
||||
const pat = this;
|
||||
|
||||
@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
|
||||
*/
|
||||
|
||||
// returns true if the given string is a note
|
||||
export const isNote = (name) => /^[a-gA-G][#b]*[0-9]$/.test(name);
|
||||
export const isNote = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name);
|
||||
export const tokenizeNote = (note) => {
|
||||
if (typeof note !== 'string') {
|
||||
return [];
|
||||
|
||||
2
packages/react/dist/index.cjs.js
vendored
2
packages/react/dist/index.cjs.js
vendored
File diff suppressed because one or more lines are too long
302
packages/react/dist/index.es.js
vendored
302
packages/react/dist/index.es.js
vendored
@ -1,15 +1,15 @@
|
||||
import n, { useCallback as N, useRef as x, useEffect as R, useState as w, useMemo as I, useLayoutEffect as K } from "react";
|
||||
import Q from "@uiw/react-codemirror";
|
||||
import { Decoration as E, EditorView as O } from "@codemirror/view";
|
||||
import { StateEffect as j, StateField as U } from "@codemirror/state";
|
||||
import { javascript as W } from "@codemirror/lang-javascript";
|
||||
import n, { useCallback as _, useRef as H, useEffect as L, useMemo as V, useState as w, useLayoutEffect as j } from "react";
|
||||
import X from "@uiw/react-codemirror";
|
||||
import { Decoration as E, EditorView as U } from "@codemirror/view";
|
||||
import { StateEffect as $, StateField as G } from "@codemirror/state";
|
||||
import { javascript as Y } from "@codemirror/lang-javascript";
|
||||
import { tags as r } from "@lezer/highlight";
|
||||
import { createTheme as X } from "@uiw/codemirror-themes";
|
||||
import { useInView as Y } from "react-hook-inview";
|
||||
import { webaudioOutput as Z, getAudioContext as ee } from "@strudel.cycles/webaudio";
|
||||
import { repl as te } from "@strudel.cycles/core";
|
||||
import { transpiler as re } from "@strudel.cycles/transpiler";
|
||||
const oe = X({
|
||||
import { createTheme as Z } from "@uiw/codemirror-themes";
|
||||
import { useInView as ee } from "react-hook-inview";
|
||||
import { webaudioOutput as te, getAudioContext as re } from "@strudel.cycles/webaudio";
|
||||
import { repl as oe } from "@strudel.cycles/core";
|
||||
import { transpiler as ne } from "@strudel.cycles/transpiler";
|
||||
const ae = Z({
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: "#222",
|
||||
@ -42,14 +42,14 @@ const oe = X({
|
||||
{ tag: r.invalid, color: "#ffffff" }
|
||||
]
|
||||
});
|
||||
const T = j.define(), ne = U.define({
|
||||
const B = $.define(), se = G.define({
|
||||
create() {
|
||||
return E.none;
|
||||
},
|
||||
update(e, t) {
|
||||
try {
|
||||
for (let o of t.effects)
|
||||
if (o.is(T))
|
||||
if (o.is(B))
|
||||
if (o.value) {
|
||||
const a = E.mark({ attributes: { style: "background-color: #FFCA2880" } });
|
||||
e = E.set([a.range(0, t.newDoc.length)]);
|
||||
@ -60,25 +60,25 @@ const T = j.define(), ne = U.define({
|
||||
return console.warn("flash error", o), e;
|
||||
}
|
||||
},
|
||||
provide: (e) => O.decorations.from(e)
|
||||
}), ae = (e) => {
|
||||
e.dispatch({ effects: T.of(!0) }), setTimeout(() => {
|
||||
e.dispatch({ effects: T.of(!1) });
|
||||
provide: (e) => U.decorations.from(e)
|
||||
}), ce = (e) => {
|
||||
e.dispatch({ effects: B.of(!0) }), setTimeout(() => {
|
||||
e.dispatch({ effects: B.of(!1) });
|
||||
}, 200);
|
||||
}, A = j.define(), se = U.define({
|
||||
}, z = $.define(), ie = G.define({
|
||||
create() {
|
||||
return E.none;
|
||||
},
|
||||
update(e, t) {
|
||||
try {
|
||||
for (let o of t.effects)
|
||||
if (o.is(A)) {
|
||||
if (o.is(z)) {
|
||||
const a = o.value.map(
|
||||
(s) => (s.context.locations || []).map(({ start: m, end: l }) => {
|
||||
const d = s.context.color || "#FFCA28";
|
||||
let c = t.newDoc.line(m.line).from + m.column, i = t.newDoc.line(l.line).from + l.column;
|
||||
const g = t.newDoc.length;
|
||||
return c > g || i > g ? void 0 : E.mark({ attributes: { style: `outline: 1.5px solid ${d};` } }).range(c, i);
|
||||
(s) => (s.context.locations || []).map(({ start: f, end: d }) => {
|
||||
const u = s.context.color || "#FFCA28";
|
||||
let c = t.newDoc.line(f.line).from + f.column, i = t.newDoc.line(d.line).from + d.column;
|
||||
const m = t.newDoc.length;
|
||||
return c > m || i > m ? void 0 : E.mark({ attributes: { style: `outline: 1.5px solid ${u};` } }).range(c, i);
|
||||
})
|
||||
).flat().filter(Boolean) || [];
|
||||
e = E.set(a, !0);
|
||||
@ -88,69 +88,69 @@ const T = j.define(), ne = U.define({
|
||||
return E.set([]);
|
||||
}
|
||||
},
|
||||
provide: (e) => O.decorations.from(e)
|
||||
}), ce = [W(), oe, se, ne];
|
||||
function ie({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, options: s, editorDidMount: m }) {
|
||||
const l = N(
|
||||
provide: (e) => U.decorations.from(e)
|
||||
}), le = [Y(), ae, ie, se];
|
||||
function de({ value: e, onChange: t, onViewChanged: o, onSelectionChange: a, options: s, editorDidMount: f }) {
|
||||
const d = _(
|
||||
(i) => {
|
||||
t?.(i);
|
||||
},
|
||||
[t]
|
||||
), d = N(
|
||||
), u = _(
|
||||
(i) => {
|
||||
o?.(i);
|
||||
},
|
||||
[o]
|
||||
), c = N(
|
||||
), c = _(
|
||||
(i) => {
|
||||
i.selectionSet && a && a?.(i.state.selection);
|
||||
},
|
||||
[a]
|
||||
);
|
||||
return /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement(Q, {
|
||||
return /* @__PURE__ */ n.createElement(n.Fragment, null, /* @__PURE__ */ n.createElement(X, {
|
||||
value: e,
|
||||
onChange: l,
|
||||
onCreateEditor: d,
|
||||
onChange: d,
|
||||
onCreateEditor: u,
|
||||
onUpdate: c,
|
||||
extensions: ce
|
||||
extensions: le
|
||||
}));
|
||||
}
|
||||
function B(...e) {
|
||||
function K(...e) {
|
||||
return e.filter(Boolean).join(" ");
|
||||
}
|
||||
function le({ view: e, pattern: t, active: o, getTime: a }) {
|
||||
const s = x([]), m = x();
|
||||
R(() => {
|
||||
function ue({ view: e, pattern: t, active: o, getTime: a }) {
|
||||
const s = H([]), f = H();
|
||||
L(() => {
|
||||
if (e)
|
||||
if (t && o) {
|
||||
let d = function() {
|
||||
let u = function() {
|
||||
try {
|
||||
const c = a(), g = [Math.max(m.current || c, c - 1 / 10, 0), c + 1 / 60];
|
||||
m.current = g[1], s.current = s.current.filter((p) => p.whole.end > c);
|
||||
const h = t.queryArc(...g).filter((p) => p.hasOnset());
|
||||
s.current = s.current.concat(h), e.dispatch({ effects: A.of(s.current) });
|
||||
const c = a(), m = [Math.max(f.current || c, c - 1 / 10, 0), c + 1 / 60];
|
||||
f.current = m[1], s.current = s.current.filter((g) => g.whole.end > c);
|
||||
const h = t.queryArc(...m).filter((g) => g.hasOnset());
|
||||
s.current = s.current.concat(h), e.dispatch({ effects: z.of(s.current) });
|
||||
} catch {
|
||||
e.dispatch({ effects: A.of([]) });
|
||||
e.dispatch({ effects: z.of([]) });
|
||||
}
|
||||
l = requestAnimationFrame(d);
|
||||
}, l = requestAnimationFrame(d);
|
||||
d = requestAnimationFrame(u);
|
||||
}, d = requestAnimationFrame(u);
|
||||
return () => {
|
||||
cancelAnimationFrame(l);
|
||||
cancelAnimationFrame(d);
|
||||
};
|
||||
} else
|
||||
s.current = [], e.dispatch({ effects: A.of([]) });
|
||||
s.current = [], e.dispatch({ effects: z.of([]) });
|
||||
}, [t, o, e]);
|
||||
}
|
||||
const de = "_container_3i85k_1", ue = "_header_3i85k_5", fe = "_buttons_3i85k_9", me = "_button_3i85k_9", ge = "_buttonDisabled_3i85k_17", pe = "_error_3i85k_21", he = "_body_3i85k_25", b = {
|
||||
container: de,
|
||||
header: ue,
|
||||
buttons: fe,
|
||||
button: me,
|
||||
buttonDisabled: ge,
|
||||
error: pe,
|
||||
body: he
|
||||
const fe = "_container_3i85k_1", me = "_header_3i85k_5", ge = "_buttons_3i85k_9", pe = "_button_3i85k_9", he = "_buttonDisabled_3i85k_17", be = "_error_3i85k_21", ve = "_body_3i85k_25", v = {
|
||||
container: fe,
|
||||
header: me,
|
||||
buttons: ge,
|
||||
button: pe,
|
||||
buttonDisabled: he,
|
||||
error: be,
|
||||
body: ve
|
||||
};
|
||||
function q({ type: e }) {
|
||||
function O({ type: e }) {
|
||||
return /* @__PURE__ */ n.createElement("svg", {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
className: "sc-h-5 sc-w-5",
|
||||
@ -174,137 +174,147 @@ function q({ type: e }) {
|
||||
})
|
||||
}[e]);
|
||||
}
|
||||
function ve({
|
||||
function Ee(e) {
|
||||
return L(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), _((t) => window.postMessage(t, "*"), []);
|
||||
}
|
||||
function we({
|
||||
defaultOutput: e,
|
||||
interval: t,
|
||||
getTime: o,
|
||||
evalOnMount: a = !1,
|
||||
initialCode: s = "",
|
||||
autolink: m = !1,
|
||||
beforeEval: l,
|
||||
afterEval: d,
|
||||
autolink: f = !1,
|
||||
beforeEval: d,
|
||||
afterEval: u,
|
||||
onEvalError: c,
|
||||
onToggle: i
|
||||
}) {
|
||||
const [g, h] = w(), [p, D] = w(), [v, k] = w(s), [y, P] = w(), [z, _] = w(), [C, H] = w(!1), F = v !== y, { scheduler: u, evaluate: L, start: $, stop: G, pause: J } = I(
|
||||
() => te({
|
||||
const m = V(() => ye(), []), [h, g] = w(), [C, N] = w(), [p, y] = w(s), [M, S] = w(), [k, D] = w(), [F, x] = w(!1), b = p !== M, { scheduler: A, evaluate: T, start: J, stop: q, pause: Q } = V(
|
||||
() => oe({
|
||||
interval: t,
|
||||
defaultOutput: e,
|
||||
onSchedulerError: h,
|
||||
onEvalError: (f) => {
|
||||
D(f), c?.(f);
|
||||
onSchedulerError: g,
|
||||
onEvalError: (l) => {
|
||||
N(l), c?.(l);
|
||||
},
|
||||
getTime: o,
|
||||
transpiler: re,
|
||||
beforeEval: ({ code: f }) => {
|
||||
k(f), l?.();
|
||||
transpiler: ne,
|
||||
beforeEval: ({ code: l }) => {
|
||||
y(l), d?.();
|
||||
},
|
||||
afterEval: ({ pattern: f, code: S }) => {
|
||||
P(S), _(f), D(), h(), m && (window.location.hash = "#" + encodeURIComponent(btoa(S))), d?.();
|
||||
afterEval: ({ pattern: l, code: P }) => {
|
||||
S(P), D(l), N(), g(), f && (window.location.hash = "#" + encodeURIComponent(btoa(P))), u?.();
|
||||
},
|
||||
onToggle: (f) => {
|
||||
H(f), i?.(f);
|
||||
onToggle: (l) => {
|
||||
x(l), i?.(l);
|
||||
}
|
||||
}),
|
||||
[e, t, o]
|
||||
), M = N(async (f = !0) => L(v, f), [L, v]), V = x();
|
||||
return R(() => {
|
||||
!V.current && a && v && (V.current = !0, M());
|
||||
}, [M, a, v]), R(() => () => {
|
||||
u.stop();
|
||||
}, [u]), {
|
||||
code: v,
|
||||
setCode: k,
|
||||
error: g || p,
|
||||
schedulerError: g,
|
||||
scheduler: u,
|
||||
evalError: p,
|
||||
evaluate: L,
|
||||
activateCode: M,
|
||||
activeCode: y,
|
||||
isDirty: F,
|
||||
pattern: z,
|
||||
started: C,
|
||||
start: $,
|
||||
stop: G,
|
||||
pause: J,
|
||||
), W = Ee(({ data: { from: l, type: P } }) => {
|
||||
P === "start" && l !== m && q();
|
||||
}), R = _(
|
||||
async (l = !0) => {
|
||||
await T(p, l), W({ type: "start", from: m });
|
||||
},
|
||||
[T, p]
|
||||
), I = H();
|
||||
return L(() => {
|
||||
!I.current && a && p && (I.current = !0, R());
|
||||
}, [R, a, p]), L(() => () => {
|
||||
A.stop();
|
||||
}, [A]), {
|
||||
code: p,
|
||||
setCode: y,
|
||||
error: h || C,
|
||||
schedulerError: h,
|
||||
scheduler: A,
|
||||
evalError: C,
|
||||
evaluate: T,
|
||||
activateCode: R,
|
||||
activeCode: M,
|
||||
isDirty: b,
|
||||
pattern: k,
|
||||
started: F,
|
||||
start: J,
|
||||
stop: q,
|
||||
pause: Q,
|
||||
togglePlay: async () => {
|
||||
C ? u.pause() : await M();
|
||||
F ? A.pause() : await R();
|
||||
}
|
||||
};
|
||||
}
|
||||
const be = () => ee().currentTime;
|
||||
function Pe({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
|
||||
function ye() {
|
||||
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
|
||||
}
|
||||
const ke = () => re().currentTime;
|
||||
function Se({ tune: e, hideOutsideView: t = !1, init: o, enableKeyboard: a }) {
|
||||
const {
|
||||
code: s,
|
||||
setCode: m,
|
||||
evaluate: l,
|
||||
activateCode: d,
|
||||
setCode: f,
|
||||
evaluate: d,
|
||||
activateCode: u,
|
||||
error: c,
|
||||
isDirty: i,
|
||||
activeCode: g,
|
||||
activeCode: m,
|
||||
pattern: h,
|
||||
started: p,
|
||||
scheduler: D,
|
||||
togglePlay: v,
|
||||
stop: k
|
||||
} = ve({
|
||||
started: g,
|
||||
scheduler: C,
|
||||
togglePlay: N,
|
||||
stop: p
|
||||
} = we({
|
||||
initialCode: e,
|
||||
defaultOutput: Z,
|
||||
getTime: be
|
||||
}), [y, P] = w(), [z, _] = Y({
|
||||
defaultOutput: te,
|
||||
getTime: ke
|
||||
}), [y, M] = w(), [S, k] = ee({
|
||||
threshold: 0.01
|
||||
}), C = x(), H = I(() => ((_ || !t) && (C.current = !0), _ || C.current), [_, t]);
|
||||
return le({
|
||||
}), D = H(), F = V(() => ((k || !t) && (D.current = !0), k || D.current), [k, t]);
|
||||
return ue({
|
||||
view: y,
|
||||
pattern: h,
|
||||
active: p && !g?.includes("strudel disable-highlighting"),
|
||||
getTime: () => D.getPhase()
|
||||
}), K(() => {
|
||||
active: g && !m?.includes("strudel disable-highlighting"),
|
||||
getTime: () => C.getPhase()
|
||||
}), j(() => {
|
||||
if (a) {
|
||||
const F = async (u) => {
|
||||
(u.ctrlKey || u.altKey) && (u.code === "Enter" ? (u.preventDefault(), ae(y), await d()) : u.code === "Period" && (k(), u.preventDefault()));
|
||||
const x = async (b) => {
|
||||
(b.ctrlKey || b.altKey) && (b.code === "Enter" ? (b.preventDefault(), ce(y), await u()) : b.code === "Period" && (p(), b.preventDefault()));
|
||||
};
|
||||
return window.addEventListener("keydown", F, !0), () => window.removeEventListener("keydown", F, !0);
|
||||
return window.addEventListener("keydown", x, !0), () => window.removeEventListener("keydown", x, !0);
|
||||
}
|
||||
}, [a, h, s, l, k, y]), /* @__PURE__ */ n.createElement("div", {
|
||||
className: b.container,
|
||||
ref: z
|
||||
}, [a, h, s, d, p, y]), /* @__PURE__ */ n.createElement("div", {
|
||||
className: v.container,
|
||||
ref: S
|
||||
}, /* @__PURE__ */ n.createElement("div", {
|
||||
className: b.header
|
||||
className: v.header
|
||||
}, /* @__PURE__ */ n.createElement("div", {
|
||||
className: b.buttons
|
||||
className: v.buttons
|
||||
}, /* @__PURE__ */ n.createElement("button", {
|
||||
className: B(b.button, p ? "sc-animate-pulse" : ""),
|
||||
onClick: () => v()
|
||||
}, /* @__PURE__ */ n.createElement(q, {
|
||||
type: p ? "pause" : "play"
|
||||
className: K(v.button, g ? "sc-animate-pulse" : ""),
|
||||
onClick: () => N()
|
||||
}, /* @__PURE__ */ n.createElement(O, {
|
||||
type: g ? "pause" : "play"
|
||||
})), /* @__PURE__ */ n.createElement("button", {
|
||||
className: B(i ? b.button : b.buttonDisabled),
|
||||
onClick: () => d()
|
||||
}, /* @__PURE__ */ n.createElement(q, {
|
||||
className: K(i ? v.button : v.buttonDisabled),
|
||||
onClick: () => u()
|
||||
}, /* @__PURE__ */ n.createElement(O, {
|
||||
type: "refresh"
|
||||
}))), c && /* @__PURE__ */ n.createElement("div", {
|
||||
className: b.error
|
||||
className: v.error
|
||||
}, c.message)), /* @__PURE__ */ n.createElement("div", {
|
||||
className: b.body
|
||||
}, H && /* @__PURE__ */ n.createElement(ie, {
|
||||
className: v.body
|
||||
}, F && /* @__PURE__ */ n.createElement(de, {
|
||||
value: s,
|
||||
onChange: m,
|
||||
onViewChanged: P
|
||||
onChange: f,
|
||||
onViewChanged: M
|
||||
})));
|
||||
}
|
||||
function ze(e) {
|
||||
return R(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), N((t) => window.postMessage(t, "*"), []);
|
||||
}
|
||||
const He = (e) => K(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]);
|
||||
const Te = (e) => j(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]);
|
||||
export {
|
||||
ie as CodeMirror,
|
||||
Pe as MiniRepl,
|
||||
B as cx,
|
||||
ae as flash,
|
||||
le as useHighlighting,
|
||||
He as useKeydown,
|
||||
ze as usePostMessage,
|
||||
ve as useStrudel
|
||||
de as CodeMirror,
|
||||
Se as MiniRepl,
|
||||
K as cx,
|
||||
ce as flash,
|
||||
ue as useHighlighting,
|
||||
Te as useKeydown,
|
||||
Ee as usePostMessage,
|
||||
we as useStrudel
|
||||
};
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { repl } from '@strudel.cycles/core';
|
||||
import { transpiler } from '@strudel.cycles/transpiler';
|
||||
import usePostMessage from './usePostMessage.mjs';
|
||||
|
||||
function useStrudel({
|
||||
defaultOutput,
|
||||
@ -14,6 +15,7 @@ function useStrudel({
|
||||
onEvalError,
|
||||
onToggle,
|
||||
}) {
|
||||
const id = useMemo(() => s4(), []);
|
||||
// scheduler
|
||||
const [schedulerError, setSchedulerError] = useState();
|
||||
const [evalError, setEvalError] = useState();
|
||||
@ -57,7 +59,19 @@ function useStrudel({
|
||||
}),
|
||||
[defaultOutput, interval, getTime],
|
||||
);
|
||||
const activateCode = useCallback(async (autostart = true) => evaluate(code, autostart), [evaluate, code]);
|
||||
const broadcast = usePostMessage(({ data: { from, type } }) => {
|
||||
if (type === 'start' && from !== id) {
|
||||
// console.log('message', from, type);
|
||||
stop();
|
||||
}
|
||||
});
|
||||
const activateCode = useCallback(
|
||||
async (autostart = true) => {
|
||||
await evaluate(code, autostart);
|
||||
broadcast({ type: 'start', from: id });
|
||||
},
|
||||
[evaluate, code],
|
||||
);
|
||||
|
||||
const inited = useRef();
|
||||
useEffect(() => {
|
||||
@ -103,3 +117,9 @@ function useStrudel({
|
||||
}
|
||||
|
||||
export default useStrudel;
|
||||
|
||||
function s4() {
|
||||
return Math.floor((1 + Math.random()) * 0x10000)
|
||||
.toString(16)
|
||||
.substring(1);
|
||||
}
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"test": "vitest run --reporter verbose -v --no-isolate",
|
||||
"snapshot": "vitest run -u --silent",
|
||||
"add-license": "cat etc/agpl-header.txt ../docs/static/js/*LICENSE.txt > /tmp/strudel-license.txt && cp /tmp/strudel-license.txt ../docs/static/js/*LICENSE.txt",
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "gh-pages -d ../docs",
|
||||
|
||||
@ -19,7 +19,7 @@ evalScope(
|
||||
import('@strudel.cycles/osc'),
|
||||
);
|
||||
|
||||
prebake();
|
||||
// prebake();
|
||||
|
||||
export function MiniRepl({ tune }) {
|
||||
return <_MiniRepl tune={tune} hideOutsideView={true} />;
|
||||
|
||||
@ -10,6 +10,9 @@ import Tutorial from './tutorial.rendered.mdx';
|
||||
// import ApiDoc from './ApiDoc';
|
||||
import './style.scss';
|
||||
import '@strudel.cycles/react/dist/style.css';
|
||||
import { initAudioOnFirstClick } from '@strudel.cycles/webaudio';
|
||||
|
||||
initAudioOnFirstClick();
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
|
||||
@ -767,10 +767,10 @@ exports[`runs examples > example "dry" example index 0 1`] = `
|
||||
|
||||
exports[`runs examples > example "each" example index 0 1`] = `
|
||||
[
|
||||
"3/4 -> 1/1: {\\"note\\":\\"c3\\"}",
|
||||
"1/2 -> 3/4: {\\"note\\":\\"d3\\"}",
|
||||
"1/4 -> 1/2: {\\"note\\":\\"e3\\"}",
|
||||
"0/1 -> 1/4: {\\"note\\":\\"g3\\"}",
|
||||
"0/1 -> 1/4: {\\"note\\":\\"c3\\"}",
|
||||
"1/4 -> 1/2: {\\"note\\":\\"d3\\"}",
|
||||
"1/2 -> 3/4: {\\"note\\":\\"e3\\"}",
|
||||
"3/4 -> 1/1: {\\"note\\":\\"g3\\"}",
|
||||
"1/1 -> 5/4: {\\"note\\":\\"c3\\"}",
|
||||
"5/4 -> 3/2: {\\"note\\":\\"d3\\"}",
|
||||
"3/2 -> 7/4: {\\"note\\":\\"e3\\"}",
|
||||
@ -779,10 +779,10 @@ exports[`runs examples > example "each" example index 0 1`] = `
|
||||
"9/4 -> 5/2: {\\"note\\":\\"d3\\"}",
|
||||
"5/2 -> 11/4: {\\"note\\":\\"e3\\"}",
|
||||
"11/4 -> 3/1: {\\"note\\":\\"g3\\"}",
|
||||
"3/1 -> 13/4: {\\"note\\":\\"c3\\"}",
|
||||
"13/4 -> 7/2: {\\"note\\":\\"d3\\"}",
|
||||
"7/2 -> 15/4: {\\"note\\":\\"e3\\"}",
|
||||
"15/4 -> 4/1: {\\"note\\":\\"g3\\"}",
|
||||
"15/4 -> 4/1: {\\"note\\":\\"c3\\"}",
|
||||
"7/2 -> 15/4: {\\"note\\":\\"d3\\"}",
|
||||
"13/4 -> 7/2: {\\"note\\":\\"e3\\"}",
|
||||
"3/1 -> 13/4: {\\"note\\":\\"g3\\"}",
|
||||
]
|
||||
`;
|
||||
|
||||
|
||||
@ -253,7 +253,7 @@ Using round brackets, we can create rhythmical sub-divisions based on three para
|
||||
The first parameter controls how may beats will be played.
|
||||
The second parameter controls the total amount of segments the beats will be distributed over.
|
||||
The third (optional) parameter controls the starting position for distributing the beats.
|
||||
One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,1)" or simply "(3,8)",
|
||||
One popular Euclidian rhythm (going by various names, such as "Pop Clave") is "(3,8,0)" or simply "(3,8)",
|
||||
resulting in a rhythmical structure of "x ~ ~ x ~ ~ x ~" (3 beats over 8 segments, starting on position 1).
|
||||
|
||||
<MiniRepl tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(4)`} />
|
||||
@ -358,7 +358,7 @@ For pitched sounds, you can use `note`, just like with synths:
|
||||
|
||||
<MiniRepl
|
||||
tune={`samples({
|
||||
"gtr": 'gtr/0001_cleanC.wav',
|
||||
'gtr': 'gtr/0001_cleanC.wav',
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').gain(.5)`}
|
||||
/>
|
||||
@ -368,7 +368,7 @@ If we want them to behave more like a synth, we can add `clip(1)`:
|
||||
|
||||
<MiniRepl
|
||||
tune={`samples({
|
||||
"gtr": 'gtr/0001_cleanC.wav',
|
||||
'gtr': 'gtr/0001_cleanC.wav',
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s('gtr').clip(1)
|
||||
.gain(.5)`}
|
||||
@ -380,8 +380,8 @@ If we have 2 samples with different base pitches, we can make them in tune by sp
|
||||
|
||||
<MiniRepl
|
||||
tune={`samples({
|
||||
"gtr": 'gtr/0001_cleanC.wav',
|
||||
"moog": { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
|
||||
'gtr': 'gtr/0001_cleanC.wav',
|
||||
'moog': { 'g3': 'moog/005_Mighty%20Moog%20G3.wav' },
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');
|
||||
note("g3 [bb3 c4] <g4 f4 eb4 f3>@2").s("gtr,moog").clip(1)
|
||||
.gain(.5)`}
|
||||
@ -393,7 +393,7 @@ We can also declare different samples for different regions of the keyboard:
|
||||
|
||||
<MiniRepl
|
||||
tune={`samples({
|
||||
"moog": {
|
||||
'moog': {
|
||||
'g2': 'moog/004_Mighty%20Moog%20G2.wav',
|
||||
'g3': 'moog/005_Mighty%20Moog%20G3.wav',
|
||||
'g4': 'moog/006_Mighty%20Moog%20G4.wav',
|
||||
@ -769,9 +769,9 @@ Together with layer, struct and voicings, this can be used to create a basic bac
|
||||
|
||||
<MiniRepl
|
||||
tune={`"<C^7 A7b13 Dm7 G7>".layer(
|
||||
x => x.voicings(['d3','g4']).struct("~ x"),
|
||||
x => x.rootNotes(2).tone(synth(osc('sawtooth4')).chain(out()))
|
||||
).note()`}
|
||||
x => x.voicings(['d3','g4']).struct("~ x").note(),
|
||||
x => x.rootNotes(2).note().s('sawtooth').cutoff(800)
|
||||
)`}
|
||||
/>
|
||||
|
||||
<!-- TODO: use range instead of octave. -->
|
||||
@ -786,17 +786,15 @@ Strudel also supports midi via [webmidi](https://npmjs.com/package/webmidi).
|
||||
|
||||
### midi(outputName?)
|
||||
|
||||
Make sure to have a midi device connected or to use an IAC Driver.
|
||||
Either connect a midi device or use the IAC Driver (Mac) or Midi Through Port (Linux) for internal midi messages.
|
||||
If no outputName is given, it uses the first midi output it finds.
|
||||
|
||||
Midi is currently not supported by the mini repl used here, but you can [open the midi example in the repl](https://strudel.tidalcycles.org/#c3RhY2soIjxDXjcgQTcgRG03IEc3PiIubS52b2ljaW5ncygpLCAnPEMzIEEyIEQzIEcyPicubSkKICAubWlkaSgp).
|
||||
|
||||
In the REPL, you will se a log of the available MIDI devices.
|
||||
|
||||
<!--<MiniRepl
|
||||
<MiniRepl
|
||||
tune={`stack("<C^7 A7 Dm7 G7>".voicings(), "<C3 A2 D3 G2>")
|
||||
.midi()`}
|
||||
/>-->
|
||||
/>
|
||||
|
||||
In the console, you will see a log of the available MIDI devices as soon as you run the code, e.g. `Midi connected! Using "Midi Through Port-0".`
|
||||
|
||||
# Superdirt API
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user