diff --git a/packages/core/evaluate.mjs b/packages/core/evaluate.mjs index 9627a2ad..340febe5 100644 --- a/packages/core/evaluate.mjs +++ b/packages/core/evaluate.mjs @@ -47,10 +47,5 @@ export const evaluate = async (code, transpiler) => { // if no transpiler is given, we expect a single instruction (!wrapExpression) const options = { wrapExpression: !!transpiler }; let evaluated = await safeEval(code, options); - if (!isPattern(evaluated)) { - console.log('evaluated', evaluated); - const message = `got "${typeof evaluated}" instead of pattern`; - throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.')); - } return { mode: 'javascript', pattern: evaluated, meta }; }; diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs index f30d21c8..5a9a3fe8 100644 --- a/packages/core/pattern.mjs +++ b/packages/core/pattern.mjs @@ -1178,7 +1178,7 @@ export function reify(thing) { * @return {Pattern} * @synonyms polyrhythm, pr * @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) { // Array test here is to avoid infinite recursions.. @@ -1193,7 +1193,7 @@ export function stack(...pats) { * * @return {Pattern} * @example - * slowcat(e5, b4, [d5, c5]) + * slowcat("e5", "b4", ["d5", "c5"]) * */ export function slowcat(...pats) { @@ -1237,7 +1237,7 @@ export function slowcatPrime(...pats) { * @synonyms slowcat * @return {Pattern} * @example - * cat(e5, b4, [d5, c5]).note() // "".note() + * cat("e5", "b4", ["d5", "c5"]).note() // "".note() * */ export function cat(...pats) { @@ -1247,7 +1247,7 @@ export function cat(...pats) { /** Like {@link Pattern.seq}, but each step has a length, relative to the whole. * @return {Pattern} * @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) { const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0)); @@ -1287,7 +1287,7 @@ export function sequence(...pats) { /** Like **cat**, but the items are crammed into one cycle. * @synonyms fastcat, sequence * @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) { @@ -1975,9 +1975,9 @@ export const press = register('press', function (pat) { * s("hh*3") * ) */ -export const hush = register('hush', function (pat) { +Pattern.prototype.hush = function () { return silence; -}); +}; /** * Applies `rev` to a pattern every other cycle, so that the pattern alternates between forwards and backwards. diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 67e2812d..3645d594 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -3,7 +3,7 @@ import { evaluate as _evaluate } from './evaluate.mjs'; import { logger } from './logger.mjs'; import { setTime } from './time.mjs'; import { evalScope } from './evaluate.mjs'; -import { register } from './pattern.mjs'; +import { register, Pattern, isPattern, silence, stack } from './pattern.mjs'; export function repl({ interval, @@ -24,22 +24,37 @@ export function repl({ getTime, onToggle, }); - let playPatterns = []; + let pPatterns = {}; + let allTransform; + + const hush = function () { + pPatterns = {}; + allTransform = undefined; + return silence; + }; + const setPattern = (pattern, autostart = true) => { pattern = editPattern?.(pattern) || pattern; scheduler.setPattern(pattern, autostart); }; setTime(() => scheduler.now()); // TODO: refactor? - const evaluate = async (code, autostart = true) => { + const evaluate = async (code, autostart = true, shouldHush = true) => { if (!code) { throw new Error('no code to evaluate'); } try { await beforeEval?.({ code }); - playPatterns = []; + shouldHush && hush(); let { pattern, meta } = await _evaluate(code, transpiler); - if (playPatterns.length) { - pattern = pattern.stack(...playPatterns); + if (Object.keys(pPatterns).length) { + pattern = stack(...Object.values(pPatterns)); + } + if (allTransform) { + pattern = allTransform(pattern); + } + if (!isPattern(pattern)) { + const message = `got "${typeof evaluated}" instead of pattern`; + throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.')); } logger(`[eval] code updated`); setPattern(pattern, autostart); @@ -62,10 +77,32 @@ export function repl({ return pat.loopAtCps(cycles, scheduler.cps); }); - const play = register('play', (pat) => { - playPatterns.push(pat); - return pat; - }); + 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; + }; + + 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; + } const fit = register('fit', (pat) => pat.withHap((hap) => @@ -80,7 +117,8 @@ export function repl({ evalScope({ loopAt, fit, - play, + all, + hush, setCps, setcps: setCps, setCpm, diff --git a/packages/transpiler/test/transpiler.test.mjs b/packages/transpiler/test/transpiler.test.mjs index 1d14986d..5f1b754f 100644 --- a/packages/transpiler/test/transpiler.test.mjs +++ b/packages/transpiler/test/transpiler.test.mjs @@ -17,9 +17,6 @@ describe('transpiler', () => { it('wraps backtick string with mini and adds location', () => { expect(transpiler('`c3`', simple).output).toEqual("m('c3', 0);"); }); - it('replaces note variables with note strings', () => { - expect(transpiler('seq(c3, d3)', simple).output).toEqual("seq('c3', 'd3');"); - }); it('keeps tagged template literal as is', () => { expect(transpiler('xxx`c3`', simple).output).toEqual('xxx`c3`;'); }); diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 256be1d2..4e66a57c 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -47,11 +47,6 @@ export function transpiler(input, options = {}) { }); return this.replace(widgetWithLocation(node)); } - // TODO: remove pseudo note variables? - if (node.type === 'Identifier' && isNoteWithOctave(node.name)) { - this.skip(); - return this.replace({ type: 'Literal', value: node.name }); - } }, leave(node, parent, prop, index) {}, });