removing Tone.Expr

no more use for this class
This commit is contained in:
Yotam Mann 2017-11-29 16:28:47 -05:00
parent 7b35eee3ed
commit 27b1513ddf
2 changed files with 0 additions and 598 deletions

View file

@ -1,457 +0,0 @@
define(["Tone/core/Tone", "Tone/signal/Add", "Tone/signal/Subtract", "Tone/signal/Multiply",
"Tone/signal/GreaterThan", "Tone/signal/GreaterThanZero", "Tone/signal/Abs", "Tone/signal/Negate",
"Tone/signal/Modulo", "Tone/signal/Pow", "Tone/signal/AudioToGain"], function(Tone){
"use strict";
/**
* @class Evaluate an expression at audio rate. <br><br>
* Parsing code modified from https://code.google.com/p/tapdigit/
* Copyright 2011 2012 Ariya Hidayat, New BSD License
*
* @extends {Tone.SignalBase}
* @constructor
* @param {string} expr the expression to generate
* @example
* //adds the signals from input[0] and input[1].
* var expr = new Tone.Expr("$0 + $1");
*/
Tone.Expr = function(){
Tone.SignalBase.call(this);
var expr = this._replacements(Array.prototype.slice.call(arguments));
var inputCount = this._parseInputs(expr);
/**
* hold onto all of the nodes for disposal
* @type {Array}
* @private
*/
this._nodes = [];
/**
* The inputs. The length is determined by the expression.
* @type {Array}
*/
this.input = new Array(inputCount);
//create a gain for each input
for (var i = 0; i < inputCount; i++){
this.input[i] = this.context.createGain();
}
//parse the syntax tree
var tree = this._parseTree(expr);
//evaluate the results
var result;
try {
result = this._eval(tree);
} catch (e){
this._disposeNodes();
throw new Error("Tone.Expr: Could evaluate expression: "+expr);
}
/**
* The output node is the result of the expression
* @type {Tone}
*/
this.output = result;
};
Tone.extend(Tone.Expr, Tone.SignalBase);
//some helpers to cut down the amount of code
function applyBinary(Constructor, args, self){
var op = new Constructor();
self._eval(args[0]).connect(op, 0, 0);
self._eval(args[1]).connect(op, 0, 1);
return op;
}
function applyUnary(Constructor, args, self){
var op = new Constructor();
self._eval(args[0]).connect(op, 0, 0);
return op;
}
function getNumber(arg){
return arg ? parseFloat(arg) : undefined;
}
function literalNumber(arg){
return arg && arg.args ? parseFloat(arg.args) : undefined;
}
/*
* the Expressions that Tone.Expr can parse.
*
* each expression belongs to a group and contains a regexp
* for selecting the operator as well as that operators method
*
* @type {Object}
* @private
*/
Tone.Expr._Expressions = {
//values
"value" : {
"signal" : {
regexp : /^\d+\.\d+|^\d+/,
method : function(arg){
var sig = new Tone.Signal(getNumber(arg));
return sig;
}
},
"input" : {
regexp : /^\$\d/,
method : function(arg, self){
return self.input[getNumber(arg.substr(1))];
}
}
},
//syntactic glue
"glue" : {
"(" : {
regexp : /^\(/,
},
")" : {
regexp : /^\)/,
},
"," : {
regexp : /^,/,
}
},
//functions
"func" : {
"abs" : {
regexp : /^abs/,
method : applyUnary.bind(this, Tone.Abs)
},
"mod" : {
regexp : /^mod/,
method : function(args, self){
var modulus = literalNumber(args[1]);
var op = new Tone.Modulo(modulus);
self._eval(args[0]).connect(op);
return op;
}
},
"pow" : {
regexp : /^pow/,
method : function(args, self){
var exp = literalNumber(args[1]);
var op = new Tone.Pow(exp);
self._eval(args[0]).connect(op);
return op;
}
},
"a2g" : {
regexp : /^a2g/,
method : function(args, self){
var op = new Tone.AudioToGain();
self._eval(args[0]).connect(op);
return op;
}
},
},
//binary expressions
"binary" : {
"+" : {
regexp : /^\+/,
precedence : 1,
method : applyBinary.bind(this, Tone.Add)
},
"-" : {
regexp : /^-/,
precedence : 1,
method : function(args, self){
//both unary and binary op
if (args.length === 1){
return applyUnary(Tone.Negate, args, self);
} else {
return applyBinary(Tone.Subtract, args, self);
}
}
},
"*" : {
regexp : /^\*/,
precedence : 0,
method : applyBinary.bind(this, Tone.Multiply)
}
},
//unary expressions
"unary" : {
"-" : {
regexp : /^-/,
method : applyUnary.bind(this, Tone.Negate)
},
"!" : {
regexp : /^!/,
method : applyUnary.bind(this, Tone.NOT)
},
},
};
/**
* @param {string} expr the expression string
* @return {number} the input count
* @private
*/
Tone.Expr.prototype._parseInputs = function(expr){
var inputArray = expr.match(/\$\d/g);
var inputMax = 0;
if (inputArray !== null){
for (var i = 0; i < inputArray.length; i++){
var inputNum = parseInt(inputArray[i].substr(1)) + 1;
inputMax = Math.max(inputMax, inputNum);
}
}
return inputMax;
};
/**
* @param {Array} args an array of arguments
* @return {string} the results of the replacements being replaced
* @private
*/
Tone.Expr.prototype._replacements = function(args){
var expr = args.shift();
for (var i = 0; i < args.length; i++){
expr = expr.replace(/%/i, args[i]);
}
return expr;
};
/**
* tokenize the expression based on the Expressions object
* @param {string} expr
* @return {Object} returns two methods on the tokenized list, next and peek
* @private
*/
Tone.Expr.prototype._tokenize = function(expr){
var position = -1;
var tokens = [];
while(expr.length > 0){
expr = expr.trim();
var token = getNextToken(expr);
tokens.push(token);
expr = expr.substr(token.value.length);
}
function getNextToken(expr){
for (var type in Tone.Expr._Expressions){
var group = Tone.Expr._Expressions[type];
for (var opName in group){
var op = group[opName];
var reg = op.regexp;
var match = expr.match(reg);
if (match !== null){
return {
type : type,
value : match[0],
method : op.method
};
}
}
}
throw new SyntaxError("Tone.Expr: Unexpected token "+expr);
}
return {
next : function(){
return tokens[++position];
},
peek : function(){
return tokens[position + 1];
}
};
};
/**
* recursively parse the string expression into a syntax tree
*
* @param {string} expr
* @return {Object}
* @private
*/
Tone.Expr.prototype._parseTree = function(expr){
var lexer = this._tokenize(expr);
var isUndef = Tone.isUndef.bind(this);
function matchSyntax(token, syn) {
return !isUndef(token) &&
token.type === "glue" &&
token.value === syn;
}
function matchGroup(token, groupName, prec) {
var ret = false;
var group = Tone.Expr._Expressions[groupName];
if (!isUndef(token)){
for (var opName in group){
var op = group[opName];
if (op.regexp.test(token.value)){
if (!isUndef(prec)){
if(op.precedence === prec){
return true;
}
} else {
return true;
}
}
}
}
return ret;
}
function parseExpression(precedence) {
if (isUndef(precedence)){
precedence = 5;
}
var expr;
if (precedence < 0){
expr = parseUnary();
} else {
expr = parseExpression(precedence-1);
}
var token = lexer.peek();
while (matchGroup(token, "binary", precedence)) {
token = lexer.next();
expr = {
operator : token.value,
method : token.method,
args : [
expr,
parseExpression(precedence-1)
]
};
token = lexer.peek();
}
return expr;
}
function parseUnary() {
var token, expr;
token = lexer.peek();
if (matchGroup(token, "unary")) {
token = lexer.next();
expr = parseUnary();
return {
operator : token.value,
method : token.method,
args : [expr]
};
}
return parsePrimary();
}
function parsePrimary() {
var token, expr;
token = lexer.peek();
if (isUndef(token)) {
throw new SyntaxError("Tone.Expr: Unexpected termination of expression");
}
if (token.type === "func") {
token = lexer.next();
return parseFunctionCall(token);
}
if (token.type === "value") {
token = lexer.next();
return {
method : token.method,
args : token.value
};
}
if (matchSyntax(token, "(")) {
lexer.next();
expr = parseExpression();
token = lexer.next();
if (!matchSyntax(token, ")")) {
throw new SyntaxError("Expected )");
}
return expr;
}
throw new SyntaxError("Tone.Expr: Parse error, cannot process token " + token.value);
}
function parseFunctionCall(func) {
var token, args = [];
token = lexer.next();
if (!matchSyntax(token, "(")) {
throw new SyntaxError("Tone.Expr: Expected ( in a function call \"" + func.value + "\"");
}
token = lexer.peek();
if (!matchSyntax(token, ")")) {
args = parseArgumentList();
}
token = lexer.next();
if (!matchSyntax(token, ")")) {
throw new SyntaxError("Tone.Expr: Expected ) in a function call \"" + func.value + "\"");
}
return {
method : func.method,
args : args,
name : name
};
}
function parseArgumentList() {
var token, expr, args = [];
// eslint-disable-next-line no-constant-condition
while (true) {
expr = parseExpression();
if (isUndef(expr)) {
break;
}
args.push(expr);
token = lexer.peek();
if (!matchSyntax(token, ",")) {
break;
}
lexer.next();
}
return args;
}
return parseExpression();
};
/**
* recursively evaluate the expression tree
* @param {Object} tree
* @return {AudioNode} the resulting audio node from the expression
* @private
*/
Tone.Expr.prototype._eval = function(tree){
if (!Tone.isUndef(tree)){
var node = tree.method(tree.args, this);
this._nodes.push(node);
return node;
}
};
/**
* dispose all the nodes
* @private
*/
Tone.Expr.prototype._disposeNodes = function(){
for (var i = 0; i < this._nodes.length; i++){
var node = this._nodes[i];
if (Tone.isFunction(node.dispose)) {
node.dispose();
} else if (Tone.isFunction(node.disconnect)) {
node.disconnect();
}
node = null;
this._nodes[i] = null;
}
this._nodes = null;
};
/**
* clean up
*/
Tone.Expr.prototype.dispose = function(){
Tone.SignalBase.prototype.dispose.call(this);
this._disposeNodes();
};
return Tone.Expr;
});

View file

@ -1,141 +0,0 @@
define(["Tone/signal/Signal", "Tone/signal/Expr", "Test", "helper/Basic",
"helper/OutputAudio", "helper/PassAudio", "helper/Offline", "helper/ConstantOutput"],
function(Signal, Expr, Test, Basic, OutputAudio, PassAudio, Offline, ConstantOutput){
describe("Expr", function(){
Basic(Expr, "1");
context("I/O", function(){
it("can create inputs", function(){
var exp = new Expr("$0 + $1");
Test.connect(exp, 0);
Test.connect(exp, 1);
exp.dispose();
});
it("has an output", function(){
var exp = new Expr("0 + 0");
exp.connect(Test);
exp.dispose();
});
it("outputs audio", function(){
return OutputAudio(function(){
new Expr("1.1").toMaster();
});
});
it("passes input", function(){
return PassAudio(function(input){
var exp = new Expr("$0");
input.connect(exp);
exp.toMaster();
});
});
});
context("Parsing", function(){
it("can do string replacements", function(){
return ConstantOutput(function(){
var exp = new Expr("% + %", 0.2, 0.8);
exp.toMaster();
}, 1);
});
it("can do string replacements with strings", function(){
return ConstantOutput(function(){
new Expr("%", "1 + 2").toMaster();
}, 3);
});
it("handles precendence", function(){
return ConstantOutput(function(){
new Expr("8 + 16 * 4 * (2 - 1)").toMaster();
}, 72);
});
it("tolerates inconsistent spacing", function(){
return ConstantOutput(function(){
new Expr("2 * 3-2 *4 ").toMaster();
}, -2);
});
it("handles parens", function(){
return ConstantOutput(function(){
new Expr("(8 + 16) * (4 - 1)").toMaster();
}, 72);
});
});
context("Math", function(){
it("does signal addition", function(){
return ConstantOutput(function(){
new Expr("1 + 3").toMaster();
}, 4);
});
it("does signal multiplication", function(){
return ConstantOutput(function(){
new Expr("1.5 * 6").toMaster();
}, 9);
});
it("does signal subtraction", function(){
return ConstantOutput(function(){
new Expr("8 - 16").toMaster();
}, -8);
});
});
context("Unary Operators", function(){
it("correctly outputs negative", function(){
return ConstantOutput(function(){
var sig = new Signal(1);
var exp = new Expr("-$0");
sig.connect(exp);
exp.toMaster();
}, -1);
});
});
context("Functions", function(){
it("handles abs(-1)", function(){
return ConstantOutput(function(){
new Expr("abs(-1)").toMaster();
}, 1);
});
it("handles abs(0.11)", function(){
return ConstantOutput(function(){
new Expr("abs(0.11)").toMaster();
}, 0.11);
});
it("handles mod(0.2, 0.9)", function(){
return ConstantOutput(function(){
new Expr("mod(0.2, 0.9)").toMaster();
}, 0.2);
});
it("handles mod(0.5, 0.25)", function(){
return ConstantOutput(function(){
new Expr("mod(0.6, 0.25)").toMaster();
}, 0.1);
});
it("computes pow(0.2, 3)", function(){
return ConstantOutput(function(){
new Expr("pow(0.2, 3)").toMaster();
}, 0.008, 0.001);
});
});
});
});