mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 16:48:00 +00:00
new core timing primitives
This commit is contained in:
parent
3fc2fe90e1
commit
696e84cafb
5 changed files with 1344 additions and 0 deletions
270
Tone/type/Frequency.js
Normal file
270
Tone/type/Frequency.js
Normal file
|
@ -0,0 +1,270 @@
|
|||
define(["Tone/core/Tone", "Tone/type/TimeBase"], function (Tone) {
|
||||
|
||||
/**
|
||||
* @param {[type]} val [description]
|
||||
* @param {[type]} units [description]
|
||||
* @example
|
||||
* Tone.Frequency("C3").eval() // 261
|
||||
* Tone.Frequency(38, "midi").eval() //
|
||||
* Tone.Frequency("C3").transpose(4).eval();
|
||||
* Tone.Frequency("440hz").transpose([0, 3, 7]).eval() // ["A4", "C5", "E5"];
|
||||
*/
|
||||
Tone.Frequency = function(val, units){
|
||||
if (this instanceof Tone.Frequency){
|
||||
|
||||
Tone.TimeBase.call(this, val, units);
|
||||
|
||||
} else {
|
||||
return new Tone.Frequency(val, units);
|
||||
}
|
||||
};
|
||||
|
||||
Tone.extend(Tone.Frequency, Tone.TimeBase);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// AUGMENT BASE EXPRESSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//clone the expressions so that
|
||||
//we can add more without modifying the original
|
||||
Tone.Frequency.prototype._primaryExpressions = Object.create(Tone.TimeBase.prototype._primaryExpressions);
|
||||
|
||||
/*
|
||||
* midi type primary expression
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._primaryExpressions.midi = {
|
||||
regexp : /^(\d+(?:\.\d+)?midi)/,
|
||||
method : function(value){
|
||||
return this.midiToFrequency(value);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* note type primary expression
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._primaryExpressions.note = {
|
||||
regexp : /^([a-g]{1}(?:b|#|x|bb)?)(-?[0-9]+)/i,
|
||||
method : function(pitch, octave){
|
||||
var index = noteToScaleIndex[pitch.toLowerCase()];
|
||||
var noteNumber = index + (parseInt(octave) + 1) * 12;
|
||||
return this.midiToFrequency(noteNumber);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* BeatsBarsSixteenths type primary expression
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._primaryExpressions.tr = {
|
||||
regexp : /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
|
||||
method : function(m, q, s){
|
||||
var total = 1;
|
||||
if (m && m !== "0"){
|
||||
total *= this._beatsToUnits(this._timeSignature() * parseFloat(m));
|
||||
}
|
||||
if (q && q !== "0"){
|
||||
total *= this._beatsToUnits(parseFloat(q));
|
||||
}
|
||||
if (s && s !== "0"){
|
||||
total *= this._beatsToUnits(parseFloat(s) / 4);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EXPRESSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Transposes the frequency by the given number of semitones.
|
||||
* @param {Interval} interval
|
||||
* @return {Tone.Frequency} this
|
||||
* @example
|
||||
* Tone.Frequency("A4").transpose(3); //"C5"
|
||||
*/
|
||||
Tone.Frequency.prototype.transpose = function(interval){
|
||||
this._expr = function(expr, interval){
|
||||
var val = expr();
|
||||
return val * this.intervalToFrequencyRatio(interval);
|
||||
}.bind(this, this._expr, interval);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an array of semitone intervals and returns
|
||||
* an array of frequencies transposed by those intervals.
|
||||
* @param {Array} intervals
|
||||
* @return {Tone.Frequency} this
|
||||
* @example
|
||||
* Tone.Frequency("A4").harmonize([0, 3, 7]); //["A4", "C5", "E5"]
|
||||
*/
|
||||
Tone.Frequency.prototype.harmonize = function(intervals){
|
||||
this._expr = function(expr, intervals){
|
||||
var val = expr();
|
||||
var ret = [];
|
||||
for (var i = 0; i < intervals.length; i++){
|
||||
ret[i] = val * this.intervalToFrequencyRatio(intervals[i]);
|
||||
}
|
||||
return ret;
|
||||
}.bind(this, this._expr, intervals);
|
||||
return this;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// UNIT CONVERSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Return the value of the frequency as a MIDI note
|
||||
* @return {MIDI}
|
||||
*/
|
||||
Tone.Frequency.prototype.toMidi = function(){
|
||||
return this.frequencyToMidi(this.eval());
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the value of the frequency in Scientific Pitch Notation
|
||||
* @return {Note}
|
||||
*/
|
||||
Tone.Frequency.prototype.toNote = function(){
|
||||
var freq = this.eval();
|
||||
var log = Math.log(freq / Tone.Frequency.A4) / Math.LN2;
|
||||
var noteNumber = Math.round(12 * log) + 57;
|
||||
var octave = Math.floor(noteNumber/12);
|
||||
if(octave < 0){
|
||||
noteNumber += -12 * octave;
|
||||
}
|
||||
var noteName = scaleIndexToNote[noteNumber % 12];
|
||||
return noteName + octave.toString();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the duration of one cycle in seconds.
|
||||
* @return {Seconds}
|
||||
*/
|
||||
Tone.Frequency.prototype.toSeconds = function(){
|
||||
return 1 / this.eval();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the duration of one cycle in ticks
|
||||
* @return {Ticks}
|
||||
*/
|
||||
Tone.Frequency.prototype.toTicks = function(){
|
||||
var quarterTime = this._beatsToUnits(1);
|
||||
var quarters = this.eval() / quarterTime;
|
||||
return Math.floor(quarters * Tone.Transport.PPQ);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// UNIT CONVERSIONS HELPERS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns the value of a frequency in the current units
|
||||
* @param {Frequency} freq
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._frequencyToUnits = function(freq){
|
||||
return freq;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of a tick in the current time units
|
||||
* @param {Ticks} ticks
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._ticksToUnits = function(ticks){
|
||||
return 1 / ((ticks * 60) / (Tone.Transport.bpm.value * Tone.Transport.PPQ));
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the value of the beats in the current units
|
||||
* @param {Number} beats
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._beatsToUnits = function(beats){
|
||||
return 1 / Tone.TimeBase.prototype._beatsToUnits.call(this, beats);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of a second in the current units
|
||||
* @param {Seconds} seconds
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._secondsToUnits = function(seconds){
|
||||
return 1 / seconds;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default units if none are given.
|
||||
* @private
|
||||
*/
|
||||
Tone.Frequency.prototype._defaultUnits = "hz";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// FREQUENCY CONVERSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Note to scale index
|
||||
* @type {Object}
|
||||
*/
|
||||
var noteToScaleIndex = {
|
||||
"cbb" : -2, "cb" : -1, "c" : 0, "c#" : 1, "cx" : 2,
|
||||
"dbb" : 0, "db" : 1, "d" : 2, "d#" : 3, "dx" : 4,
|
||||
"ebb" : 2, "eb" : 3, "e" : 4, "e#" : 5, "ex" : 6,
|
||||
"fbb" : 3, "fb" : 4, "f" : 5, "f#" : 6, "fx" : 7,
|
||||
"gbb" : 5, "gb" : 6, "g" : 7, "g#" : 8, "gx" : 9,
|
||||
"abb" : 7, "ab" : 8, "a" : 9, "a#" : 10, "ax" : 11,
|
||||
"bbb" : 9, "bb" : 10, "b" : 11, "b#" : 12, "bx" : 13,
|
||||
};
|
||||
|
||||
/**
|
||||
* scale index to note (sharps)
|
||||
* @type {Array}
|
||||
*/
|
||||
var scaleIndexToNote = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
|
||||
|
||||
/**
|
||||
* The [concert pitch](https://en.wikipedia.org/wiki/Concert_pitch)
|
||||
* A4's values in Hertz.
|
||||
* @type {Frequency}
|
||||
* @static
|
||||
*/
|
||||
Tone.Frequency.A4 = 440;
|
||||
|
||||
/**
|
||||
* Convert a MIDI note to frequency value.
|
||||
* @param {MIDI} midi The midi number to convert.
|
||||
* @return {Frequency} the corresponding frequency value
|
||||
* @example
|
||||
* tone.midiToFrequency(69); // returns 440
|
||||
*/
|
||||
Tone.Frequency.prototype.midiToFrequency = function(midi){
|
||||
return Tone.Frequency.A4 * Math.pow(2, (midi - 69) / 12);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a frequency value to a MIDI note.
|
||||
* @param {Frequency} frequency The value to frequency value to convert.
|
||||
* @returns {MIDI}
|
||||
* @example
|
||||
* tone.midiToFrequency(440); // returns 69
|
||||
*/
|
||||
Tone.Frequency.prototype.frequencyToMidi = function(frequency){
|
||||
return 69 + 12 * Math.log2(frequency / Tone.Frequency.A4);
|
||||
};
|
||||
|
||||
return Tone.Frequency;
|
||||
});
|
227
Tone/type/Time.js
Normal file
227
Tone/type/Time.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
define(["Tone/core/Tone", "Tone/type/TimeBase"], function (Tone) {
|
||||
|
||||
/**
|
||||
* @param {[type]} val [description]
|
||||
* @param {[type]} units [description]
|
||||
*/
|
||||
Tone.Time = function(val, units){
|
||||
if (this instanceof Tone.Time){
|
||||
|
||||
Tone.TimeBase.call(this, val, units);
|
||||
|
||||
} else {
|
||||
return new Tone.Time(val, units);
|
||||
}
|
||||
};
|
||||
|
||||
Tone.extend(Tone.Time, Tone.TimeBase);
|
||||
|
||||
//clone the expressions so that
|
||||
//we can add more without modifying the original
|
||||
Tone.Time.prototype._unaryExpressions = Object.create(Tone.TimeBase.prototype._unaryExpressions);
|
||||
|
||||
/*
|
||||
* Adds an additional unary expression
|
||||
* which quantizes values to the next subdivision
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.Time.prototype._unaryExpressions.quantize = {
|
||||
regexp : /^@/,
|
||||
method : function(rh){
|
||||
return Tone.Transport.nextSubdivision(rh());
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Adds an additional unary expression
|
||||
* which adds the current clock time.
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.Time.prototype._unaryExpressions.now = {
|
||||
regexp : /^\+/,
|
||||
method : function(lh){
|
||||
return this.now() + lh();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Quantize the time by the given subdivision. Optionally add a
|
||||
* percentage which will move the time value towards the ideal
|
||||
* quantized value by that percentage.
|
||||
* @param {Number|Time} val The subdivision to quantize to
|
||||
* @param {NormalRange} [perc=1] Move the time value
|
||||
* towards the quantized value by
|
||||
* a percentage.
|
||||
* @return {Tone.Time} this
|
||||
* @example
|
||||
* Tone.Time(21).quantize(2).eval() //returns 22
|
||||
* Tone.Time(0.6).quantize("4n", 0.5).eval() //returns 0.55
|
||||
*/
|
||||
Tone.Time.prototype.quantize = function(subdiv, perc){
|
||||
perc = this.defaultArg(perc, 1);
|
||||
this._expr = function(expr, subdivision, percent){
|
||||
expr = expr();
|
||||
subdivision = subdivision.eval();
|
||||
var multiple = Math.round(expr / subdivision);
|
||||
var ideal = multiple * subdivision;
|
||||
var diff = ideal - expr;
|
||||
return expr + diff * percent;
|
||||
}.bind(this, this._expr, new this.constructor(subdiv), perc);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds the current clock time to the time expression
|
||||
* @return {Tone.Time} this
|
||||
*/
|
||||
Tone.Time.prototype.addNow = function(){
|
||||
this._expr = function(expr){
|
||||
return expr() + this.now();
|
||||
}.bind(this, this._expr);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
* Override the default value return when no arguments are passed in.
|
||||
* The default value is 'now'
|
||||
* @private
|
||||
*/
|
||||
Tone.Time.prototype._defaultExpr = function(){
|
||||
return function(expr){
|
||||
return expr() + this.now();
|
||||
}.bind(this, this._expr);
|
||||
};
|
||||
|
||||
|
||||
//CONVERSIONS//////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Convert a Time to Notation. Values will be thresholded to the nearest 128th note.
|
||||
* @return {Notation}
|
||||
*/
|
||||
Tone.Time.prototype.toNotation = function(){
|
||||
var time = this.eval();
|
||||
var testNotations = ["1m", "2n", "4n", "8n", "16n", "32n", "64n", "128n"];
|
||||
var retNotation = this._toNotationHelper(time, testNotations);
|
||||
//try the same thing but with tripelets
|
||||
var testTripletNotations = ["1m", "2n", "2t", "4n", "4t", "8n", "8t", "16n", "16t", "32n", "32t", "64n", "64t", "128n"];
|
||||
var retTripletNotation = this._toNotationHelper(time, testTripletNotations);
|
||||
//choose the simpler expression of the two
|
||||
if (retTripletNotation.split("+").length < retNotation.split("+").length){
|
||||
return retTripletNotation;
|
||||
} else {
|
||||
return retNotation;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper method for Tone.toNotation
|
||||
* @param {Number} units
|
||||
* @param {Array} testNotations
|
||||
* @return {String}
|
||||
* @private
|
||||
*/
|
||||
Tone.Time.prototype._toNotationHelper = function(units, testNotations){
|
||||
//the threshold is the last value in the array
|
||||
var threshold = this._notationToUnits(testNotations[testNotations.length - 1]);
|
||||
var retNotation = "";
|
||||
for (var i = 0; i < testNotations.length; i++){
|
||||
var notationTime = this._notationToUnits(testNotations[i]);
|
||||
//account for floating point errors (i.e. round up if the value is 0.999999)
|
||||
var multiple = units / notationTime;
|
||||
var floatingPointError = 0.000001;
|
||||
if (1 - multiple % 1 < floatingPointError){
|
||||
multiple += floatingPointError;
|
||||
}
|
||||
multiple = Math.floor(multiple);
|
||||
if (multiple > 0){
|
||||
if (multiple === 1){
|
||||
retNotation += testNotations[i];
|
||||
} else {
|
||||
retNotation += multiple.toString() + "*" + testNotations[i];
|
||||
}
|
||||
units -= multiple * notationTime;
|
||||
if (units < threshold){
|
||||
break;
|
||||
} else {
|
||||
retNotation += " + ";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (retNotation === ""){
|
||||
retNotation = "0";
|
||||
}
|
||||
return retNotation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a notation value to the current units
|
||||
* @param {Notation} notation
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.Time.prototype._notationToUnits = function(notation){
|
||||
var primaryExprs = this._primaryExpressions;
|
||||
var notationExprs = [primaryExprs.n, primaryExprs.t, primaryExprs.m];
|
||||
for (var i = 0; i < notationExprs.length; i++){
|
||||
var expr = notationExprs[i];
|
||||
var match = notation.match(expr.regexp);
|
||||
if (match){
|
||||
return expr.method.call(this, match[1]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time encoded as Bars:Beats:Sixteenths.
|
||||
* @return {BarsBeatsSixteenths}
|
||||
*/
|
||||
Tone.Time.prototype.toBarsBeatsSixteenths = function(){
|
||||
var quarterTime = this._beatsToUnits(1);
|
||||
var quarters = this.eval() / quarterTime;
|
||||
var measures = Math.floor(quarters / this._timeSignature());
|
||||
var sixteenths = (quarters % 1) * 4;
|
||||
quarters = Math.floor(quarters) % this._timeSignature();
|
||||
var progress = [measures, quarters, sixteenths];
|
||||
return progress.join(":");
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in ticks.
|
||||
* @return {Ticks}
|
||||
*/
|
||||
Tone.Time.prototype.toTicks = function(){
|
||||
var quarterTime = this._beatsToUnits(1);
|
||||
var quarters = this.eval() / quarterTime;
|
||||
return Math.floor(quarters * Tone.Transport.PPQ);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in samples
|
||||
* @return {Samples}
|
||||
*/
|
||||
Tone.Time.prototype.toSamples = function(){
|
||||
return this.eval() * this.context.sampleRate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time as a frequency value
|
||||
* @return {Frequency}
|
||||
*/
|
||||
Tone.Time.prototype.toFrequency = function(){
|
||||
return 1/this.eval();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in seconds.
|
||||
* @return {Seconds}
|
||||
*/
|
||||
Tone.Time.prototype.toSeconds = function(){
|
||||
return this.eval();
|
||||
};
|
||||
|
||||
return Tone.Time;
|
||||
});
|
502
Tone/type/TimeBase.js
Normal file
502
Tone/type/TimeBase.js
Normal file
|
@ -0,0 +1,502 @@
|
|||
define(["Tone/core/Tone"], function (Tone) {
|
||||
|
||||
/**
|
||||
* @class Tone.TimeBase is a flexible encoding of time
|
||||
* which can be evaluated to and from a string.
|
||||
* Parsing code modified from https://code.google.com/p/tapdigit/
|
||||
* Copyright 2011 2012 Ariya Hidayat, New BSD License
|
||||
* @extends {Tone}
|
||||
* @param {Time} val The time value as a number or string
|
||||
* @param {String=} units Unit values
|
||||
* @example
|
||||
* Tone.TimeBase(4, "n")
|
||||
* Tone.TimeBase(2, "t")
|
||||
* Tone.TimeBase("2t").add("1m")
|
||||
* Tone.TimeBase("2t + 1m");
|
||||
*/
|
||||
Tone.TimeBase = function(val, units){
|
||||
|
||||
//allows it to be constructed with or without 'new'
|
||||
if (this instanceof Tone.TimeBase) {
|
||||
|
||||
/**
|
||||
* Any expressions parsed from the Time
|
||||
* @type {Array}
|
||||
* @private
|
||||
*/
|
||||
this._expr = this._noOp;
|
||||
|
||||
//default units
|
||||
units = this.defaultArg(units, this._defaultUnits);
|
||||
|
||||
//get the value from the given time
|
||||
if (this.isString(val)){
|
||||
this._expr = this._parseExprString(val);
|
||||
} else if (this.isNumber(val)){
|
||||
var method = this._primaryExpressions[units].method;
|
||||
this._expr = method.bind(this, val);
|
||||
} else if (this.isUndef(val)){
|
||||
//default expression
|
||||
this._expr = this._defaultExpr();
|
||||
}
|
||||
} else {
|
||||
|
||||
return new Tone.TimeBase(val, units);
|
||||
}
|
||||
};
|
||||
|
||||
Tone.extend(Tone.TimeBase);
|
||||
|
||||
/**
|
||||
* Repalce the current time value with the value
|
||||
* given by the expression string.
|
||||
* @param {String} exprString
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.set = function(exprString){
|
||||
this._expr = this._parseExprString(exprString);
|
||||
return this;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ABSTRACT SYNTAX TREE PARSER
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Tone.TimeBase.prototype._primaryExpressions = {
|
||||
"n" : {
|
||||
regexp : /^(\d+)n/i,
|
||||
method : function(value){
|
||||
value = parseInt(value);
|
||||
if (value === 1){
|
||||
return this._beatsToUnits(this._timeSignature());
|
||||
} else {
|
||||
return this._beatsToUnits(4 / value);
|
||||
}
|
||||
}
|
||||
},
|
||||
"t" : {
|
||||
regexp : /^(\d+)t/i,
|
||||
method : function(value){
|
||||
value = parseInt(value);
|
||||
return this._beatsToUnits(8 / (parseInt(value) * 3));
|
||||
}
|
||||
},
|
||||
"m" : {
|
||||
regexp : /^(\d+)m/i,
|
||||
method : function(value){
|
||||
return this._beatsToUnits(parseInt(value) * this._timeSignature());
|
||||
}
|
||||
},
|
||||
"i" : {
|
||||
regexp : /^(\d+)i/i,
|
||||
method : function(value){
|
||||
return this._ticksToUnits(parseInt(value));
|
||||
}
|
||||
},
|
||||
"hz" : {
|
||||
regexp : /^(\d+(?:\.\d+)?)hz/i,
|
||||
method : function(value){
|
||||
return this._frequencyToUnits(parseFloat(value));
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
regexp : /^(\d+(?:\.\d+)?):(\d+(?:\.\d+)?):?(\d+(?:\.\d+)?)?/,
|
||||
method : function(m, q, s){
|
||||
var total = 0;
|
||||
if (m && m !== "0"){
|
||||
total += this._beatsToUnits(this._timeSignature() * parseFloat(m));
|
||||
}
|
||||
if (q && q !== "0"){
|
||||
total += this._beatsToUnits(parseFloat(q));
|
||||
}
|
||||
if (s && s !== "0"){
|
||||
total += this._beatsToUnits(parseFloat(s) / 4);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
},
|
||||
"s" : {
|
||||
regexp : /^(\d+(?:\.\d+)?s)/,
|
||||
method : function(value){
|
||||
return this._secondsToUnits(parseFloat(value));
|
||||
}
|
||||
},
|
||||
"samples" : {
|
||||
regexp : /^(\d+)samples/,
|
||||
method : function(value){
|
||||
return parseInt(value) / this.context.sampleRate;
|
||||
}
|
||||
},
|
||||
"default" : {
|
||||
regexp : /^(\d+(?:\.\d+)?)/,
|
||||
method : function(value){
|
||||
return this._primaryExpressions[this._defaultUnits].method.call(this, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tone.TimeBase.prototype._binaryExpressions = {
|
||||
"+" : {
|
||||
regexp : /^\+/,
|
||||
precedence : 2,
|
||||
method : function(lh, rh){
|
||||
return lh() + rh();
|
||||
}
|
||||
},
|
||||
"-" : {
|
||||
regexp : /^\-/,
|
||||
precedence : 2,
|
||||
method : function(lh, rh){
|
||||
return lh() - rh();
|
||||
}
|
||||
},
|
||||
"*" : {
|
||||
regexp : /^\*/,
|
||||
precedence : 1,
|
||||
method : function(lh, rh){
|
||||
return lh() * rh();
|
||||
}
|
||||
},
|
||||
"/" : {
|
||||
regexp : /^\//,
|
||||
precedence : 1,
|
||||
method : function(lh, rh){
|
||||
return lh() / rh();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tone.TimeBase.prototype._unaryExpressions = {
|
||||
"neg" : {
|
||||
regexp : /^\-/,
|
||||
method : function(lh){
|
||||
return -lh();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tone.TimeBase.prototype._syntaxGlue = {
|
||||
"(" : {
|
||||
regexp : /^\(/
|
||||
},
|
||||
")" : {
|
||||
regexp : /^\)/
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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.TimeBase.prototype._tokenize = function(expr){
|
||||
var position = -1;
|
||||
var tokens = [];
|
||||
|
||||
while(expr.length > 0){
|
||||
expr = expr.trim();
|
||||
var token = getNextToken(expr, this);
|
||||
tokens.push(token);
|
||||
expr = expr.substr(token.value.length);
|
||||
}
|
||||
|
||||
function getNextToken(expr, context){
|
||||
var expressions = ["_binaryExpressions", "_unaryExpressions", "_primaryExpressions", "_syntaxGlue"];
|
||||
for (var i = 0; i < expressions.length; i++){
|
||||
var group = context[expressions[i]];
|
||||
for (var opName in group){
|
||||
var op = group[opName];
|
||||
var reg = op.regexp;
|
||||
var match = expr.match(reg);
|
||||
if (match !== null){
|
||||
return {
|
||||
method : op.method,
|
||||
precedence : op.precedence,
|
||||
regexp : op.regexp,
|
||||
value : match[0],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new SyntaxError("Unexpected token "+expr);
|
||||
}
|
||||
|
||||
return {
|
||||
next : function(){
|
||||
return tokens[++position];
|
||||
},
|
||||
peek : function(){
|
||||
return tokens[position + 1];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a token, find the value within the groupName
|
||||
* @param {Object} token
|
||||
* @param {String} groupName
|
||||
* @param {Number} precedence
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._matchGroup = function(token, group, prec) {
|
||||
var ret = false;
|
||||
if (!this.isUndef(token)){
|
||||
for (var opName in group){
|
||||
var op = group[opName];
|
||||
if (op.regexp.test(token.value)){
|
||||
if (!this.isUndef(prec)){
|
||||
if(op.precedence === prec){
|
||||
return op;
|
||||
}
|
||||
} else {
|
||||
return op;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Match a binary expression given the token and the precedence
|
||||
* @param {Lexer} lexer
|
||||
* @param {Number} precedence
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._parseBinary = function(lexer, precedence){
|
||||
if (this.isUndef(precedence)){
|
||||
precedence = 2;
|
||||
}
|
||||
var expr;
|
||||
if (precedence < 0){
|
||||
expr = this._parseUnary(lexer);
|
||||
} else {
|
||||
expr = this._parseBinary(lexer, precedence - 1);
|
||||
}
|
||||
var token = lexer.peek();
|
||||
while (token && this._matchGroup(token, this._binaryExpressions, precedence)){
|
||||
token = lexer.next();
|
||||
expr = token.method.bind(this, expr, this._parseBinary(lexer, precedence - 1));
|
||||
token = lexer.peek();
|
||||
}
|
||||
return expr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Match a unary expression.
|
||||
* @param {Lexer} lexer
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._parseUnary = function(lexer){
|
||||
var token, expr;
|
||||
token = lexer.peek();
|
||||
var op = this._matchGroup(token, this._unaryExpressions);
|
||||
if (op) {
|
||||
token = lexer.next();
|
||||
expr = this._parseUnary(lexer);
|
||||
return op.method.bind(this, expr);
|
||||
}
|
||||
return this._parsePrimary(lexer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Match a primary expression (a value).
|
||||
* @param {Lexer} lexer
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._parsePrimary = function(lexer){
|
||||
var token, expr;
|
||||
token = lexer.peek();
|
||||
if (this.isUndef(token)) {
|
||||
throw new SyntaxError("Unexpected end of expression");
|
||||
}
|
||||
if (this._matchGroup(token, this._primaryExpressions)) {
|
||||
token = lexer.next();
|
||||
var matching = token.value.match(token.regexp);
|
||||
return token.method.bind(this, matching[1], matching[2], matching[3]);
|
||||
}
|
||||
if (token && token.value === "("){
|
||||
lexer.next();
|
||||
expr = this._parseBinary(lexer);
|
||||
token = lexer.next();
|
||||
if (!(token && token.value === ")")) {
|
||||
throw new SyntaxError("Expected )");
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
throw new SyntaxError("Cannot process token " + token.value);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively parse the string expression into a syntax tree.
|
||||
* @param {string} expr
|
||||
* @return {Function} the bound method to be evaluated later
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._parseExprString = function(exprString){
|
||||
var lexer = this._tokenize(exprString);
|
||||
var tree = this._parseBinary(lexer);
|
||||
return tree;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// DEFAULTS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* The initial expression value
|
||||
* @return {Number} The initial value 0
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._noOp = function(){
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default expression value if no arguments are given
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._defaultExpr = function(){
|
||||
return this._noOp;
|
||||
};
|
||||
|
||||
/**
|
||||
* The default units if none are given.
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._defaultUnits = "s";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// UNIT CONVERSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Returns the value of a frequency in the current units
|
||||
* @param {Frequency} freq
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._frequencyToUnits = function(freq){
|
||||
return 1/freq;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the value of the beats in the current units
|
||||
* @param {Number} beats
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._beatsToUnits = function(beats){
|
||||
return (60 / Tone.Transport.bpm.value) * beats;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of a second in the current units
|
||||
* @param {Seconds} seconds
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._secondsToUnits = function(seconds){
|
||||
return seconds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of a tick in the current time units
|
||||
* @param {Ticks} ticks
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._ticksToUnits = function(ticks){
|
||||
return ticks * (this._beatsToUnits(1) / Tone.Transport.PPQ);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time signature.
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._timeSignature = function(){
|
||||
return Tone.Transport.timeSignature;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// EXPRESSIONS
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Push an expression onto the expression list
|
||||
* @param {Time} val
|
||||
* @param {String} type
|
||||
* @param {String} units
|
||||
* @return {Tone.TimeBase}
|
||||
* @private
|
||||
*/
|
||||
Tone.TimeBase.prototype._pushExpr = function(val, name, units){
|
||||
//create the expression
|
||||
if (!(val instanceof Tone.TimeBase)){
|
||||
val = new Tone.TimeBase(val, units);
|
||||
}
|
||||
this._expr = this._binaryExpressions[name].method.bind(this, this._expr, val._expr);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Subtract the current value by the given time.
|
||||
* @param {Time} val The value to divide by
|
||||
* @param {String=} units Optional units to use with the value.
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.add = function(val, units){
|
||||
return this._pushExpr(val, "+", units);
|
||||
};
|
||||
|
||||
/**
|
||||
* Subtract the current value by the given time.
|
||||
* @param {Time} val The value to divide by
|
||||
* @param {String=} units Optional units to use with the value.
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.sub = function(val, units){
|
||||
return this._pushExpr(val, "-", units);
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiply the current value by the given time.
|
||||
* @param {Time} val The value to divide by
|
||||
* @param {String=} units Optional units to use with the value.
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.mult = function(val, units){
|
||||
return this._pushExpr(val, "*", units);
|
||||
};
|
||||
|
||||
/**
|
||||
* Divide the current value by the given time.
|
||||
* @param {Time} val The value to divide by
|
||||
* @param {String=} units Optional units to use with the value.
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.div = function(val, units){
|
||||
return this._pushExpr(val, "/", units);
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the time value. Returns the time
|
||||
* in seconds.
|
||||
* @return {Seconds}
|
||||
*/
|
||||
Tone.TimeBase.prototype.eval = function(){
|
||||
return this._expr();
|
||||
};
|
||||
|
||||
/**
|
||||
* Clean up
|
||||
* @return {Tone.TimeBase} this
|
||||
*/
|
||||
Tone.TimeBase.prototype.dispose = function(){
|
||||
this._expr = null;
|
||||
};
|
||||
|
||||
return Tone.TimeBase;
|
||||
});
|
121
Tone/type/TransportTime.js
Normal file
121
Tone/type/TransportTime.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
define(["Tone/core/Tone", "Tone/type/Time"], function (Tone) {
|
||||
|
||||
/**
|
||||
* @extends {Tone.Time}
|
||||
*/
|
||||
Tone.TransportTime = function(val, units){
|
||||
if (this instanceof Tone.TransportTime){
|
||||
|
||||
Tone.Time.call(this, val, units);
|
||||
|
||||
} else {
|
||||
return new Tone.TransportTime(val, units);
|
||||
}
|
||||
};
|
||||
|
||||
Tone.extend(Tone.TransportTime, Tone.Time);
|
||||
|
||||
//clone the expressions so that
|
||||
//we can add more without modifying the original
|
||||
Tone.TransportTime.prototype._unaryExpressions = Object.create(Tone.Time.prototype._unaryExpressions);
|
||||
|
||||
/**
|
||||
* Adds an additional unary expression
|
||||
* which quantizes values to the next subdivision
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
Tone.TransportTime.prototype._unaryExpressions.quantize = {
|
||||
regexp : /^@/,
|
||||
method : function(rh){
|
||||
var subdivision = rh();
|
||||
var multiple = Math.ceil(Tone.Transport.ticks / subdivision);
|
||||
return multiple * subdivision;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
* The value of a beat in ticks.
|
||||
* @param {Number} beats
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TransportTime.prototype._beatsToUnits = function(beats){
|
||||
return Tone.Transport.PPQ * beats;
|
||||
};
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @param {Ticks} ticks
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TransportTime.prototype._ticksToUnits = function(ticks){
|
||||
return ticks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the value of a second in the current units
|
||||
* @param {Seconds} seconds
|
||||
* @return {Number}
|
||||
* @private
|
||||
*/
|
||||
Tone.TransportTime.prototype._secondsToUnits = function(seconds){
|
||||
var quarterTime = (60 / Tone.Transport.bpm.value);
|
||||
var quarters = seconds / quarterTime;
|
||||
return Math.floor(quarters * Tone.Transport.PPQ);
|
||||
};
|
||||
|
||||
/**
|
||||
* Evaluate the time expression. Returns values in ticks
|
||||
* @return {Ticks}
|
||||
*/
|
||||
Tone.TransportTime.prototype.eval = function(){
|
||||
return Math.floor(this._expr());
|
||||
};
|
||||
|
||||
/**
|
||||
* The current time along the Transport
|
||||
* @return {Ticks} The Transport's position in ticks.
|
||||
*/
|
||||
Tone.TransportTime.prototype.now = function(){
|
||||
return Tone.Transport.ticks;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in ticks.
|
||||
* @return {Ticks}
|
||||
*/
|
||||
Tone.TransportTime.prototype.toTicks = function(){
|
||||
return this.eval();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in samples
|
||||
* @return {Samples}
|
||||
*/
|
||||
Tone.TransportTime.prototype.toSamples = function(){
|
||||
return this.toSeconds() * this.context.sampleRate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time as a frequency value
|
||||
* @return {Frequency}
|
||||
*/
|
||||
Tone.TransportTime.prototype.toFrequency = function(){
|
||||
return 1/this.toSeconds();
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the time in seconds.
|
||||
* @return {Seconds}
|
||||
*/
|
||||
Tone.TransportTime.prototype.toSeconds = function(){
|
||||
var beatTime = 60/Tone.Transport.bpm.value;
|
||||
var tickTime = beatTime / Tone.Transport.PPQ;
|
||||
return this.eval() * tickTime;
|
||||
};
|
||||
|
||||
return Tone.TransportTime;
|
||||
});
|
224
Tone/type/Type.js
Normal file
224
Tone/type/Type.js
Normal file
|
@ -0,0 +1,224 @@
|
|||
define(["Tone/core/Tone", "Tone/type/Time", "Tone/type/Frequency", "Tone/type/TransportTime"],
|
||||
function (Tone) {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// TYPES
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Units which a value can take on.
|
||||
* @enum {String}
|
||||
*/
|
||||
Tone.Type = {
|
||||
/**
|
||||
* Default units
|
||||
* @typedef {Default}
|
||||
*/
|
||||
Default : "number",
|
||||
/**
|
||||
* Time can be described in a number of ways. Read more [Time](https://github.com/Tonejs/Tone.js/wiki/Time).
|
||||
*
|
||||
* <ul>
|
||||
* <li>Numbers, which will be taken literally as the time (in seconds).</li>
|
||||
* <li>Notation, ("4n", "8t") describes time in BPM and time signature relative values.</li>
|
||||
* <li>TransportTime, ("4:3:2") will also provide tempo and time signature relative times
|
||||
* in the form BARS:QUARTERS:SIXTEENTHS.</li>
|
||||
* <li>Frequency, ("8hz") is converted to the length of the cycle in seconds.</li>
|
||||
* <li>Now-Relative, ("+1") prefix any of the above with "+" and it will be interpreted as
|
||||
* "the current time plus whatever expression follows".</li>
|
||||
* <li>Expressions, ("3:0 + 2 - (1m / 7)") any of the above can also be combined
|
||||
* into a mathematical expression which will be evaluated to compute the desired time.</li>
|
||||
* <li>No Argument, for methods which accept time, no argument will be interpreted as
|
||||
* "now" (i.e. the currentTime).</li>
|
||||
* </ul>
|
||||
*
|
||||
* @typedef {Time}
|
||||
*/
|
||||
Time : "time",
|
||||
/**
|
||||
* Frequency can be described similar to time, except ultimately the
|
||||
* values are converted to frequency instead of seconds. A number
|
||||
* is taken literally as the value in hertz. Additionally any of the
|
||||
* Time encodings can be used. Note names in the form
|
||||
* of NOTE OCTAVE (i.e. C4) are also accepted and converted to their
|
||||
* frequency value.
|
||||
* @typedef {Frequency}
|
||||
*/
|
||||
Frequency : "frequency",
|
||||
/**
|
||||
* TransportTime describes a position along the Transport's timeline. It is
|
||||
* similar to Time in that it uses all the same encodings, but TransportTime specifically
|
||||
* pertains to the Transport's timeline, which is startable, stoppable, loopable, and seekable.
|
||||
* [Read more](https://github.com/Tonejs/Tone.js/wiki/TransportTime)
|
||||
* @typedef {TransportTime}
|
||||
*/
|
||||
TransportTime : "transportTime",
|
||||
/**
|
||||
* Ticks are the basic subunit of the Transport. They are
|
||||
* the smallest unit of time that the Transport supports.
|
||||
* @typedef {Ticks}
|
||||
*/
|
||||
Ticks : "ticks",
|
||||
/**
|
||||
* Normal values are within the range [0, 1].
|
||||
* @typedef {NormalRange}
|
||||
*/
|
||||
NormalRange : "normalRange",
|
||||
/**
|
||||
* AudioRange values are between [-1, 1].
|
||||
* @typedef {AudioRange}
|
||||
*/
|
||||
AudioRange : "audioRange",
|
||||
/**
|
||||
* Decibels are a logarithmic unit of measurement which is useful for volume
|
||||
* because of the logarithmic way that we perceive loudness. 0 decibels
|
||||
* means no change in volume. -10db is approximately half as loud and 10db
|
||||
* is twice is loud.
|
||||
* @typedef {Decibels}
|
||||
*/
|
||||
Decibels : "db",
|
||||
/**
|
||||
* Half-step note increments, i.e. 12 is an octave above the root. and 1 is a half-step up.
|
||||
* @typedef {Interval}
|
||||
*/
|
||||
Interval : "interval",
|
||||
/**
|
||||
* Beats per minute.
|
||||
* @typedef {BPM}
|
||||
*/
|
||||
BPM : "bpm",
|
||||
/**
|
||||
* The value must be greater than or equal to 0.
|
||||
* @typedef {Positive}
|
||||
*/
|
||||
Positive : "positive",
|
||||
/**
|
||||
* A cent is a hundredth of a semitone.
|
||||
* @typedef {Cents}
|
||||
*/
|
||||
Cents : "cents",
|
||||
/**
|
||||
* Angle between 0 and 360.
|
||||
* @typedef {Degrees}
|
||||
*/
|
||||
Degrees : "degrees",
|
||||
/**
|
||||
* A number representing a midi note.
|
||||
* @typedef {MIDI}
|
||||
*/
|
||||
MIDI : "midi",
|
||||
/**
|
||||
* A colon-separated representation of time in the form of
|
||||
* Bars:Beats:Sixteenths.
|
||||
* @typedef {BarsBeatsSixteenths}
|
||||
*/
|
||||
BarsBeatsSixteenths : "barsBeatsSixteenths",
|
||||
/**
|
||||
* Sampling is the reduction of a continuous signal to a discrete signal.
|
||||
* Audio is typically sampled 44100 times per second.
|
||||
* @typedef {Samples}
|
||||
*/
|
||||
Samples : "samples",
|
||||
/**
|
||||
* Hertz are a frequency representation defined as one cycle per second.
|
||||
* @typedef {Hertz}
|
||||
*/
|
||||
Hertz : "hertz",
|
||||
/**
|
||||
* A frequency represented by a letter name,
|
||||
* accidental and octave. This system is known as
|
||||
* [Scientific Pitch Notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation).
|
||||
* @typedef {Note}
|
||||
*/
|
||||
Note : "note",
|
||||
/**
|
||||
* One millisecond is a thousandth of a second.
|
||||
* @typedef {Milliseconds}
|
||||
*/
|
||||
Milliseconds : "milliseconds",
|
||||
/**
|
||||
* Seconds are the time unit of the AudioContext. In the end,
|
||||
* all values need to be evaluated to seconds.
|
||||
* @typedef {Seconds}
|
||||
*/
|
||||
Seconds : "seconds",
|
||||
/**
|
||||
* A string representing a duration relative to a measure.
|
||||
* <ul>
|
||||
* <li>"4n" = quarter note</li>
|
||||
* <li>"2m" = two measures</li>
|
||||
* <li>"8t" = eighth-note triplet</li>
|
||||
* </ul>
|
||||
* @typedef {Notation}
|
||||
*/
|
||||
Notation : "notation",
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// AUGMENT TONE's PROTOTYPE
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Convert Time into seconds.
|
||||
*
|
||||
* Unlike the method which it overrides, this takes into account
|
||||
* transporttime and musical notation.
|
||||
*
|
||||
* Time : 1.40
|
||||
* Notation: 4n|1m|2t
|
||||
* Now Relative: +3n
|
||||
* Math: 3n+16n or even complicated expressions ((3n*2)/6 + 1)
|
||||
*
|
||||
* @param {Time} time
|
||||
* @return {Seconds}
|
||||
*/
|
||||
Tone.prototype.toSeconds = function(time){
|
||||
if (this.isNumber(time)){
|
||||
return time;
|
||||
} else if (this.isString(time) || this.isUndef(time)){
|
||||
return (new Tone.Time(time)).eval();
|
||||
} else if (time instanceof Tone.TransportTime){
|
||||
return time.toSeconds();
|
||||
} else if (time instanceof Tone.Time){
|
||||
return time.eval();
|
||||
} else if (time instanceof Tone.Frequency){
|
||||
return time.toSeconds();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a frequency representation into a number.
|
||||
* @param {Frequency} freq
|
||||
* @return {Hertz} the frequency in hertz
|
||||
*/
|
||||
Tone.prototype.toFrequency = function(freq){
|
||||
if (this.isNumber(freq)){
|
||||
return freq;
|
||||
} else if (this.isString(freq) || this.isUndef(freq)){
|
||||
return (new Tone.Frequency(freq)).eval();
|
||||
} else if (freq instanceof Tone.Frequency){
|
||||
return freq.eval();
|
||||
} else if (freq instanceof Tone.Time){
|
||||
return freq.toFrequency();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a time representation into ticks.
|
||||
* @param {Time} time
|
||||
* @return {Ticks} the time in ticks
|
||||
*/
|
||||
Tone.prototype.toTicks = function(time){
|
||||
if (this.isNumber(time) || this.isString(time) || this.isUndef(time)){
|
||||
return (new Tone.TransportTime(time)).eval();
|
||||
} else if (time instanceof Tone.Frequency){
|
||||
return time.toTicks();
|
||||
} else if (time instanceof Tone.TransportTime){
|
||||
return time.eval();
|
||||
} else if (time instanceof Tone.Time){
|
||||
return time.toTicks();
|
||||
}
|
||||
};
|
||||
|
||||
return Tone;
|
||||
});
|
Loading…
Reference in a new issue