mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 16:48:00 +00:00
Merge branch 'dev' of https://github.com/Tonejs/Tone.js into dev
This commit is contained in:
commit
1d265a48a0
30 changed files with 353 additions and 118 deletions
|
@ -42,7 +42,7 @@ module.exports = {
|
|||
"keyword-spacing" : ["error", { "before": true }],
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||
"space-before-blocks": ["error", "never"]
|
||||
"space-before-blocks": ["error", { "functions": "never", "keywords": "never", "classes": "always" }]
|
||||
// "one-var-declaration-per-line": [ "error" , "always" ],
|
||||
// "object-curly-newline": [ "error" , { "multiline": true }],
|
||||
// "array-bracket-newline": [ "error" , "always" ],
|
||||
|
|
|
@ -89,6 +89,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
//set the attackCurve initially
|
||||
this.attackCurve = options.attackCurve;
|
||||
this.releaseCurve = options.releaseCurve;
|
||||
this.decayCurve = options.decayCurve;
|
||||
};
|
||||
|
||||
Tone.extend(Tone.Envelope, Tone.AudioNode);
|
||||
|
@ -104,6 +105,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
"sustain" : 0.5,
|
||||
"release" : 1,
|
||||
"attackCurve" : "linear",
|
||||
"decayCurve" : "exponential",
|
||||
"releaseCurve" : "exponential",
|
||||
};
|
||||
|
||||
|
@ -121,6 +123,51 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get the curve
|
||||
* @param {Array|String} curve
|
||||
* @param {String} direction In/Out
|
||||
* @return {String} The curve name
|
||||
* @private
|
||||
*/
|
||||
Tone.Envelope.prototype._getCurve = function(curve, direction){
|
||||
if (Tone.isString(curve)){
|
||||
return curve;
|
||||
} else if (Tone.isArray(curve)){
|
||||
//look up the name in the curves array
|
||||
for (var t in Tone.Envelope.Type){
|
||||
if (Tone.Envelope.Type[t][direction] === curve){
|
||||
return t;
|
||||
}
|
||||
}
|
||||
//otherwise just return the array
|
||||
return curve;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Assign a the curve to the given name using the direction
|
||||
* @param {String} name
|
||||
* @param {String} direction In/Out
|
||||
* @param {Array} curve
|
||||
* @private
|
||||
*/
|
||||
Tone.Envelope.prototype._setCurve = function(name, direction, curve){
|
||||
//check if it's a valid type
|
||||
if (Tone.Envelope.Type.hasOwnProperty(curve)){
|
||||
var curveDef = Tone.Envelope.Type[curve];
|
||||
if (Tone.isObject(curveDef)){
|
||||
this[name] = curveDef[direction];
|
||||
} else {
|
||||
this[name] = curveDef;
|
||||
}
|
||||
} else if (Tone.isArray(curve)){
|
||||
this[name] = curve;
|
||||
} else {
|
||||
throw new Error("Tone.Envelope: invalid curve: " + curve);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The shape of the attack.
|
||||
* Can be any of these strings:
|
||||
|
@ -147,33 +194,10 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
*/
|
||||
Object.defineProperty(Tone.Envelope.prototype, "attackCurve", {
|
||||
get : function(){
|
||||
if (Tone.isString(this._attackCurve)){
|
||||
return this._attackCurve;
|
||||
} else if (Tone.isArray(this._attackCurve)){
|
||||
//look up the name in the curves array
|
||||
for (var type in Tone.Envelope.Type){
|
||||
if (Tone.Envelope.Type[type].In === this._attackCurve){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
//otherwise just return the array
|
||||
return this._attackCurve;
|
||||
}
|
||||
return this._getCurve(this._attackCurve, "In");
|
||||
},
|
||||
set : function(curve){
|
||||
//check if it's a valid type
|
||||
if (Tone.Envelope.Type.hasOwnProperty(curve)){
|
||||
var curveDef = Tone.Envelope.Type[curve];
|
||||
if (Tone.isObject(curveDef)){
|
||||
this._attackCurve = curveDef.In;
|
||||
} else {
|
||||
this._attackCurve = curveDef;
|
||||
}
|
||||
} else if (Tone.isArray(curve)){
|
||||
this._attackCurve = curve;
|
||||
} else {
|
||||
throw new Error("Tone.Envelope: invalid curve: " + curve);
|
||||
}
|
||||
this._setCurve("_attackCurve", "In", curve);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -187,32 +211,31 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
*/
|
||||
Object.defineProperty(Tone.Envelope.prototype, "releaseCurve", {
|
||||
get : function(){
|
||||
if (Tone.isString(this._releaseCurve)){
|
||||
return this._releaseCurve;
|
||||
} else if (Tone.isArray(this._releaseCurve)){
|
||||
//look up the name in the curves array
|
||||
for (var type in Tone.Envelope.Type){
|
||||
if (Tone.Envelope.Type[type].Out === this._releaseCurve){
|
||||
return type;
|
||||
}
|
||||
}
|
||||
//otherwise just return the array
|
||||
return this._releaseCurve;
|
||||
}
|
||||
return this._getCurve(this._releaseCurve, "Out");
|
||||
},
|
||||
set : function(curve){
|
||||
//check if it's a valid type
|
||||
if (Tone.Envelope.Type.hasOwnProperty(curve)){
|
||||
var curveDef = Tone.Envelope.Type[curve];
|
||||
if (Tone.isObject(curveDef)){
|
||||
this._releaseCurve = curveDef.Out;
|
||||
} else {
|
||||
this._releaseCurve = curveDef;
|
||||
}
|
||||
} else if (Tone.isArray(curve)){
|
||||
this._releaseCurve = curve;
|
||||
} else {
|
||||
this._setCurve("_releaseCurve", "Out", curve);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The shape of the decay either "linear" or "exponential"
|
||||
* @memberOf Tone.Envelope#
|
||||
* @type {String}
|
||||
* @name decayCurve
|
||||
* @example
|
||||
* env.decayCurve = "linear";
|
||||
*/
|
||||
Object.defineProperty(Tone.Envelope.prototype, "decayCurve", {
|
||||
get : function(){
|
||||
return this._decayCurve;
|
||||
},
|
||||
set : function(curve){
|
||||
var curves = ["linear", "exponential"];
|
||||
if (!curves.includes(curve)){
|
||||
throw new Error("Tone.Envelope: invalid curve: " + curve);
|
||||
} else {
|
||||
this._decayCurve = curve;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -250,19 +273,27 @@ define(["Tone/core/Tone", "Tone/signal/Signal",
|
|||
} else if (attack > 0){
|
||||
this._sig.cancelAndHoldAtTime(time);
|
||||
var curve = this._attackCurve;
|
||||
//take only a portion of the curve
|
||||
if (attack < originalAttack){
|
||||
var percentComplete = 1 - attack / originalAttack;
|
||||
var sliceIndex = Math.floor(percentComplete * this._attackCurve.length);
|
||||
curve = this._attackCurve.slice(sliceIndex);
|
||||
//the first index is the current value
|
||||
curve[0] = currentValue;
|
||||
//find the starting position in the curve
|
||||
for (var i = 1; i < curve.length; i++){
|
||||
//the starting index is between the two values
|
||||
if (curve[i-1] <= currentValue && currentValue <= curve[i]){
|
||||
curve = this._attackCurve.slice(i);
|
||||
//the first index is the current value
|
||||
curve[0] = currentValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this._sig.setValueCurveAtTime(curve, time, attack, velocity);
|
||||
}
|
||||
//decay
|
||||
if (decay){
|
||||
this._sig.targetRampTo(velocity * this.sustain, decay, attack + time);
|
||||
var decayValue = velocity * this.sustain;
|
||||
var decayStart = time + attack;
|
||||
if (this._decayCurve === "linear"){
|
||||
this._sig.linearRampTo(decayValue, decay, decayStart);
|
||||
} else if (this._decayCurve === "exponential"){
|
||||
this._sig.targetRampTo(decayValue, decay, decayStart);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
|
|
@ -195,8 +195,6 @@ define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
|
|||
set : function(count){
|
||||
count = Math.max(count, 1);
|
||||
if (this._oscillators.length !== count){
|
||||
// var partials = this.partials;
|
||||
// var type = this.type;
|
||||
//dispose the previous oscillators
|
||||
this._forEach(function(osc){
|
||||
osc.dispose();
|
||||
|
@ -209,7 +207,7 @@ define(["Tone/core/Tone", "Tone/source/Source", "Tone/source/Oscillator",
|
|||
} else {
|
||||
osc.type = this._type;
|
||||
}
|
||||
osc.phase = this._phase;
|
||||
osc.phase = this._phase + (i / count) * 360;
|
||||
osc.volume.value = -6 - count*1.1;
|
||||
this.frequency.connect(osc.frequency);
|
||||
this.detune.connect(osc.detune);
|
||||
|
|
|
@ -10,7 +10,7 @@ if (process.env.BROWSER === "chrome"){
|
|||
} else if (process.env.BROWSER === "safari"){
|
||||
BROWSERS = ["Safari"];
|
||||
} else {
|
||||
BROWSERS = ["HeadlessChrome"];
|
||||
BROWSERS = ["HeadlessChrome", "HeadlessFirefox"];
|
||||
}
|
||||
|
||||
module.exports = function(config){
|
||||
|
@ -106,6 +106,7 @@ module.exports = function(config){
|
|||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
autoWatch : false,
|
||||
// restartOnFileChange : true,
|
||||
|
||||
// start these browsers
|
||||
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
|
||||
|
|
BIN
test/audio/compare/ampEnvelope.wav
Normal file
BIN
test/audio/compare/ampEnvelope.wav
Normal file
Binary file not shown.
BIN
test/audio/compare/ampEnvelope2.wav
Normal file
BIN
test/audio/compare/ampEnvelope2.wav
Normal file
Binary file not shown.
BIN
test/audio/compare/ampEnvelope3.wav
Normal file
BIN
test/audio/compare/ampEnvelope3.wav
Normal file
Binary file not shown.
Binary file not shown.
|
@ -1,10 +1,60 @@
|
|||
define(["Tone/component/AmplitudeEnvelope", "helper/Basic", "helper/Offline",
|
||||
"Tone/component/Envelope", "helper/Test", "Tone/signal/Signal"],
|
||||
function(AmplitudeEnvelope, Basic, Offline, Envelope, Test, Signal){
|
||||
"Tone/component/Envelope", "helper/Test", "Tone/signal/Signal", "helper/CompareToFile", "Tone/source/Oscillator"],
|
||||
function(AmplitudeEnvelope, Basic, Offline, Envelope, Test, Signal, CompareToFile, Oscillator){
|
||||
describe("AmplitudeEnvelope", function(){
|
||||
|
||||
Basic(AmplitudeEnvelope);
|
||||
|
||||
context("Comparisons", function(){
|
||||
|
||||
it("matches a file", function(){
|
||||
return CompareToFile(function(){
|
||||
var ampEnv = new AmplitudeEnvelope({
|
||||
attack : 0.1,
|
||||
decay : 0.2,
|
||||
sustain : 0.1,
|
||||
release : 0.2,
|
||||
}).toMaster();
|
||||
var osc = new Oscillator().start(0).connect(ampEnv);
|
||||
ampEnv.triggerAttack(0);
|
||||
ampEnv.triggerRelease(0.3);
|
||||
}, "ampEnvelope.wav");
|
||||
});
|
||||
|
||||
it("matches a file with multiple retriggers", function(){
|
||||
return CompareToFile(function(){
|
||||
var ampEnv = new AmplitudeEnvelope({
|
||||
attack : 0.1,
|
||||
decay : 0.2,
|
||||
sustain : 0.1,
|
||||
release : 0.2,
|
||||
}).toMaster();
|
||||
var osc = new Oscillator().start(0).connect(ampEnv);
|
||||
ampEnv.triggerAttack(0);
|
||||
ampEnv.triggerAttack(0.3);
|
||||
}, "ampEnvelope2.wav");
|
||||
});
|
||||
|
||||
it("matches a file with ripple attack/release", function(){
|
||||
return CompareToFile(function(){
|
||||
var ampEnv = new AmplitudeEnvelope({
|
||||
attack : 0.5,
|
||||
attackCurve : "ripple",
|
||||
decay : 0.2,
|
||||
sustain : 0.1,
|
||||
release : 0.3,
|
||||
releaseCurve : "ripple",
|
||||
}).toMaster();
|
||||
var osc = new Oscillator().start(0).connect(ampEnv);
|
||||
ampEnv.triggerAttack(0);
|
||||
ampEnv.triggerRelease(0.7);
|
||||
ampEnv.triggerAttack(1);
|
||||
ampEnv.triggerRelease(1.6);
|
||||
}, "ampEnvelope3.wav");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
context("Envelope", function(){
|
||||
|
||||
it("handles input and output connections", function(){
|
||||
|
|
|
@ -13,7 +13,8 @@ function(Envelope, Basic, Offline, Test, PassAudio, APITest){
|
|||
"sustain" : "NormalRange=",
|
||||
"release" : "Time=",
|
||||
"attackCurve" : ["linear", "exponential"],
|
||||
"releaseCurve" : ["linear", "exponential"]
|
||||
"releaseCurve" : ["linear", "exponential"],
|
||||
"decayCurve" : ["linear", "exponential"]
|
||||
});
|
||||
APITest.constructor(Envelope, ["Time=", "Time=", "NormalRange=", "Time="]);
|
||||
|
||||
|
@ -94,6 +95,24 @@ function(Envelope, Basic, Offline, Test, PassAudio, APITest){
|
|||
env2.dispose();
|
||||
});
|
||||
|
||||
it("can set decay to exponential or linear", function(){
|
||||
var env = new Envelope(0.01, 0.01, 0.5, 0.3);
|
||||
env.decayCurve = "exponential";
|
||||
expect(env.decayCurve).to.equal("exponential");
|
||||
env.triggerAttack();
|
||||
env.dispose();
|
||||
//and can be linear
|
||||
var env2 = new Envelope(0.01, 0.01, 0.5, 0.3);
|
||||
env2.decayCurve = "linear";
|
||||
expect(env2.decayCurve).to.equal("linear");
|
||||
env2.triggerAttack();
|
||||
//and test a non-curve
|
||||
expect(function(){
|
||||
env2.decayCurve = "other";
|
||||
}).to.throw(Error);
|
||||
env2.dispose();
|
||||
});
|
||||
|
||||
it("can set release to exponential or linear", function(){
|
||||
var env = new Envelope(0.01, 0.01, 0.5, 0.3);
|
||||
env.releaseCurve = "exponential";
|
||||
|
@ -157,6 +176,50 @@ function(Envelope, Basic, Offline, Test, PassAudio, APITest){
|
|||
});
|
||||
});
|
||||
|
||||
it("correctly schedules a linear decay", function(){
|
||||
var e = {
|
||||
attack : 0.1,
|
||||
decay : 0.5,
|
||||
sustain : 0,
|
||||
release : 0.1,
|
||||
};
|
||||
return Offline(function(){
|
||||
var env = new Envelope(e.attack, e.decay, e.sustain, e.release);
|
||||
env.decayCurve = "linear";
|
||||
env.toMaster();
|
||||
env.triggerAttack(0);
|
||||
}, 0.7).then(function(buffer){
|
||||
expect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);
|
||||
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.8, 0.01);
|
||||
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.6, 0.01);
|
||||
expect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.4, 0.01);
|
||||
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.2, 0.01);
|
||||
expect(buffer.getValueAtTime(0.6)).to.be.closeTo(0, 0.01);
|
||||
});
|
||||
});
|
||||
|
||||
it("correctly schedules an exponential decay", function(){
|
||||
var e = {
|
||||
attack : 0.1,
|
||||
decay : 0.5,
|
||||
sustain : 0,
|
||||
release : 0.1,
|
||||
};
|
||||
return Offline(function(){
|
||||
var env = new Envelope(e.attack, e.decay, e.sustain, e.release);
|
||||
env.decayCurve = "exponential";
|
||||
env.toMaster();
|
||||
env.triggerAttack(0);
|
||||
}, 0.7).then(function(buffer){
|
||||
expect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);
|
||||
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.27, 0.01);
|
||||
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.07, 0.01);
|
||||
expect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.02, 0.01);
|
||||
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.005, 0.01);
|
||||
expect(buffer.getValueAtTime(0.6)).to.be.closeTo(0, 0.01);
|
||||
});
|
||||
});
|
||||
|
||||
it("can schedule a very short attack", function(){
|
||||
var e = {
|
||||
attack : 0.001,
|
||||
|
@ -432,6 +495,52 @@ function(Envelope, Basic, Offline, Test, PassAudio, APITest){
|
|||
});
|
||||
});
|
||||
|
||||
it("can schedule multiple 'sine' attack/releases with no discontinuities", function(){
|
||||
return Offline(function(){
|
||||
var env = new Envelope(0.1, 0.2, 0.2, 0.4).toMaster();
|
||||
env.attackCurve = "sine";
|
||||
env.releaseCurve = "sine";
|
||||
env.triggerAttackRelease(0, 0.4);
|
||||
env.triggerAttackRelease(0.4, 0.11);
|
||||
env.triggerAttackRelease(0.45, 0.1);
|
||||
env.triggerAttackRelease(1.1, 0.09);
|
||||
env.triggerAttackRelease(1.5, 0.3);
|
||||
env.triggerAttackRelease(1.8, 0.29);
|
||||
}, 2).then(function(buffer){
|
||||
//test for discontinuities
|
||||
var lastSample = 0;
|
||||
buffer.forEach(function(sample, time){
|
||||
expect(sample).to.be.at.most(1);
|
||||
var diff = Math.abs(lastSample - sample);
|
||||
expect(diff).to.be.lessThan(0.002);
|
||||
lastSample = sample;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("can schedule multiple 'cosine' attack/releases with no discontinuities", function(){
|
||||
return Offline(function(){
|
||||
var env = new Envelope(0.1, 0.2, 0.2, 0.4).toMaster();
|
||||
env.attackCurve = "cosine";
|
||||
env.releaseCurve = "cosine";
|
||||
env.triggerAttackRelease(0, 0.4);
|
||||
env.triggerAttackRelease(0.4, 0.11);
|
||||
env.triggerAttackRelease(0.45, 0.1);
|
||||
env.triggerAttackRelease(1.1, 0.09);
|
||||
env.triggerAttackRelease(1.5, 0.3);
|
||||
env.triggerAttackRelease(1.8, 0.29);
|
||||
}, 2).then(function(buffer){
|
||||
//test for discontinuities
|
||||
var lastSample = 0;
|
||||
buffer.forEach(function(sample, time){
|
||||
expect(sample).to.be.at.most(1);
|
||||
var diff = Math.abs(lastSample - sample);
|
||||
expect(diff).to.be.lessThan(0.002);
|
||||
lastSample = sample;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("reports its current envelope value (.value)", function(){
|
||||
return Offline(function(){
|
||||
var env = new Envelope(1, 0.2, 1).toMaster();
|
||||
|
@ -612,24 +721,27 @@ function(Envelope, Basic, Offline, Test, PassAudio, APITest){
|
|||
it("can retrigger partial envelope with custom type", function(){
|
||||
return Offline(function(){
|
||||
var env = new Envelope({
|
||||
attack : 0.3,
|
||||
attack : 0.5,
|
||||
sustain : 1,
|
||||
release : 0.3,
|
||||
release : 0.5,
|
||||
decay : 0,
|
||||
attackCurve : "step",
|
||||
releaseCurve : "step",
|
||||
attackCurve : "cosine",
|
||||
releaseCurve : "sine",
|
||||
}).toMaster();
|
||||
env.triggerAttackRelease(0.1, 0.3);
|
||||
env.triggerAttackRelease(0.1, 0.35);
|
||||
env.triggerAttackRelease(0.1, 0.8);
|
||||
env.triggerAttack(0);
|
||||
env.triggerRelease(0.2);
|
||||
env.triggerAttack(0.5);
|
||||
}, 1).then(function(buffer){
|
||||
buffer.forEach(function(sample, time){
|
||||
if (time > 0.3 && time < 0.5){
|
||||
expect(sample).to.be.above(0);
|
||||
} else if (time < 0.1){
|
||||
expect(sample).to.equal(0);
|
||||
}
|
||||
});
|
||||
expect(buffer.getValueAtTime(0)).to.equal(0);
|
||||
expect(buffer.getValueAtTime(0.1)).to.be.closeTo(0.32, 0.01);
|
||||
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(0.6, 0.01);
|
||||
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.53, 0.01);
|
||||
expect(buffer.getValueAtTime(0.4)).to.be.closeTo(0.38, 0.01);
|
||||
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.2, 0.01);
|
||||
expect(buffer.getValueAtTime(0.6)).to.be.closeTo(0.52, 0.01);
|
||||
expect(buffer.getValueAtTime(0.7)).to.be.closeTo(0.78, 0.01);
|
||||
expect(buffer.getValueAtTime(0.8)).to.be.closeTo(0.95, 0.01);
|
||||
expect(buffer.getValueAtTime(0.9)).to.be.closeTo(1, 0.01);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
define(["helper/Offline", "Tone/core/Buffer", "audiobuffer-to-wav", "fft-js"], function(Offline, Buffer, audioBufferToWav, FFT){
|
||||
define(["helper/Offline", "Tone/core/Buffer", "audiobuffer-to-wav", "fft-js", "Tone/core/Tone"], function(Offline, Buffer, audioBufferToWav, FFT, Tone){
|
||||
|
||||
return function(callback, url, threshold, RENDER_NEW){
|
||||
if (!RENDER_NEW){
|
||||
|
||||
threshold = threshold || 20;
|
||||
threshold = Tone.defaultArg(threshold, 0.001);
|
||||
var baseUrl = "./audio/compare/";
|
||||
return Buffer.fromUrl(baseUrl+url).then(function(buffer){
|
||||
return Offline(callback, buffer.duration, buffer.numberOfChannels).then(function(renderedBuffer){
|
||||
|
@ -16,6 +15,8 @@ define(["helper/Offline", "Tone/core/Buffer", "audiobuffer-to-wav", "fft-js"], f
|
|||
//go through and compare everything
|
||||
var renderedValues = buffers.rendered.toArray();
|
||||
var targetValues = buffers.target.toArray();
|
||||
var difference = 0;
|
||||
var samples = 0;
|
||||
targetValues.forEach(function(channel, channelNumber){
|
||||
var fftSize = 4096;
|
||||
var renderedChannel = renderedValues[channelNumber];
|
||||
|
@ -26,11 +27,13 @@ define(["helper/Offline", "Tone/core/Buffer", "audiobuffer-to-wav", "fft-js"], f
|
|||
var renderedMagnitudes = FFT.util.fftMag(renderedPhasors);
|
||||
var targetMagnitudes = FFT.util.fftMag(targetPhasors);
|
||||
targetMagnitudes.forEach(function(value, index){
|
||||
expect(value).to.be.closeTo(renderedMagnitudes[index], threshold);
|
||||
difference += Math.abs(renderedMagnitudes[index] - value);
|
||||
samples++;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
expect(difference/samples).to.be.lt(threshold);
|
||||
});
|
||||
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/AMSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile"],
|
||||
function(AMSynth, Basic, InstrumentTest, CompareToFile) {
|
||||
function(AMSynth, Basic, InstrumentTest, CompareToFile){
|
||||
|
||||
describe("AMSynth", function(){
|
||||
|
||||
|
@ -11,7 +11,7 @@ function(AMSynth, Basic, InstrumentTest, CompareToFile) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new AMSynth().toMaster();
|
||||
synth.triggerAttackRelease("C5", 0.1, 0.1);
|
||||
}, "amSynth.wav", 50);
|
||||
}, "amSynth.wav", 0.15);
|
||||
});
|
||||
|
||||
context("API", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/DuoSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile", "helper/Supports"],
|
||||
function(DuoSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
||||
function(DuoSynth, Basic, InstrumentTest, CompareToFile, Supports){
|
||||
|
||||
describe("DuoSynth", function(){
|
||||
|
||||
|
@ -33,7 +33,7 @@ function(DuoSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new DuoSynth().toMaster();
|
||||
synth.triggerAttackRelease("C5", 0.1, 0.1);
|
||||
}, "duoSynth.wav", 150);
|
||||
}, "duoSynth.wav", 0.01);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ function(FMSynth, Basic, InstrumentTest, CompareToFile, Supports){
|
|||
return CompareToFile(function(){
|
||||
const synth = new FMSynth().toMaster();
|
||||
synth.triggerAttackRelease("G4", 0.1, 0.05);
|
||||
}, "fmSynth.wav", 40);
|
||||
}, "fmSynth.wav", 0.1);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/MembraneSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile"],
|
||||
function(MembraneSynth, Basic, InstrumentTest, CompareToFile) {
|
||||
function(MembraneSynth, Basic, InstrumentTest, CompareToFile){
|
||||
|
||||
describe("MembraneSynth", function(){
|
||||
|
||||
|
@ -11,7 +11,7 @@ function(MembraneSynth, Basic, InstrumentTest, CompareToFile) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new MembraneSynth().toMaster();
|
||||
synth.triggerAttackRelease("F#2", 0.1, 0.05);
|
||||
}, "membraneSynth.wav", 50);
|
||||
}, "membraneSynth.wav", 0.5);
|
||||
});
|
||||
|
||||
context("API", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/MetalSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile", "helper/Supports"],
|
||||
function(MetalSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
||||
function(MetalSynth, Basic, InstrumentTest, CompareToFile, Supports){
|
||||
|
||||
describe("MetalSynth", function(){
|
||||
|
||||
|
@ -12,7 +12,7 @@ function(MetalSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new MetalSynth().toMaster();
|
||||
synth.triggerAttackRelease(0.1, 0.05);
|
||||
}, "metalSynth.wav", 200);
|
||||
}, "metalSynth.wav", 5.9);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/MonoSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile", "helper/Supports", "helper/Offline"],
|
||||
function(MonoSynth, Basic, InstrumentTest, CompareToFile, Supports, Offline) {
|
||||
function(MonoSynth, Basic, InstrumentTest, CompareToFile, Supports, Offline){
|
||||
|
||||
describe("MonoSynth", function(){
|
||||
|
||||
|
@ -12,7 +12,7 @@ function(MonoSynth, Basic, InstrumentTest, CompareToFile, Supports, Offline) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new MonoSynth().toMaster();
|
||||
synth.triggerAttackRelease("C4", 0.1, 0.05);
|
||||
}, "monoSynth.wav", 250);
|
||||
}, "monoSynth.wav", 1.75);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ define(["Tone/instrument/NoiseSynth", "helper/Basic", "helper/InstrumentTests",
|
|||
}).toMaster();
|
||||
synth.triggerAttack(0);
|
||||
synth.triggerAttack(0.3);
|
||||
}, "noiseSynth.wav", 110);
|
||||
}, "noiseSynth.wav", 3.8);
|
||||
});
|
||||
|
||||
it("matches another file", function(){
|
||||
|
@ -34,7 +34,7 @@ define(["Tone/instrument/NoiseSynth", "helper/Basic", "helper/InstrumentTests",
|
|||
}
|
||||
}).toMaster();
|
||||
synth.triggerAttackRelease(0.1, 0);
|
||||
}, "noiseSynthRelease.wav", 110);
|
||||
}, "noiseSynthRelease.wav", 3.8);
|
||||
});
|
||||
|
||||
context("API", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["Tone/instrument/PluckSynth", "helper/Basic",
|
||||
"helper/InstrumentTests", "helper/CompareToFile", "helper/Supports"],
|
||||
function(PluckSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
||||
function(PluckSynth, Basic, InstrumentTest, CompareToFile, Supports){
|
||||
|
||||
describe("PluckSynth", function(){
|
||||
|
||||
|
@ -13,7 +13,7 @@ function(PluckSynth, Basic, InstrumentTest, CompareToFile, Supports) {
|
|||
return CompareToFile(function(){
|
||||
const synth = new PluckSynth().toMaster();
|
||||
synth.triggerAttack("C4");
|
||||
}, "pluckSynth.wav", 250);
|
||||
}, "pluckSynth.wav", 0.2);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ function(Synth, Basic, InstrumentTest, APITest, Offline, Frequency, CompareToFil
|
|||
return CompareToFile(function(){
|
||||
const synth = new Synth().toMaster();
|
||||
synth.triggerAttackRelease("C4", 0.1, 0.05);
|
||||
}, "synth_basic.wav");
|
||||
}, "synth_basic.wav", 0.3);
|
||||
});
|
||||
|
||||
it("matches a file melody", function(){
|
||||
|
@ -21,7 +21,7 @@ function(Synth, Basic, InstrumentTest, APITest, Offline, Frequency, CompareToFil
|
|||
synth.triggerAttack("E4", 0.1, 0.5);
|
||||
synth.triggerAttackRelease("G4", 0.5, 0.3);
|
||||
synth.triggerAttackRelease("B4", 0.5, 0.5, 0.2);
|
||||
}, "synth_melody.wav");
|
||||
}, "synth_melody.wav", 0.3);
|
||||
});
|
||||
|
||||
context("API", function(){
|
||||
|
|
|
@ -13,7 +13,7 @@ function(BasicTests, AMOscillator, Offline, SourceTests, OscillatorTests, Test,
|
|||
return CompareToFile(function(){
|
||||
var osc = new AMOscillator().toMaster();
|
||||
osc.start(0.1).stop(0.4);
|
||||
}, "amOscillator.wav");
|
||||
}, "amOscillator.wav", 0.01);
|
||||
});
|
||||
|
||||
context("Amplitude Modulation", function(){
|
||||
|
|
|
@ -13,7 +13,7 @@ function(BasicTests, FMOscillator, Offline, SourceTests, OscillatorTests, Test,
|
|||
return CompareToFile(function(){
|
||||
var osc = new FMOscillator().toMaster();
|
||||
osc.start(0);
|
||||
}, "fmOscillator.wav");
|
||||
}, "fmOscillator.wav", 0.01);
|
||||
});
|
||||
|
||||
context("Frequency Modulation", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["helper/Basic", "Tone/source/FatOscillator", "helper/Offline",
|
||||
"helper/SourceTests", "helper/OscillatorTests", "helper/CompareToFile"],
|
||||
function(BasicTests, FatOscillator, Offline, SourceTests, OscillatorTests, CompareToFile) {
|
||||
function(BasicTests, FatOscillator, Offline, SourceTests, OscillatorTests, CompareToFile){
|
||||
|
||||
describe("FatOscillator", function(){
|
||||
|
||||
|
@ -13,7 +13,7 @@ function(BasicTests, FatOscillator, Offline, SourceTests, OscillatorTests, Compa
|
|||
return CompareToFile(function(){
|
||||
var osc = new FatOscillator().toMaster();
|
||||
osc.start(0);
|
||||
}, "fatOscillator.wav");
|
||||
}, "fatOscillator.wav", 0.2);
|
||||
});
|
||||
|
||||
context("Detuned Oscillators", function(){
|
||||
|
|
|
@ -22,7 +22,7 @@ function(BasicTests, GrainPlayer, Offline, SourceTests, Buffer, Test, Tone, Comp
|
|||
player.start(0.1).stop(0.2);
|
||||
player.detune = -100,
|
||||
player.playbackRate = 2;
|
||||
}, "grainPlayer.wav");
|
||||
}, "grainPlayer.wav", 0.16);
|
||||
});
|
||||
|
||||
context("Constructor", function(){
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
define(["helper/Basic", "Tone/source/Noise", "helper/SourceTests", "helper/OutputAudio", "helper/CompareToFile"],
|
||||
function(BasicTests, Noise, SourceTests, OutputAudio, CompareToFile) {
|
||||
function(BasicTests, Noise, SourceTests, OutputAudio, CompareToFile){
|
||||
|
||||
describe("Noise", function(){
|
||||
|
||||
|
@ -11,7 +11,7 @@ define(["helper/Basic", "Tone/source/Noise", "helper/SourceTests", "helper/Outpu
|
|||
return CompareToFile(function(){
|
||||
const noise = new Noise().toMaster();
|
||||
noise.start(0.1).stop(0.2);
|
||||
}, "noise.wav", 150);
|
||||
}, "noise.wav", 9);
|
||||
});
|
||||
|
||||
context("Get/Set", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["helper/Basic", "Tone/source/OmniOscillator", "helper/Offline",
|
||||
"helper/SourceTests", "helper/OscillatorTests", "helper/OutputAudio", "helper/CompareToFile"],
|
||||
function(BasicTests, OmniOscillator, Offline, SourceTests, OscillatorTests, OutputAudio, CompareToFile) {
|
||||
function(BasicTests, OmniOscillator, Offline, SourceTests, OscillatorTests, OutputAudio, CompareToFile){
|
||||
|
||||
describe("OmniOscillator", function(){
|
||||
|
||||
|
@ -13,7 +13,7 @@ function(BasicTests, OmniOscillator, Offline, SourceTests, OscillatorTests, Outp
|
|||
return CompareToFile(function(){
|
||||
const osc = new OmniOscillator(220, "fmsquare").toMaster();
|
||||
osc.start(0.1).stop(0.2);
|
||||
}, "omniOscillator.wav", 100);
|
||||
}, "omniOscillator.wav", 1.6);
|
||||
});
|
||||
|
||||
context("Sound", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["helper/Basic", "Tone/source/Oscillator", "helper/Offline", "helper/SourceTests",
|
||||
"helper/OscillatorTests", "helper/OutputAudio", "Tone/core/Transport", "helper/CompareToFile"],
|
||||
function(BasicTests, Oscillator, Offline, SourceTests, OscillatorTests, OutputAudio, Transport, CompareToFile) {
|
||||
function(BasicTests, Oscillator, Offline, SourceTests, OscillatorTests, OutputAudio, Transport, CompareToFile){
|
||||
|
||||
describe("Oscillator", function(){
|
||||
|
||||
|
@ -14,7 +14,7 @@ function(BasicTests, Oscillator, Offline, SourceTests, OscillatorTests, OutputAu
|
|||
const osc = new Oscillator().toMaster();
|
||||
osc.type = "square";
|
||||
osc.start(0).stop(0.2);
|
||||
}, "oscillator.wav");
|
||||
}, "oscillator.wav", 0.005);
|
||||
});
|
||||
|
||||
context("Get/Set", function(){
|
||||
|
|
|
@ -21,7 +21,7 @@ function(BasicTests, Player, Offline, SourceTests, Buffer, Meter, Test, Tone, Co
|
|||
const player = new Player(buffer).toMaster();
|
||||
player.start(0.1).stop(0.2);
|
||||
player.playbackRate = 2;
|
||||
}, "player.wav");
|
||||
}, "player.wav", 0.005);
|
||||
});
|
||||
|
||||
context("Constructor", function(){
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
define(["helper/Basic", "Tone/source/PulseOscillator", "helper/Offline",
|
||||
"helper/SourceTests", "helper/OscillatorTests", "helper/CompareToFile"],
|
||||
function(BasicTests, PulseOscillator, Offline, SourceTests, OscillatorTests, CompareToFile) {
|
||||
function(BasicTests, PulseOscillator, Offline, SourceTests, OscillatorTests, CompareToFile){
|
||||
|
||||
describe("PulseOscillator", function(){
|
||||
|
||||
|
@ -13,7 +13,7 @@ function(BasicTests, PulseOscillator, Offline, SourceTests, OscillatorTests, Com
|
|||
return CompareToFile(function(){
|
||||
var osc = new PulseOscillator().toMaster();
|
||||
osc.start(0);
|
||||
}, "pulseOscillator.wav", 50);
|
||||
}, "pulseOscillator.wav", 0.03);
|
||||
});
|
||||
|
||||
context("Phase Rotation", function(){
|
||||
|
|
|
@ -447,15 +447,55 @@ define(["helper/Test", "Tone/source/TickSource", "helper/Offline", "helper/Basic
|
|||
source.dispose();
|
||||
});
|
||||
|
||||
it("always increments by 1", function(){
|
||||
var source = new TickSource(200);
|
||||
source.frequency.setValueAtTime(200, 0);
|
||||
source.frequency.linearRampToValueAtTime(1000, 4);
|
||||
it("always increments by 1 at a fixed rate", function(){
|
||||
var source = new TickSource(960);
|
||||
source.start(0);
|
||||
var previousTick = -1;
|
||||
source.forEachTickBetween(0, 10, function(time, ticks){
|
||||
var previousTime = -1;
|
||||
source.forEachTickBetween(1000, 1010, function(time, ticks){
|
||||
expect(time).to.be.gt(previousTime);
|
||||
if (previousTick !== -1){
|
||||
expect(ticks - previousTick).to.equal(1);
|
||||
}
|
||||
previousTick = ticks;
|
||||
previousTime = time;
|
||||
});
|
||||
source.dispose();
|
||||
});
|
||||
|
||||
it("always increments by 1 when linearly changing rate", function(){
|
||||
var source = new TickSource(200);
|
||||
source.frequency.setValueAtTime(200, 0);
|
||||
source.frequency.linearRampToValueAtTime(1000, 100);
|
||||
source.start(10);
|
||||
var previousTick = -1;
|
||||
var previousTime = -1;
|
||||
source.forEachTickBetween(10, 30, function(time, ticks){
|
||||
expect(time).to.be.gt(previousTime);
|
||||
expect(ticks - previousTick).to.equal(1);
|
||||
previousTick = ticks;
|
||||
previousTime = time;
|
||||
});
|
||||
source.dispose();
|
||||
});
|
||||
|
||||
it("always increments by 1 when setting values", function(){
|
||||
var source = new TickSource(200);
|
||||
source.frequency.setValueAtTime(300, 0);
|
||||
source.frequency.setValueAtTime(3, 0.1);
|
||||
source.frequency.setValueAtTime(100, 0.2);
|
||||
source.frequency.setValueAtTime(10, 0.3);
|
||||
source.frequency.setValueAtTime(1000, 0.4);
|
||||
source.frequency.setValueAtTime(1, 0.5);
|
||||
source.frequency.setValueAtTime(50, 0.6);
|
||||
source.start(0);
|
||||
var previousTick = -1;
|
||||
var previousTime = -1;
|
||||
source.forEachTickBetween(0, 10, function(time, ticks){
|
||||
expect(time).to.be.gt(previousTime);
|
||||
expect(ticks - previousTick).to.equal(1);
|
||||
previousTick = ticks;
|
||||
previousTime = time;
|
||||
});
|
||||
source.dispose();
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue