mirror of
https://github.com/Tonejs/Tone.js
synced 2025-01-09 18:38:46 +00:00
Merge branch 'dev'
This commit is contained in:
commit
e0411838b1
57 changed files with 1654 additions and 24345 deletions
53
.gitignore
vendored
53
.gitignore
vendored
|
@ -1,56 +1,23 @@
|
||||||
|
.DS_Store
|
||||||
|
*.asd
|
||||||
*.scssc
|
*.scssc
|
||||||
|
|
||||||
examples/scratch.html
|
|
||||||
|
|
||||||
*.sublime-workspace
|
*.sublime-workspace
|
||||||
|
|
||||||
*.sublime-project
|
*.sublime-project
|
||||||
|
|
||||||
# grunt modules
|
|
||||||
node_modules
|
node_modules
|
||||||
gulp/description
|
|
||||||
|
|
||||||
TODO.txt
|
TODO.txt
|
||||||
|
|
||||||
# all the npm stuff
|
|
||||||
utils/npm/Tone
|
|
||||||
utils/npm/build/Tone.js
|
|
||||||
utils/npm/build/Tone.min.js
|
|
||||||
utils/npm/build/Tone.Preset.js
|
|
||||||
utils/npm/README.md
|
|
||||||
|
|
||||||
utils/jsdoc/*.json
|
|
||||||
|
|
||||||
examples/deps/FileSaver.js
|
|
||||||
|
|
||||||
examples/oscilloscope.html
|
|
||||||
|
|
||||||
.idea
|
|
||||||
|
|
||||||
wiki
|
wiki
|
||||||
test/performance
|
|
||||||
|
|
||||||
examples/crashes.html
|
examples/scratch.html
|
||||||
|
examples/deps/FileSaver.js
|
||||||
examples/style/examples.css.map
|
examples/oscilloscope.html
|
||||||
|
|
||||||
examples/deps/Tone.dat.gui.js
|
|
||||||
|
|
||||||
examples/deps/dat.gui.js
|
|
||||||
|
|
||||||
test/mainTest.js
|
|
||||||
|
|
||||||
test/Main.js
|
|
||||||
|
|
||||||
build/p5.Tone.min.js
|
|
||||||
build/p5.Tone.js
|
|
||||||
|
|
||||||
.DS_Store
|
|
||||||
examples/graph.html
|
examples/graph.html
|
||||||
|
|
||||||
*.asd
|
test/performance
|
||||||
|
test/mainTest.js
|
||||||
|
test/Main.js
|
||||||
test/supports.html
|
test/supports.html
|
||||||
|
|
||||||
test/coverage/
|
test/coverage/
|
||||||
|
|
||||||
|
build/*
|
||||||
|
|
56
.travis.yml
56
.travis.yml
|
@ -1,18 +1,46 @@
|
||||||
sudo: false
|
sudo: false
|
||||||
dist: trusty
|
dist: trusty
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "8"
|
- '8'
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
chrome: stable
|
chrome: stable
|
||||||
before_script:
|
before_script:
|
||||||
- cd gulp
|
- cd gulp
|
||||||
- npm install -g karma
|
- npm install -g jsdoc
|
||||||
- npm install -g gulp
|
- npm install -g karma
|
||||||
- npm install
|
- npm install -g gulp
|
||||||
- git config --global user.email "travis@travis-ci.org"
|
- npm install
|
||||||
- git config --global user.name "Travis CI"
|
- git config --global user.email "travis@travis-ci.org"
|
||||||
|
- git config --global user.name "Travis CI"
|
||||||
script: gulp travis-test
|
script: gulp travis-test
|
||||||
after_success:
|
after_success:
|
||||||
- sh success.sh
|
- sh success.sh
|
||||||
|
before_deploy:
|
||||||
|
- node increment_version.js
|
||||||
|
- cd ../
|
||||||
|
deploy:
|
||||||
|
- provider: npm
|
||||||
|
skip_cleanup: true
|
||||||
|
email: yotammann@gmail.com
|
||||||
|
api_key: $NPM_TOKEN
|
||||||
|
tag: next
|
||||||
|
on:
|
||||||
|
repo: Tonejs/Tone.js
|
||||||
|
branch: dev
|
||||||
|
# publish without @next when pushing on master
|
||||||
|
- provider: npm
|
||||||
|
skip_cleanup: true
|
||||||
|
email: yotammann@gmail.com
|
||||||
|
api_key: $NPM_TOKEN
|
||||||
|
on:
|
||||||
|
repo: Tonejs/Tone.js
|
||||||
|
branch: master
|
||||||
|
# publish build files for releases
|
||||||
|
- provider: releases
|
||||||
|
api-key: $GH_TOKEN
|
||||||
|
file_glob: true
|
||||||
|
file: build/*
|
||||||
|
skip_cleanup: true
|
||||||
|
on:
|
||||||
|
tags: true
|
||||||
|
|
|
@ -3,12 +3,16 @@
|
||||||
* [Code coverage](https://coveralls.io/github/Tonejs/Tone.js) analysis
|
* [Code coverage](https://coveralls.io/github/Tonejs/Tone.js) analysis
|
||||||
* [Dev build](https://tonejs.github.io/build/dev/Tone.js) with each successful commit
|
* [Dev build](https://tonejs.github.io/build/dev/Tone.js) with each successful commit
|
||||||
* [Versioned docs](https://tonejs.github.io/docs/Tone) plus a [dev build of the docs](https://tonejs.github.io/docs/dev/Tone) on successful commits
|
* [Versioned docs](https://tonejs.github.io/docs/Tone) plus a [dev build of the docs](https://tonejs.github.io/docs/dev/Tone) on successful commits
|
||||||
* Tone.AudioNode is base class for all classes which generate or process audio
|
* [Tone.AudioNode](https://tonejs.github.io/docs/AudioNode) is base class for all classes which generate or process audio
|
||||||
* [Tone.Sampler](https://tonejs.github.io/docs/Sampler) simplifies creating multisampled instruments
|
* [Tone.Sampler](https://tonejs.github.io/docs/Sampler) simplifies creating multisampled instruments
|
||||||
* [Tone.Solo](https://tonejs.github.io/docs/Solo) makes it easier to mute/solo audio
|
* [Tone.Solo](https://tonejs.github.io/docs/Solo) makes it easier to mute/solo audio
|
||||||
* [Mixer](https://tonejs.github.io/examples/#mixer) and [sampler](https://tonejs.github.io/examples/#sampler) examples
|
* [Mixer](https://tonejs.github.io/examples/#mixer) and [sampler](https://tonejs.github.io/examples/#sampler) examples
|
||||||
* Making type-checking methods static
|
* Making type-checking methods static
|
||||||
* [Tone.TransportTimelineSignal](https://tonejs.github.io/docs/TransportTimelineSignal) is a signal which can be scheduled along the Transport
|
* [Tone.TransportTimelineSignal](https://tonejs.github.io/docs/TransportTimelineSignal) is a signal which can be scheduled along the Transport
|
||||||
|
* [Tone.FFT](https://tonejs.github.io/docs/FFT) and [Tone.Waveform](https://tonejs.github.io/docs/Waveform) abstract Tone.Analyser
|
||||||
|
* [Tone.Meter](https://tonejs.github.io/docs/Meter) returns decibels
|
||||||
|
* [Tone.Envelope](https://tonejs.github.io/docs/Envelope) uses exponential approach instead of exponential curve for decay and release curves
|
||||||
|
* [Tone.BufferSource](https://tonejs.github.io/docs/BufferSource) fadeIn/Out can be either "linear" or "exponential" curve
|
||||||
|
|
||||||
### r10
|
### r10
|
||||||
|
|
||||||
|
|
13
README.md
13
README.md
|
@ -15,6 +15,7 @@ Tone.js is a Web Audio framework for creating interactive music in the browser.
|
||||||
|
|
||||||
* download [full](https://tonejs.github.io/build/Tone.js) | [min](https://tonejs.github.io/build/Tone.min.js)
|
* download [full](https://tonejs.github.io/build/Tone.js) | [min](https://tonejs.github.io/build/Tone.min.js)
|
||||||
* `npm install tone`
|
* `npm install tone`
|
||||||
|
* dev -> `npm install tone@next`
|
||||||
|
|
||||||
[Full Installation Instruction](https://github.com/Tonejs/Tone.js/wiki/Installation).
|
[Full Installation Instruction](https://github.com/Tonejs/Tone.js/wiki/Installation).
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ synth.triggerAttackRelease("C4", "8n");
|
||||||
|
|
||||||
#### Tone.Synth
|
#### Tone.Synth
|
||||||
|
|
||||||
[Tone.Synth](https://tonejs.github.io/docs/#Synth) is a basic synthesizer with a single [oscillator](https://tonejs.github.io/docs/#OmniOscillator) and an [ADSR envelope](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope).
|
[Tone.Synth](https://tonejs.github.io/docs/#Synth) is a basic synthesizer with a single [oscillator](https://tonejs.github.io/docs/#OmniOscillator) and an [ADSR envelope](https://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope).
|
||||||
|
|
||||||
#### triggerAttackRelease
|
#### triggerAttackRelease
|
||||||
|
|
||||||
|
@ -48,7 +49,7 @@ Tone.js abstracts away the AudioContext time. Instead of defining all values in
|
||||||
|
|
||||||
### Transport
|
### Transport
|
||||||
|
|
||||||
[Tone.Transport](https://tonejs.github.io/docs/#Transport) is the master timekeeper, allowing for application-wide synchronization and scheduling of sources, signals and events along a shared timeline. Time expressions (like the ones above) are evaluated against the Transport's BPM which can be set like this: `Tone.Transport.bpm.value = 120`.
|
[Tone.Transport](https://tonejs.github.io/docs/#Transport) is the master timekeeper, allowing for application-wide synchronization and scheduling of sources, signals and events along a shared timeline. Time expressions (like the ones above) are evaluated against the Transport's BPM which can be set like this: `Tone.Transport.bpm.value = 120`.
|
||||||
|
|
||||||
### Loops
|
### Loops
|
||||||
|
|
||||||
|
@ -101,7 +102,7 @@ var synth = new Tone.Synth({
|
||||||
synth.triggerAttack("D3", "+1");
|
synth.triggerAttack("D3", "+1");
|
||||||
```
|
```
|
||||||
|
|
||||||
All instruments are monophonic (one voice) but can be made polyphonic when the constructor is passed in as the second argument to [Tone.PolySynth](https://tonejs.github.io/docs/#PolySynth).
|
All instruments are monophonic (one voice) but can be made polyphonic when the constructor is passed in as the second argument to [Tone.PolySynth](https://tonejs.github.io/docs/#PolySynth).
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
//a 4 voice Synth
|
//a 4 voice Synth
|
||||||
|
@ -114,7 +115,7 @@ polySynth.triggerAttackRelease(["C4", "E4", "G4", "B4"], "2n");
|
||||||
|
|
||||||
# Effects
|
# Effects
|
||||||
|
|
||||||
In the above examples, the synthesizer was always connected directly to the [master output](https://tonejs.github.io/docs/#Master), but the output of the synth could also be routed through one (or more) effects before going to the speakers.
|
In the above examples, the synthesizer was always connected directly to the [master output](https://tonejs.github.io/docs/#Master), but the output of the synth could also be routed through one (or more) effects before going to the speakers.
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
//create a distortion effect
|
//create a distortion effect
|
||||||
|
@ -138,7 +139,7 @@ var pwm = new Tone.PWMOscillator("Bb3").toMaster().start();
|
||||||
|
|
||||||
# Signals
|
# Signals
|
||||||
|
|
||||||
Like the underlying Web Audio API, Tone.js is built with audio-rate signal control over nearly everything. This is a powerful feature which allows for sample-accurate synchronization and scheduling of parameters.
|
Like the underlying Web Audio API, Tone.js is built with audio-rate signal control over nearly everything. This is a powerful feature which allows for sample-accurate synchronization and scheduling of parameters.
|
||||||
|
|
||||||
[Read more](https://github.com/Tonejs/Tone.js/wiki/Signals).
|
[Read more](https://github.com/Tonejs/Tone.js/wiki/Signals).
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ Tone.js makes extensive use of the native Web Audio Nodes such as the GainNode a
|
||||||
|
|
||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
There are many ways to contribute to Tone.js. Check out [this wiki](https://github.com/Tonejs/Tone.js/wiki/Contributing) if you're interested.
|
There are many ways to contribute to Tone.js. Check out [this wiki](https://github.com/Tonejs/Tone.js/wiki/Contributing) if you're interested.
|
||||||
|
|
||||||
If you have questions (or answers) that are not necessarily bugs/issues, please post them to the [forum](https://groups.google.com/forum/#!forum/tonejs).
|
If you have questions (or answers) that are not necessarily bugs/issues, please post them to the [forum](https://groups.google.com/forum/#!forum/tonejs).
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ define(["Tone/core/Tone", "Tone/core/AudioNode"], function (Tone) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible return types of Tone.Analyser.analyse()
|
* Possible return types of analyser.getValue()
|
||||||
* @enum {String}
|
* @enum {String}
|
||||||
*/
|
*/
|
||||||
Tone.Analyser.Type = {
|
Tone.Analyser.Type = {
|
||||||
|
@ -85,7 +85,7 @@ define(["Tone/core/Tone", "Tone/core/AudioNode"], function (Tone) {
|
||||||
* result as a TypedArray.
|
* result as a TypedArray.
|
||||||
* @returns {TypedArray}
|
* @returns {TypedArray}
|
||||||
*/
|
*/
|
||||||
Tone.Analyser.prototype.analyse = function(){
|
Tone.Analyser.prototype.getValue = function(){
|
||||||
if (this._type === Tone.Analyser.Type.FFT){
|
if (this._type === Tone.Analyser.Type.FFT){
|
||||||
this._analyser.getFloatFrequencyData(this._buffer);
|
this._analyser.getFloatFrequencyData(this._buffer);
|
||||||
} else if (this._type === Tone.Analyser.Type.Waveform){
|
} else if (this._type === Tone.Analyser.Type.Waveform){
|
||||||
|
@ -111,7 +111,7 @@ define(["Tone/core/Tone", "Tone/core/AudioNode"], function (Tone) {
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The analysis function returned by Tone.Analyser.analyse(), either "fft" or "waveform".
|
* The analysis function returned by analyser.getValue(), either "fft" or "waveform".
|
||||||
* @memberOf Tone.Analyser#
|
* @memberOf Tone.Analyser#
|
||||||
* @type {String}
|
* @type {String}
|
||||||
* @name type
|
* @name type
|
||||||
|
|
|
@ -245,9 +245,9 @@ define(["Tone/core/Tone", "Tone/signal/TimelineSignal",
|
||||||
}
|
}
|
||||||
//attack
|
//attack
|
||||||
if (this._attackCurve === "linear"){
|
if (this._attackCurve === "linear"){
|
||||||
this._sig.linearRampToValue(velocity, attack, time);
|
this._sig.linearRampTo(velocity, attack, time);
|
||||||
} else if (this._attackCurve === "exponential"){
|
} else if (this._attackCurve === "exponential"){
|
||||||
this._sig.exponentialRampToValue(velocity, attack, time);
|
this._sig.targetRampTo(velocity, attack, time);
|
||||||
} else if (attack > 0){
|
} else if (attack > 0){
|
||||||
this._sig.setRampPoint(time);
|
this._sig.setRampPoint(time);
|
||||||
var curve = this._attackCurve;
|
var curve = this._attackCurve;
|
||||||
|
@ -262,7 +262,7 @@ define(["Tone/core/Tone", "Tone/signal/TimelineSignal",
|
||||||
this._sig.setValueCurveAtTime(curve, time, attack, velocity);
|
this._sig.setValueCurveAtTime(curve, time, attack, velocity);
|
||||||
}
|
}
|
||||||
//decay
|
//decay
|
||||||
this._sig.exponentialRampToValue(velocity * this.sustain, decay, attack + time);
|
this._sig.targetRampTo(velocity * this.sustain, decay, attack + time);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -280,9 +280,9 @@ define(["Tone/core/Tone", "Tone/signal/TimelineSignal",
|
||||||
if (currentValue > 0){
|
if (currentValue > 0){
|
||||||
var release = this.toSeconds(this.release);
|
var release = this.toSeconds(this.release);
|
||||||
if (this._releaseCurve === "linear"){
|
if (this._releaseCurve === "linear"){
|
||||||
this._sig.linearRampToValue(0, release, time);
|
this._sig.linearRampTo(0, release, time);
|
||||||
} else if (this._releaseCurve === "exponential"){
|
} else if (this._releaseCurve === "exponential"){
|
||||||
this._sig.exponentialRampToValue(0, release, time);
|
this._sig.targetRampTo(0, release, time);
|
||||||
} else{
|
} else{
|
||||||
var curve = this._releaseCurve;
|
var curve = this._releaseCurve;
|
||||||
if (Tone.isArray(curve)){
|
if (Tone.isArray(curve)){
|
||||||
|
|
69
Tone/component/FFT.js
Normal file
69
Tone/component/FFT.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], function (Tone) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Get the current waveform data of the connected audio source.
|
||||||
|
* @extends {Tone.AudioNode}
|
||||||
|
* @param {Number=} size The size of the FFT. Value must be a power of
|
||||||
|
* two in the range 32 to 32768.
|
||||||
|
*/
|
||||||
|
Tone.FFT = function(){
|
||||||
|
|
||||||
|
var options = Tone.defaults(arguments, ["size"], Tone.FFT);
|
||||||
|
options.type = Tone.Analyser.Type.FFT;
|
||||||
|
Tone.AudioNode.call(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The analyser node.
|
||||||
|
* @private
|
||||||
|
* @type {Tone.Analyser}
|
||||||
|
*/
|
||||||
|
this._analyser = this.input = this.output = new Tone.Analyser(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tone.extend(Tone.FFT, Tone.AudioNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default values.
|
||||||
|
* @type {Object}
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
Tone.FFT.defaults = {
|
||||||
|
"size" : 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the waveform of the audio source. Returns the waveform data
|
||||||
|
* of length [size](#size) as a Float32Array with values between -1 and 1.
|
||||||
|
* @returns {TypedArray}
|
||||||
|
*/
|
||||||
|
Tone.FFT.prototype.getValue = function(){
|
||||||
|
return this._analyser.getValue();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of analysis. This must be a power of two in the range 32 to 32768.
|
||||||
|
* @memberOf Tone.FFT#
|
||||||
|
* @type {Number}
|
||||||
|
* @name size
|
||||||
|
*/
|
||||||
|
Object.defineProperty(Tone.FFT.prototype, "size", {
|
||||||
|
get : function(){
|
||||||
|
return this._analyser.size;
|
||||||
|
},
|
||||||
|
set : function(size){
|
||||||
|
this._analyser.size = size;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up.
|
||||||
|
* @return {Tone.FFT} this
|
||||||
|
*/
|
||||||
|
Tone.FFT.prototype.dispose = function(){
|
||||||
|
Tone.AudioNode.prototype.dispose.call(this);
|
||||||
|
this._analyser.dispose();
|
||||||
|
this._analyser = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tone.FFT;
|
||||||
|
});
|
|
@ -9,36 +9,26 @@ define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], fun
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends {Tone.AudioNode}
|
* @extends {Tone.AudioNode}
|
||||||
* @param {String} type Either "level" or "signal".
|
|
||||||
* @param {Number} smoothing The amount of smoothing applied between frames.
|
* @param {Number} smoothing The amount of smoothing applied between frames.
|
||||||
* @example
|
* @example
|
||||||
* var meter = new Tone.Meter();
|
* var meter = new Tone.Meter();
|
||||||
* var mic = new Tone.UserMedia().open();
|
* var mic = new Tone.UserMedia().open();
|
||||||
* //connect mic to the meter
|
* //connect mic to the meter
|
||||||
* mic.connect(meter);
|
* mic.connect(meter);
|
||||||
* //the current level of the mic input
|
* //the current level of the mic input in decibels
|
||||||
* var level = meter.value;
|
* var level = meter.getValue();
|
||||||
*/
|
*/
|
||||||
Tone.Meter = function(){
|
Tone.Meter = function(){
|
||||||
|
|
||||||
var options = Tone.defaults(arguments, ["type", "smoothing"], Tone.Meter);
|
var options = Tone.defaults(arguments, ["smoothing"], Tone.Meter);
|
||||||
Tone.AudioNode.call(this);
|
Tone.AudioNode.call(this);
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of the meter, either "level" or "signal".
|
|
||||||
* A "level" meter will return the volume level (rms) of the
|
|
||||||
* input signal and a "signal" meter will return
|
|
||||||
* the signal value of the input.
|
|
||||||
* @type {String}
|
|
||||||
*/
|
|
||||||
this.type = options.type;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The analyser node which computes the levels.
|
* The analyser node which computes the levels.
|
||||||
* @private
|
* @private
|
||||||
* @type {Tone.Analyser}
|
* @type {Tone.Analyser}
|
||||||
*/
|
*/
|
||||||
this.input = this.output = this._analyser = new Tone.Analyser("waveform", 512);
|
this.input = this.output = this._analyser = new Tone.Analyser("waveform", 1024);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of carryover between the current and last frame.
|
* The amount of carryover between the current and last frame.
|
||||||
|
@ -46,26 +36,10 @@ define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], fun
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
*/
|
*/
|
||||||
this.smoothing = options.smoothing;
|
this.smoothing = options.smoothing;
|
||||||
|
|
||||||
/**
|
|
||||||
* The last computed value
|
|
||||||
* @type {Number}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._lastValue = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Tone.extend(Tone.Meter, Tone.AudioNode);
|
Tone.extend(Tone.Meter, Tone.AudioNode);
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
* @enum {String}
|
|
||||||
*/
|
|
||||||
Tone.Meter.Type = {
|
|
||||||
Level : "level",
|
|
||||||
Signal : "signal"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The defaults
|
* The defaults
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
|
@ -73,39 +47,44 @@ define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], fun
|
||||||
* @const
|
* @const
|
||||||
*/
|
*/
|
||||||
Tone.Meter.defaults = {
|
Tone.Meter.defaults = {
|
||||||
"smoothing" : 0.8,
|
"smoothing" : 0.8
|
||||||
"type" : Tone.Meter.Type.Level
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current value of the meter. A value of 1 is
|
* Get the current decibel value of the incoming signal
|
||||||
* "unity".
|
* @returns {Decibels}
|
||||||
|
*/
|
||||||
|
Tone.Meter.prototype.getLevel = function(){
|
||||||
|
this._analyser.type = "fft";
|
||||||
|
var values = this._analyser.getValue();
|
||||||
|
var offset = 28; // normalizes most signal levels
|
||||||
|
// TODO: compute loudness from FFT
|
||||||
|
return Math.max.apply(this, values) + offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the signal value of the incoming signal
|
||||||
|
* @returns {Number}
|
||||||
|
*/
|
||||||
|
Tone.Meter.prototype.getValue = function(){
|
||||||
|
this._analyser.type = "waveform";
|
||||||
|
var value = this._analyser.getValue();
|
||||||
|
return value[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value from 0 -> 1 where 0 represents no time averaging with the last analysis frame.
|
||||||
* @memberOf Tone.Meter#
|
* @memberOf Tone.Meter#
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
* @name value
|
* @name smoothing
|
||||||
* @readOnly
|
* @readOnly
|
||||||
*/
|
*/
|
||||||
Object.defineProperty(Tone.Meter.prototype, "value", {
|
Object.defineProperty(Tone.Meter.prototype, "smoothing", {
|
||||||
get : function(){
|
get : function(){
|
||||||
var signal = this._analyser.analyse();
|
return this._analyser.smoothing;
|
||||||
if (this.type === Tone.Meter.Type.Level){
|
},
|
||||||
//rms
|
set : function(val){
|
||||||
var sum = 0;
|
this._analyser.smoothing = val;
|
||||||
for (var i = 0; i < signal.length; i++){
|
|
||||||
sum += Math.pow(signal[i], 2);
|
|
||||||
}
|
|
||||||
var rms = Math.sqrt(sum / signal.length);
|
|
||||||
//smooth it
|
|
||||||
rms = Math.max(rms, this._lastValue * this.smoothing);
|
|
||||||
this._lastValue = rms;
|
|
||||||
//scale it
|
|
||||||
var unity = 0.35;
|
|
||||||
var val = rms / unity;
|
|
||||||
//scale the output curve
|
|
||||||
return Math.sqrt(val);
|
|
||||||
} else {
|
|
||||||
return signal[0];
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
68
Tone/component/Waveform.js
Normal file
68
Tone/component/Waveform.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], function (Tone) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Get the current waveform data of the connected audio source.
|
||||||
|
* @extends {Tone.AudioNode}
|
||||||
|
* @param {Number=} size The size of the FFT. Value must be a power of
|
||||||
|
* two in the range 32 to 32768.
|
||||||
|
*/
|
||||||
|
Tone.Waveform = function(){
|
||||||
|
|
||||||
|
var options = Tone.defaults(arguments, ["size"], Tone.Waveform);
|
||||||
|
options.type = Tone.Analyser.Type.Waveform;
|
||||||
|
Tone.AudioNode.call(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The analyser node.
|
||||||
|
* @private
|
||||||
|
* @type {Tone.Analyser}
|
||||||
|
*/
|
||||||
|
this._analyser = this.input = this.output = new Tone.Analyser(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
Tone.extend(Tone.Waveform, Tone.AudioNode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default values.
|
||||||
|
* @type {Object}
|
||||||
|
* @const
|
||||||
|
*/
|
||||||
|
Tone.Waveform.defaults = {
|
||||||
|
"size" : 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the waveform of the audio source. Returns the waveform data
|
||||||
|
* of length [size](#size) as a Float32Array with values between -1 and 1.
|
||||||
|
* @returns {TypedArray}
|
||||||
|
*/
|
||||||
|
Tone.Waveform.prototype.getValue = function(){
|
||||||
|
return this._analyser.getValue();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of analysis. This must be a power of two in the range 32 to 32768.
|
||||||
|
* @memberOf Tone.Waveform#
|
||||||
|
* @type {Number}
|
||||||
|
* @name size
|
||||||
|
*/
|
||||||
|
Object.defineProperty(Tone.Waveform.prototype, "size", {
|
||||||
|
get : function(){
|
||||||
|
return this._analyser.size;
|
||||||
|
},
|
||||||
|
set : function(size){
|
||||||
|
this._analyser.size = size;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Clean up.
|
||||||
|
* @return {Tone.Waveform} this
|
||||||
|
*/
|
||||||
|
Tone.Waveform.prototype.dispose = function(){
|
||||||
|
Tone.AudioNode.prototype.dispose.call(this);
|
||||||
|
this._analyser.dispose();
|
||||||
|
this._analyser = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tone.Waveform;
|
||||||
|
});
|
|
@ -1,7 +1,7 @@
|
||||||
define(["Tone/core/Tone", "Tone/core/Context"], function (Tone) {
|
define(["Tone/core/Tone", "Tone/core/Context"], function (Tone) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Tone.AudioNode is a base class for classes which process audio.
|
* @class Tone.AudioNode is the base class for classes which process audio.
|
||||||
* AudioNodes have inputs and outputs.
|
* AudioNodes have inputs and outputs.
|
||||||
* @param {AudioContext=} context The audio context to use with the class
|
* @param {AudioContext=} context The audio context to use with the class
|
||||||
* @extends {Tone}
|
* @extends {Tone}
|
||||||
|
@ -26,7 +26,7 @@ define(["Tone/core/Tone", "Tone/core/Context"], function (Tone) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the audio context belonging to this instance.
|
* Get the audio context belonging to this instance.
|
||||||
* @type {AudioNode}
|
* @type {Tone.Context}
|
||||||
* @memberOf Tone.AudioNode#
|
* @memberOf Tone.AudioNode#
|
||||||
* @name context
|
* @name context
|
||||||
* @readOnly
|
* @readOnly
|
||||||
|
@ -144,6 +144,7 @@ define(["Tone/core/Tone", "Tone/core/Context"], function (Tone) {
|
||||||
* node.chain(effect, panVol, Tone.Master);
|
* node.chain(effect, panVol, Tone.Master);
|
||||||
* @param {...AudioParam|Tone|AudioNode} nodes
|
* @param {...AudioParam|Tone|AudioNode} nodes
|
||||||
* @returns {Tone.AudioNode} this
|
* @returns {Tone.AudioNode} this
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
Tone.AudioNode.prototype.chain = function(){
|
Tone.AudioNode.prototype.chain = function(){
|
||||||
var currentUnit = this;
|
var currentUnit = this;
|
||||||
|
@ -159,6 +160,7 @@ define(["Tone/core/Tone", "Tone/core/Context"], function (Tone) {
|
||||||
* connect the output of this node to the rest of the nodes in parallel.
|
* connect the output of this node to the rest of the nodes in parallel.
|
||||||
* @param {...AudioParam|Tone|AudioNode} nodes
|
* @param {...AudioParam|Tone|AudioNode} nodes
|
||||||
* @returns {Tone.AudioNode} this
|
* @returns {Tone.AudioNode} this
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
Tone.AudioNode.prototype.fan = function(){
|
Tone.AudioNode.prototype.fan = function(){
|
||||||
for (var i = 0; i < arguments.length; i++){
|
for (var i = 0; i < arguments.length; i++){
|
||||||
|
|
|
@ -168,7 +168,9 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
* freq.setValueAtTime("G4", "+1");
|
* freq.setValueAtTime("G4", "+1");
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.setValueAtTime = function(value, time){
|
Tone.Param.prototype.setValueAtTime = function(value, time){
|
||||||
this._param.setValueAtTime(this._fromUnits(value), this.toSeconds(time));
|
time = this.toSeconds(time);
|
||||||
|
Tone.isPast(time);
|
||||||
|
this._param.setValueAtTime(this._fromUnits(value), time);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -182,12 +184,12 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.setRampPoint = function(now){
|
Tone.Param.prototype.setRampPoint = function(now){
|
||||||
now = Tone.defaultArg(now, this.now());
|
now = Tone.defaultArg(now, this.now());
|
||||||
|
this.cancelAndHoldAtTime(this.context.currentTime);
|
||||||
var currentVal = this._param.value;
|
var currentVal = this._param.value;
|
||||||
// exponentialRampToValueAt cannot ever ramp from or to 0
|
|
||||||
// More info: https://bugzilla.mozilla.org/show_bug.cgi?id=1125600#c2
|
|
||||||
if (currentVal === 0){
|
if (currentVal === 0){
|
||||||
currentVal = this._minOutput;
|
currentVal = this._minOutput;
|
||||||
}
|
}
|
||||||
|
// cancel and hold at the given time
|
||||||
this._param.setValueAtTime(currentVal, now);
|
this._param.setValueAtTime(currentVal, now);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -202,7 +204,9 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.linearRampToValueAtTime = function(value, endTime){
|
Tone.Param.prototype.linearRampToValueAtTime = function(value, endTime){
|
||||||
value = this._fromUnits(value);
|
value = this._fromUnits(value);
|
||||||
this._param.linearRampToValueAtTime(value, this.toSeconds(endTime));
|
endTime = this.toSeconds(endTime);
|
||||||
|
Tone.isPast(endTime);
|
||||||
|
this._param.linearRampToValueAtTime(value, endTime);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -217,7 +221,9 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
Tone.Param.prototype.exponentialRampToValueAtTime = function(value, endTime){
|
Tone.Param.prototype.exponentialRampToValueAtTime = function(value, endTime){
|
||||||
value = this._fromUnits(value);
|
value = this._fromUnits(value);
|
||||||
value = Math.max(this._minOutput, value);
|
value = Math.max(this._minOutput, value);
|
||||||
this._param.exponentialRampToValueAtTime(value, this.toSeconds(endTime));
|
endTime = this.toSeconds(endTime);
|
||||||
|
Tone.isPast(endTime);
|
||||||
|
this._param.exponentialRampToValueAtTime(value, endTime);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -233,9 +239,9 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
* @returns {Tone.Param} this
|
* @returns {Tone.Param} this
|
||||||
* @example
|
* @example
|
||||||
* //exponentially ramp to the value 2 over 4 seconds.
|
* //exponentially ramp to the value 2 over 4 seconds.
|
||||||
* signal.exponentialRampToValue(2, 4);
|
* signal.exponentialRampTo(2, 4);
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.exponentialRampToValue = function(value, rampTime, startTime){
|
Tone.Param.prototype.exponentialRampTo = function(value, rampTime, startTime){
|
||||||
startTime = this.toSeconds(startTime);
|
startTime = this.toSeconds(startTime);
|
||||||
this.setRampPoint(startTime);
|
this.setRampPoint(startTime);
|
||||||
this.exponentialRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
|
this.exponentialRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
|
||||||
|
@ -254,15 +260,46 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
* @returns {Tone.Param} this
|
* @returns {Tone.Param} this
|
||||||
* @example
|
* @example
|
||||||
* //linearly ramp to the value 4 over 3 seconds.
|
* //linearly ramp to the value 4 over 3 seconds.
|
||||||
* signal.linearRampToValue(4, 3);
|
* signal.linearRampTo(4, 3);
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.linearRampToValue = function(value, rampTime, startTime){
|
Tone.Param.prototype.linearRampTo = function(value, rampTime, startTime){
|
||||||
startTime = this.toSeconds(startTime);
|
startTime = this.toSeconds(startTime);
|
||||||
this.setRampPoint(startTime);
|
this.setRampPoint(startTime);
|
||||||
this.linearRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
|
this.linearRampToValueAtTime(value, startTime + this.toSeconds(rampTime));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert between Time and time constant. The time
|
||||||
|
* constant returned can be used in setTargetAtTime.
|
||||||
|
* @param {Time} time The time to convert
|
||||||
|
* @return {Number} The time constant to get an exponentially approaching
|
||||||
|
* curve to over 99% of towards the target value.
|
||||||
|
*/
|
||||||
|
Tone.Param.prototype.getTimeConstant = function(time){
|
||||||
|
return Math.log(this.toSeconds(time)+1)/Math.log(200);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start exponentially approaching the target value at the given time. Since it
|
||||||
|
* is an exponential approach it will continue approaching after the ramp duration. The
|
||||||
|
* rampTime is the time that it takes to reach over 99% of the way towards the value.
|
||||||
|
* @param {number} value The value to ramp to.
|
||||||
|
* @param {Time} rampTime the time that it takes the
|
||||||
|
* value to ramp from it's current value
|
||||||
|
* @param {Time} [startTime=now] When the ramp should start.
|
||||||
|
* @returns {Tone.Param} this
|
||||||
|
* @example
|
||||||
|
* //exponentially ramp to the value 2 over 4 seconds.
|
||||||
|
* signal.exponentialRampTo(2, 4);
|
||||||
|
*/
|
||||||
|
Tone.Param.prototype.targetRampTo = function(value, rampTime, startTime){
|
||||||
|
startTime = this.toSeconds(startTime);
|
||||||
|
this.setRampPoint(startTime);
|
||||||
|
this.setTargetAtTime(value, startTime, this.getTimeConstant(rampTime));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start exponentially approaching the target value at the given time with
|
* Start exponentially approaching the target value at the given time with
|
||||||
* a rate having the given time constant.
|
* a rate having the given time constant.
|
||||||
|
@ -314,6 +351,31 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is similar to [cancelScheduledValues](#cancelScheduledValues) except
|
||||||
|
* it holds the automated value at cancelTime until the next automated event.
|
||||||
|
* @param {Time} cancelTime
|
||||||
|
* @returns {Tone.Param} this
|
||||||
|
*/
|
||||||
|
Tone.Param.prototype.cancelAndHoldAtTime = function(cancelTime){
|
||||||
|
cancelTime = this.toSeconds(cancelTime);
|
||||||
|
if (this._param.cancelAndHoldAtTime){
|
||||||
|
this._param.cancelAndHoldAtTime(cancelTime);
|
||||||
|
} else {
|
||||||
|
//fallback for unsupported browsers
|
||||||
|
//can't cancel and hold at any time in the future
|
||||||
|
//just do it immediately for gapless automation curves
|
||||||
|
var now = this.context.currentTime;
|
||||||
|
this._param.cancelScheduledValues(now);
|
||||||
|
var currentVal = this._param.value;
|
||||||
|
if (currentVal === 0){
|
||||||
|
currentVal = this._minOutput;
|
||||||
|
}
|
||||||
|
this._param.setValueAtTime(currentVal, now + this.sampleTime);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ramps to the given value over the duration of the rampTime.
|
* Ramps to the given value over the duration of the rampTime.
|
||||||
* Automatically selects the best ramp type (exponential or linear)
|
* Automatically selects the best ramp type (exponential or linear)
|
||||||
|
@ -333,11 +395,11 @@ define(["Tone/core/Tone", "Tone/type/Type"], function(Tone){
|
||||||
* signal.rampTo(0, 10, 5)
|
* signal.rampTo(0, 10, 5)
|
||||||
*/
|
*/
|
||||||
Tone.Param.prototype.rampTo = function(value, rampTime, startTime){
|
Tone.Param.prototype.rampTo = function(value, rampTime, startTime){
|
||||||
rampTime = Tone.defaultArg(rampTime, 0);
|
rampTime = Tone.defaultArg(rampTime, 0.1);
|
||||||
if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM || this.units === Tone.Type.Decibels){
|
if (this.units === Tone.Type.Frequency || this.units === Tone.Type.BPM || this.units === Tone.Type.Decibels){
|
||||||
this.exponentialRampToValue(value, rampTime, startTime);
|
this.exponentialRampTo(value, rampTime, startTime);
|
||||||
} else {
|
} else {
|
||||||
this.linearRampToValue(value, rampTime, startTime);
|
this.linearRampTo(value, rampTime, startTime);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,8 +4,8 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class A Timeline class for scheduling and maintaining state
|
* @class A Timeline class for scheduling and maintaining state
|
||||||
* along a timeline. All events must have a "time" property.
|
* along a timeline. All events must have a "time" property.
|
||||||
* Internally, events are stored in time order for fast
|
* Internally, events are stored in time order for fast
|
||||||
* retrieval.
|
* retrieval.
|
||||||
* @extends {Tone}
|
* @extends {Tone}
|
||||||
* @param {Positive} [memory=Infinity] The number of previous events that are retained.
|
* @param {Positive} [memory=Infinity] The number of previous events that are retained.
|
||||||
|
@ -23,12 +23,19 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
this._timeline = [];
|
this._timeline = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of items to remove from the list.
|
* An array of items to remove from the list.
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this._toRemove = [];
|
this._toRemove = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of items to add from the list (once it's done iterating)
|
||||||
|
* @type {Array}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._toAdd = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flag if the timeline is mid iteration
|
* Flag if the timeline is mid iteration
|
||||||
* @private
|
* @private
|
||||||
|
@ -70,8 +77,8 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert an event object onto the timeline. Events must have a "time" attribute.
|
* Insert an event object onto the timeline. Events must have a "time" attribute.
|
||||||
* @param {Object} event The event object to insert into the
|
* @param {Object} event The event object to insert into the
|
||||||
* timeline.
|
* timeline.
|
||||||
* @returns {Tone.Timeline} this
|
* @returns {Tone.Timeline} this
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype.add = function(event){
|
Tone.Timeline.prototype.add = function(event){
|
||||||
|
@ -79,16 +86,16 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
if (Tone.isUndef(event.time)){
|
if (Tone.isUndef(event.time)){
|
||||||
throw new Error("Tone.Timeline: events must have a time attribute");
|
throw new Error("Tone.Timeline: events must have a time attribute");
|
||||||
}
|
}
|
||||||
if (this._timeline.length){
|
if (this._iterating){
|
||||||
|
this._toAdd.push(event);
|
||||||
|
} else {
|
||||||
var index = this._search(event.time);
|
var index = this._search(event.time);
|
||||||
this._timeline.splice(index + 1, 0, event);
|
this._timeline.splice(index + 1, 0, event);
|
||||||
} else {
|
//if the length is more than the memory, remove the previous ones
|
||||||
this._timeline.push(event);
|
if (this.length > this.memory){
|
||||||
}
|
var diff = this.length - this.memory;
|
||||||
//if the length is more than the memory, remove the previous ones
|
this._timeline.splice(0, diff);
|
||||||
if (this.length > this.memory){
|
}
|
||||||
var diff = this.length - this.memory;
|
|
||||||
this._timeline.splice(0, diff);
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -113,12 +120,12 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
/**
|
/**
|
||||||
* Get the nearest event whose time is less than or equal to the given time.
|
* Get the nearest event whose time is less than or equal to the given time.
|
||||||
* @param {Number} time The time to query.
|
* @param {Number} time The time to query.
|
||||||
* @param {String} comparitor Which value in the object to compare
|
* @param {String} comparator Which value in the object to compare
|
||||||
* @returns {Object} The event object set after that time.
|
* @returns {Object} The event object set after that time.
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype.get = function(time, comparitor){
|
Tone.Timeline.prototype.get = function(time, comparator){
|
||||||
comparitor = Tone.defaultArg(comparitor, "time");
|
comparator = Tone.defaultArg(comparator, "time");
|
||||||
var index = this._search(time, comparitor);
|
var index = this._search(time, comparator);
|
||||||
if (index !== -1){
|
if (index !== -1){
|
||||||
return this._timeline[index];
|
return this._timeline[index];
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,12 +152,12 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
/**
|
/**
|
||||||
* Get the event which is scheduled after the given time.
|
* Get the event which is scheduled after the given time.
|
||||||
* @param {Number} time The time to query.
|
* @param {Number} time The time to query.
|
||||||
* @param {String} comparitor Which value in the object to compare
|
* @param {String} comparator Which value in the object to compare
|
||||||
* @returns {Object} The event object after the given time
|
* @returns {Object} The event object after the given time
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype.getAfter = function(time, comparitor){
|
Tone.Timeline.prototype.getAfter = function(time, comparator){
|
||||||
comparitor = Tone.defaultArg(comparitor, "time");
|
comparator = Tone.defaultArg(comparator, "time");
|
||||||
var index = this._search(time, comparitor);
|
var index = this._search(time, comparator);
|
||||||
if (index + 1 < this._timeline.length){
|
if (index + 1 < this._timeline.length){
|
||||||
return this._timeline[index + 1];
|
return this._timeline[index + 1];
|
||||||
} else {
|
} else {
|
||||||
|
@ -161,17 +168,17 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
/**
|
/**
|
||||||
* Get the event before the event at the given time.
|
* Get the event before the event at the given time.
|
||||||
* @param {Number} time The time to query.
|
* @param {Number} time The time to query.
|
||||||
* @param {String} comparitor Which value in the object to compare
|
* @param {String} comparator Which value in the object to compare
|
||||||
* @returns {Object} The event object before the given time
|
* @returns {Object} The event object before the given time
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype.getBefore = function(time, comparitor){
|
Tone.Timeline.prototype.getBefore = function(time, comparator){
|
||||||
comparitor = Tone.defaultArg(comparitor, "time");
|
comparator = Tone.defaultArg(comparator, "time");
|
||||||
var len = this._timeline.length;
|
var len = this._timeline.length;
|
||||||
//if it's after the last item, return the last item
|
//if it's after the last item, return the last item
|
||||||
if (len > 0 && this._timeline[len - 1][comparitor] < time){
|
if (len > 0 && this._timeline[len - 1][comparator] < time){
|
||||||
return this._timeline[len - 1];
|
return this._timeline[len - 1];
|
||||||
}
|
}
|
||||||
var index = this._search(time, comparitor);
|
var index = this._search(time, comparator);
|
||||||
if (index - 1 >= 0){
|
if (index - 1 >= 0){
|
||||||
return this._timeline[index - 1];
|
return this._timeline[index - 1];
|
||||||
} else {
|
} else {
|
||||||
|
@ -219,11 +226,9 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
* @returns {Tone.Timeline} this
|
* @returns {Tone.Timeline} this
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype.cancelBefore = function(time){
|
Tone.Timeline.prototype.cancelBefore = function(time){
|
||||||
if (this._timeline.length){
|
var index = this._search(time);
|
||||||
var index = this._search(time);
|
if (index >= 0){
|
||||||
if (index >= 0){
|
this._timeline = this._timeline.slice(index + 1);
|
||||||
this._timeline = this._timeline.slice(index + 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -243,21 +248,24 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does a binary serach on the timeline array and returns the
|
* Does a binary search on the timeline array and returns the
|
||||||
* nearest event index whose time is after or equal to the given time.
|
* nearest event index whose time is after or equal to the given time.
|
||||||
* If a time is searched before the first index in the timeline, -1 is returned.
|
* If a time is searched before the first index in the timeline, -1 is returned.
|
||||||
* If the time is after the end, the index of the last item is returned.
|
* If the time is after the end, the index of the last item is returned.
|
||||||
* @param {Number} time
|
* @param {Number} time
|
||||||
* @param {String} comparitor Which value in the object to compare
|
* @param {String} comparator Which value in the object to compare
|
||||||
* @return {Number} the index in the timeline array
|
* @return {Number} the index in the timeline array
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype._search = function(time, comparitor){
|
Tone.Timeline.prototype._search = function(time, comparator){
|
||||||
comparitor = Tone.defaultArg(comparitor, "time");
|
if (this._timeline.length === 0){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
comparator = Tone.defaultArg(comparator, "time");
|
||||||
var beginning = 0;
|
var beginning = 0;
|
||||||
var len = this._timeline.length;
|
var len = this._timeline.length;
|
||||||
var end = len;
|
var end = len;
|
||||||
if (len > 0 && this._timeline[len - 1][comparitor] <= time){
|
if (len > 0 && this._timeline[len - 1][comparator] <= time){
|
||||||
return len - 1;
|
return len - 1;
|
||||||
}
|
}
|
||||||
while (beginning < end){
|
while (beginning < end){
|
||||||
|
@ -265,34 +273,34 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
var midPoint = Math.floor(beginning + (end - beginning) / 2);
|
var midPoint = Math.floor(beginning + (end - beginning) / 2);
|
||||||
var event = this._timeline[midPoint];
|
var event = this._timeline[midPoint];
|
||||||
var nextEvent = this._timeline[midPoint + 1];
|
var nextEvent = this._timeline[midPoint + 1];
|
||||||
if (event[comparitor] === time){
|
if (event[comparator] === time){
|
||||||
//choose the last one that has the same time
|
//choose the last one that has the same time
|
||||||
for (var i = midPoint; i < this._timeline.length; i++){
|
for (var i = midPoint; i < this._timeline.length; i++){
|
||||||
var testEvent = this._timeline[i];
|
var testEvent = this._timeline[i];
|
||||||
if (testEvent[comparitor] === time){
|
if (testEvent[comparator] === time){
|
||||||
midPoint = i;
|
midPoint = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return midPoint;
|
return midPoint;
|
||||||
} else if (event[comparitor] < time && nextEvent[comparitor] > time){
|
} else if (event[comparator] < time && nextEvent[comparator] > time){
|
||||||
return midPoint;
|
return midPoint;
|
||||||
} else if (event[comparitor] > time){
|
} else if (event[comparator] > time){
|
||||||
//search lower
|
//search lower
|
||||||
end = midPoint;
|
end = midPoint;
|
||||||
} else {
|
} else {
|
||||||
//search upper
|
//search upper
|
||||||
beginning = midPoint + 1;
|
beginning = midPoint + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal iterator. Applies extra safety checks for
|
* Internal iterator. Applies extra safety checks for
|
||||||
* removing items from the array.
|
* removing items from the array.
|
||||||
* @param {Function} callback
|
* @param {Function} callback
|
||||||
* @param {Number=} lowerBound
|
* @param {Number=} lowerBound
|
||||||
* @param {Number=} upperBound
|
* @param {Number=} upperBound
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Tone.Timeline.prototype._iterate = function(callback, lowerBound, upperBound){
|
Tone.Timeline.prototype._iterate = function(callback, lowerBound, upperBound){
|
||||||
|
@ -303,15 +311,14 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
callback.call(this, this._timeline[i]);
|
callback.call(this, this._timeline[i]);
|
||||||
}
|
}
|
||||||
this._iterating = false;
|
this._iterating = false;
|
||||||
if (this._toRemove.length > 0){
|
this._toRemove.forEach(function(event){
|
||||||
for (var j = 0; j < this._toRemove.length; j++){
|
this.remove(event);
|
||||||
var index = this._timeline.indexOf(this._toRemove[j]);
|
}.bind(this));
|
||||||
if (index !== -1){
|
this._toRemove = [];
|
||||||
this._timeline.splice(index, 1);
|
this._toAdd.forEach(function(event){
|
||||||
}
|
this.add(event);
|
||||||
}
|
}.bind(this));
|
||||||
this._toRemove = [];
|
this._toAdd = [];
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -353,7 +360,7 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over everything in the array at or after the given time. Similar to
|
* Iterate over everything in the array at or after the given time. Similar to
|
||||||
* forEachAfter, but includes the item(s) at the given time.
|
* forEachAfter, but includes the item(s) at the given time.
|
||||||
* @param {Number} time The time to check if items are before
|
* @param {Number} time The time to check if items are before
|
||||||
* @param {Function} callback The callback to invoke with every item
|
* @param {Function} callback The callback to invoke with every item
|
||||||
|
@ -383,7 +390,7 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
this._iterate(function(event){
|
this._iterate(function(event){
|
||||||
if (event.time === time){
|
if (event.time === time){
|
||||||
callback.call(this, event);
|
callback.call(this, event);
|
||||||
}
|
}
|
||||||
}, 0, upperBound);
|
}, 0, upperBound);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -397,8 +404,9 @@ define(["Tone/core/Tone"], function (Tone) {
|
||||||
Tone.prototype.dispose.call(this);
|
Tone.prototype.dispose.call(this);
|
||||||
this._timeline = null;
|
this._timeline = null;
|
||||||
this._toRemove = null;
|
this._toRemove = null;
|
||||||
|
this._toAdd = null;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
return Tone.Timeline;
|
return Tone.Timeline;
|
||||||
});
|
});
|
||||||
|
|
|
@ -508,6 +508,16 @@ define(function(){
|
||||||
return Tone.context.now();
|
return Tone.context.now();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds warning in the console if the scheduled time has passed.
|
||||||
|
* @type {Time}
|
||||||
|
*/
|
||||||
|
Tone.isPast = function(time){
|
||||||
|
if (time < Tone.context.currentTime){
|
||||||
|
console.warn("Time '" + time + "' is in the past. Scheduled time must be ≥ AudioContext.currentTime");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// INHERITANCE
|
// INHERITANCE
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -680,7 +690,7 @@ define(function(){
|
||||||
* @type {String}
|
* @type {String}
|
||||||
* @static
|
* @static
|
||||||
*/
|
*/
|
||||||
Tone.version = "r11";
|
Tone.version = "r11-dev";
|
||||||
|
|
||||||
// allow optional silencing of this log
|
// allow optional silencing of this log
|
||||||
if (!window.TONE_SILENCE_VERSION_LOGGING) {
|
if (!window.TONE_SILENCE_VERSION_LOGGING) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
define(["Tone/core/Tone", "Tone/core/Clock", "Tone/type/Type", "Tone/core/Timeline",
|
define(["Tone/core/Tone", "Tone/core/Clock", "Tone/type/Type", "Tone/core/Timeline",
|
||||||
"Tone/core/Emitter", "Tone/core/Gain", "Tone/core/IntervalTimeline"],
|
"Tone/core/Emitter", "Tone/core/Gain", "Tone/core/IntervalTimeline",
|
||||||
|
"Tone/core/TransportRepeatEvent", "Tone/core/TransportEvent"],
|
||||||
function(Tone){
|
function(Tone){
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -10,10 +11,10 @@ function(Tone){
|
||||||
* Tone.Transport timing events pass in the exact time of the scheduled event
|
* Tone.Transport timing events pass in the exact time of the scheduled event
|
||||||
* in the argument of the callback function. Pass that time value to the object
|
* in the argument of the callback function. Pass that time value to the object
|
||||||
* you're scheduling. <br><br>
|
* you're scheduling. <br><br>
|
||||||
* A single transport is created for you when the library is initialized.
|
* A single transport is created for you when the library is initialized.
|
||||||
* <br><br>
|
* <br><br>
|
||||||
* The transport emits the events: "start", "stop", "pause", and "loop" which are
|
* The transport emits the events: "start", "stop", "pause", and "loop" which are
|
||||||
* called with the time of that event as the argument.
|
* called with the time of that event as the argument.
|
||||||
*
|
*
|
||||||
* @extends {Tone.Emitter}
|
* @extends {Tone.Emitter}
|
||||||
* @singleton
|
* @singleton
|
||||||
|
@ -38,20 +39,20 @@ function(Tone){
|
||||||
// LOOPING
|
// LOOPING
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the transport loops or not.
|
* If the transport loops or not.
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.loop = false;
|
this.loop = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loop start position in ticks
|
* The loop start position in ticks
|
||||||
* @type {Ticks}
|
* @type {Ticks}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this._loopStart = 0;
|
this._loopStart = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loop end position in ticks
|
* The loop end position in ticks
|
||||||
* @type {Ticks}
|
* @type {Ticks}
|
||||||
* @private
|
* @private
|
||||||
|
@ -76,14 +77,14 @@ function(Tone){
|
||||||
* @type {Tone.Clock}
|
* @type {Tone.Clock}
|
||||||
*/
|
*/
|
||||||
this._clock = new Tone.Clock({
|
this._clock = new Tone.Clock({
|
||||||
"callback" : this._processTick.bind(this),
|
"callback" : this._processTick.bind(this),
|
||||||
"frequency" : 0,
|
"frequency" : 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._bindClockEvents();
|
this._bindClockEvents();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Beats Per Minute of the Transport.
|
* The Beats Per Minute of the Transport.
|
||||||
* @type {BPM}
|
* @type {BPM}
|
||||||
* @signal
|
* @signal
|
||||||
* @example
|
* @example
|
||||||
|
@ -100,7 +101,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time signature, or more accurately the numerator
|
* The time signature, or more accurately the numerator
|
||||||
* of the time signature over a denominator of 4.
|
* of the time signature over a denominator of 4.
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -117,13 +118,6 @@ function(Tone){
|
||||||
*/
|
*/
|
||||||
this._scheduledEvents = {};
|
this._scheduledEvents = {};
|
||||||
|
|
||||||
/**
|
|
||||||
* The event ID counter
|
|
||||||
* @type {Number}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._eventID = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scheduled events.
|
* The scheduled events.
|
||||||
* @type {Tone.Timeline}
|
* @type {Tone.Timeline}
|
||||||
|
@ -139,15 +133,8 @@ function(Tone){
|
||||||
this._repeatedEvents = new Tone.IntervalTimeline();
|
this._repeatedEvents = new Tone.IntervalTimeline();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Events that occur once
|
|
||||||
* @type {Array}
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
this._onceEvents = new Tone.Timeline();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All of the synced Signals
|
* All of the synced Signals
|
||||||
* @private
|
* @private
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
this._syncedSignals = [];
|
this._syncedSignals = [];
|
||||||
|
@ -171,7 +158,6 @@ function(Tone){
|
||||||
this._swingAmount = 0;
|
this._swingAmount = 0;
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Tone.extend(Tone.Transport, Tone.Emitter);
|
Tone.extend(Tone.Transport, Tone.Emitter);
|
||||||
|
@ -204,14 +190,14 @@ function(Tone){
|
||||||
Tone.Transport.prototype._processTick = function(tickTime){
|
Tone.Transport.prototype._processTick = function(tickTime){
|
||||||
var ticks = this._clock.ticks;
|
var ticks = this._clock.ticks;
|
||||||
//handle swing
|
//handle swing
|
||||||
if (this._swingAmount > 0 &&
|
if (this._swingAmount > 0 &&
|
||||||
ticks % this._ppq !== 0 && //not on a downbeat
|
ticks % this._ppq !== 0 && //not on a downbeat
|
||||||
ticks % (this._swingTicks * 2) !== 0){
|
ticks % (this._swingTicks * 2) !== 0){
|
||||||
//add some swing
|
//add some swing
|
||||||
var progress = (ticks % (this._swingTicks * 2)) / (this._swingTicks * 2);
|
var progress = (ticks % (this._swingTicks * 2)) / (this._swingTicks * 2);
|
||||||
var amount = Math.sin((progress) * Math.PI) * this._swingAmount;
|
var amount = Math.sin((progress) * Math.PI) * this._swingAmount;
|
||||||
tickTime += Tone.Time(this._swingTicks * 2/3, "i") * amount;
|
tickTime += Tone.Time(this._swingTicks * 2/3, "i") * amount;
|
||||||
}
|
}
|
||||||
//do the loop test
|
//do the loop test
|
||||||
if (this.loop){
|
if (this.loop){
|
||||||
if (ticks >= this._loopEnd){
|
if (ticks >= this._loopEnd){
|
||||||
|
@ -222,23 +208,9 @@ function(Tone){
|
||||||
this.emit("loop", tickTime);
|
this.emit("loop", tickTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//process the single occurrence events
|
//invoke the timeline events scheduled on this tick
|
||||||
this._onceEvents.forEachBefore(ticks, function(event){
|
|
||||||
event.callback(tickTime);
|
|
||||||
//remove the event
|
|
||||||
delete this._scheduledEvents[event.id.toString()];
|
|
||||||
}.bind(this));
|
|
||||||
//and clear the single occurrence timeline
|
|
||||||
this._onceEvents.cancelBefore(ticks);
|
|
||||||
//fire the next tick events if their time has come
|
|
||||||
this._timeline.forEachAtTime(ticks, function(event){
|
this._timeline.forEachAtTime(ticks, function(event){
|
||||||
event.callback(tickTime);
|
event.invoke(tickTime);
|
||||||
});
|
|
||||||
//process the repeated events
|
|
||||||
this._repeatedEvents.forEachAtTime(ticks, function(event){
|
|
||||||
if ((ticks - event.time) % event.interval === 0){
|
|
||||||
event.callback(tickTime);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,7 +222,7 @@ function(Tone){
|
||||||
* Schedule an event along the timeline.
|
* Schedule an event along the timeline.
|
||||||
* @param {Function} callback The callback to be invoked at the time.
|
* @param {Function} callback The callback to be invoked at the time.
|
||||||
* @param {TransportTime} time The time to invoke the callback at.
|
* @param {TransportTime} time The time to invoke the callback at.
|
||||||
* @return {Number} The id of the event which can be used for canceling the event.
|
* @return {Number} The id of the event which can be used for canceling the event.
|
||||||
* @example
|
* @example
|
||||||
* //trigger the callback when the Transport reaches the desired time
|
* //trigger the callback when the Transport reaches the desired time
|
||||||
* Tone.Transport.schedule(function(time){
|
* Tone.Transport.schedule(function(time){
|
||||||
|
@ -258,75 +230,55 @@ function(Tone){
|
||||||
* }, "128i");
|
* }, "128i");
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.schedule = function(callback, time){
|
Tone.Transport.prototype.schedule = function(callback, time){
|
||||||
var event = {
|
var event = new Tone.TransportEvent(this, {
|
||||||
"time" : this.toTicks(time),
|
"time" : this.toTicks(time),
|
||||||
"callback" : callback
|
"callback" : callback
|
||||||
};
|
});
|
||||||
var id = this._eventID++;
|
return this._addEvent(event, this._timeline);
|
||||||
this._scheduledEvents[id.toString()] = {
|
|
||||||
"event" : event,
|
|
||||||
"timeline" : this._timeline
|
|
||||||
};
|
|
||||||
this._timeline.add(event);
|
|
||||||
return id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a repeated event along the timeline. The event will fire
|
* Schedule a repeated event along the timeline. The event will fire
|
||||||
* at the `interval` starting at the `startTime` and for the specified
|
* at the `interval` starting at the `startTime` and for the specified
|
||||||
* `duration`.
|
* `duration`.
|
||||||
* @param {Function} callback The callback to invoke.
|
* @param {Function} callback The callback to invoke.
|
||||||
* @param {Time} interval The duration between successive
|
* @param {Time} interval The duration between successive
|
||||||
* callbacks.
|
* callbacks. Must be a positive number.
|
||||||
* @param {TimelinePosition=} startTime When along the timeline the events should
|
* @param {TimelinePosition=} startTime When along the timeline the events should
|
||||||
* start being invoked.
|
* start being invoked.
|
||||||
* @param {Time} [duration=Infinity] How long the event should repeat.
|
* @param {Time} [duration=Infinity] How long the event should repeat.
|
||||||
* @return {Number} The ID of the scheduled event. Use this to cancel
|
* @return {Number} The ID of the scheduled event. Use this to cancel
|
||||||
* the event.
|
* the event.
|
||||||
* @example
|
* @example
|
||||||
* //a callback invoked every eighth note after the first measure
|
* //a callback invoked every eighth note after the first measure
|
||||||
* Tone.Transport.scheduleRepeat(callback, "8n", "1m");
|
* Tone.Transport.scheduleRepeat(callback, "8n", "1m");
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.scheduleRepeat = function(callback, interval, startTime, duration){
|
Tone.Transport.prototype.scheduleRepeat = function(callback, interval, startTime, duration){
|
||||||
if (interval <= 0){
|
var event = new Tone.TransportRepeatEvent(this, {
|
||||||
throw new Error("Tone.Transport: repeat events must have an interval larger than 0");
|
"callback" : callback,
|
||||||
}
|
"interval" : this.toTicks(interval),
|
||||||
var event = {
|
|
||||||
"time" : this.toTicks(startTime),
|
"time" : this.toTicks(startTime),
|
||||||
"duration" : this.toTicks(Tone.defaultArg(duration, Infinity)),
|
"duration" : this.toTicks(Tone.defaultArg(duration, Infinity)),
|
||||||
"interval" : this.toTicks(interval),
|
});
|
||||||
"callback" : callback
|
//kick it off if the Transport is started
|
||||||
};
|
return this._addEvent(event, this._repeatedEvents);
|
||||||
var id = this._eventID++;
|
|
||||||
this._scheduledEvents[id.toString()] = {
|
|
||||||
"event" : event,
|
|
||||||
"timeline" : this._repeatedEvents
|
|
||||||
};
|
|
||||||
this._repeatedEvents.add(event);
|
|
||||||
return id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule an event that will be removed after it is invoked.
|
* Schedule an event that will be removed after it is invoked.
|
||||||
* Note that if the given time is less than the current transport time,
|
* Note that if the given time is less than the current transport time,
|
||||||
* the event will be invoked immediately.
|
* the event will be invoked immediately.
|
||||||
* @param {Function} callback The callback to invoke once.
|
* @param {Function} callback The callback to invoke once.
|
||||||
* @param {TransportTime} time The time the callback should be invoked.
|
* @param {TransportTime} time The time the callback should be invoked.
|
||||||
* @returns {Number} The ID of the scheduled event.
|
* @returns {Number} The ID of the scheduled event.
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.scheduleOnce = function(callback, time){
|
Tone.Transport.prototype.scheduleOnce = function(callback, time){
|
||||||
var id = this._eventID++;
|
var event = new Tone.TransportEvent(this, {
|
||||||
var event = {
|
|
||||||
"time" : this.toTicks(time),
|
"time" : this.toTicks(time),
|
||||||
"callback" : callback,
|
"callback" : callback,
|
||||||
"id" : id
|
"once" : true
|
||||||
};
|
});
|
||||||
this._scheduledEvents[id.toString()] = {
|
return this._addEvent(event, this._timeline);
|
||||||
"event" : event,
|
|
||||||
"timeline" : this._onceEvents
|
|
||||||
};
|
|
||||||
this._onceEvents.add(event);
|
|
||||||
return id;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -338,24 +290,41 @@ function(Tone){
|
||||||
if (this._scheduledEvents.hasOwnProperty(eventId)){
|
if (this._scheduledEvents.hasOwnProperty(eventId)){
|
||||||
var item = this._scheduledEvents[eventId.toString()];
|
var item = this._scheduledEvents[eventId.toString()];
|
||||||
item.timeline.remove(item.event);
|
item.timeline.remove(item.event);
|
||||||
|
item.event.dispose();
|
||||||
delete this._scheduledEvents[eventId.toString()];
|
delete this._scheduledEvents[eventId.toString()];
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an event to the correct timeline. Keep track of the
|
||||||
|
* timeline it was added to.
|
||||||
|
* @param {Tone.TransportEvent} event
|
||||||
|
* @param {Tone.Timeline} timeline
|
||||||
|
* @returns {Number} the event id which was just added
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Tone.Transport.prototype._addEvent = function(event, timeline){
|
||||||
|
this._scheduledEvents[event.id.toString()] = {
|
||||||
|
"event" : event,
|
||||||
|
"timeline" : timeline
|
||||||
|
};
|
||||||
|
timeline.add(event);
|
||||||
|
return event.id;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove scheduled events from the timeline after
|
* Remove scheduled events from the timeline after
|
||||||
* the given time. Repeated events will be removed
|
* the given time. Repeated events will be removed
|
||||||
* if their startTime is after the given time
|
* if their startTime is after the given time
|
||||||
* @param {TransportTime} [after=0] Clear all events after
|
* @param {TransportTime} [after=0] Clear all events after
|
||||||
* this time.
|
* this time.
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.cancel = function(after){
|
Tone.Transport.prototype.cancel = function(after){
|
||||||
after = Tone.defaultArg(after, 0);
|
after = Tone.defaultArg(after, 0);
|
||||||
after = this.toTicks(after);
|
after = this.toTicks(after);
|
||||||
this._timeline.cancel(after);
|
this._timeline.cancel(after);
|
||||||
this._onceEvents.cancel(after);
|
|
||||||
this._repeatedEvents.cancel(after);
|
this._repeatedEvents.cancel(after);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
@ -402,7 +371,7 @@ function(Tone){
|
||||||
* @param {TransportTime=} offset The timeline offset to start the transport.
|
* @param {TransportTime=} offset The timeline offset to start the transport.
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
* @example
|
* @example
|
||||||
* //start the transport in one second starting at beginning of the 5th measure.
|
* //start the transport in one second starting at beginning of the 5th measure.
|
||||||
* Tone.Transport.start("+1", "4:0:0");
|
* Tone.Transport.start("+1", "4:0:0");
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.start = function(time, offset){
|
Tone.Transport.prototype.start = function(time, offset){
|
||||||
|
@ -416,7 +385,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the transport and all sources synced to the transport.
|
* Stop the transport and all sources synced to the transport.
|
||||||
* @param {Time} [time=now] The time when the transport should stop.
|
* @param {Time} [time=now] The time when the transport should stop.
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
* @example
|
* @example
|
||||||
* Tone.Transport.stop();
|
* Tone.Transport.stop();
|
||||||
|
@ -457,7 +426,7 @@ function(Tone){
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time signature as just the numerator over 4.
|
* The time signature as just the numerator over 4.
|
||||||
* For example 4/4 would be just 4 and 6/8 would be 3.
|
* For example 4/4 would be just 4 and 6/8 would be 3.
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {Number|Array}
|
* @type {Number|Array}
|
||||||
|
@ -514,9 +483,9 @@ function(Tone){
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the loop start and stop at the same time.
|
* Set the loop start and stop at the same time.
|
||||||
* @param {TransportTime} startPosition
|
* @param {TransportTime} startPosition
|
||||||
* @param {TransportTime} endPosition
|
* @param {TransportTime} endPosition
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
* @example
|
* @example
|
||||||
* //loop over the first measure
|
* //loop over the first measure
|
||||||
|
@ -530,7 +499,7 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The swing value. Between 0-1 where 1 equal to
|
* The swing value. Between 0-1 where 1 equal to
|
||||||
* the note + half the subdivision.
|
* the note + half the subdivision.
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {NormalRange}
|
* @type {NormalRange}
|
||||||
|
@ -547,10 +516,10 @@ function(Tone){
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the subdivision which the swing will be applied to.
|
* Set the subdivision which the swing will be applied to.
|
||||||
* The default value is an 8th note. Value must be less
|
* The default value is an 8th note. Value must be less
|
||||||
* than a quarter note.
|
* than a quarter note.
|
||||||
*
|
*
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {Time}
|
* @type {Time}
|
||||||
* @name swingSubdivision
|
* @name swingSubdivision
|
||||||
|
@ -566,7 +535,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Transport's position in Bars:Beats:Sixteenths.
|
* The Transport's position in Bars:Beats:Sixteenths.
|
||||||
* Setting the value will jump to that position right away.
|
* Setting the value will jump to that position right away.
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {BarsBeatsSixteenths}
|
* @type {BarsBeatsSixteenths}
|
||||||
* @name position
|
* @name position
|
||||||
|
@ -583,7 +552,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Transport's position in seconds
|
* The Transport's position in seconds
|
||||||
* Setting the value will jump to that position right away.
|
* Setting the value will jump to that position right away.
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {Seconds}
|
* @type {Seconds}
|
||||||
* @name seconds
|
* @name seconds
|
||||||
|
@ -600,7 +569,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Transport's loop position as a normalized value. Always
|
* The Transport's loop position as a normalized value. Always
|
||||||
* returns 0 if the transport if loop is not true.
|
* returns 0 if the transport if loop is not true.
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @name progress
|
* @name progress
|
||||||
* @type {NormalRange}
|
* @type {NormalRange}
|
||||||
|
@ -617,7 +586,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The transports current tick position.
|
* The transports current tick position.
|
||||||
*
|
*
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {Ticks}
|
* @type {Ticks}
|
||||||
* @name ticks
|
* @name ticks
|
||||||
|
@ -645,9 +614,9 @@ function(Tone){
|
||||||
/**
|
/**
|
||||||
* Pulses Per Quarter note. This is the smallest resolution
|
* Pulses Per Quarter note. This is the smallest resolution
|
||||||
* the Transport timing supports. This should be set once
|
* the Transport timing supports. This should be set once
|
||||||
* on initialization and not set again. Changing this value
|
* on initialization and not set again. Changing this value
|
||||||
* after other objects have been created can cause problems.
|
* after other objects have been created can cause problems.
|
||||||
*
|
*
|
||||||
* @memberOf Tone.Transport#
|
* @memberOf Tone.Transport#
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
* @name PPQ
|
* @name PPQ
|
||||||
|
@ -716,14 +685,14 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attaches the signal to the tempo control signal so that
|
* Attaches the signal to the tempo control signal so that
|
||||||
* any changes in the tempo will change the signal in the same
|
* any changes in the tempo will change the signal in the same
|
||||||
* ratio.
|
* ratio.
|
||||||
*
|
*
|
||||||
* @param {Tone.Signal} signal
|
* @param {Tone.Signal} signal
|
||||||
* @param {number=} ratio Optionally pass in the ratio between
|
* @param {number=} ratio Optionally pass in the ratio between
|
||||||
* the two signals. Otherwise it will be computed
|
* the two signals. Otherwise it will be computed
|
||||||
* based on their current values.
|
* based on their current values.
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.syncSignal = function(signal, ratio){
|
Tone.Transport.prototype.syncSignal = function(signal, ratio){
|
||||||
|
@ -747,9 +716,9 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsyncs a previously synced signal from the transport's control.
|
* Unsyncs a previously synced signal from the transport's control.
|
||||||
* See Tone.Transport.syncSignal.
|
* See Tone.Transport.syncSignal.
|
||||||
* @param {Tone.Signal} signal
|
* @param {Tone.Signal} signal
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
*/
|
*/
|
||||||
Tone.Transport.prototype.unsyncSignal = function(signal){
|
Tone.Transport.prototype.unsyncSignal = function(signal){
|
||||||
|
@ -765,7 +734,7 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up.
|
* Clean up.
|
||||||
* @returns {Tone.Transport} this
|
* @returns {Tone.Transport} this
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -777,8 +746,6 @@ function(Tone){
|
||||||
this.bpm = null;
|
this.bpm = null;
|
||||||
this._timeline.dispose();
|
this._timeline.dispose();
|
||||||
this._timeline = null;
|
this._timeline = null;
|
||||||
this._onceEvents.dispose();
|
|
||||||
this._onceEvents = null;
|
|
||||||
this._repeatedEvents.dispose();
|
this._repeatedEvents.dispose();
|
||||||
this._repeatedEvents = null;
|
this._repeatedEvents = null;
|
||||||
return this;
|
return this;
|
||||||
|
|
92
Tone/core/TransportEvent.js
Normal file
92
Tone/core/TransportEvent.js
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
define(["Tone/core/Tone"], function(Tone){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Tone.TransportEvent is an internal class used by (Tone.Transport)[Transport]
|
||||||
|
* to schedule events. Do no invoke this class directly, it is
|
||||||
|
* handled from within Tone.Transport.
|
||||||
|
* @extends {Tone}
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
Tone.TransportEvent = function(Transport, options){
|
||||||
|
|
||||||
|
options = Tone.defaultArg(options, Tone.TransportEvent.defaults);
|
||||||
|
Tone.call(this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to the Transport that created it
|
||||||
|
* @type {Tone.Transport}
|
||||||
|
*/
|
||||||
|
this.Transport = Transport;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique id of the event
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
this.id = Tone.TransportEvent._eventId++;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the event starts
|
||||||
|
* @type {Ticks}
|
||||||
|
*/
|
||||||
|
this.time = options.time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The callback to invoke
|
||||||
|
* @type {Function}
|
||||||
|
*/
|
||||||
|
this.callback = options.callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the event should be removed after being created.
|
||||||
|
* @type {Boolean}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._once = options.once;
|
||||||
|
};
|
||||||
|
|
||||||
|
Tone.extend(Tone.TransportEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The defaults
|
||||||
|
* @static
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Tone.TransportEvent.defaults = {
|
||||||
|
"once" : false,
|
||||||
|
"callback" : Tone.noOp,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current ID counter
|
||||||
|
* @private
|
||||||
|
* @static
|
||||||
|
* @type {Number}
|
||||||
|
*/
|
||||||
|
Tone.TransportEvent._eventId = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the callback even callback.
|
||||||
|
* @param {Time} time The AudioContext time in seconds of the event
|
||||||
|
*/
|
||||||
|
Tone.TransportEvent.prototype.invoke = function(time){
|
||||||
|
if (this.callback){
|
||||||
|
this.callback(time);
|
||||||
|
if (this._once && this.Transport){
|
||||||
|
this.Transport.clear(this.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up
|
||||||
|
* @return {Tone.TransportEvent} this
|
||||||
|
*/
|
||||||
|
Tone.TransportEvent.prototype.dispose = function(){
|
||||||
|
Tone.prototype.dispose.call(this);
|
||||||
|
this.Transport = null;
|
||||||
|
this.callback = null;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tone.TransportEvent;
|
||||||
|
});
|
130
Tone/core/TransportRepeatEvent.js
Normal file
130
Tone/core/TransportRepeatEvent.js
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
define(["Tone/core/Tone", "Tone/core/TransportEvent"], function(Tone){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Tone.TransportRepeatEvent is an internal class used by Tone.Transport
|
||||||
|
* to schedule repeat events. This class should not be instantiated directly.
|
||||||
|
* @extends {Tone.TransportEvent}
|
||||||
|
* @param {Object} options
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent = function(Transport, options){
|
||||||
|
|
||||||
|
Tone.TransportEvent.call(this, Transport, options);
|
||||||
|
options = Tone.defaultArg(options, Tone.TransportRepeatEvent.defaults);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the event should stop repeating
|
||||||
|
* @type {Ticks}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.duration = options.duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval of the repeated event
|
||||||
|
* @type {Ticks}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._interval = options.interval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the current timeline event
|
||||||
|
* @type {Number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._currentId = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the next timeline event
|
||||||
|
* @type {Number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._nextId = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time of the next event
|
||||||
|
* @type {Ticks}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._nextTick = this.time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a reference to the bound start method
|
||||||
|
* @type {Function}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this._boundRestart = this._restart.bind(this);
|
||||||
|
this.Transport.on("start loopStart", this._boundRestart);
|
||||||
|
this._restart();
|
||||||
|
};
|
||||||
|
|
||||||
|
Tone.extend(Tone.TransportRepeatEvent, Tone.TransportEvent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The defaults
|
||||||
|
* @static
|
||||||
|
* @type {Object}
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent.defaults = {
|
||||||
|
"duration" : Infinity,
|
||||||
|
"interval" : 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoke the callback. Returns the tick time which
|
||||||
|
* the next event should be scheduled at.
|
||||||
|
* @param {Number} time The AudioContext time in seconds of the event
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent.prototype.invoke = function(time){
|
||||||
|
//create more events if necessary
|
||||||
|
this._createEvents();
|
||||||
|
//call the super class
|
||||||
|
Tone.TransportEvent.prototype.invoke.call(this, time);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push more events onto the timeline to keep up with the position of the timeline
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent.prototype._createEvents = function(){
|
||||||
|
// schedule the next event
|
||||||
|
var ticks = this.Transport.ticks;
|
||||||
|
if (ticks >= this.time && ticks >= this._nextTick &&
|
||||||
|
this._nextTick + this._interval < this.time + this.duration){
|
||||||
|
this._nextTick += this._interval;
|
||||||
|
this._currentId = this._nextId;
|
||||||
|
this._nextId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, "i"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push more events onto the timeline to keep up with the position of the timeline
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent.prototype._restart = function(){
|
||||||
|
this.Transport.clear(this._currentId);
|
||||||
|
this.Transport.clear(this._nextId);
|
||||||
|
var ticks = this.Transport.ticks;
|
||||||
|
this._nextTick = this.time;
|
||||||
|
if (ticks > this.time){
|
||||||
|
this._nextTick = this.time + Math.ceil((ticks - this.time) / this._interval) * this._interval;
|
||||||
|
}
|
||||||
|
this._currentId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, "i"));
|
||||||
|
this._nextTick += this._interval;
|
||||||
|
this._nextId = this.Transport.scheduleOnce(this.invoke.bind(this), Tone.TransportTime(this._nextTick, "i"));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clean up
|
||||||
|
* @return {Tone.TransportRepeatEvent} this
|
||||||
|
*/
|
||||||
|
Tone.TransportRepeatEvent.prototype.dispose = function(){
|
||||||
|
this.Transport.clear(this._currentId);
|
||||||
|
this.Transport.clear(this._nextId);
|
||||||
|
this.Transport.off("start loopStart", this._boundRestart);
|
||||||
|
this._boundCreateEvents = null;
|
||||||
|
Tone.TransportEvent.prototype.dispose.call(this);
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tone.TransportRepeatEvent;
|
||||||
|
});
|
|
@ -102,7 +102,7 @@ define(["Tone/core/Tone", "Tone/instrument/Instrument", "Tone/source/FMOscillato
|
||||||
"harmonicity" : options.harmonicity,
|
"harmonicity" : options.harmonicity,
|
||||||
"modulationIndex" : options.modulationIndex
|
"modulationIndex" : options.modulationIndex
|
||||||
});
|
});
|
||||||
osc.connect(this._highpass).start(0);
|
osc.connect(this._highpass).start();
|
||||||
this._oscillators[i] = osc;
|
this._oscillators[i] = osc;
|
||||||
|
|
||||||
var mult = new Tone.Multiply(inharmRatios[i]);
|
var mult = new Tone.Multiply(inharmRatios[i]);
|
||||||
|
|
|
@ -121,7 +121,8 @@ define(["Tone/core/Tone", "Tone/instrument/Instrument", "Tone/core/Buffers", "To
|
||||||
"buffer" : buffer,
|
"buffer" : buffer,
|
||||||
"playbackRate" : Tone.intervalToFrequencyRatio(difference),
|
"playbackRate" : Tone.intervalToFrequencyRatio(difference),
|
||||||
"fadeIn" : this.attack,
|
"fadeIn" : this.attack,
|
||||||
"fadeOut" : this.release
|
"fadeOut" : this.release,
|
||||||
|
"curve" : "exponential",
|
||||||
}).connect(this.output);
|
}).connect(this.output);
|
||||||
source.start(time, 0, buffer.duration, velocity);
|
source.start(time, 0, buffer.duration, velocity);
|
||||||
// add it to the active sources
|
// add it to the active sources
|
||||||
|
|
|
@ -3,7 +3,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class A signal which adds the method getValueAtTime.
|
* @class A signal which adds the method getValueAtTime.
|
||||||
* Code and inspiration from https://github.com/jsantell/web-audio-automation-timeline
|
* Code and inspiration from https://github.com/jsantell/web-audio-automation-timeline
|
||||||
* @extends {Tone.Signal}
|
* @extends {Tone.Signal}
|
||||||
* @param {Number=} value The initial value of the signal
|
* @param {Number=} value The initial value of the signal
|
||||||
|
@ -13,7 +13,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
|
|
||||||
var options = Tone.defaults(arguments, ["value", "units"], Tone.Signal);
|
var options = Tone.defaults(arguments, ["value", "units"], Tone.Signal);
|
||||||
Tone.Signal.call(this, options);
|
Tone.Signal.call(this, options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The scheduled events
|
* The scheduled events
|
||||||
* @type {Tone.Timeline}
|
* @type {Tone.Timeline}
|
||||||
|
@ -48,7 +48,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current value of the signal.
|
* The current value of the signal.
|
||||||
* @memberOf Tone.TimelineSignal#
|
* @memberOf Tone.TimelineSignal#
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
* @name value
|
* @name value
|
||||||
|
@ -79,7 +79,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
* @param {Time} time The time when the change should occur.
|
* @param {Time} time The time when the change should occur.
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
* @example
|
* @example
|
||||||
* //set the frequency to "G4" in exactly 1 second from now.
|
* //set the frequency to "G4" in exactly 1 second from now.
|
||||||
* freq.setValueAtTime("G4", "+1");
|
* freq.setValueAtTime("G4", "+1");
|
||||||
*/
|
*/
|
||||||
Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) {
|
Tone.TimelineSignal.prototype.setValueAtTime = function (value, startTime) {
|
||||||
|
@ -96,11 +96,11 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules a linear continuous change in parameter value from the
|
* Schedules a linear continuous change in parameter value from the
|
||||||
* previous scheduled parameter value to the given value.
|
* previous scheduled parameter value to the given value.
|
||||||
*
|
*
|
||||||
* @param {number} value
|
* @param {number} value
|
||||||
* @param {Time} endTime
|
* @param {Time} endTime
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) {
|
Tone.TimelineSignal.prototype.linearRampToValueAtTime = function (value, endTime) {
|
||||||
|
@ -116,11 +116,11 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedules an exponential continuous change in parameter value from
|
* Schedules an exponential continuous change in parameter value from
|
||||||
* the previous scheduled parameter value to the given value.
|
* the previous scheduled parameter value to the given value.
|
||||||
*
|
*
|
||||||
* @param {number} value
|
* @param {number} value
|
||||||
* @param {Time} endTime
|
* @param {Time} endTime
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) {
|
Tone.TimelineSignal.prototype.exponentialRampToValueAtTime = function (value, endTime) {
|
||||||
|
@ -151,10 +151,10 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
/**
|
/**
|
||||||
* Start exponentially approaching the target value at the given time with
|
* Start exponentially approaching the target value at the given time with
|
||||||
* a rate having the given time constant.
|
* a rate having the given time constant.
|
||||||
* @param {number} value
|
* @param {number} value
|
||||||
* @param {Time} startTime
|
* @param {Time} startTime
|
||||||
* @param {number} timeConstant
|
* @param {number} timeConstant
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
|
Tone.TimelineSignal.prototype.setTargetAtTime = function (value, startTime, timeConstant) {
|
||||||
value = this._fromUnits(value);
|
value = this._fromUnits(value);
|
||||||
|
@ -173,11 +173,11 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set an array of arbitrary values starting at the given time for the given duration.
|
* Set an array of arbitrary values starting at the given time for the given duration.
|
||||||
* @param {Float32Array} values
|
* @param {Float32Array} values
|
||||||
* @param {Time} startTime
|
* @param {Time} startTime
|
||||||
* @param {Time} duration
|
* @param {Time} duration
|
||||||
* @param {NormalRange} [scaling=1] If the values in the curve should be scaled by some value
|
* @param {NormalRange} [scaling=1] If the values in the curve should be scaled by some value
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
Tone.TimelineSignal.prototype.setValueCurveAtTime = function (values, startTime, duration, scaling) {
|
Tone.TimelineSignal.prototype.setValueCurveAtTime = function (values, startTime, duration, scaling) {
|
||||||
scaling = Tone.defaultArg(scaling, 1);
|
scaling = Tone.defaultArg(scaling, 1);
|
||||||
|
@ -192,9 +192,8 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels all scheduled parameter changes with times greater than or
|
* Cancels all scheduled parameter changes with times greater than or
|
||||||
* equal to startTime.
|
* equal to startTime.
|
||||||
*
|
|
||||||
* @param {Time} startTime
|
* @param {Time} startTime
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
|
@ -205,13 +204,25 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels all scheduled parameter changes with times greater than or
|
||||||
|
* equal to cancelTime and sets the output of the signal to be the value
|
||||||
|
* at cancelTime. Similar to (cancelScheduledValues)[#cancelscheduledvalues].
|
||||||
|
* @param {Time} cancelTime
|
||||||
|
* @returns {Tone.TimelineSignal} this
|
||||||
|
*/
|
||||||
|
Tone.TimelineSignal.prototype.cancelAndHoldAtTime = function (cancelTime) {
|
||||||
|
this.setRampPoint(this.toSeconds(cancelTime));
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the computed value at the given time. This provides
|
* Sets the computed value at the given time. This provides
|
||||||
* a point from which a linear or exponential curve
|
* a point from which a linear or exponential curve
|
||||||
* can be scheduled after. Will cancel events after
|
* can be scheduled after. Will cancel events after
|
||||||
* the given time and shorten the currently scheduled
|
* the given time and shorten the currently scheduled
|
||||||
* linear or exponential ramp so that it ends at `time` .
|
* linear or exponential ramp so that it ends at `time` .
|
||||||
* This is to avoid discontinuities and clicks in envelopes.
|
* This is to avoid discontinuities and clicks in envelopes.
|
||||||
* @param {Time} time When to set the ramp point
|
* @param {Time} time When to set the ramp point
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
*/
|
*/
|
||||||
|
@ -237,8 +248,8 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
this.exponentialRampToValueAtTime(val, time);
|
this.exponentialRampToValueAtTime(val, time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.setValueAtTime(val, time);
|
|
||||||
}
|
}
|
||||||
|
this.setValueAtTime(val, time);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -310,13 +321,13 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
value = this._initial;
|
value = this._initial;
|
||||||
} else if (before.type === Tone.TimelineSignal.Type.Target){
|
} else if (before.type === Tone.TimelineSignal.Type.Target){
|
||||||
var previous = this._events.getBefore(before.time);
|
var previous = this._events.getBefore(before.time);
|
||||||
var previouVal;
|
var previousVal;
|
||||||
if (previous === null){
|
if (previous === null){
|
||||||
previouVal = this._initial;
|
previousVal = this._initial;
|
||||||
} else {
|
} else {
|
||||||
previouVal = previous.value;
|
previousVal = previous.value;
|
||||||
}
|
}
|
||||||
value = this._exponentialApproach(before.time, previouVal, before.value, before.constant, time);
|
value = this._exponentialApproach(before.time, previousVal, before.value, before.constant, time);
|
||||||
} else if (after === null){
|
} else if (after === null){
|
||||||
value = before.value;
|
value = before.value;
|
||||||
} else if (after.type === Tone.TimelineSignal.Type.Linear){
|
} else if (after.type === Tone.TimelineSignal.Type.Linear){
|
||||||
|
@ -330,12 +341,12 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When signals connect to other signals or AudioParams,
|
* When signals connect to other signals or AudioParams,
|
||||||
* they take over the output value of that signal or AudioParam.
|
* they take over the output value of that signal or AudioParam.
|
||||||
* For all other nodes, the behavior is the same as a default <code>connect</code>.
|
* For all other nodes, the behavior is the same as a default <code>connect</code>.
|
||||||
*
|
*
|
||||||
* @override
|
* @override
|
||||||
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
|
* @param {AudioParam|AudioNode|Tone.Signal|Tone} node
|
||||||
* @param {number} [outputNumber=0] The output number to connect from.
|
* @param {number} [outputNumber=0] The output number to connect from.
|
||||||
* @param {number} [inputNumber=0] The input number to connect to.
|
* @param {number} [inputNumber=0] The input number to connect to.
|
||||||
* @returns {Tone.TimelineSignal} this
|
* @returns {Tone.TimelineSignal} this
|
||||||
|
@ -385,4 +396,4 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Timeline"], function
|
||||||
};
|
};
|
||||||
|
|
||||||
return Tone.TimelineSignal;
|
return Tone.TimelineSignal;
|
||||||
});
|
});
|
||||||
|
|
|
@ -82,6 +82,12 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
*/
|
*/
|
||||||
this.fadeOut = options.fadeOut;
|
this.fadeOut = options.fadeOut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The curve applied to the fades, either "linear" or "exponential"
|
||||||
|
* @type {String}
|
||||||
|
*/
|
||||||
|
this.curve = options.curve;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value that the buffer ramps to
|
* The value that the buffer ramps to
|
||||||
* @type {Gain}
|
* @type {Gain}
|
||||||
|
@ -96,6 +102,7 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
*/
|
*/
|
||||||
this._onendedTimeout = -1;
|
this._onendedTimeout = -1;
|
||||||
|
|
||||||
|
//set some values initially
|
||||||
this.loop = options.loop;
|
this.loop = options.loop;
|
||||||
this.loopStart = options.loopStart;
|
this.loopStart = options.loopStart;
|
||||||
this.loopEnd = options.loopEnd;
|
this.loopEnd = options.loopEnd;
|
||||||
|
@ -117,6 +124,7 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
"loopEnd" : 0,
|
"loopEnd" : 0,
|
||||||
"fadeIn" : 0,
|
"fadeIn" : 0,
|
||||||
"fadeOut" : 0,
|
"fadeOut" : 0,
|
||||||
|
"curve" : "linear",
|
||||||
"playbackRate" : 1
|
"playbackRate" : 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,30 +173,27 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
offset = Tone.defaultArg(offset, 0);
|
offset = Tone.defaultArg(offset, 0);
|
||||||
}
|
}
|
||||||
offset = this.toSeconds(offset);
|
offset = this.toSeconds(offset);
|
||||||
//the values in seconds
|
|
||||||
time = this.toSeconds(time);
|
|
||||||
|
|
||||||
gain = Tone.defaultArg(gain, 1);
|
gain = Tone.defaultArg(gain, 1);
|
||||||
this._gain = gain;
|
this._gain = gain;
|
||||||
|
|
||||||
//the fadeIn time
|
fadeInTime = this.toSeconds(Tone.defaultArg(fadeInTime, this.fadeIn));
|
||||||
if (Tone.isUndef(fadeInTime)){
|
this.fadeIn = fadeInTime;
|
||||||
fadeInTime = this.toSeconds(this.fadeIn);
|
|
||||||
} else {
|
|
||||||
fadeInTime = this.toSeconds(fadeInTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fadeInTime > 0){
|
if (fadeInTime > 0){
|
||||||
this._gainNode.gain.setValueAtTime(0, time);
|
this._gainNode.gain.setValueAtTime(0, time);
|
||||||
this._gainNode.gain.linearRampToValueAtTime(this._gain, time + fadeInTime);
|
if (this.curve === "linear"){
|
||||||
|
this._gainNode.gain.linearRampToValueAtTime(this._gain, time + fadeInTime);
|
||||||
|
} else {
|
||||||
|
this._gainNode.gain.setTargetAtTime(this._gain, time, this._gainNode.gain.getTimeConstant(fadeInTime));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._gainNode.gain.setValueAtTime(gain, time);
|
this._gainNode.gain.setValueAtTime(gain, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._startTime = time + fadeInTime;
|
this._startTime = time;
|
||||||
|
|
||||||
var computedDur = Tone.defaultArg(duration, this.buffer.duration - offset);
|
var computedDur = this.toSeconds(Tone.defaultArg(duration, this.buffer.duration - offset));
|
||||||
computedDur = this.toSeconds(computedDur);
|
|
||||||
computedDur = Math.max(computedDur, 0);
|
computedDur = Math.max(computedDur, 0);
|
||||||
|
|
||||||
if (!this.loop || (this.loop && !Tone.isUndef(duration))){
|
if (!this.loop || (this.loop && !Tone.isUndef(duration))){
|
||||||
|
@ -196,7 +201,7 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
if (!this.loop){
|
if (!this.loop){
|
||||||
computedDur = Math.min(computedDur, this.buffer.duration - offset);
|
computedDur = Math.min(computedDur, this.buffer.duration - offset);
|
||||||
}
|
}
|
||||||
this.stop(time + computedDur + fadeInTime, this.fadeOut);
|
this.stop(time + computedDur, this.fadeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
//start the buffer source
|
//start the buffer source
|
||||||
|
@ -212,6 +217,7 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
}
|
}
|
||||||
this._source.buffer = this.buffer.get();
|
this._source.buffer = this.buffer.get();
|
||||||
this._source.loopEnd = this.loopEnd || this.buffer.duration;
|
this._source.loopEnd = this.loopEnd || this.buffer.duration;
|
||||||
|
Tone.isPast(time);
|
||||||
this._source.start(time, offset);
|
this._source.start(time, offset);
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Tone.BufferSource: buffer is either not set or not loaded.");
|
throw new Error("Tone.BufferSource: buffer is either not set or not loaded.");
|
||||||
|
@ -232,26 +238,35 @@ define(["Tone/core/Tone", "Tone/core/Buffer", "Tone/source/Source", "Tone/core/G
|
||||||
|
|
||||||
time = this.toSeconds(time);
|
time = this.toSeconds(time);
|
||||||
|
|
||||||
//the fadeOut time
|
//if this is before the previous stop
|
||||||
if (Tone.isUndef(fadeOutTime)){
|
|
||||||
fadeOutTime = this.toSeconds(this.fadeOut);
|
|
||||||
} else {
|
|
||||||
fadeOutTime = this.toSeconds(fadeOutTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
//only stop if the last stop was scheduled later
|
|
||||||
if (this._stopTime === -1 || this._stopTime > time){
|
if (this._stopTime === -1 || this._stopTime > time){
|
||||||
|
|
||||||
|
//stop if it's schedule before the start time
|
||||||
|
if (time <= this._startTime){
|
||||||
|
this._gainNode.gain.cancelScheduledValues(time);
|
||||||
|
this._gainNode.gain.value = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
time = Math.max(this._startTime + this.fadeIn + this.sampleTime, time);
|
||||||
|
//cancel the previous curve
|
||||||
|
this._gainNode.gain.cancelScheduledValues(time);
|
||||||
this._stopTime = time;
|
this._stopTime = time;
|
||||||
|
|
||||||
//cancel the end curve
|
//the fadeOut time
|
||||||
this._gainNode.gain.cancelScheduledValues(this._startTime + this.sampleTime);
|
fadeOutTime = this.toSeconds(Tone.defaultArg(fadeOutTime, this.fadeOut));
|
||||||
time = Math.max(this._startTime, time);
|
|
||||||
|
|
||||||
//set a new one
|
//set a new one
|
||||||
if (fadeOutTime > 0){
|
var heldDuration = Math.min(time - this._startTime - this.fadeIn - this.sampleTime, this.buffer.duration);
|
||||||
var startFade = Math.max(this._startTime, time - fadeOutTime);
|
fadeOutTime = Math.min(heldDuration, fadeOutTime);
|
||||||
|
var startFade = time - fadeOutTime;
|
||||||
|
if (fadeOutTime > this.sampleTime){
|
||||||
this._gainNode.gain.setValueAtTime(this._gain, startFade);
|
this._gainNode.gain.setValueAtTime(this._gain, startFade);
|
||||||
this._gainNode.gain.linearRampToValueAtTime(0, time);
|
if (this.curve === "linear"){
|
||||||
|
this._gainNode.gain.linearRampToValueAtTime(0, time);
|
||||||
|
} else {
|
||||||
|
this._gainNode.gain.setTargetAtTime(0, startFade, this._gainNode.gain.getTimeConstant(fadeOutTime));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this._gainNode.gain.setValueAtTime(0, time);
|
this._gainNode.gain.setValueAtTime(0, time);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/source/Source", "Tone/core/Transport"],
|
define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/source/Source", "Tone/core/Transport"],
|
||||||
function(Tone){
|
function(Tone){
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
@ -9,7 +9,7 @@ function(Tone){
|
||||||
*/
|
*/
|
||||||
if (window.OscillatorNode && !OscillatorNode.prototype.start){
|
if (window.OscillatorNode && !OscillatorNode.prototype.start){
|
||||||
OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn;
|
OscillatorNode.prototype.start = OscillatorNode.prototype.noteOn;
|
||||||
OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff;
|
OscillatorNode.prototype.stop = OscillatorNode.prototype.noteOff;
|
||||||
if (!OscillatorNode.prototype.setPeriodicWave){
|
if (!OscillatorNode.prototype.setPeriodicWave){
|
||||||
OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable;
|
OscillatorNode.prototype.setPeriodicWave = OscillatorNode.prototype.setWaveTable;
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Tone.Oscillator supports a number of features including
|
* @class Tone.Oscillator supports a number of features including
|
||||||
* phase rotation, multiple oscillator types (see Tone.Oscillator.type),
|
* phase rotation, multiple oscillator types (see Tone.Oscillator.type),
|
||||||
* and Transport syncing (see Tone.Oscillator.syncFrequency).
|
* and Transport syncing (see Tone.Oscillator.syncFrequency).
|
||||||
*
|
*
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -32,7 +32,7 @@ function(Tone){
|
||||||
* var osc = new Tone.Oscillator(440, "sine").toMaster().start();
|
* var osc = new Tone.Oscillator(440, "sine").toMaster().start();
|
||||||
*/
|
*/
|
||||||
Tone.Oscillator = function(){
|
Tone.Oscillator = function(){
|
||||||
|
|
||||||
var options = Tone.defaults(arguments, ["frequency", "type"], Tone.Oscillator);
|
var options = Tone.defaults(arguments, ["frequency", "type"], Tone.Oscillator);
|
||||||
Tone.Source.call(this, options);
|
Tone.Source.call(this, options);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ function(Tone){
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this._oscillator = null;
|
this._oscillator = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The frequency control.
|
* The frequency control.
|
||||||
* @type {Frequency}
|
* @type {Frequency}
|
||||||
|
@ -85,7 +85,7 @@ function(Tone){
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
this._type = null;
|
this._type = null;
|
||||||
|
|
||||||
//setup
|
//setup
|
||||||
this.type = options.type;
|
this.type = options.type;
|
||||||
this.phase = this._phase;
|
this.phase = this._phase;
|
||||||
|
@ -120,7 +120,7 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* start the oscillator
|
* start the oscillator
|
||||||
* @param {Time} [time=now]
|
* @param {Time} [time=now]
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Tone.Oscillator.prototype._start = function(time){
|
Tone.Oscillator.prototype._start = function(time){
|
||||||
|
@ -132,7 +132,9 @@ function(Tone){
|
||||||
this.frequency.connect(this._oscillator.frequency);
|
this.frequency.connect(this._oscillator.frequency);
|
||||||
this.detune.connect(this._oscillator.detune);
|
this.detune.connect(this._oscillator.detune);
|
||||||
//start the oscillator
|
//start the oscillator
|
||||||
this._oscillator.start(this.toSeconds(time));
|
time = this.toSeconds(time);
|
||||||
|
Tone.isPast(time);
|
||||||
|
this._oscillator.start(time);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,7 +145,9 @@ function(Tone){
|
||||||
*/
|
*/
|
||||||
Tone.Oscillator.prototype._stop = function(time){
|
Tone.Oscillator.prototype._stop = function(time){
|
||||||
if (this._oscillator){
|
if (this._oscillator){
|
||||||
this._oscillator.stop(this.toSeconds(time));
|
time = this.toSeconds(time);
|
||||||
|
Tone.isPast(time);
|
||||||
|
this._oscillator.stop(time);
|
||||||
this._oscillator = null;
|
this._oscillator = null;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -151,14 +155,14 @@ function(Tone){
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync the signal to the Transport's bpm. Any changes to the transports bpm,
|
* Sync the signal to the Transport's bpm. Any changes to the transports bpm,
|
||||||
* will also affect the oscillators frequency.
|
* will also affect the oscillators frequency.
|
||||||
* @returns {Tone.Oscillator} this
|
* @returns {Tone.Oscillator} this
|
||||||
* @example
|
* @example
|
||||||
* Tone.Transport.bpm.value = 120;
|
* Tone.Transport.bpm.value = 120;
|
||||||
* osc.frequency.value = 440;
|
* osc.frequency.value = 440;
|
||||||
* //the ration between the bpm and the frequency will be maintained
|
* //the ration between the bpm and the frequency will be maintained
|
||||||
* osc.syncFrequency();
|
* osc.syncFrequency();
|
||||||
* Tone.Transport.bpm.value = 240;
|
* Tone.Transport.bpm.value = 240;
|
||||||
* // the frequency of the oscillator is doubled to 880
|
* // the frequency of the oscillator is doubled to 880
|
||||||
*/
|
*/
|
||||||
Tone.Oscillator.prototype.syncFrequency = function(){
|
Tone.Oscillator.prototype.syncFrequency = function(){
|
||||||
|
@ -167,7 +171,7 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsync the oscillator's frequency from the Transport.
|
* Unsync the oscillator's frequency from the Transport.
|
||||||
* See Tone.Oscillator.syncFrequency
|
* See Tone.Oscillator.syncFrequency
|
||||||
* @returns {Tone.Oscillator} this
|
* @returns {Tone.Oscillator} this
|
||||||
*/
|
*/
|
||||||
|
@ -181,11 +185,11 @@ function(Tone){
|
||||||
* setting the first x number of partials of the oscillator. For example: "sine4" would
|
* setting the first x number of partials of the oscillator. For example: "sine4" would
|
||||||
* set be the first 4 partials of the sine wave and "triangle8" would set the first
|
* set be the first 4 partials of the sine wave and "triangle8" would set the first
|
||||||
* 8 partials of the triangle wave.
|
* 8 partials of the triangle wave.
|
||||||
* <br><br>
|
* <br><br>
|
||||||
* Uses PeriodicWave internally even for native types so that it can set the phase.
|
* Uses PeriodicWave internally even for native types so that it can set the phase.
|
||||||
* PeriodicWave equations are from the
|
* PeriodicWave equations are from the
|
||||||
* [Webkit Web Audio implementation](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp&sq=package:chromium).
|
* [Webkit Web Audio implementation](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/WebKit/Source/modules/webaudio/PeriodicWave.cpp&sq=package:chromium).
|
||||||
*
|
*
|
||||||
* @memberOf Tone.Oscillator#
|
* @memberOf Tone.Oscillator#
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @name type
|
* @name type
|
||||||
|
@ -212,7 +216,7 @@ function(Tone){
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the real and imaginary components based
|
* Returns the real and imaginary components based
|
||||||
* on the oscillator type.
|
* on the oscillator type.
|
||||||
* @returns {Array} [real, imaginary]
|
* @returns {Array} [real, imaginary]
|
||||||
* @private
|
* @private
|
||||||
|
@ -223,7 +227,7 @@ function(Tone){
|
||||||
|
|
||||||
var real = new Float32Array(periodicWaveSize);
|
var real = new Float32Array(periodicWaveSize);
|
||||||
var imag = new Float32Array(periodicWaveSize);
|
var imag = new Float32Array(periodicWaveSize);
|
||||||
|
|
||||||
var partialCount = 1;
|
var partialCount = 1;
|
||||||
if (type === Tone.Oscillator.Type.Custom){
|
if (type === Tone.Oscillator.Type.Custom){
|
||||||
partialCount = this._partials.length + 1;
|
partialCount = this._partials.length + 1;
|
||||||
|
@ -240,9 +244,9 @@ function(Tone){
|
||||||
|
|
||||||
for (var n = 1; n < periodicWaveSize; ++n) {
|
for (var n = 1; n < periodicWaveSize; ++n) {
|
||||||
var piFactor = 2 / (n * Math.PI);
|
var piFactor = 2 / (n * Math.PI);
|
||||||
var b;
|
var b;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Tone.Oscillator.Type.Sine:
|
case Tone.Oscillator.Type.Sine:
|
||||||
b = (n <= partialCount) ? 1 : 0;
|
b = (n <= partialCount) ? 1 : 0;
|
||||||
break;
|
break;
|
||||||
case Tone.Oscillator.Type.Square:
|
case Tone.Oscillator.Type.Square:
|
||||||
|
@ -258,7 +262,7 @@ function(Tone){
|
||||||
b = 0;
|
b = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Tone.Oscillator.Type.Custom:
|
case Tone.Oscillator.Type.Custom:
|
||||||
b = this._partials[n - 1];
|
b = this._partials[n - 1];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -276,10 +280,10 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the inverse FFT for a given phase.
|
* Compute the inverse FFT for a given phase.
|
||||||
* @param {Float32Array} real
|
* @param {Float32Array} real
|
||||||
* @param {Float32Array} imag
|
* @param {Float32Array} imag
|
||||||
* @param {NormalRange} phase
|
* @param {NormalRange} phase
|
||||||
* @return {AudioRange}
|
* @return {AudioRange}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
@ -311,12 +315,12 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The partials of the waveform. A partial represents
|
* The partials of the waveform. A partial represents
|
||||||
* the amplitude at a harmonic. The first harmonic is the
|
* the amplitude at a harmonic. The first harmonic is the
|
||||||
* fundamental frequency, the second is the octave and so on
|
* fundamental frequency, the second is the octave and so on
|
||||||
* following the harmonic series.
|
* following the harmonic series.
|
||||||
* Setting this value will automatically set the type to "custom".
|
* Setting this value will automatically set the type to "custom".
|
||||||
* The value is an empty array when the type is not "custom".
|
* The value is an empty array when the type is not "custom".
|
||||||
* @memberOf Tone.Oscillator#
|
* @memberOf Tone.Oscillator#
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
* @name partials
|
* @name partials
|
||||||
|
@ -330,7 +334,7 @@ function(Tone){
|
||||||
} else {
|
} else {
|
||||||
return this._partials;
|
return this._partials;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set : function(partials){
|
set : function(partials){
|
||||||
this._partials = partials;
|
this._partials = partials;
|
||||||
this.type = Tone.Oscillator.Type.Custom;
|
this.type = Tone.Oscillator.Type.Custom;
|
||||||
|
@ -338,7 +342,7 @@ function(Tone){
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The phase of the oscillator in degrees.
|
* The phase of the oscillator in degrees.
|
||||||
* @memberOf Tone.Oscillator#
|
* @memberOf Tone.Oscillator#
|
||||||
* @type {Degrees}
|
* @type {Degrees}
|
||||||
* @name phase
|
* @name phase
|
||||||
|
@ -348,7 +352,7 @@ function(Tone){
|
||||||
Object.defineProperty(Tone.Oscillator.prototype, "phase", {
|
Object.defineProperty(Tone.Oscillator.prototype, "phase", {
|
||||||
get : function(){
|
get : function(){
|
||||||
return this._phase * (180 / Math.PI);
|
return this._phase * (180 / Math.PI);
|
||||||
},
|
},
|
||||||
set : function(phase){
|
set : function(phase){
|
||||||
this._phase = phase * Math.PI / 180;
|
this._phase = phase * Math.PI / 180;
|
||||||
//reset the type
|
//reset the type
|
||||||
|
@ -377,4 +381,4 @@ function(Tone){
|
||||||
};
|
};
|
||||||
|
|
||||||
return Tone.Oscillator;
|
return Tone.Oscillator;
|
||||||
});
|
});
|
||||||
|
|
23365
build/Tone.js
23365
build/Tone.js
File diff suppressed because it is too large
Load diff
14
build/Tone.min.js
vendored
14
build/Tone.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
||||||
|
|
||||||
<script src="../build/Tone.js"></script>
|
<script src="../build/Tone.js"></script>
|
||||||
<script src="./scripts/jquery.min.js"></script>
|
<script src="./scripts/jquery.min.js"></script>
|
||||||
<script src="./scripts/draggabilly.js"></script>
|
<script src="./scripts/draggabilly.js"></script>
|
||||||
|
@ -30,22 +30,22 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="Content" class="FullScreen">
|
<div id="Content" class="FullScreen">
|
||||||
<div id="Title">Analyser</div>
|
<div id="Title">Analyser</div>
|
||||||
<div id="Explanation">
|
<div id="Explanation">
|
||||||
<a href="https://tonejs.github.io/docs/#Analyser" target="_blank">Tone.Analyser</a>
|
<a href="https://tonejs.github.io/docs/#Analyser" target="_blank">Tone.Analyser</a>
|
||||||
analyses the incoming audio to produce a TypedArray of either the
|
analyses the incoming audio to produce a TypedArray of either the
|
||||||
<a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform" target="_blank">FFT data</a>
|
<a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform" target="_blank">FFT data</a>
|
||||||
or the waveform. The default <code>returnType</code> is "byte" which returns values
|
or the waveform. The default <code>returnType</code> is "byte" which returns values
|
||||||
in the range 0-255.
|
in the range 0-255.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
//analyse the frequency/amplitude of the incoming signal
|
//analyse the frequency/amplitude of the incoming signal
|
||||||
var fft = new Tone.Analyser("fft", 32);
|
var fft = new Tone.FFT(32);
|
||||||
|
|
||||||
//get the waveform data for the audio
|
//get the waveform data for the audio
|
||||||
var waveform = new Tone.Analyser("waveform", 1024);
|
var waveform = new Tone.Waveform(1024);
|
||||||
|
|
||||||
var player = new Tone.Player({
|
var player = new Tone.Player({
|
||||||
"url" : "./audio/FWDL.[mp3|ogg]",
|
"url" : "./audio/FWDL.[mp3|ogg]",
|
||||||
|
@ -77,10 +77,9 @@
|
||||||
fftContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
fftContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||||
var barWidth = canvasWidth / fft.size;
|
var barWidth = canvasWidth / fft.size;
|
||||||
for (var i = 0, len = values.length; i < len; i++){
|
for (var i = 0, len = values.length; i < len; i++){
|
||||||
var val = values[i] / 255;
|
|
||||||
var x = canvasWidth * (i / len);
|
var x = canvasWidth * (i / len);
|
||||||
var y = val * canvasHeight;
|
var y = (values[i] + 140) * 2;
|
||||||
fftContext.fillStyle = "rgba(0, 0, 0, " + val + ")";
|
fftContext.fillStyle = "rgba(0, 0, 0, " + i/len + ")";
|
||||||
fftContext.fillRect(x, canvasHeight - y, barWidth, canvasHeight);
|
fftContext.fillRect(x, canvasHeight - y, barWidth, canvasHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,14 +93,13 @@
|
||||||
function drawWaveform(values){
|
function drawWaveform(values){
|
||||||
//draw the waveform
|
//draw the waveform
|
||||||
waveContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
waveContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||||
var values = waveform.analyse();
|
|
||||||
waveContext.beginPath();
|
waveContext.beginPath();
|
||||||
waveContext.lineJoin = "round";
|
waveContext.lineJoin = "round";
|
||||||
waveContext.lineWidth = 6;
|
waveContext.lineWidth = 6;
|
||||||
waveContext.strokeStyle = waveformGradient;
|
waveContext.strokeStyle = waveformGradient;
|
||||||
waveContext.moveTo(0, (values[0] / 255) * canvasHeight);
|
waveContext.moveTo(0, (values[0] / 255) * canvasHeight);
|
||||||
for (var i = 1, len = values.length; i < len; i++){
|
for (var i = 1, len = values.length; i < len; i++){
|
||||||
var val = values[i] / 255;
|
var val = (values[i] + 1) / 2;
|
||||||
var x = canvasWidth * (i / len);
|
var x = canvasWidth * (i / len);
|
||||||
var y = val * canvasHeight;
|
var y = val * canvasHeight;
|
||||||
waveContext.lineTo(x, y);
|
waveContext.lineTo(x, y);
|
||||||
|
@ -123,7 +121,7 @@
|
||||||
//make the gradient
|
//make the gradient
|
||||||
waveformGradient = waveContext.createLinearGradient(0, 0, canvasWidth, canvasHeight);
|
waveformGradient = waveContext.createLinearGradient(0, 0, canvasWidth, canvasHeight);
|
||||||
waveformGradient.addColorStop(0, "#ddd");
|
waveformGradient.addColorStop(0, "#ddd");
|
||||||
waveformGradient.addColorStop(1, "#000");
|
waveformGradient.addColorStop(1, "#000");
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeCanvases();
|
sizeCanvases();
|
||||||
|
@ -132,10 +130,10 @@
|
||||||
function loop(){
|
function loop(){
|
||||||
requestAnimationFrame(loop);
|
requestAnimationFrame(loop);
|
||||||
//get the fft data and draw it
|
//get the fft data and draw it
|
||||||
var fftValues = fft.analyse();
|
var fftValues = fft.getValue();
|
||||||
drawFFT(fftValues);
|
drawFFT(fftValues);
|
||||||
//get the waveform valeus and draw it
|
//get the waveform valeus and draw it
|
||||||
var waveformValues = waveform.analyse();
|
var waveformValues = waveform.getValue();
|
||||||
drawWaveform(waveformValues);
|
drawWaveform(waveformValues);
|
||||||
}
|
}
|
||||||
loop();
|
loop();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
||||||
|
|
||||||
<script src="../build/Tone.js"></script>
|
<script src="../build/Tone.js"></script>
|
||||||
<script src="./scripts/jquery.min.js"></script>
|
<script src="./scripts/jquery.min.js"></script>
|
||||||
<script src="./scripts/draggabilly.js"></script>
|
<script src="./scripts/draggabilly.js"></script>
|
||||||
|
@ -31,23 +31,22 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="Content" class="FullScreen">
|
<div id="Content" class="FullScreen">
|
||||||
<div id="Title">Meter</div>
|
<div id="Title">Meter</div>
|
||||||
<div id="Explanation">
|
<div id="Explanation">
|
||||||
<a href="https://tonejs.github.io/docs/#Meter" target="_blank">Tone.Meter</a>
|
<a href="https://tonejs.github.io/docs/#Meter" target="_blank">Tone.Meter</a>
|
||||||
gives you the level of the incoming signal (between 0-1). Values above 1
|
gives you the level of the incoming signal in decibels.
|
||||||
are clipping.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
//create a level meter
|
//create a level meter
|
||||||
var meter = new Tone.Meter("level");
|
var meter = new Tone.Meter();
|
||||||
|
|
||||||
var player = new Tone.Player({
|
var player = new Tone.Player({
|
||||||
"url" : "./audio/FWDL.[mp3|ogg]",
|
"url" : "./audio/FWDL.[mp3|ogg]",
|
||||||
"loop" : true
|
"loop" : true
|
||||||
}).connect(meter).toMaster();
|
}).connect(meter).toMaster();
|
||||||
|
|
||||||
// GUI //
|
// GUI //
|
||||||
|
|
||||||
//start button
|
//start button
|
||||||
|
@ -72,7 +71,8 @@
|
||||||
var meterGraident;
|
var meterGraident;
|
||||||
|
|
||||||
function drawMeter(){
|
function drawMeter(){
|
||||||
var level = meter.value * 0.8; //scale it since values go above 1 when clipping
|
var level = meter.getLevel();
|
||||||
|
level = Tone.dbToGain(level); //scale it between 0 - 1
|
||||||
meterContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
meterContext.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||||
meterContext.fillStyle = meterGraident;
|
meterContext.fillStyle = meterGraident;
|
||||||
meterContext.fillRect(0, 0, canvasWidth, canvasHeight);
|
meterContext.fillRect(0, 0, canvasWidth, canvasHeight);
|
||||||
|
@ -91,8 +91,8 @@
|
||||||
//make the gradient
|
//make the gradient
|
||||||
meterGraident = meterContext.createLinearGradient(0, 0, canvasWidth, canvasHeight);
|
meterGraident = meterContext.createLinearGradient(0, 0, canvasWidth, canvasHeight);
|
||||||
meterGraident.addColorStop(0, "#BFFF02");
|
meterGraident.addColorStop(0, "#BFFF02");
|
||||||
meterGraident.addColorStop(0.8, "#02FF24");
|
meterGraident.addColorStop(0.8, "#02FF24");
|
||||||
meterGraident.addColorStop(1, "#FF0202");
|
meterGraident.addColorStop(1, "#FF0202");
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeCanvases();
|
sizeCanvases();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
<link rel="icon" type="image/png" sizes="174x174" href="./style/favicon.png">
|
||||||
|
|
||||||
<script src="../build/Tone.js"></script>
|
<script src="../build/Tone.js"></script>
|
||||||
<script src="./scripts/jquery.min.js"></script>
|
<script src="./scripts/jquery.min.js"></script>
|
||||||
<script src="./scripts/draggabilly.js"></script>
|
<script src="./scripts/draggabilly.js"></script>
|
||||||
|
@ -44,10 +44,7 @@
|
||||||
//directly to the master output because of feedback.
|
//directly to the master output because of feedback.
|
||||||
var mic = new Tone.UserMedia();
|
var mic = new Tone.UserMedia();
|
||||||
|
|
||||||
var analyser = new Tone.Analyser({
|
var analyser = new Tone.Waveform(256);
|
||||||
"type" : "waveform",
|
|
||||||
"size" : 256
|
|
||||||
});
|
|
||||||
|
|
||||||
mic.connect(analyser);
|
mic.connect(analyser);
|
||||||
|
|
||||||
|
@ -74,14 +71,14 @@
|
||||||
requestAnimationFrame(drawLoop);
|
requestAnimationFrame(drawLoop);
|
||||||
//draw the waveform
|
//draw the waveform
|
||||||
context.clearRect(0, 0, canvasWidth, canvasHeight);
|
context.clearRect(0, 0, canvasWidth, canvasHeight);
|
||||||
var values = analyser.analyse();
|
var values = analyser.getValue();
|
||||||
context.beginPath();
|
context.beginPath();
|
||||||
context.lineJoin = "round";
|
context.lineJoin = "round";
|
||||||
context.lineWidth = 6;
|
context.lineWidth = 6;
|
||||||
context.strokeStyle = "white";
|
context.strokeStyle = "white";
|
||||||
context.moveTo(0, (values[0] / 255) * canvasHeight);
|
context.moveTo(0, (values[0] + 1) / 2 * canvasHeight);
|
||||||
for (var i = 1, len = values.length; i < len; i++){
|
for (var i = 1, len = values.length; i < len; i++){
|
||||||
var val = values[i] / 255;
|
var val = (values[i] + 1) / 2;
|
||||||
var x = canvasWidth * (i / (len - 1));
|
var x = canvasWidth * (i / (len - 1));
|
||||||
var y = val * canvasHeight;
|
var y = val * canvasHeight;
|
||||||
context.lineTo(x, y);
|
context.lineTo(x, y);
|
||||||
|
@ -89,7 +86,7 @@
|
||||||
context.stroke();
|
context.stroke();
|
||||||
}
|
}
|
||||||
drawLoop();
|
drawLoop();
|
||||||
|
|
||||||
Interface.Button({
|
Interface.Button({
|
||||||
type : "toggle",
|
type : "toggle",
|
||||||
text : "Open Mic",
|
text : "Open Mic",
|
||||||
|
@ -105,6 +102,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
<script src="https://tonejs.github.io/Logo/build/Logo.js"></script>
|
<script src="https://tonejs.github.io/Logo/build/Logo.js"></script>
|
||||||
<script src="./scripts/StartAudioContext.js"></script>
|
<script src="./scripts/StartAudioContext.js"></script>
|
||||||
<script src="./scripts/Interface.js"></script>
|
<script src="./scripts/Interface.js"></script>
|
||||||
<script src="./scripts/nexusUI.js"></script>
|
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
<link rel="stylesheet" type="text/css" href="./style/examples.css">
|
||||||
|
|
||||||
|
@ -28,108 +27,64 @@
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="Content" class="FullScreen">
|
<div id="Content" class="FullScreen">
|
||||||
<div id="Title">rampTo</div>
|
<div id="Title">rampTo</div>
|
||||||
<div id="Explanation">
|
<div id="Explanation">
|
||||||
In Tone.js, many of a class' members are <a href="https://tonejs.github.io/docs/#Signal">Tone.Signals</a>.
|
In Tone.js, many of a class' members are <a href="https://tonejs.github.io/docs/#Signal">Tone.Signals</a>.
|
||||||
Working with signals is different than working with numbers or strings:
|
Working with signals is different than working with numbers or strings:
|
||||||
Signals are values which are updated at audio rate,
|
Signals are values which are updated at audio rate,
|
||||||
which allows for sample-accurate scheduling and ramping. <code>.rampTo(value, rampTime)</code>
|
which allows for sample-accurate scheduling and ramping. <code>.rampTo(value, rampTime)</code>
|
||||||
smoothly changes the signal from the current value to the target value over the duration of the rampTime.
|
smoothly changes the signal from the current value to the target value over the duration of the rampTime.
|
||||||
This example uses <code>.rampTo</code> in to smooth out changes in volume and frequency.
|
This example uses <code>.rampTo</code> in to smooth out changes in volume and frequency.
|
||||||
<br><br>
|
|
||||||
As the large dot gets closer to each of the smaller dots, a different harmonic is heard depending
|
|
||||||
on the distance to that smaller dot. The "harmony" slider adjusts each of the oscillators frequencies'
|
|
||||||
distance from the fundamental frequency.
|
|
||||||
</div>
|
</div>
|
||||||
<canvas nx="joints"></canvas>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
Tone.Master.volume.value = -Infinity;
|
var oscillators = [];
|
||||||
|
|
||||||
var oscillators = {};
|
|
||||||
|
|
||||||
var bassFreq = 32;
|
var bassFreq = 32;
|
||||||
|
|
||||||
var reverb = new Tone.JCReverb().toMaster();
|
|
||||||
|
|
||||||
for (var i = 0; i < 8; i++){
|
for (var i = 0; i < 8; i++){
|
||||||
oscillators["node" + i] = new Tone.Oscillator({
|
oscillators.push(new Tone.Oscillator({
|
||||||
"frequency" : bassFreq * i,
|
"frequency" : bassFreq * i,
|
||||||
"type" : "sawtooth10",
|
"type" : "sawtooth10",
|
||||||
|
"volume" : -Infinity,
|
||||||
"detune" : Math.random() * 30 - 15,
|
"detune" : Math.random() * 30 - 15,
|
||||||
}).connect(reverb).start();
|
}).start().toMaster());
|
||||||
}
|
}
|
||||||
|
|
||||||
// GUI //
|
Interface.Slider({
|
||||||
|
name : "harmony",
|
||||||
nx.onload = function(){
|
min : 0.5,
|
||||||
nx.colorize("#7F33ED");
|
max : 2,
|
||||||
|
value : 1,
|
||||||
joints1.nodeSize = 25;
|
drag : function(value){
|
||||||
joints1.val.x = Math.random();
|
oscillators.forEach(function(osc, i){
|
||||||
joints1.val.y = Math.random();
|
osc.frequency.rampTo(bassFreq * i * value, 0.4);
|
||||||
joints1.resize($("#Content").width(), 250);
|
});
|
||||||
joints1.animate("bounce");
|
},
|
||||||
var width = joints1.width;
|
});
|
||||||
var height = joints1.height;
|
|
||||||
joints1.threshold = Math.max($("#Content").width() / 1.5, 60);
|
|
||||||
joints1.init();
|
|
||||||
joints1.draw();
|
|
||||||
|
|
||||||
$(window).on("resize", function(){
|
|
||||||
joints1.resize($("#Content").width(), 250);
|
|
||||||
joints1.threshold = Math.max($("#Content").width() / 1.5, 60);
|
|
||||||
joints1.draw();
|
|
||||||
});
|
|
||||||
|
|
||||||
function setValues(data){
|
|
||||||
for (var n in oscillators){
|
|
||||||
oscillators[n].volume.cancelScheduledValues();
|
|
||||||
if (data.hasOwnProperty(n)){
|
|
||||||
oscillators[n].volume.rampTo((1 - Math.pow(data[n], 0.5)) * -60, 0.3);
|
|
||||||
} else {
|
|
||||||
oscillators[n].volume.rampTo(-Infinity, 0.4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
joints1.on("*", setValues);
|
|
||||||
|
|
||||||
Interface.Slider({
|
|
||||||
name : "harmony",
|
|
||||||
min : 0.5,
|
|
||||||
max : 2,
|
|
||||||
value : 1,
|
|
||||||
drag : function(value){
|
|
||||||
var i = 0;
|
|
||||||
for (var n in oscillators){
|
|
||||||
var osc = oscillators[n];
|
|
||||||
osc.volume.cancelScheduledValues();
|
|
||||||
osc.frequency.rampTo(bassFreq * i * value, 0.4);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
Interface.Button({
|
Interface.Button({
|
||||||
text : "Unmute",
|
text : "Unmute",
|
||||||
activeText : "Mute",
|
activeText : "Mute",
|
||||||
type : "toggle",
|
type : "toggle",
|
||||||
key : 32, //spacebar
|
key : 32, //spacebar
|
||||||
start : function(){
|
start : function(){
|
||||||
Tone.Master.volume.rampTo(-20, 0.5);
|
oscillators.forEach(function(osc){
|
||||||
},
|
osc.volume.rampTo(-20, 1);
|
||||||
end : function(){
|
});
|
||||||
Tone.Master.volume.rampTo(-Infinity, 0.5);
|
},
|
||||||
},
|
end : function(){
|
||||||
});
|
oscillators.forEach(function(osc){
|
||||||
}
|
osc.volume.rampTo(-Infinity, 1);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
'A7' : 'A7.[mp3|ogg]',
|
'A7' : 'A7.[mp3|ogg]',
|
||||||
'C8' : 'C8.[mp3|ogg]'
|
'C8' : 'C8.[mp3|ogg]'
|
||||||
}, {
|
}, {
|
||||||
'release' : 0.1,
|
'release' : 1,
|
||||||
'baseUrl' : './audio/salamander/'
|
'baseUrl' : './audio/salamander/'
|
||||||
}).toMaster();
|
}).toMaster();
|
||||||
|
|
||||||
|
|
127
gulp/gulpfile.js
127
gulp/gulpfile.js
|
@ -143,19 +143,6 @@ gulp.task("example", function() {
|
||||||
gulp.watch(["../examples/style/examples.scss"], ["sass"]);
|
gulp.watch(["../examples/style/examples.scss"], ["sass"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* THE WEBSERVER
|
|
||||||
*/
|
|
||||||
gulp.task("server", function(){
|
|
||||||
gulp.src("../")
|
|
||||||
.pipe(webserver({
|
|
||||||
// livereload: false,
|
|
||||||
directoryListing: true,
|
|
||||||
port : 3000,
|
|
||||||
open: false
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LINTING
|
* LINTING
|
||||||
*/
|
*/
|
||||||
|
@ -177,7 +164,7 @@ gulp.task("collectTests", function(done){
|
||||||
var tests = ["../test/*/*.js", "!../test/helper/*.js", "!../test/tests/*.js"];
|
var tests = ["../test/*/*.js", "!../test/helper/*.js", "!../test/tests/*.js"];
|
||||||
if (argv.file){
|
if (argv.file){
|
||||||
tests = ["../test/*/"+argv.file+".js"];
|
tests = ["../test/*/"+argv.file+".js"];
|
||||||
} else if (argv.signal || argv.core || argv.component || argv.instrument ||
|
} else if (argv.signal || argv.core || argv.component || argv.instrument ||
|
||||||
argv.source || argv.effect || argv.event || argv.type || argv.examples){
|
argv.source || argv.effect || argv.event || argv.type || argv.examples){
|
||||||
tests = [];
|
tests = [];
|
||||||
if (argv.signal){
|
if (argv.signal){
|
||||||
|
@ -207,7 +194,7 @@ gulp.task("collectTests", function(done){
|
||||||
if (argv.examples){
|
if (argv.examples){
|
||||||
tests.push("../test/examples/*.js");
|
tests.push("../test/examples/*.js");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(argv.signal === undefined);
|
// console.log(argv.signal === undefined);
|
||||||
var allFiles = [];
|
var allFiles = [];
|
||||||
var task = gulp.src(tests)
|
var task = gulp.src(tests)
|
||||||
|
@ -231,45 +218,6 @@ gulp.task("collectTests", function(done){
|
||||||
*/
|
*/
|
||||||
gulp.task("travis-test", ["lint", "karma-test"]);
|
gulp.task("travis-test", ["lint", "karma-test"]);
|
||||||
|
|
||||||
/**
|
|
||||||
* COMMIT BUILD
|
|
||||||
*/
|
|
||||||
gulp.task("cloneBuild", function(done) {
|
|
||||||
var gitUser = "";
|
|
||||||
if (process.env.TRAVIS && process.env.GH_TOKEN){
|
|
||||||
gitUser = process.env.GH_TOKEN+"@";
|
|
||||||
}
|
|
||||||
git.clone("https://"+gitUser+"github.com/Tonejs/build", {args: `${TMP_FOLDER}/build`}, done);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("moveToDev", ["build", "cloneBuild"], function(){
|
|
||||||
// move files to 'dev' folder
|
|
||||||
return gulp.src("../build/*.js")
|
|
||||||
.pipe(gulp.dest(`${TMP_FOLDER}/build/dev/`));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("commitDev", ["moveToDev"], function(){
|
|
||||||
process.chdir(`${TMP_FOLDER}/build`);
|
|
||||||
return gulp.src("./dev/*")
|
|
||||||
.pipe(git.add())
|
|
||||||
.pipe(git.commit(`${VERSION} build #${process.env.TRAVIS_BUILD_NUMBER}: ${process.env.TRAVIS_COMMIT_MESSAGE}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("pushBuild", ["commitDev"], function(done){
|
|
||||||
if (process.env.TRAVIS && process.env.GH_TOKEN){
|
|
||||||
git.push("origin", "gh-pages", {args: " -f"}, function (err) {
|
|
||||||
if (err) throw err;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("commitDevBuild", ["pushBuild"], function(){
|
|
||||||
return del([`${TMP_FOLDER}/build`], { force : true});
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* COVERALLS
|
* COVERALLS
|
||||||
*/
|
*/
|
||||||
|
@ -277,74 +225,3 @@ gulp.task("coveralls", function(){
|
||||||
return gulp.src("../test/coverage/**/lcov.info")
|
return gulp.src("../test/coverage/**/lcov.info")
|
||||||
.pipe(coveralls());
|
.pipe(coveralls());
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* JS DOC ATTRIBUTES
|
|
||||||
*/
|
|
||||||
|
|
||||||
gulp.task("cloneSite", function(done){
|
|
||||||
var gitUser = "";
|
|
||||||
if (process.env.TRAVIS && process.env.GH_TOKEN){
|
|
||||||
gitUser = process.env.GH_TOKEN+"@";
|
|
||||||
}
|
|
||||||
git.clone("https://"+gitUser+"github.com/Tonejs/tonejs.github.io", {args: `${TMP_FOLDER}/Site`}, done);
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("commitSite", ["buildJsdocs"], function(){
|
|
||||||
process.chdir(`${TMP_FOLDER}/Site`);
|
|
||||||
return gulp.src("*")
|
|
||||||
.pipe(git.add())
|
|
||||||
.pipe(git.commit(`${VERSION} build #${process.env.TRAVIS_BUILD_NUMBER}: ${process.env.TRAVIS_COMMIT_MESSAGE}`));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("pushJSDocs", ["commitSite"], function(done){
|
|
||||||
if (process.env.TRAVIS && process.env.GH_TOKEN){
|
|
||||||
git.push("origin", "master", {args: " -f"}, function (err) {
|
|
||||||
if (err) throw err;
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("empty.md", ["cloneSite"], function(){
|
|
||||||
return gulp.src("../Tone/*/*.js")
|
|
||||||
.pipe(tap(function(file){
|
|
||||||
var className = path.basename(file.path, ".js");
|
|
||||||
var pathSplit = file.path.split("/");
|
|
||||||
var category = pathSplit[pathSplit.length-2];
|
|
||||||
file.contents = Buffer.from(`---\ntitle: ${className}\nlayout: ${className === "Type" ? "type" : "doc"}\nversion: ${VERSION}\n---`);
|
|
||||||
}))
|
|
||||||
.pipe(rename({extname: ".md"}))
|
|
||||||
.pipe(flatten())
|
|
||||||
.pipe(gulp.dest(`${TMP_FOLDER}/Site/_documentation/${VERSION.includes("dev") ? "dev" : VERSION}`))
|
|
||||||
.pipe(tap(function(file){
|
|
||||||
// and another one which just forwards
|
|
||||||
var className = path.basename(file.path, ".md");
|
|
||||||
file.contents = Buffer.from(`---\ntitle: ${className}\nlayout: forward\n---`);
|
|
||||||
}))
|
|
||||||
.pipe(gulp.dest(`${TMP_FOLDER}/Site/_documentation/`));
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("buildJsdocs", ["empty.md"], function(done){
|
|
||||||
glob("../Tone/*/*.js", function(err, files){
|
|
||||||
var docs = child_process.execSync(`./node_modules/.bin/jsdoc -X -a public ${files.join(" ")}`);
|
|
||||||
docs = JSON.parse(docs)
|
|
||||||
//filter out some stuff
|
|
||||||
docs = docs.filter(function(datum){
|
|
||||||
//is public
|
|
||||||
return datum.access !== "private" &&
|
|
||||||
//doesnt inherit
|
|
||||||
(!datum.hasOwnProperty('inherits') || !datum.inherits.startsWith('Tone#')) &&
|
|
||||||
//isnt undocumented (or a default value)
|
|
||||||
(!datum.undocumented || datum.longname.includes('defaults'))
|
|
||||||
});
|
|
||||||
var dest = `${TMP_FOLDER}/Site/_data/jsdocs-${VERSION}.json`;
|
|
||||||
fs.writeFile(dest, JSON.stringify(docs, undefined, '\t'), done);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
gulp.task("commitJSDocs", ["pushJSDocs"], function(){
|
|
||||||
return del([`${TMP_FOLDER}/Site`], { force : true});
|
|
||||||
});
|
|
25
gulp/increment_version.js
Normal file
25
gulp/increment_version.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
const semver = require('semver')
|
||||||
|
const child_process = require('child_process')
|
||||||
|
|
||||||
|
const devVersion = child_process.execSync('npm show tone@next version').toString()
|
||||||
|
const masterVersion = child_process.execSync('npm show tone version').toString()
|
||||||
|
|
||||||
|
//go with whichever is the latest version
|
||||||
|
let version = masterVersion
|
||||||
|
if (semver.gt(devVersion, masterVersion)){
|
||||||
|
version = devVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
version = version.split('.')
|
||||||
|
//increment the patch
|
||||||
|
version[2] = parseInt(version[2]) + 1
|
||||||
|
//put it back in semver
|
||||||
|
version = version.join('.')
|
||||||
|
console.log(`incrementing to version ${version}`)
|
||||||
|
|
||||||
|
//write it to the package.json
|
||||||
|
const packageFile = '../package.json'
|
||||||
|
const package = JSON.parse(fs.readFileSync(packageFile, 'utf-8'))
|
||||||
|
package.version = version
|
||||||
|
fs.writeFileSync(packageFile, JSON.stringify(package, undefined, ' '))
|
123
gulp/package-lock.json
generated
123
gulp/package-lock.json
generated
|
@ -218,11 +218,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
|
||||||
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
"integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
|
||||||
},
|
},
|
||||||
"babylon": {
|
|
||||||
"version": "7.0.0-beta.19",
|
|
||||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.19.tgz",
|
|
||||||
"integrity": "sha512-Vg0C9s/REX6/WIXN37UKpv5ZhRi6A4pjHlpkE34+8/a6c2W1Q692n3hmc+SZG5lKRnaExLUbxtJ1SVT+KaCQ/A=="
|
|
||||||
},
|
|
||||||
"backo2": {
|
"backo2": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
|
||||||
|
@ -389,14 +384,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
|
||||||
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
|
"integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c="
|
||||||
},
|
},
|
||||||
"catharsis": {
|
|
||||||
"version": "0.8.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.9.tgz",
|
|
||||||
"integrity": "sha1-mMyJDKZS3S7w5ws3klMQ/56Q/Is=",
|
|
||||||
"requires": {
|
|
||||||
"underscore-contrib": "0.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"center-align": {
|
"center-align": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
||||||
|
@ -2441,6 +2428,11 @@
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
|
||||||
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "4.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
|
||||||
|
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -3858,39 +3850,12 @@
|
||||||
"esprima": "2.7.3"
|
"esprima": "2.7.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"js2xmlparser": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=",
|
|
||||||
"requires": {
|
|
||||||
"xmlcreate": "1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jsbn": {
|
"jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"jsdoc": {
|
|
||||||
"version": "3.5.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.5.4.tgz",
|
|
||||||
"integrity": "sha512-VmTw0J+2L16IxAe0JSDSAcH0F+DbZxaj8wN1AjHtKMQU/hO0ciIl5ZE93XqrrFIbknobuqHKJCXZj6+Hk57MjA==",
|
|
||||||
"requires": {
|
|
||||||
"babylon": "7.0.0-beta.19",
|
|
||||||
"bluebird": "3.5.0",
|
|
||||||
"catharsis": "0.8.9",
|
|
||||||
"escape-string-regexp": "1.0.5",
|
|
||||||
"js2xmlparser": "3.0.0",
|
|
||||||
"klaw": "2.0.0",
|
|
||||||
"marked": "0.3.6",
|
|
||||||
"mkdirp": "0.5.1",
|
|
||||||
"requizzle": "0.2.1",
|
|
||||||
"strip-json-comments": "2.0.1",
|
|
||||||
"taffydb": "2.6.2",
|
|
||||||
"underscore": "1.8.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"jshint": {
|
"jshint": {
|
||||||
"version": "2.9.5",
|
"version": "2.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz",
|
||||||
|
@ -4101,14 +4066,6 @@
|
||||||
"is-buffer": "1.1.5"
|
"is-buffer": "1.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"klaw": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/klaw/-/klaw-2.0.0.tgz",
|
|
||||||
"integrity": "sha1-WcEo4Nxc5BAgEVEZTuucv4WGUPY=",
|
|
||||||
"requires": {
|
|
||||||
"graceful-fs": "4.1.11"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"lazy-cache": {
|
"lazy-cache": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
|
||||||
|
@ -4462,6 +4419,13 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"readable-stream": "1.0.34",
|
"readable-stream": "1.0.34",
|
||||||
"semver": "4.3.6"
|
"semver": "4.3.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"semver": {
|
||||||
|
"version": "4.3.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
|
||||||
|
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"longest": {
|
"longest": {
|
||||||
|
@ -4511,11 +4475,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz",
|
||||||
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
|
"integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ="
|
||||||
},
|
},
|
||||||
"marked": {
|
|
||||||
"version": "0.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz",
|
|
||||||
"integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc="
|
|
||||||
},
|
|
||||||
"md5-hex": {
|
"md5-hex": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz",
|
||||||
|
@ -4726,7 +4685,7 @@
|
||||||
"requires": {
|
"requires": {
|
||||||
"hosted-git-info": "2.5.0",
|
"hosted-git-info": "2.5.0",
|
||||||
"is-builtin-module": "1.0.0",
|
"is-builtin-module": "1.0.0",
|
||||||
"semver": "4.3.6",
|
"semver": "5.4.1",
|
||||||
"validate-npm-package-license": "3.0.1"
|
"validate-npm-package-license": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -5439,21 +5398,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||||
},
|
},
|
||||||
"requizzle": {
|
|
||||||
"version": "0.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.1.tgz",
|
|
||||||
"integrity": "sha1-aUPDUwxNmn5G8c3dUcFY/GcM294=",
|
|
||||||
"requires": {
|
|
||||||
"underscore": "1.6.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"underscore": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
|
|
||||||
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"resolve": {
|
"resolve": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
|
||||||
|
@ -5574,9 +5518,9 @@
|
||||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "4.3.6",
|
"version": "5.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
|
||||||
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
|
"integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
|
||||||
},
|
},
|
||||||
"sequencify": {
|
"sequencify": {
|
||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
|
@ -5964,21 +5908,11 @@
|
||||||
"get-stdin": "4.0.1"
|
"get-stdin": "4.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"strip-json-comments": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
|
||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
|
||||||
},
|
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||||
},
|
},
|
||||||
"taffydb": {
|
|
||||||
"version": "2.6.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/taffydb/-/taffydb-2.6.2.tgz",
|
|
||||||
"integrity": "sha1-fLy2S1oUG2ou/CxdLGe04VCyomg="
|
|
||||||
},
|
|
||||||
"textextensions": {
|
"textextensions": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/textextensions/-/textextensions-1.0.2.tgz",
|
||||||
|
@ -6119,26 +6053,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
|
||||||
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
|
"integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo="
|
||||||
},
|
},
|
||||||
"underscore": {
|
|
||||||
"version": "1.8.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz",
|
|
||||||
"integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI="
|
|
||||||
},
|
|
||||||
"underscore-contrib": {
|
|
||||||
"version": "0.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore-contrib/-/underscore-contrib-0.3.0.tgz",
|
|
||||||
"integrity": "sha1-ZltmwkeD+PorGMn4y7Dix9SMJsc=",
|
|
||||||
"requires": {
|
|
||||||
"underscore": "1.6.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"underscore": {
|
|
||||||
"version": "1.6.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz",
|
|
||||||
"integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"unique-stream": {
|
"unique-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz",
|
||||||
|
@ -6367,11 +6281,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",
|
||||||
"integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo="
|
"integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo="
|
||||||
},
|
},
|
||||||
"xmlcreate": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8="
|
|
||||||
},
|
|
||||||
"xmlhttprequest-ssl": {
|
"xmlhttprequest-ssl": {
|
||||||
"version": "1.5.3",
|
"version": "1.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
"gulp-tap": "^0.1.3",
|
"gulp-tap": "^0.1.3",
|
||||||
"gulp-uglify": "^2.0.0",
|
"gulp-uglify": "^2.0.0",
|
||||||
"gulp-util": "^3.0.7",
|
"gulp-util": "^3.0.7",
|
||||||
"jsdoc": "^3.4.3",
|
|
||||||
"jshint": "^2.9.4",
|
"jshint": "^2.9.4",
|
||||||
"karma": "^1.7.0",
|
"karma": "^1.7.0",
|
||||||
"karma-chrome-launcher": "^2.2.0",
|
"karma-chrome-launcher": "^2.2.0",
|
||||||
|
@ -35,6 +34,7 @@
|
||||||
"karma-requirejs": "^1.1.0",
|
"karma-requirejs": "^1.1.0",
|
||||||
"mocha": "^3.0.2",
|
"mocha": "^3.0.2",
|
||||||
"requirejs": "^2.1.22",
|
"requirejs": "^2.1.22",
|
||||||
|
"semver": "^5.4.1",
|
||||||
"yargs": "^7.0.2"
|
"yargs": "^7.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
51
gulp/push_build.sh
Executable file
51
gulp/push_build.sh
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TMP_DIR=$(pwd)/tmp
|
||||||
|
mkdir $TMP_DIR
|
||||||
|
|
||||||
|
TONE_DIR=$(pwd)/..
|
||||||
|
|
||||||
|
BUILD_DIR=$TMP_DIR/build
|
||||||
|
|
||||||
|
# clone the build repo
|
||||||
|
if [ "$TRAVIS" = "true" ]; then
|
||||||
|
GITHUB_USER=${GH_TOKEN}@
|
||||||
|
fi
|
||||||
|
|
||||||
|
git clone https://${GITHUB_USER}github.com/Tonejs/build $BUILD_DIR > /dev/null 2>&1
|
||||||
|
cd $BUILD_DIR
|
||||||
|
git checkout gh-pages
|
||||||
|
|
||||||
|
# generate a new build
|
||||||
|
gulp build
|
||||||
|
|
||||||
|
|
||||||
|
# push to the appropriate location
|
||||||
|
if [ "$TRAVIS" = "true" ]; then
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BRANCH" = "dev" ]; then
|
||||||
|
|
||||||
|
# dev builds go into the dev folder
|
||||||
|
cp -a $TONE_DIR/build/. $BUILD_DIR/dev/
|
||||||
|
|
||||||
|
elif [ "$TRAVIS_BRANCH" = "master" ]; then
|
||||||
|
|
||||||
|
# master builds are on the root level folder
|
||||||
|
cp -a $TONE_DIR/build/. $BUILD_DIR/
|
||||||
|
|
||||||
|
# and also in a folder with the version name
|
||||||
|
VERSION=$(node $TONE_DIR/gulp/version.js $TONE_DIR)
|
||||||
|
mkdir $BUILD_DIR/$VERSION
|
||||||
|
cp -a $TONE_DIR/build/. $BUILD_DIR/$VERSION
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# push the build
|
||||||
|
git add .
|
||||||
|
git commit -m "build #$TRAVIS_BUILD_NUMBER: $TRAVIS_COMMIT_MESSAGE"
|
||||||
|
git push -f
|
||||||
|
|
||||||
|
rm -rf $TMP_DIR
|
|
@ -2,11 +2,13 @@
|
||||||
|
|
||||||
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
|
if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
|
||||||
|
|
||||||
# only commit the builds when not a PR
|
# commit the build
|
||||||
gulp commitDevBuild
|
sh push_build.sh
|
||||||
gulp commitJSDocs
|
|
||||||
|
# update the site
|
||||||
|
sh update_site.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# do coveralls either way
|
|
||||||
gulp coveralls
|
# upload coveralls
|
||||||
|
gulp coveralls
|
||||||
|
|
18
gulp/update_site.sh
Executable file
18
gulp/update_site.sh
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
TMP_DIR=$(pwd)/tmp/
|
||||||
|
mkdir $TMP_DIR
|
||||||
|
SITE_DIR=$TMP_DIR/Site
|
||||||
|
|
||||||
|
# clone the tonejs.github.io site
|
||||||
|
if [ "$TRAVIS" = "true" ]; then
|
||||||
|
GITHUB_USER=${GH_TOKEN}@
|
||||||
|
fi
|
||||||
|
|
||||||
|
git clone https://${GITHUB_USER}github.com/Tonejs/tonejs.github.io $SITE_DIR > /dev/null 2>&1
|
||||||
|
|
||||||
|
cd $SITE_DIR
|
||||||
|
# run the update script
|
||||||
|
sh update.sh
|
||||||
|
|
||||||
|
rm -rf $TMP_DIR
|
7
gulp/version.js
Executable file
7
gulp/version.js
Executable file
|
@ -0,0 +1,7 @@
|
||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
|
||||||
|
var VERSION = fs.readFileSync(`${process.argv[2]}/Tone/core/Tone.js`, 'utf-8')
|
||||||
|
.match(/(?:Tone\.version\s*=\s*)(?:'|")(.*)(?:'|");/m)[1];
|
||||||
|
|
||||||
|
console.log(VERSION)
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tone",
|
"name": "tone",
|
||||||
"version": "0.10.0",
|
"version": "0.11.0",
|
||||||
"description": "A Web Audio framework for making interactive music in the browser.",
|
"description": "A Web Audio framework for making interactive music in the browser.",
|
||||||
"main": "build/Tone.js",
|
"main": "build/Tone.js",
|
||||||
"files": [
|
"files": [
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["Tone/component/Analyser", "Test", "helper/Basic", "helper/Supports"],
|
define(["Tone/component/Analyser", "Test", "helper/Basic", "helper/Supports", "Tone/source/Noise"],
|
||||||
function (Analyser, Test, Basic, Supports) {
|
function (Analyser, Test, Basic, Supports, Noise) {
|
||||||
|
|
||||||
describe("Analyser", function(){
|
describe("Analyser", function(){
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ define(["Tone/component/Analyser", "Test", "helper/Basic", "helper/Supports"],
|
||||||
|
|
||||||
it("can run fft analysis", function(){
|
it("can run fft analysis", function(){
|
||||||
var anl = new Analyser("fft", 512);
|
var anl = new Analyser("fft", 512);
|
||||||
analysis = anl.analyse();
|
analysis = anl.getValue();
|
||||||
expect(analysis.length).to.equal(512);
|
expect(analysis.length).to.equal(512);
|
||||||
for (i = 0; i < analysis.length; i++){
|
for (i = 0; i < analysis.length; i++){
|
||||||
expect(analysis[i]).is.lessThan(0);
|
expect(analysis[i]).is.lessThan(0);
|
||||||
|
@ -41,14 +41,22 @@ define(["Tone/component/Analyser", "Test", "helper/Basic", "helper/Supports"],
|
||||||
anl.dispose();
|
anl.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can run waveform analysis", function(){
|
it("can run waveform analysis", function(done){
|
||||||
|
var noise = new Noise();
|
||||||
var anl = new Analyser("waveform", 256);
|
var anl = new Analyser("waveform", 256);
|
||||||
analysis = anl.analyse();
|
noise.connect(anl);
|
||||||
expect(analysis.length).to.equal(256);
|
noise.start();
|
||||||
for (i = 0; i < analysis.length; i++){
|
|
||||||
expect(analysis[i]).is.within(0, 1);
|
setTimeout(function(){
|
||||||
}
|
analysis = anl.getValue();
|
||||||
anl.dispose();
|
expect(analysis.length).to.equal(256);
|
||||||
|
for (i = 0; i < analysis.length; i++){
|
||||||
|
expect(analysis[i]).is.within(-1, 1);
|
||||||
|
}
|
||||||
|
anl.dispose();
|
||||||
|
noise.dispose();
|
||||||
|
done()
|
||||||
|
}, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("throws an error if an invalid type is set", function(){
|
it("throws an error if an invalid type is set", function(){
|
||||||
|
@ -60,4 +68,4 @@ define(["Tone/component/Analyser", "Test", "helper/Basic", "helper/Supports"],
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["Tone/component/Envelope", "helper/Basic", "helper/Offline", "Test",
|
define(["Tone/component/Envelope", "helper/Basic", "helper/Offline", "Test",
|
||||||
"helper/Supports", "helper/PassAudio", "helper/APITest"],
|
"helper/Supports", "helper/PassAudio", "helper/APITest"],
|
||||||
function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
describe("Envelope", function(){
|
describe("Envelope", function(){
|
||||||
|
|
||||||
|
@ -152,10 +152,10 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
env.toMaster();
|
env.toMaster();
|
||||||
env.triggerAttack(0);
|
env.triggerAttack(0);
|
||||||
}, 0.7).then(function(buffer){
|
}, 0.7).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
var target = 1 - (time - 0.2) * 10;
|
var target = 1 - (time - 0.2) * 10;
|
||||||
expect(sample).to.be.closeTo(target, 0.01);
|
expect(sample).to.be.closeTo(target, 0.01);
|
||||||
}, 0.2, 0.2);
|
}, 0.2, 0.2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -228,13 +228,8 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
env.triggerAttack(attackTime);
|
env.triggerAttack(attackTime);
|
||||||
env.triggerRelease(releaseTime);
|
env.triggerRelease(releaseTime);
|
||||||
}, 0.6).then(function(buffer){
|
}, 0.6).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
expect(buffer.getValueAtTime(attackTime - 0.001)).to.equal(0);
|
||||||
if (time < attackTime - 0.001){
|
expect(buffer.getValueAtTime(e.attack + e.decay + releaseTime + e.release)).to.be.below(0.01);
|
||||||
expect(sample).to.equal(0);
|
|
||||||
} else if (time > e.attack + e.decay + releaseTime + e.release){
|
|
||||||
expect(sample).to.equal(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -253,11 +248,8 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
env.triggerAttack(attackTime);
|
env.triggerAttack(attackTime);
|
||||||
}, 0.4).then(function(buffer){
|
}, 0.4).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time < attackTime - 0.001){
|
expect(buffer.getValueAtTime(attackTime - 0.001)).to.equal(0);
|
||||||
expect(sample).to.equal(0);
|
expect(buffer.getValueAtTime(attackTime + e.attack + e.decay)).to.be.below(0.01);
|
||||||
} else if (time > attackTime + e.attack + e.decay){
|
|
||||||
expect(sample).to.equal(0);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -317,7 +309,7 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
} else if (time < duration + e.release){
|
} else if (time < duration + e.release){
|
||||||
expect(sample).to.be.within(0, e.sustain + 0.01);
|
expect(sample).to.be.within(0, e.sustain + 0.01);
|
||||||
} else {
|
} else {
|
||||||
expect(sample).to.be.below(0.001);
|
expect(sample).to.be.below(0.0015);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -375,7 +367,7 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
expect(sample).to.be.below(0.02);
|
expect(sample).to.be.below(0.02);
|
||||||
} else if (time > 0.5 && time < 0.8){
|
} else if (time > 0.5 && time < 0.8){
|
||||||
expect(sample).to.be.above(0);
|
expect(sample).to.be.above(0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -575,7 +567,7 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
env.triggerAttackRelease(0.4, 0.1, 0.5);
|
env.triggerAttackRelease(0.4, 0.1, 0.5);
|
||||||
}, 0.8).then(function(buffer){
|
}, 0.8).then(function(buffer){
|
||||||
buffer.forEach(function(sample){
|
buffer.forEach(function(sample){
|
||||||
expect(sample).to.be.lte(0.5);
|
expect(sample).to.be.at.most(0.51);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -605,4 +597,4 @@ function (Envelope, Basic, Offline, Test, Supports, PassAudio, APITest) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
52
test/component/FFT.js
Normal file
52
test/component/FFT.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
define(["Tone/component/FFT", "Test", "helper/Basic", "helper/Supports", "Tone/source/Noise"],
|
||||||
|
function (FFT, Test, Basic, Supports, Noise) {
|
||||||
|
|
||||||
|
describe("FFT", function(){
|
||||||
|
|
||||||
|
Basic(FFT);
|
||||||
|
|
||||||
|
it("handles input connection", function(){
|
||||||
|
var fft = new FFT();
|
||||||
|
Test.connect(fft);
|
||||||
|
fft.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get and set properties", function(){
|
||||||
|
var fft = new FFT();
|
||||||
|
fft.set({
|
||||||
|
"size" : 128
|
||||||
|
});
|
||||||
|
var values = fft.get();
|
||||||
|
expect(values.size).to.equal(128);
|
||||||
|
fft.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can correctly set the size", function(){
|
||||||
|
var fft = new FFT(512);
|
||||||
|
expect(fft.size).to.equal(512);
|
||||||
|
fft.size = 1024;
|
||||||
|
expect(fft.size).to.equal(1024);
|
||||||
|
fft.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("can run waveform analysis", function(done){
|
||||||
|
var noise = new Noise();
|
||||||
|
var fft = new FFT(256);
|
||||||
|
noise.connect(fft);
|
||||||
|
noise.start();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
analysis = fft.getValue();
|
||||||
|
expect(analysis.length).to.equal(256);
|
||||||
|
for (i = 0; i < analysis.length; i++){
|
||||||
|
expect(analysis[i]).is.within(-200, 0);
|
||||||
|
}
|
||||||
|
fft.dispose();
|
||||||
|
noise.dispose();
|
||||||
|
done()
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
define(["Tone/component/FrequencyEnvelope", "helper/Basic", "helper/Offline", "Test", "Tone/component/Envelope"],
|
define(["Tone/component/FrequencyEnvelope", "helper/Basic", "helper/Offline", "Test", "Tone/component/Envelope"],
|
||||||
function (FrequencyEnvelope, Basic, Offline, Test, Envelope) {
|
function (FrequencyEnvelope, Basic, Offline, Test, Envelope) {
|
||||||
describe("FrequencyEnvelope", function(){
|
describe("FrequencyEnvelope", function(){
|
||||||
|
|
||||||
|
@ -70,11 +70,11 @@ function (FrequencyEnvelope, Basic, Offline, Test, Envelope) {
|
||||||
if (time < e.attack){
|
if (time < e.attack){
|
||||||
expect(sample).to.be.within(200, 1600);
|
expect(sample).to.be.within(200, 1600);
|
||||||
} else if (time < e.attack + e.decay){
|
} else if (time < e.attack + e.decay){
|
||||||
expect(sample).to.be.closeTo(1600, 2);
|
expect(sample).to.be.closeTo(1600, 10);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
define(["Tone/component/Meter", "helper/Basic", "helper/Offline", "Test",
|
define(["Tone/component/Meter", "helper/Basic", "helper/Offline", "Test",
|
||||||
"Tone/signal/Signal", "helper/PassAudio", "Tone/type/Type",
|
"Tone/signal/Signal", "helper/PassAudio", "Tone/type/Type",
|
||||||
"Tone/component/Merge", "Tone/source/Oscillator"],
|
"Tone/component/Merge", "Tone/source/Oscillator"],
|
||||||
function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillator) {
|
function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillator) {
|
||||||
describe("Meter", function(){
|
describe("Meter", function(){
|
||||||
|
|
||||||
|
@ -18,11 +18,9 @@ function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillato
|
||||||
it("handles getter/setter as Object", function(){
|
it("handles getter/setter as Object", function(){
|
||||||
var meter = new Meter();
|
var meter = new Meter();
|
||||||
var values = {
|
var values = {
|
||||||
"type" : "signal",
|
|
||||||
"smoothing" : 0.2
|
"smoothing" : 0.2
|
||||||
};
|
};
|
||||||
meter.set(values);
|
meter.set(values);
|
||||||
expect(meter.get().type).to.equal("signal");
|
|
||||||
expect(meter.get().smoothing).to.equal(0.2);
|
expect(meter.get().smoothing).to.equal(0.2);
|
||||||
meter.dispose();
|
meter.dispose();
|
||||||
});
|
});
|
||||||
|
@ -40,14 +38,14 @@ function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillato
|
||||||
return PassAudio(function(input){
|
return PassAudio(function(input){
|
||||||
meter = new Meter();
|
meter = new Meter();
|
||||||
input.chain(meter, Tone.Master);
|
input.chain(meter, Tone.Master);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("measures the incoming signal", function(done){
|
it("measures the incoming signal", function(done){
|
||||||
var meter = new Meter("signal");
|
var meter = new Meter();
|
||||||
var signal = new Signal(1).connect(meter);
|
var signal = new Signal(1).connect(meter);
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
expect(meter.value).to.be.closeTo(1, 0.05);
|
expect(meter.getValue()).to.be.closeTo(1, 0.05);
|
||||||
meter.dispose();
|
meter.dispose();
|
||||||
signal.dispose();
|
signal.dispose();
|
||||||
done();
|
done();
|
||||||
|
@ -59,7 +57,7 @@ function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillato
|
||||||
var osc = new Oscillator().connect(meter).start();
|
var osc = new Oscillator().connect(meter).start();
|
||||||
osc.volume.value = -6;
|
osc.volume.value = -6;
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
expect(meter.value).to.be.closeTo(1, 0.1);
|
expect(meter.getLevel()).to.be.closeTo(-6, 1);
|
||||||
meter.dispose();
|
meter.dispose();
|
||||||
osc.dispose();
|
osc.dispose();
|
||||||
done();
|
done();
|
||||||
|
@ -67,4 +65,4 @@ function (Meter, Basic, Offline, Test, Signal, PassAudio, Tone, Merge, Oscillato
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
52
test/component/Waveform.js
Normal file
52
test/component/Waveform.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
define(["Tone/component/Waveform", "Test", "helper/Basic", "helper/Supports", "Tone/source/Noise"],
|
||||||
|
function (Waveform, Test, Basic, Supports, Noise) {
|
||||||
|
|
||||||
|
describe("Waveform", function(){
|
||||||
|
|
||||||
|
Basic(Waveform);
|
||||||
|
|
||||||
|
it("handles input connection", function(){
|
||||||
|
var anl = new Waveform();
|
||||||
|
Test.connect(anl);
|
||||||
|
anl.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can get and set properties", function(){
|
||||||
|
var anl = new Waveform();
|
||||||
|
anl.set({
|
||||||
|
"size" : 128
|
||||||
|
});
|
||||||
|
var values = anl.get();
|
||||||
|
expect(values.size).to.equal(128);
|
||||||
|
anl.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can correctly set the size", function(){
|
||||||
|
var anl = new Waveform(512);
|
||||||
|
expect(anl.size).to.equal(512);
|
||||||
|
anl.size = 1024;
|
||||||
|
expect(anl.size).to.equal(1024);
|
||||||
|
anl.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("can run waveform analysis", function(done){
|
||||||
|
var noise = new Noise();
|
||||||
|
var anl = new Waveform(256);
|
||||||
|
noise.connect(anl);
|
||||||
|
noise.start();
|
||||||
|
|
||||||
|
setTimeout(function(){
|
||||||
|
analysis = anl.getValue();
|
||||||
|
expect(analysis.length).to.equal(256);
|
||||||
|
for (i = 0; i < analysis.length; i++){
|
||||||
|
expect(analysis[i]).is.within(-1, 1);
|
||||||
|
}
|
||||||
|
anl.dispose();
|
||||||
|
noise.dispose();
|
||||||
|
done()
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signal/Signal", "Tone/core/Transport"],
|
define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signal/Signal", "Tone/core/Transport"],
|
||||||
function (Basic, Test, Param, Tone, Signal, Transport) {
|
function (Basic, Test, Param, Tone, Signal, Transport) {
|
||||||
|
|
||||||
describe("Param", function(){
|
describe("Param", function(){
|
||||||
|
@ -114,7 +114,7 @@ define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signa
|
||||||
expect(param.value).to.be.closeTo(0, 0.01);
|
expect(param.value).to.be.closeTo(0, 0.01);
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Scheduling API", function(){
|
context("Scheduling API", function(){
|
||||||
|
@ -141,14 +141,14 @@ define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signa
|
||||||
it ("can schedule an exponential ramp", function(){
|
it ("can schedule an exponential ramp", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.exponentialRampToValueAtTime(3, 1);
|
param.exponentialRampToValueAtTime(3, "+1");
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can approach a target value", function(){
|
it ("can approach a target value", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.setTargetAtTime(0.2, 1, 2);
|
param.setTargetAtTime(0.2, "+1", 2);
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -162,30 +162,45 @@ define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signa
|
||||||
it ("can schedule multiple automations", function(){
|
it ("can schedule multiple automations", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.linearRampToValueAtTime(0.5, 0.5);
|
param.linearRampToValueAtTime(0.5, "+0.5");
|
||||||
param.linearRampToValueAtTime(0, 1);
|
param.linearRampToValueAtTime(0, "+1");
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can cancel an automation", function(){
|
it ("can cancel an automation", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.linearRampToValueAtTime(0.5, 0.5);
|
param.linearRampToValueAtTime(0.5, "+0.5");
|
||||||
param.cancelScheduledValues(0);
|
param.cancelScheduledValues(0);
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can cancelAndHold an automation", function(){
|
||||||
|
var gain = Tone.context.createGain();
|
||||||
|
var param = new Param(gain.gain);
|
||||||
|
param.linearRampToValueAtTime(0.5, "+0.5");
|
||||||
|
param.cancelAndHoldAtTime(0);
|
||||||
|
param.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
it ("can set a linear ramp from the current time", function(){
|
it ("can set a linear ramp from the current time", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.linearRampToValue(0.5, 0.5);
|
param.linearRampTo(0.5, 0.5);
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can set an exponential ramp from the current time", function(){
|
it ("can set an exponential ramp from the current time", function(){
|
||||||
var gain = Tone.context.createGain();
|
var gain = Tone.context.createGain();
|
||||||
var param = new Param(gain.gain);
|
var param = new Param(gain.gain);
|
||||||
param.exponentialRampToValue(0.5, 0.5);
|
param.exponentialRampTo(0.5, 0.5);
|
||||||
|
param.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("can set an exponential approach ramp from the current time", function(){
|
||||||
|
var gain = Tone.context.createGain();
|
||||||
|
var param = new Param(gain.gain);
|
||||||
|
param.targetRampTo(0.5, 0.5);
|
||||||
param.dispose();
|
param.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -209,4 +224,4 @@ define(["helper/Basic", "Test", "Tone/core/Param", "Tone/type/Type", "Tone/signa
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -126,7 +126,7 @@ define(["Test", "Tone/core/Timeline"], function (Test, Timeline) {
|
||||||
sched.dispose();
|
sched.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it ("can get the scheduled event at the given time", function(){
|
it ("can get the scheduled event at the given time", function(){
|
||||||
var sched = new Timeline();
|
var sched = new Timeline();
|
||||||
sched.add({
|
sched.add({
|
||||||
|
@ -261,7 +261,7 @@ define(["Test", "Tone/core/Timeline"], function (Test, Timeline) {
|
||||||
sched.dispose();
|
sched.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
it ("has no problem with many items", function(){
|
it ("has no problem with many items", function(){
|
||||||
var sched = new Timeline();
|
var sched = new Timeline();
|
||||||
|
@ -528,6 +528,26 @@ define(["Test", "Tone/core/Timeline"], function (Test, Timeline) {
|
||||||
expect(sched.length).to.equal(0);
|
expect(sched.length).to.equal(0);
|
||||||
sched.dispose();
|
sched.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("can add items during iteration", function(){
|
||||||
|
var sched = new Timeline();
|
||||||
|
for (var i = 0; i < 1000; i++){
|
||||||
|
sched.add({"time" : i});
|
||||||
|
}
|
||||||
|
var added = false;
|
||||||
|
sched.forEach(function(event){
|
||||||
|
if (!added){
|
||||||
|
added = true;
|
||||||
|
sched.add({
|
||||||
|
"time" : 10,
|
||||||
|
"added" : true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
expect(sched.length).to.equal(1001);
|
||||||
|
sched.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -178,7 +178,7 @@ define(["Test", "Tone/core/Tone", "helper/PassAudio", "Tone/source/Oscillator",
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Tone.setContext", function(){
|
context("Tone.context", function(){
|
||||||
|
|
||||||
it ("can set a new context", function(){
|
it ("can set a new context", function(){
|
||||||
var origCtx = Tone.context;
|
var origCtx = Tone.context;
|
||||||
|
@ -207,6 +207,19 @@ define(["Test", "Tone/core/Tone", "helper/PassAudio", "Tone/source/Oscillator",
|
||||||
return ctx.close();
|
return ctx.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("tests if the audio context time has passed", function(){
|
||||||
|
// overwrite warn to throw errors
|
||||||
|
var originalWarn = console.warn;
|
||||||
|
console.warn = function(warning){
|
||||||
|
throw new Error(warning);
|
||||||
|
};
|
||||||
|
var currentTime = Tone.context.currentTime;
|
||||||
|
expect(function(){
|
||||||
|
Tone.isPast(currentTime-1);
|
||||||
|
}).to.throw(Error);
|
||||||
|
console.warn = originalWarn;
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Tone.prototype.set / get", function(){
|
context("Tone.prototype.set / get", function(){
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["Test", "Tone/core/Transport", "Tone/core/Tone", "helper/Offline",
|
define(["Test", "Tone/core/Transport", "Tone/core/Tone", "helper/Offline",
|
||||||
"Tone/type/TransportTime", "Tone/signal/Signal", "helper/BufferTest"],
|
"Tone/type/TransportTime", "Tone/signal/Signal", "helper/BufferTest"],
|
||||||
function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
|
|
||||||
describe("Transport", function(){
|
describe("Transport", function(){
|
||||||
|
@ -230,7 +230,7 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
context("state", function(){
|
context("state", function(){
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
it("resets ticks on stop but not on pause", function(){
|
it("resets ticks on stop but not on pause", function(){
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
Transport.start(0).pause(0.1).stop(0.2);
|
Transport.start(0).pause(0.1).stop(0.2);
|
||||||
|
|
||||||
var pausedTicks = 0;
|
var pausedTicks = 0;
|
||||||
|
|
||||||
return function(time){
|
return function(time){
|
||||||
|
@ -363,10 +363,10 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
}, 0.6);
|
}, 0.6);
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
context("schedule", function(){
|
||||||
|
|
||||||
context("schedule", function(){
|
|
||||||
|
|
||||||
it ("can schedule an event on the timeline", function(){
|
it ("can schedule an event on the timeline", function(){
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var eventID = Transport.schedule(function(){}, 0);
|
var eventID = Transport.schedule(function(){}, 0);
|
||||||
|
@ -376,24 +376,32 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
|
|
||||||
|
|
||||||
it ("scheduled event gets invoked with the time of the event", function(){
|
it ("scheduled event gets invoked with the time of the event", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var startTime = 0.1;
|
var startTime = 0.1;
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
expect(time).to.be.closeTo(startTime, 0.01);
|
expect(time).to.be.closeTo(startTime, 0.01);
|
||||||
|
wasCalled = true;
|
||||||
}, 0);
|
}, 0);
|
||||||
Transport.start(startTime);
|
Transport.start(startTime);
|
||||||
}, 0.2);
|
}, 0.2).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can schedule events with TransportTime", function(){
|
it ("can schedule events with TransportTime", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var startTime = 0.1;
|
var startTime = 0.1;
|
||||||
var eighth = Transport.toSeconds("8n");
|
var eighth = Transport.toSeconds("8n");
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
expect(time).to.be.closeTo(startTime + eighth, 0.01);
|
expect(time).to.be.closeTo(startTime + eighth, 0.01);
|
||||||
|
wasCalled = true;
|
||||||
}, TransportTime("8n"));
|
}, TransportTime("8n"));
|
||||||
Transport.start(startTime);
|
Transport.start(startTime);
|
||||||
}, 0.5);
|
}, 0.5).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can cancel a scheduled event", function(){
|
it ("can cancel a scheduled event", function(){
|
||||||
|
@ -401,7 +409,7 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
var eventID = Transport.schedule(function(){
|
var eventID = Transport.schedule(function(){
|
||||||
throw new Error("should not call this function");
|
throw new Error("should not call this function");
|
||||||
}, 0);
|
}, 0);
|
||||||
Transport.cancel(eventID);
|
Transport.clear(eventID);
|
||||||
Transport.start();
|
Transport.start();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -424,25 +432,30 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
Transport.scheduleOnce(Tone.noOp, 0);
|
Transport.scheduleOnce(Tone.noOp, 0);
|
||||||
Transport.scheduleOnce(Tone.noOp, 1);
|
Transport.scheduleOnce(Tone.noOp, 1);
|
||||||
Transport.scheduleOnce(Tone.noOp, 2);
|
Transport.scheduleOnce(Tone.noOp, 2);
|
||||||
expect(Transport._onceEvents.length).to.equal(3);
|
expect(Transport._timeline.length).to.equal(3);
|
||||||
Transport.cancel(2);
|
Transport.cancel(2);
|
||||||
expect(Transport._onceEvents.length).to.equal(2);
|
expect(Transport._timeline.length).to.equal(2);
|
||||||
Transport.cancel(0);
|
Transport.cancel(0);
|
||||||
expect(Transport._onceEvents.length).to.equal(0);
|
expect(Transport._timeline.length).to.equal(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("scheduled event anywhere along the timeline", function(){
|
it ("scheduled event anywhere along the timeline", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var startTime = Transport.now();
|
var startTime = Transport.now();
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
expect(time).to.be.closeTo(startTime + 0.5, 0.001);
|
expect(time).to.be.closeTo(startTime + 0.5, 0.001);
|
||||||
|
wasCalled = true;
|
||||||
}, 0.5);
|
}, 0.5);
|
||||||
Transport.start(startTime);
|
Transport.start(startTime);
|
||||||
}, 0.6);
|
}, 0.6).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can schedule multiple events and invoke them in the right order", function(){
|
it ("can schedule multiple events and invoke them in the right order", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var first = false;
|
var first = false;
|
||||||
Transport.schedule(function(){
|
Transport.schedule(function(){
|
||||||
|
@ -450,9 +463,12 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
}, 0.1);
|
}, 0.1);
|
||||||
Transport.schedule(function(){
|
Transport.schedule(function(){
|
||||||
expect(first).to.be.true;
|
expect(first).to.be.true;
|
||||||
|
wasCalled = true;
|
||||||
}, 0.11);
|
}, 0.11);
|
||||||
Tone.Transport.start();
|
Tone.Transport.start();
|
||||||
}, 0.2);
|
}, 0.2).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("invokes the event again if the timeline is restarted", function(){
|
it ("invokes the event again if the timeline is restarted", function(){
|
||||||
|
@ -467,9 +483,27 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can add an event after the Transport is started", function(){
|
||||||
|
var wasCalled = false;
|
||||||
|
return Offline(function(Transport){
|
||||||
|
Transport.start(0);
|
||||||
|
var wasScheduled = false;
|
||||||
|
return function(time){
|
||||||
|
if (time > 0.1 && !wasScheduled){
|
||||||
|
wasScheduled = true;
|
||||||
|
Transport.schedule(function(){
|
||||||
|
wasCalled = true;
|
||||||
|
}, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0.3).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("scheduleRepeat", function(){
|
context("scheduleRepeat", function(){
|
||||||
|
|
||||||
it ("can schedule a repeated event", function(){
|
it ("can schedule a repeated event", function(){
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
|
@ -483,7 +517,6 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var startTime = 0.1;
|
var startTime = 0.1;
|
||||||
var eventID = Transport.scheduleRepeat(function(time){
|
var eventID = Transport.scheduleRepeat(function(time){
|
||||||
Transport.clear(eventID);
|
|
||||||
expect(time).to.be.closeTo(startTime, 0.01);
|
expect(time).to.be.closeTo(startTime, 0.01);
|
||||||
invoked = true;
|
invoked = true;
|
||||||
}, 1, 0);
|
}, 1, 0);
|
||||||
|
@ -546,6 +579,7 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("repeats at the repeat interval", function(){
|
it ("repeats at the repeat interval", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var repeatTime = -1;
|
var repeatTime = -1;
|
||||||
Transport.scheduleRepeat(function(time){
|
Transport.scheduleRepeat(function(time){
|
||||||
|
@ -553,9 +587,12 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
expect(time - repeatTime).to.be.closeTo(0.1, 0.01);
|
expect(time - repeatTime).to.be.closeTo(0.1, 0.01);
|
||||||
}
|
}
|
||||||
repeatTime = time;
|
repeatTime = time;
|
||||||
|
wasCalled = true;
|
||||||
}, 0.1, 0);
|
}, 0.1, 0);
|
||||||
Transport.start();
|
Transport.start();
|
||||||
}, 0.5);
|
}, 0.5).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can schedule multiple events and invoke them in the right order", function(){
|
it ("can schedule multiple events and invoke them in the right order", function(){
|
||||||
|
@ -578,18 +615,10 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("cannot schedule an event with an interval of 0", function(){
|
|
||||||
return Offline(function(Transport){
|
|
||||||
expect(function(){
|
|
||||||
Transport.scheduleRepeat(function(){}, 0, 10);
|
|
||||||
}).to.throw(Error);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it ("repeats for the given interval", function(){
|
it ("repeats for the given interval", function(){
|
||||||
var repeatCount = 0;
|
var repeatCount = 0;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
Transport.scheduleRepeat(function(){
|
Transport.scheduleRepeat(function(time){
|
||||||
repeatCount++;
|
repeatCount++;
|
||||||
}, 0.1, 0, 0.5);
|
}, 0.1, 0, 0.5);
|
||||||
Transport.start();
|
Transport.start();
|
||||||
|
@ -598,9 +627,49 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can add an event after the Transport is started", function(){
|
||||||
|
var invocations = 0;
|
||||||
|
return Offline(function(Transport){
|
||||||
|
Transport.start(0);
|
||||||
|
var wasScheduled = false;
|
||||||
|
var times = [0.15, 0.3]
|
||||||
|
return function(time){
|
||||||
|
if (time > 0.1 && !wasScheduled){
|
||||||
|
wasScheduled = true;
|
||||||
|
Transport.scheduleRepeat(function(time){
|
||||||
|
expect(time).to.be.closeTo(times[invocations], 0.01);
|
||||||
|
invocations++;
|
||||||
|
}, 0.15, 0.15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0.31).then(function(){
|
||||||
|
expect(invocations).to.equal(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("can add an event to the past after the Transport is started", function(){
|
||||||
|
var invocations = 0;
|
||||||
|
return Offline(function(Transport){
|
||||||
|
Transport.start(0);
|
||||||
|
var wasScheduled = false;
|
||||||
|
var times = [0.15, 0.25]
|
||||||
|
return function(time){
|
||||||
|
if (time >= 0.12 && !wasScheduled){
|
||||||
|
wasScheduled = true;
|
||||||
|
Transport.scheduleRepeat(function(time){
|
||||||
|
expect(time).to.be.closeTo(times[invocations], 0.01);
|
||||||
|
invocations++;
|
||||||
|
}, 0.1, 0.05);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0.3).then(function(){
|
||||||
|
expect(invocations).to.equal(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("scheduleOnce", function(){
|
context("scheduleOnce", function(){
|
||||||
|
|
||||||
it ("can schedule a single event on the timeline", function(){
|
it ("can schedule a single event on the timeline", function(){
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
|
@ -683,25 +752,29 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
context("events", function(){
|
context("events", function(){
|
||||||
|
|
||||||
it("invokes start/stop/pause events", function(){
|
it("invokes start/stop/pause events", function(){
|
||||||
var invokations = 0;
|
var invocations = 0;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
Tone.Transport.on("start pause stop", function(){
|
Tone.Transport.on("start pause stop", function(){
|
||||||
invokations++;
|
invocations++;
|
||||||
});
|
});
|
||||||
Transport.start().stop(0.1).start(0.2);
|
Transport.start().stop(0.1).start(0.2);
|
||||||
}, 0.5).then(function(){
|
}, 0.5).then(function(){
|
||||||
expect(invokations).to.equal(3);
|
expect(invocations).to.equal(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("invokes start event with correct offset", function(){
|
it("invokes start event with correct offset", function(){
|
||||||
|
var wasCalled = false;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
Transport.on("start", function(time, offset){
|
Transport.on("start", function(time, offset){
|
||||||
expect(time).to.be.closeTo(0.2, 0.01);
|
expect(time).to.be.closeTo(0.2, 0.01);
|
||||||
expect(offset).to.be.closeTo(0.5, 0.001);
|
expect(offset).to.be.closeTo(0.5, 0.001);
|
||||||
|
wasCalled = true;
|
||||||
});
|
});
|
||||||
Transport.start(0.2, "4n");
|
Transport.start(0.2, "4n");
|
||||||
}, 0.3);
|
}, 0.3).then(function(){
|
||||||
|
expect(wasCalled).to.be.true;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("invokes the event just before the scheduled time", function(){
|
it("invokes the event just before the scheduled time", function(){
|
||||||
|
@ -719,20 +792,20 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes in the time argument to the events", function(){
|
it("passes in the time argument to the events", function(){
|
||||||
var invokations = 0;
|
var invocations = 0;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
var now = Transport.now();
|
var now = Transport.now();
|
||||||
Transport.on("start", function(time){
|
Transport.on("start", function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).to.be.closeTo(now + 0.1, 0.01);
|
expect(time).to.be.closeTo(now + 0.1, 0.01);
|
||||||
});
|
});
|
||||||
Transport.on("stop", function(time){
|
Transport.on("stop", function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).to.be.closeTo(now + 0.2, 0.01);
|
expect(time).to.be.closeTo(now + 0.2, 0.01);
|
||||||
});
|
});
|
||||||
Transport.start("+0.1").stop("+0.2");
|
Transport.start("+0.1").stop("+0.2");
|
||||||
}, 0.3).then(function(){
|
}, 0.3).then(function(){
|
||||||
expect(invokations).to.equal(2);
|
expect(invocations).to.equal(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -778,37 +851,37 @@ function (Test, Transport, Tone, Offline, TransportTime, Signal, BufferTest) {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can swing", function(){
|
it("can swing", function(){
|
||||||
var invokations = 0;
|
var invocations = 0;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
Transport.swing = 1;
|
Transport.swing = 1;
|
||||||
Transport.swingSubdivision = "8n";
|
Transport.swingSubdivision = "8n";
|
||||||
var eightNote = Transport.toSeconds("8n");
|
var eightNote = Transport.toSeconds("8n");
|
||||||
//downbeat, no swing
|
//downbeat, no swing
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).is.closeTo(0, 0.001);
|
expect(time).is.closeTo(0, 0.001);
|
||||||
}, 0);
|
}, 0);
|
||||||
//eighth note has swing
|
//eighth note has swing
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).is.closeTo(eightNote * 5/3, 0.001);
|
expect(time).is.closeTo(eightNote * 5/3, 0.001);
|
||||||
}, "8n");
|
}, "8n");
|
||||||
//sixteenth note is also swung
|
//sixteenth note is also swung
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).is.closeTo(eightNote, 0.05);
|
expect(time).is.closeTo(eightNote, 0.05);
|
||||||
}, "16n");
|
}, "16n");
|
||||||
//no swing on the quarter
|
//no swing on the quarter
|
||||||
Transport.schedule(function(time){
|
Transport.schedule(function(time){
|
||||||
invokations++;
|
invocations++;
|
||||||
expect(time).is.closeTo(eightNote * 2, 0.001);
|
expect(time).is.closeTo(eightNote * 2, 0.001);
|
||||||
}, "4n");
|
}, "4n");
|
||||||
Transport.start(0).stop(0.7);
|
Transport.start(0).stop(0.7);
|
||||||
}, 0.7).then(function(){
|
}, 0.7).then(function(){
|
||||||
expect(invokations).to.equal(4);
|
expect(invocations).to.equal(4);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
26
test/core/TransportEvent.js
Normal file
26
test/core/TransportEvent.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
define(["Test", "Tone/core/TransportEvent", "Tone/core/Tone", "helper/Offline", "helper/PassAudio", "Tone/source/Oscillator", "Tone/core/AudioNode"],
|
||||||
|
function (Test, TransportEvent, Tone, Offline, PassAudio, Oscillator, AudioNode) {
|
||||||
|
|
||||||
|
describe("TransportEvent", function(){
|
||||||
|
|
||||||
|
it ("can be created and disposed", function(){
|
||||||
|
return Offline(function(Transport){
|
||||||
|
var event = new TransportEvent(Transport, {
|
||||||
|
"time" : 0
|
||||||
|
});
|
||||||
|
event.dispose();
|
||||||
|
Test.wasDisposed(event);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("generates a unique event ID", function(){
|
||||||
|
return Offline(function(Transport){
|
||||||
|
var event = new TransportEvent(Transport, {
|
||||||
|
"time" : 0
|
||||||
|
});
|
||||||
|
expect(event.id).to.be.a('number');
|
||||||
|
event.dispose();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
37
test/core/TransportRepeatEvent.js
Normal file
37
test/core/TransportRepeatEvent.js
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
define(["Test", "Tone/core/TransportRepeatEvent", "Tone/core/Tone", "helper/Offline", "helper/PassAudio", "Tone/source/Oscillator", "Tone/core/AudioNode"],
|
||||||
|
function (Test, TransportRepeatEvent, Tone, Offline, PassAudio, Oscillator, AudioNode) {
|
||||||
|
|
||||||
|
describe("TransportRepeatEvent", function(){
|
||||||
|
|
||||||
|
it ("can be created and disposed", function(){
|
||||||
|
return Offline(function(Transport){
|
||||||
|
var event = new TransportRepeatEvent(Transport, {
|
||||||
|
"time" : 0
|
||||||
|
});
|
||||||
|
event.dispose();
|
||||||
|
Test.wasDisposed(event);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("generates a unique event ID", function(){
|
||||||
|
return Offline(function(Transport){
|
||||||
|
var event = new TransportRepeatEvent(Transport, {
|
||||||
|
"time" : 0
|
||||||
|
});
|
||||||
|
expect(event.id).to.be.a('number');
|
||||||
|
event.dispose();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("is removed from the Transport when disposed", function(){
|
||||||
|
return Offline(function(Transport){
|
||||||
|
var event = new TransportRepeatEvent(Transport, {
|
||||||
|
"time" : 0
|
||||||
|
});
|
||||||
|
event.dispose();
|
||||||
|
expect(Transport._timeline.length).to.equal(0);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,5 +1,5 @@
|
||||||
define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
"Tone/core/Transport", "Tone/event/Event", "helper/Offline", "Test"],
|
"Tone/core/Transport", "Tone/event/Event", "helper/Offline", "Test"],
|
||||||
function (Basic, Part, Tone, Transport, Event, Offline, Test) {
|
function (Basic, Part, Tone, Transport, Event, Offline, Test) {
|
||||||
|
|
||||||
describe("Part", function(){
|
describe("Part", function(){
|
||||||
|
@ -210,7 +210,7 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
//loop duration is the same
|
//loop duration is the same
|
||||||
expect(firstEvent.loopEnd).to.equal("1m");
|
expect(firstEvent.loopEnd).to.equal("1m");
|
||||||
expect(firstEvent.loopStart).to.equal("4n");
|
expect(firstEvent.loopStart).to.equal("4n");
|
||||||
|
|
||||||
var secondEvent = part.at(0.3);
|
var secondEvent = part.at(0.3);
|
||||||
expect(secondEvent.humanize).to.equal(0.1);
|
expect(secondEvent.humanize).to.equal(0.1);
|
||||||
expect(secondEvent.probability).to.equal(0.2);
|
expect(secondEvent.probability).to.equal(0.2);
|
||||||
|
@ -412,7 +412,7 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Looping", function(){
|
context("Looping", function(){
|
||||||
|
|
||||||
it ("can be set to loop", function(){
|
it ("can be set to loop", function(){
|
||||||
|
@ -462,20 +462,20 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
"loopEnd" : 0.5,
|
"loopEnd" : 0.5,
|
||||||
"loop" : true,
|
"loop" : true,
|
||||||
"callback" : function(time, value){
|
"callback" : function(time, value){
|
||||||
if (value === 1){
|
if (value === 1 && !switched){
|
||||||
switched = true;
|
switched = true;
|
||||||
part.loopEnd = 0.2;
|
part.loopEnd = 0.2;
|
||||||
} else if (switched){
|
} else if (switched){
|
||||||
expect(value).to.equal(0);
|
expect(value).to.equal(0);
|
||||||
invoked = true;
|
invoked = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events : [[0, 0], [0.25, 1]]
|
events : [[0, 0], [0.25, 1]]
|
||||||
}).start(0);
|
}).start(0);
|
||||||
Transport.start();
|
Transport.start();
|
||||||
}, 0.7).then(function(){
|
}, 0.7).then(function(){
|
||||||
expect(invoked).to.be.true;
|
expect(invoked).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("a started part will be stopped if it is before the loopStart", function(){
|
it ("a started part will be stopped if it is before the loopStart", function(){
|
||||||
|
@ -492,7 +492,7 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
} else if (switched){
|
} else if (switched){
|
||||||
expect(value).to.equal(1);
|
expect(value).to.equal(1);
|
||||||
invoked = true;
|
invoked = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events : [[0, 0], [0.25, 1]]
|
events : [[0, 0], [0.25, 1]]
|
||||||
}).start(0);
|
}).start(0);
|
||||||
|
@ -502,7 +502,7 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it ("can loop a specific number of times", function(){
|
it ("can loop a specific number of times", function(){
|
||||||
var callCount = 0;
|
var callCount = 0;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
|
@ -582,7 +582,7 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
part.loopEnd = 0.3;
|
part.loopEnd = 0.3;
|
||||||
Transport.start(0.2).stop(0.61).start(0.8);
|
Transport.start(0.2).stop(0.61).start(0.8);
|
||||||
}, 2).then(function(){
|
}, 2).then(function(){
|
||||||
expect(eventTimeIndex).to.equal(7);
|
expect(eventTimeIndex).to.equal(8);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -710,4 +710,4 @@ define(["helper/Basic", "Tone/event/Part", "Tone/core/Tone",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(["Test", "Tone/type/Type", "Tone/core/Transport", "Tone/type/Time", "Tone/type/Frequency"],
|
define(["Test", "Tone/type/Type", "Tone/core/Transport", "Tone/type/Time", "Tone/type/Frequency"],
|
||||||
function (Test, Type, Transport, Time, Frequency) {
|
function (Test, Type, Transport, Time, Frequency) {
|
||||||
|
|
||||||
//modified from http://stackoverflow.com/questions/15298912/javascript-generating-combinations-from-n-arrays-with-m-elements
|
//modified from http://stackoverflow.com/questions/15298912/javascript-generating-combinations-from-n-arrays-with-m-elements
|
||||||
|
@ -67,26 +67,37 @@ function (Test, Type, Transport, Time, Frequency) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function silenceWarning(cb){
|
||||||
|
var warning = console.warn;
|
||||||
|
console.warn = function(){};
|
||||||
|
cb();
|
||||||
|
console.warn = warning;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
method : function(constructor, fn, args, consArgs){
|
method : function(constructor, fn, args, consArgs){
|
||||||
|
|
||||||
it (fn+" ("+args.join(", ") + ")", function(){
|
it (fn+" ("+args.join(", ") + ")", function(){
|
||||||
var permutations = generateArgs(args);
|
silenceWarning(function(){
|
||||||
for (var i = 0; i < permutations.length; i++){
|
var permutations = generateArgs(args);
|
||||||
var instance = new constructor(consArgs);
|
for (var i = 0; i < permutations.length; i++){
|
||||||
instance[fn].apply(instance, permutations[i]);
|
var instance = new constructor(consArgs);
|
||||||
instance.dispose();
|
instance[fn].apply(instance, permutations[i]);
|
||||||
}
|
instance.dispose();
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
member : function(constructor, member, param, consArgs){
|
member : function(constructor, member, param, consArgs){
|
||||||
it (member+" = "+param, function(){
|
it (member+" = "+param, function(){
|
||||||
var permutations = generateArgs([param]);
|
silenceWarning(function(){
|
||||||
for (var i = 0; i < permutations.length; i++){
|
var permutations = generateArgs([param]);
|
||||||
var instance = new constructor(consArgs);
|
for (var i = 0; i < permutations.length; i++){
|
||||||
instance[member] = permutations[i];
|
var instance = new constructor(consArgs);
|
||||||
instance.dispose();
|
instance[member] = permutations[i];
|
||||||
}
|
instance.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
constructor : function(constructor, args){
|
constructor : function(constructor, args){
|
||||||
|
@ -99,15 +110,17 @@ function (Test, Type, Transport, Time, Frequency) {
|
||||||
}
|
}
|
||||||
|
|
||||||
it ("constructor ( "+ argString + " )", function(){
|
it ("constructor ( "+ argString + " )", function(){
|
||||||
var permutations = generateArgs(args);
|
silenceWarning(function(){
|
||||||
for (var i = 0; i < permutations.length; i++){
|
var permutations = generateArgs(args);
|
||||||
var Temp = function(){}; // temporary constructor
|
for (var i = 0; i < permutations.length; i++){
|
||||||
Temp.prototype = constructor.prototype;
|
var Temp = function(){}; // temporary constructor
|
||||||
var tmpInst = new Temp();
|
Temp.prototype = constructor.prototype;
|
||||||
constructor.apply(tmpInst, permutations[i]);
|
var tmpInst = new Temp();
|
||||||
tmpInst.dispose();
|
constructor.apply(tmpInst, permutations[i]);
|
||||||
}
|
tmpInst.dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
"helper/PassAudioStereo", "Test", "helper/Offline", "Tone/signal/Signal", "Tone/component/Merge"],
|
"helper/PassAudioStereo", "Test", "helper/Offline", "Tone/signal/Signal", "Tone/component/Merge"],
|
||||||
function (OutputAudio, Effect, PassAudio, PassAudioStereo, Test, Offline, Signal, Merge) {
|
function (OutputAudio, Effect, PassAudio, PassAudioStereo, Test, Offline, Signal, Merge) {
|
||||||
|
|
||||||
return function(Constr, args, before){
|
return function(Constr, args, before){
|
||||||
|
@ -55,7 +55,7 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
input.connect(instance);
|
input.connect(instance);
|
||||||
instance.toMaster();
|
instance.toMaster();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("passes audio in both channels", function(){
|
it("passes audio in both channels", function(){
|
||||||
return PassAudioStereo(function(input){
|
return PassAudioStereo(function(input){
|
||||||
|
@ -66,7 +66,7 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
input.connect(instance);
|
input.connect(instance);
|
||||||
instance.toMaster();
|
instance.toMaster();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can pass 100% dry signal", function(){
|
it("can pass 100% dry signal", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -78,8 +78,8 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
var signalL = new Signal(-1).connect(merge.left);
|
var signalL = new Signal(-1).connect(merge.left);
|
||||||
var signalR = new Signal(1).connect(merge.right);
|
var signalR = new Signal(1).connect(merge.right);
|
||||||
//make the signals ramp
|
//make the signals ramp
|
||||||
signalL.linearRampToValue(1, 1);
|
signalL.linearRampTo(1, 1);
|
||||||
signalR.linearRampToValue(-1, 1);
|
signalR.linearRampTo(-1, 1);
|
||||||
instance.wet.value = 0;
|
instance.wet.value = 0;
|
||||||
}, 0.5, 2).then(function(buffer){
|
}, 0.5, 2).then(function(buffer){
|
||||||
buffer.forEach(function(L, R, time){
|
buffer.forEach(function(L, R, time){
|
||||||
|
@ -89,7 +89,7 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
expect(R).to.be.closeTo(rightValue, 0.001);
|
expect(R).to.be.closeTo(rightValue, 0.001);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("effects the incoming signal", function(){
|
it("effects the incoming signal", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -101,8 +101,8 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
var signalL = new Signal(-1).connect(merge.left);
|
var signalL = new Signal(-1).connect(merge.left);
|
||||||
var signalR = new Signal(1).connect(merge.right);
|
var signalR = new Signal(1).connect(merge.right);
|
||||||
//make the signals ramp
|
//make the signals ramp
|
||||||
signalL.linearRampToValue(1, 1);
|
signalL.linearRampTo(1, 1);
|
||||||
signalR.linearRampToValue(-1, 1);
|
signalR.linearRampTo(-1, 1);
|
||||||
if (instance.start){
|
if (instance.start){
|
||||||
instance.start();
|
instance.start();
|
||||||
}
|
}
|
||||||
|
@ -114,14 +114,14 @@ define(["helper/OutputAudio", "Tone/effect/Effect", "helper/PassAudio",
|
||||||
leftEffected = true;
|
leftEffected = true;
|
||||||
}
|
}
|
||||||
if (Math.abs(R - rightValue) > 0.01){
|
if (Math.abs(R - rightValue) > 0.01){
|
||||||
rightEffected = true;
|
rightEffected = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
expect(leftEffected).to.be.true;
|
expect(leftEffected).to.be.true;
|
||||||
expect(rightEffected).to.be.true;
|
expect(rightEffected).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["Tone/instrument/PolySynth", "helper/Basic", "helper/InstrumentTests", "helper/OutputAudioStereo",
|
define(["Tone/instrument/PolySynth", "helper/Basic", "helper/InstrumentTests", "helper/OutputAudioStereo",
|
||||||
"Tone/instrument/Instrument", "Test", "helper/OutputAudio", "Tone/instrument/MonoSynth", "helper/Offline"],
|
"Tone/instrument/Instrument", "Test", "helper/OutputAudio", "Tone/instrument/MonoSynth", "helper/Offline"],
|
||||||
function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test, OutputAudio, MonoSynth, Offline) {
|
function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test, OutputAudio, MonoSynth, Offline) {
|
||||||
|
|
||||||
describe("PolySynth", function(){
|
describe("PolySynth", function(){
|
||||||
|
@ -27,7 +27,7 @@ function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test
|
||||||
polySynth.toMaster();
|
polySynth.toMaster();
|
||||||
polySynth.triggerAttackRelease(["C4", "D4"], [0.1, 0.2]);
|
polySynth.triggerAttackRelease(["C4", "D4"], [0.1, 0.2]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("triggerAttack and triggerRelease can be invoked without arrays", function(){
|
it("triggerAttack and triggerRelease can be invoked without arrays", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -38,9 +38,9 @@ function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test
|
||||||
polySynth.triggerRelease("C4", 0.1);
|
polySynth.triggerRelease("C4", 0.1);
|
||||||
}, 0.3).then(function(buffer){
|
}, 0.3).then(function(buffer){
|
||||||
expect(buffer.getFirstSoundTime()).to.be.closeTo(0, 0.01);
|
expect(buffer.getFirstSoundTime()).to.be.closeTo(0, 0.01);
|
||||||
expect(buffer.getLastSoundTime()).to.be.closeTo(0.2, 0.01);
|
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(0, 0.01);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can stop all of the currently playing sounds", function(){
|
it("can stop all of the currently playing sounds", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -51,9 +51,9 @@ function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test
|
||||||
polySynth.releaseAll(0.1);
|
polySynth.releaseAll(0.1);
|
||||||
}, 0.3).then(function(buffer){
|
}, 0.3).then(function(buffer){
|
||||||
expect(buffer.getFirstSoundTime()).to.be.closeTo(0, 0.01);
|
expect(buffer.getFirstSoundTime()).to.be.closeTo(0, 0.01);
|
||||||
expect(buffer.getLastSoundTime()).to.be.closeTo(0.2, 0.01);
|
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(0, 0.01);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("is silent before being triggered", function(){
|
it("is silent before being triggered", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -62,7 +62,7 @@ function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test
|
||||||
}).then(function(buffer){
|
}).then(function(buffer){
|
||||||
expect(buffer.isSilent()).to.be.true;
|
expect(buffer.isSilent()).to.be.true;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can be scheduled to start in the future", function(){
|
it("can be scheduled to start in the future", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -116,4 +116,4 @@ function (PolySynth, Basic, InstrumentTests, OutputAudioStereo, Instrument, Test
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
"Tone/type/Type", "Tone/core/Transport", "Tone/component/LFO", "helper/ConstantOutput"],
|
"Tone/type/Type", "Tone/core/Transport", "Tone/component/LFO", "helper/ConstantOutput"],
|
||||||
function (Offline, Basic, Test, Signal, Tone, Transport, LFO, ConstantOutput) {
|
function (Offline, Basic, Test, Signal, Tone, Transport, LFO, ConstantOutput) {
|
||||||
|
|
||||||
describe("Signal", function(){
|
describe("Signal", function(){
|
||||||
|
@ -77,13 +77,13 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
|
|
||||||
it ("can schedule an exponential ramp", function(){
|
it ("can schedule an exponential ramp", function(){
|
||||||
var sig = new Signal(1);
|
var sig = new Signal(1);
|
||||||
sig.exponentialRampToValueAtTime(3, 1);
|
sig.exponentialRampToValueAtTime(3, "+1");
|
||||||
sig.dispose();
|
sig.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
it ("can approach a target value", function(){
|
it ("can approach a target value", function(){
|
||||||
var sig = new Signal(1);
|
var sig = new Signal(1);
|
||||||
sig.setTargetAtTime(0.2, 1, 2);
|
sig.setTargetAtTime(0.2, "+1", 2);
|
||||||
sig.dispose();
|
sig.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -119,10 +119,23 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
}, 1);
|
}, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can cancel and hold an automation curve", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var sig = new Signal(0).toMaster();
|
||||||
|
sig.linearRampTo(2, 1);
|
||||||
|
sig.cancelAndHoldAtTime(0.5)
|
||||||
|
}, 1).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(1, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.75)).to.be.closeTo(1, 0.1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it ("can set a linear ramp from the current time", function(){
|
it ("can set a linear ramp from the current time", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var sig = new Signal(0).toMaster();
|
var sig = new Signal(0).toMaster();
|
||||||
sig.linearRampToValue(2, 0.3);
|
sig.linearRampTo(2, 0.3);
|
||||||
}, 0.5).then(function(buffer){
|
}, 0.5).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time > 0.3){
|
if (time > 0.3){
|
||||||
|
@ -135,7 +148,7 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
it ("can set an linear ramp in the future", function(){
|
it ("can set an linear ramp in the future", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var sig = new Signal(1).toMaster();
|
var sig = new Signal(1).toMaster();
|
||||||
sig.linearRampToValue(50, 0.3, 0.2);
|
sig.linearRampTo(50, 0.3, 0.2);
|
||||||
}, 0.6).then(function(buffer){
|
}, 0.6).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time >= 0.6){
|
if (time >= 0.6){
|
||||||
|
@ -147,11 +160,31 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can set a exponential approach ramp from the current time", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var sig = new Signal(0).toMaster();
|
||||||
|
sig.targetRampTo(1, 0.3);
|
||||||
|
}, 0.5).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.be.below(0.0001);
|
||||||
|
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(1, 0.02);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("can set an exponential approach ramp in the future", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var sig = new Signal(1).toMaster();
|
||||||
|
sig.targetRampTo(50, 0.3, 0.2);
|
||||||
|
}, 0.7).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.be.closeTo(1, 0.0001);
|
||||||
|
expect(buffer.getValueAtTime(0.2)).to.be.closeTo(1, 0.0001);
|
||||||
|
expect(buffer.getValueAtTime(0.6)).to.be.closeTo(50, 0.5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it ("can set an exponential ramp from the current time", function(){
|
it ("can set an exponential ramp from the current time", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var sig = new Signal(1).toMaster();
|
var sig = new Signal(1).toMaster();
|
||||||
sig.exponentialRampToValue(50, 0.4);
|
sig.exponentialRampTo(50, 0.4);
|
||||||
}, 0.6).then(function(buffer){
|
}, 0.6).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time >= 0.4){
|
if (time >= 0.4){
|
||||||
|
@ -166,7 +199,7 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
it ("can set an exponential ramp in the future", function(){
|
it ("can set an exponential ramp in the future", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var sig = new Signal(1).toMaster();
|
var sig = new Signal(1).toMaster();
|
||||||
sig.exponentialRampToValue(50, 0.3, 0.2);
|
sig.exponentialRampTo(50, 0.3, 0.2);
|
||||||
}, 0.8).then(function(buffer){
|
}, 0.8).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time >= 0.6){
|
if (time >= 0.6){
|
||||||
|
@ -207,7 +240,7 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Units", function(){
|
context("Units", function(){
|
||||||
|
@ -273,7 +306,7 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
expect(signal.value).to.be.closeTo(0, 0.01);
|
expect(signal.value).to.be.closeTo(0, 0.01);
|
||||||
signal.dispose();
|
signal.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
context("Transport Syncing", function(){
|
context("Transport Syncing", function(){
|
||||||
|
@ -387,7 +420,7 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
"frequency" : 10,
|
"frequency" : 10,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).toMaster();
|
}).toMaster();
|
||||||
|
@ -399,4 +432,4 @@ define(["helper/Offline", "helper/Basic", "Test", "Tone/signal/Signal",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
define(["Test", "Tone/signal/TimelineSignal", "helper/Offline", "Tone/type/Type", "helper/Supports"],
|
define(["Test", "Tone/signal/TimelineSignal", "helper/Offline", "Tone/type/Type", "helper/Supports"],
|
||||||
function (Test, TimelineSignal, Offline, Tone, Supports) {
|
function (Test, TimelineSignal, Offline, Tone, Supports) {
|
||||||
|
|
||||||
describe("TimelineSignal", function(){
|
describe("TimelineSignal", function(){
|
||||||
|
@ -78,7 +78,7 @@ define(["Test", "Tone/signal/TimelineSignal", "helper/Offline", "Tone/type/Type"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("can get set a curve in the future", function(){
|
it("can get set a curve in the future", function(){
|
||||||
var sched;
|
var sched;
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -103,8 +103,21 @@ define(["Test", "Tone/signal/TimelineSignal", "helper/Offline", "Tone/type/Type"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it ("can cancel and hold an automation curve", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var sig = new TimelineSignal(0).toMaster();
|
||||||
|
sig.linearRampTo(2, 1);
|
||||||
|
sig.cancelAndHoldAtTime(0.5)
|
||||||
|
}, 1).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(1, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.75)).to.be.closeTo(1, 0.1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (Supports.ACCURATE_SIGNAL_SCHEDULING){
|
if (Supports.ACCURATE_SIGNAL_SCHEDULING){
|
||||||
|
|
||||||
it("can match a complex scheduled curve", function(){
|
it("can match a complex scheduled curve", function(){
|
||||||
var sched;
|
var sched;
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
|
@ -169,4 +182,4 @@ define(["Test", "Tone/signal/TimelineSignal", "helper/Offline", "Tone/type/Type"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -145,6 +145,22 @@ define(["Test", "Tone/signal/TransportTimelineSignal", "helper/Offline", "Tone/t
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("can cancel a scheduled value", function(){
|
||||||
|
var sched;
|
||||||
|
return Offline(function(Transport){
|
||||||
|
sched = new TransportTimelineSignal(0).toMaster();
|
||||||
|
sched.setValueAtTime(0, 0);
|
||||||
|
sched.linearRampToValueAtTime(1, 1);
|
||||||
|
sched.cancelAndHoldAtTime(0.5);
|
||||||
|
Transport.start(0);
|
||||||
|
}, 1).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.be.closeTo(0, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.25, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0.5, 0.1);
|
||||||
|
expect(buffer.getValueAtTime(0.75)).to.be.closeTo(0.5, 0.1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("can automate values with different units", function(){
|
it("can automate values with different units", function(){
|
||||||
var sched;
|
var sched;
|
||||||
return Offline(function(Transport){
|
return Offline(function(Transport){
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
"Tone/core/Buffer", "helper/Meter", "Tone/core/Tone"],
|
"Tone/core/Buffer", "helper/Meter", "Tone/core/Tone"],
|
||||||
function (BasicTests, BufferSource, Offline, Buffer, Meter, Tone) {
|
function (BasicTests, BufferSource, Offline, Buffer, Meter, Tone) {
|
||||||
|
|
||||||
if (window.__karma__){
|
if (window.__karma__){
|
||||||
|
@ -423,14 +423,14 @@ define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fades from the end", function(){
|
it("fades from the end when passed into the stop call", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var player = new BufferSource(onesBuffer).toMaster();
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
player.start(0).stop(0.2, 0.1)
|
player.start(0).stop(0.2, 0.1)
|
||||||
}, 0.3).then(function(buffer){
|
}, 0.3).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time < 0.1){
|
if (time < 0.101){
|
||||||
expect(sample).to.equal(1);
|
expect(sample).to.be.closeTo(1, 0.01);
|
||||||
} else if (time < 0.2){
|
} else if (time < 0.2){
|
||||||
expect(sample).to.be.lessThan(1);
|
expect(sample).to.be.lessThan(1);
|
||||||
} else {
|
} else {
|
||||||
|
@ -440,14 +440,32 @@ define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("fades at the end of the file at the files duration", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
|
player.fadeOut = 0.1;
|
||||||
|
player.start(0);
|
||||||
|
}, 0.6).then(function(buffer){
|
||||||
|
buffer.forEach(function(sample, time){
|
||||||
|
if (time < 0.401){
|
||||||
|
expect(sample).to.be.closeTo(1, 0.01);
|
||||||
|
} else if (time < 0.5){
|
||||||
|
expect(sample).to.be.lessThan(1);
|
||||||
|
} else {
|
||||||
|
expect(sample).to.equal(0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("cant fade for shorter than the fade in time", function(){
|
it("cant fade for shorter than the fade in time", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var player = new BufferSource(onesBuffer).toMaster();
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
player.fadeIn = 0.15
|
player.fadeIn = 0.15;
|
||||||
player.start(0).stop(0.2, 0.1)
|
player.start(0).stop(0.2, 0.1);
|
||||||
}, 0.3).then(function(buffer){
|
}, 0.3).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
buffer.forEach(function(sample, time){
|
||||||
if (time < 0.149){
|
if (time < 0.14){
|
||||||
expect(sample).to.be.lessThan(1);
|
expect(sample).to.be.lessThan(1);
|
||||||
} else if (Math.abs(time - 0.15) < 1e-4){
|
} else if (Math.abs(time - 0.15) < 1e-4){
|
||||||
expect(sample).to.be.closeTo(1, 0.05);
|
expect(sample).to.be.closeTo(1, 0.05);
|
||||||
|
@ -458,21 +476,53 @@ define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fades at the end of the file", function(){
|
it("the fade out can shorten to fit the duration of the sample", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var player = new BufferSource(onesBuffer).toMaster();
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
player.fadeOut = 0.1;
|
player.fadeOut = 1;
|
||||||
player.start(0);
|
player.start(0).stop(0.5);
|
||||||
}, 0.6).then(function(buffer){
|
}, 0.51).then(function(buffer){
|
||||||
buffer.forEach(function(sample, time){
|
expect(buffer.getValueAtTime(0)).to.equal(1);
|
||||||
if (time < 0.4){
|
expect(buffer.getValueAtTime(0.25)).to.be.closeTo(0.5, 0.01);
|
||||||
expect(sample).to.equal(1);
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0, 0.01);
|
||||||
} else if (time < 0.5){
|
});
|
||||||
expect(sample).to.be.lessThan(1);
|
});
|
||||||
} else {
|
|
||||||
expect(sample).to.equal(0);
|
it("the fade out will only start after the fade in", function(){
|
||||||
}
|
return Offline(function(){
|
||||||
});
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
|
player.fadeIn = 0.1;
|
||||||
|
player.fadeOut = 1;
|
||||||
|
player.start(0).stop(0.5);
|
||||||
|
}, 0.51).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.equal(0);
|
||||||
|
expect(buffer.getValueAtTime(0.05)).to.be.closeTo(0.5, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.5, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0, 0.01);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("can fade with an exponential curve", function(){
|
||||||
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
|
player.curve = "exponential";
|
||||||
|
expect(player.curve).to.equal("exponential");
|
||||||
|
player.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fades in and out exponentially", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var player = new BufferSource(onesBuffer).toMaster();
|
||||||
|
player.curve = "exponential";
|
||||||
|
player.fadeIn = 0.1;
|
||||||
|
player.fadeOut = 1;
|
||||||
|
player.start(0).stop(0.5);
|
||||||
|
}, 0.51).then(function(buffer){
|
||||||
|
expect(buffer.getValueAtTime(0)).to.equal(0);
|
||||||
|
expect(buffer.getValueAtTime(0.05)).to.be.closeTo(0.93, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.1)).to.be.closeTo(1, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.3)).to.be.closeTo(0.05, 0.01);
|
||||||
|
expect(buffer.getValueAtTime(0.5)).to.be.closeTo(0, 0.01);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -519,6 +569,26 @@ define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not play if the stop time is at the start time", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var player = new BufferSource(buffer);
|
||||||
|
player.toMaster();
|
||||||
|
player.start(0).stop(0);
|
||||||
|
}, 0.3).then(function(buffer){
|
||||||
|
expect(buffer.isSilent()).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not play if the stop time is at before start time", function(){
|
||||||
|
return Offline(function(){
|
||||||
|
var player = new BufferSource(buffer);
|
||||||
|
player.toMaster();
|
||||||
|
player.start(0.1).stop(0);
|
||||||
|
}, 0.3).then(function(buffer){
|
||||||
|
expect(buffer.isSilent()).to.be.true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("stops playing at the earlier time if invoked with 'stop' at a later time", function(){
|
it("stops playing at the earlier time if invoked with 'stop' at a later time", function(){
|
||||||
return Offline(function(){
|
return Offline(function(){
|
||||||
var player = new BufferSource(buffer);
|
var player = new BufferSource(buffer);
|
||||||
|
@ -531,4 +601,4 @@ define(["helper/Basic", "Tone/source/BufferSource", "helper/Offline",
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue