build
This commit is contained in:
parent
3b248ae94c
commit
966de74d5b
10 changed files with 301 additions and 39 deletions
12
docs/dist/parse.js
vendored
12
docs/dist/parse.js
vendored
|
|
@ -1,6 +1,7 @@
|
|||
import * as krill from "../_snowpack/link/repl/krill-parser.js";
|
||||
import * as strudel from "../_snowpack/link/strudel.js";
|
||||
import {Scale, Note, Interval} from "../_snowpack/pkg/@tonaljs/tonal.js";
|
||||
import {addMiniLocations} from "./shapeshifter.js";
|
||||
const {pure, Pattern, Fraction, stack, slowcat, sequence, timeCat, silence} = strudel;
|
||||
const applyOptions = (parent) => (pat, i) => {
|
||||
const ast = parent.source_[i];
|
||||
|
|
@ -39,6 +40,7 @@ function resolveReplications(ast) {
|
|||
{
|
||||
type_: "element",
|
||||
source_: child.source_,
|
||||
location_: child.location_,
|
||||
options_: {
|
||||
operator: {
|
||||
type_: "stretch",
|
||||
|
|
@ -80,7 +82,15 @@ export function patternifyAST(ast) {
|
|||
return silence;
|
||||
}
|
||||
if (typeof ast.source_ !== "object") {
|
||||
return ast.source_;
|
||||
if (!addMiniLocations) {
|
||||
return ast.source_;
|
||||
}
|
||||
if (!ast.location_) {
|
||||
console.warn("no location for", ast);
|
||||
return ast.source_;
|
||||
}
|
||||
const {start, end} = ast.location_;
|
||||
return pure(ast.source_).withLocation({start, end});
|
||||
}
|
||||
return patternifyAST(ast.source_);
|
||||
case "stretch":
|
||||
|
|
|
|||
101
docs/dist/shapeshifter.js
vendored
101
docs/dist/shapeshifter.js
vendored
|
|
@ -10,6 +10,7 @@ const { Pattern } = strudel;
|
|||
const isNote = (name) => /^[a-gC-G][bs]?[0-9]$/.test(name);
|
||||
|
||||
const addLocations = true;
|
||||
export const addMiniLocations = true;
|
||||
|
||||
export default (code) => {
|
||||
const ast = parseScriptWithLocation(code);
|
||||
|
|
@ -23,16 +24,39 @@ export default (code) => {
|
|||
return node;
|
||||
}
|
||||
const grandparent = parents[parents.length - 2];
|
||||
const isPatternArg = (parent) =>
|
||||
parent?.type === 'CallExpression' && Object.keys(Pattern.prototype.factories).includes(parent.callee.name);
|
||||
const isTimeCat = parent?.type === 'ArrayExpression' && isPatternArg(grandparent);
|
||||
const isMarkable = isPatternArg(parent) || isTimeCat;
|
||||
const isTimeCat = parent?.type === 'ArrayExpression' && isPatternFactory(grandparent);
|
||||
const isMarkable = isPatternFactory(parent) || isTimeCat;
|
||||
// operator overloading => still not done
|
||||
const operators = {
|
||||
'*': 'fast',
|
||||
'/': 'slow',
|
||||
'&': 'stack',
|
||||
'&&': 'append',
|
||||
};
|
||||
if (
|
||||
node.type === 'BinaryExpression' &&
|
||||
operators[node.operator] &&
|
||||
['LiteralNumericExpression', 'LiteralStringExpression', 'IdentifierExpression'].includes(node.right?.type) &&
|
||||
canBeOverloaded(node.left)
|
||||
) {
|
||||
let arg = node.left;
|
||||
if (node.left.type === 'IdentifierExpression') {
|
||||
arg = wrapReify(node.left);
|
||||
}
|
||||
return new CallExpression({
|
||||
callee: new StaticMemberExpression({
|
||||
property: operators[node.operator],
|
||||
object: wrapReify(arg),
|
||||
}),
|
||||
arguments: [node.right],
|
||||
});
|
||||
}
|
||||
// replace pseudo note variables
|
||||
if (node.type === 'IdentifierExpression') {
|
||||
if (isNote(node.name)) {
|
||||
const value = node.name[1] === 's' ? node.name.replace('s', '#') : node.name;
|
||||
if (addLocations && isMarkable) {
|
||||
return addPureWithLocation(value, node, ast.locations, nodesWithLocation);
|
||||
return reifyWithLocation(value, node, ast.locations, nodesWithLocation);
|
||||
}
|
||||
return new LiteralStringExpression({ value });
|
||||
}
|
||||
|
|
@ -42,7 +66,26 @@ export default (code) => {
|
|||
}
|
||||
if (addLocations && node.type === 'LiteralStringExpression' && isMarkable) {
|
||||
// console.log('add', node);
|
||||
return addPureWithLocation(node.value, node, ast.locations, nodesWithLocation);
|
||||
return reifyWithLocation(node.value, node, ast.locations, nodesWithLocation);
|
||||
}
|
||||
if (!addMiniLocations) {
|
||||
return node;
|
||||
}
|
||||
// mini notation location handling
|
||||
const miniFunctions = ['mini', 'm'];
|
||||
const isAlreadyWrapped = parent?.type === 'CallExpression' && parent.callee.name === 'withLocationOffset';
|
||||
if (node.type === 'CallExpression' && miniFunctions.includes(node.callee.name) && !isAlreadyWrapped) {
|
||||
// mini('c3')
|
||||
if (node.arguments.length > 1) {
|
||||
// TODO: transform mini(...args) to cat(...args.map(mini)) ?
|
||||
console.warn('multi arg mini locations not supported yet...');
|
||||
return node;
|
||||
}
|
||||
return wrapLocationOffset(node, node.arguments, ast.locations, nodesWithLocation);
|
||||
}
|
||||
if (node.type === 'StaticMemberExpression' && miniFunctions.includes(node.property) && !isAlreadyWrapped) {
|
||||
// 'c3'.mini or 'c3'.m
|
||||
return wrapLocationOffset(node, node.object, ast.locations, nodesWithLocation);
|
||||
}
|
||||
return node;
|
||||
},
|
||||
|
|
@ -53,15 +96,49 @@ export default (code) => {
|
|||
return codegen(shifted);
|
||||
};
|
||||
|
||||
// turns node in pure(value).withLocation(location), where location is the node's location in the source code
|
||||
// with this, the pure pattern can pass its location to the event, to know where to highlight when it's active
|
||||
function addPureWithLocation(value, node, locations, nodesWithLocation) {
|
||||
// console.log('addPure', value, node);
|
||||
function wrapReify(node) {
|
||||
return new CallExpression({
|
||||
callee: new IdentifierExpression({
|
||||
name: 'reify',
|
||||
}),
|
||||
arguments: [node],
|
||||
});
|
||||
}
|
||||
|
||||
function isPatternFactory(node) {
|
||||
return node?.type === 'CallExpression' && Object.keys(Pattern.prototype.factories).includes(node.callee.name);
|
||||
}
|
||||
|
||||
function canBeOverloaded(node) {
|
||||
return (node.type === 'IdentifierExpression' && isNote(node.name)) || isPatternFactory(node);
|
||||
// TODO: support sequence(c3).transpose(3).x.y.z
|
||||
}
|
||||
|
||||
// turn node into withLocationOffset(node, location)
|
||||
function wrapLocationOffset(node, stringNode, locations, nodesWithLocation) {
|
||||
// console.log('wrapppp', stringNode);
|
||||
const expression = {
|
||||
type: 'CallExpression',
|
||||
callee: {
|
||||
type: 'IdentifierExpression',
|
||||
name: 'withLocationOffset',
|
||||
},
|
||||
arguments: [node, getLocationObject(stringNode, locations)],
|
||||
};
|
||||
nodesWithLocation.push(expression);
|
||||
// console.log('wrapped', codegen(expression));
|
||||
return expression;
|
||||
}
|
||||
|
||||
// turns node in reify(value).withLocation(location), where location is the node's location in the source code
|
||||
// with this, the reified pattern can pass its location to the event, to know where to highlight when it's active
|
||||
function reifyWithLocation(value, node, locations, nodesWithLocation) {
|
||||
// console.log('reifyWithLocation', value, node);
|
||||
const withLocation = new CallExpression({
|
||||
callee: new StaticMemberExpression({
|
||||
object: new CallExpression({
|
||||
callee: new IdentifierExpression({
|
||||
name: 'pure',
|
||||
name: 'reify',
|
||||
}),
|
||||
arguments: [new LiteralStringExpression({ value })],
|
||||
}),
|
||||
|
|
@ -82,7 +159,7 @@ function getLocationObject(node, locations) {
|
|||
console.log("locationAST", locationAST);*/
|
||||
|
||||
/*const callAST = parseScript(
|
||||
`pure(${node.name}).withLocation(${JSON.stringify(
|
||||
`reify(${node.name}).withLocation(${JSON.stringify(
|
||||
ast.locations.get(node)
|
||||
)})`
|
||||
).statements[0].expression;*/
|
||||
|
|
|
|||
11
docs/dist/tonal.js
vendored
11
docs/dist/tonal.js
vendored
|
|
@ -2,7 +2,7 @@ import {Note, Interval, Scale} from "../_snowpack/pkg/@tonaljs/tonal.js";
|
|||
import {Pattern as _Pattern} from "../_snowpack/link/strudel.js";
|
||||
const Pattern = _Pattern;
|
||||
function toNoteEvent(event) {
|
||||
if (typeof event === "string") {
|
||||
if (typeof event === "string" || typeof event === "number") {
|
||||
return {value: event};
|
||||
}
|
||||
if (event.value) {
|
||||
|
|
@ -53,13 +53,20 @@ Pattern.prototype._mapNotes = function(func) {
|
|||
Pattern.prototype._transpose = function(intervalOrSemitones) {
|
||||
return this._mapNotes(({value, scale}) => {
|
||||
const interval = !isNaN(Number(intervalOrSemitones)) ? Interval.fromSemitones(intervalOrSemitones) : String(intervalOrSemitones);
|
||||
if (typeof value === "number") {
|
||||
const semitones = typeof interval === "string" ? Interval.semitones(interval) || 0 : interval;
|
||||
return {value: value + semitones};
|
||||
}
|
||||
return {value: Note.transpose(value, interval), scale};
|
||||
});
|
||||
};
|
||||
Pattern.prototype._scaleTranspose = function(offset) {
|
||||
return this._mapNotes(({value, scale}) => {
|
||||
if (!scale) {
|
||||
throw new Error("can only use scaleOffset after .scale");
|
||||
throw new Error("can only use scaleTranspose after .scale");
|
||||
}
|
||||
if (typeof value !== "string") {
|
||||
throw new Error("can only use scaleTranspose with notes");
|
||||
}
|
||||
return {value: scaleTranspose(scale, Number(offset), value), scale};
|
||||
});
|
||||
|
|
|
|||
3
docs/dist/useRepl.js
vendored
3
docs/dist/useRepl.js
vendored
|
|
@ -30,6 +30,8 @@ function useRepl({tune, defaultSynth, autolink = true, onEvent}) {
|
|||
setError(void 0);
|
||||
setActiveCode(_code);
|
||||
} catch (err) {
|
||||
err.message = "evaluation error: " + err.message;
|
||||
console.warn(err);
|
||||
setError(err);
|
||||
}
|
||||
};
|
||||
|
|
@ -68,6 +70,7 @@ function useRepl({tune, defaultSynth, autolink = true, onEvent}) {
|
|||
try {
|
||||
return pattern?.query(span) || [];
|
||||
} catch (err) {
|
||||
err.message = "query error: " + err.message;
|
||||
setError(err);
|
||||
return [];
|
||||
}
|
||||
|
|
|
|||
2
docs/dist/voicings.js
vendored
2
docs/dist/voicings.js
vendored
|
|
@ -18,7 +18,7 @@ Pattern.prototype.voicings = function(range) {
|
|||
range = ["F3", "A4"];
|
||||
}
|
||||
return this.fmapNested((event) => {
|
||||
lastVoicing = getVoicing(event.value, lastVoicing, range);
|
||||
lastVoicing = getVoicing(event.value?.value || event.value, lastVoicing, range);
|
||||
return stack(...lastVoicing);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue