Skip to content

Commit a75b9a5

Browse files
committed
Merge branch 'dev'
2 parents e32f4b5 + 4138216 commit a75b9a5

File tree

175 files changed

+9388
-10665
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

175 files changed

+9388
-10665
lines changed

.github/CONTRIBUTING.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
Bug fixes and contributions are welcome!
2+
3+
If you're looking for ideas for where to get started, consider jumping in on any of these areas:
4+
5+
### Examples
6+
7+
To contribute examples, please follow the current style of the examples. Add your example's title and file name to `ExampleList.js` file for it to appear in the examples list on the index page.
8+
9+
### Docs
10+
11+
There is always more work that can be done on documentation. Especially adding good examples to methods and members to make the docs more informative and useful for people coming from diverse musical and technical backgrounds.
12+
13+
All of the docs are written in [jsdoc](http://usejsdoc.org/)-style comments in the source code. If you catch a mistake, please send a pull request.
14+
15+
Along with this, It'd be great to integrate more visuals and references in the docs to help illustrate concepts.
16+
17+
### Forum
18+
19+
If you are someone who is familiar with Tone.js, consider jumping in on [the forum](https://groups.google.com/forum/#!forum/tonejs) to answer some questions.
20+
21+
### Tutorials
22+
23+
I'd love to see more tutorials for newcomers to Tone.js to help them get up and running or solve a particular issue. If you make a tutorial, please send me a link.
24+
25+
### Tests
26+
27+
Tone.js has an extensive [test suite](Testing) using Mocha and Chai. I'd love help getting more of these tests to pass on Safari and Firefox.
28+
29+
Along with more unit tests, I'd also be great to have more tests which run in the online context and generate music to help find bugs by ear that the automated tests might not illuminate. [Audiokit](http://audiokit.io/tests/), for example, has a great suite of aural tests.
30+
31+
### Synths/Effects
32+
33+
If you'd like to contribute a cool and expressive synth or effect, i'd love to hear it. Please send me an example that i can play with along with the PR.

.github/ISSUE_TEMPLATE.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Bugs and feature requests only please. For help questions, check out [the forum](https://groups.google.com/forum/#!forum/tonejs).
2+
3+
If possible, please include a link which illustrates the issue.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
1. Please make all pull requests on the `dev` branch.
2+
2. Don't commit build files
3+
2. Try to get all [tests](https://github.com/Tonejs/Tone.js/wiki/Testing) to pass.
4+
5+

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,5 @@ build/p5.Tone.js
5050
examples/graph.html
5151

5252
*.asd
53+
54+
test/supports.html

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ sudo: required
22
dist: trusty
33
language: node_js
44
node_js:
5-
- "4.2"
5+
- "7"
66

77
before_install:
88
- export CHROME_BIN=/usr/bin/google-chrome

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
### r10
2+
3+
* Tone.Context wraps AudioContext
4+
* Tone.OfflineContext wraps OfflineAudioContext
5+
* Tone.Offline: method for rendering audio offline
6+
* Rewriting tests with Tone.Offline
7+
* Optimizing Tone.Draw to only loop when events are scheduled: [#194](https://github.com/Tonejs/Tone.js/issues/194)
8+
* Time.eval->valueOf which takes advantage of build-in primitive evaluation [#205](https://github.com/Tonejs/Tone.js/issues/205)
9+
* [Offline example](https://tonejs.github.io/examples/#offline)
10+
111
### r9
212

313
* Tone.Clock performance and lookAhead updates.

Tone/component/Analyser.js

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@ define(["Tone/core/Tone"], function (Tone) {
22

33
"use strict";
44

5+
/**
6+
* AnalyserNode.getFloatTimeDomainData polyfill
7+
* @private
8+
*/
9+
if (window.AnalyserNode && !AnalyserNode.prototype.getFloatTimeDomainData){
10+
//referenced https://github.com/mohayonao/get-float-time-domain-data
11+
AnalyserNode.prototype.getFloatTimeDomainData = function(array){
12+
var uint8 = new Uint8Array(array.length);
13+
this.getByteTimeDomainData(uint8);
14+
for (var i = 0; i < uint8.length; i++){
15+
array[i] = (uint8[i] - 128) / 128;
16+
}
17+
};
18+
}
19+
20+
521
/**
622
* @class Wrapper around the native Web Audio's
723
* [AnalyserNode](http://webaudio.github.io/web-audio-api/#idl-def-AnalyserNode).
@@ -104,17 +120,7 @@ define(["Tone/core/Tone"], function (Tone) {
104120
if (this._returnType === Tone.Analyser.ReturnType.Byte){
105121
this._analyser.getByteTimeDomainData(this._buffer);
106122
} else {
107-
if (this.isFunction(AnalyserNode.prototype.getFloatTimeDomainData)){
108-
this._analyser.getFloatTimeDomainData(this._buffer);
109-
} else {
110-
var uint8 = new Uint8Array(this._buffer.length);
111-
this._analyser.getByteTimeDomainData(uint8);
112-
//referenced https://github.com/mohayonao/get-float-time-domain-data
113-
// POLYFILL
114-
for (var i = 0; i < uint8.length; i++){
115-
this._buffer[i] = (uint8[i] - 128) * 0.0078125;
116-
}
117-
}
123+
this._analyser.getFloatTimeDomainData(this._buffer);
118124
}
119125
}
120126
return this._buffer;

Tone/component/MidSideMerge.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -61,25 +61,12 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/signal/Expr", "Tone/compon
6161
this.side.connect(this._right, 0, 1);
6262
this._left.connect(this._merge, 0, 0);
6363
this._right.connect(this._merge, 0, 1);
64-
sqrtTwo.connect(this._left, 0, 2);
65-
sqrtTwo.connect(this._right, 0, 2);
64+
this.context.getConstant(Math.SQRT1_2).connect(this._left, 0, 2);
65+
this.context.getConstant(Math.SQRT1_2).connect(this._right, 0, 2);
6666
};
6767

6868
Tone.extend(Tone.MidSideMerge);
6969

70-
/**
71-
* A constant signal equal to 1 / sqrt(2).
72-
* @type {Number}
73-
* @signal
74-
* @private
75-
* @static
76-
*/
77-
var sqrtTwo = null;
78-
79-
Tone._initAudioContext(function(){
80-
sqrtTwo = new Tone.Signal(1 / Math.sqrt(2));
81-
});
82-
8370
/**
8471
* clean up
8572
* @returns {Tone.MidSideMerge} this

Tone/component/MidSideSplit.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,12 @@ define(["Tone/core/Tone", "Tone/signal/Expr", "Tone/signal/Signal", "Tone/compon
4343
this._split.connect(this.mid, 1, 1);
4444
this._split.connect(this.side, 0, 0);
4545
this._split.connect(this.side, 1, 1);
46-
sqrtTwo.connect(this.mid, 0, 2);
47-
sqrtTwo.connect(this.side, 0, 2);
46+
this.context.getConstant(Math.SQRT1_2).connect(this.mid, 0, 2);
47+
this.context.getConstant(Math.SQRT1_2).connect(this.side, 0, 2);
4848
};
4949

5050
Tone.extend(Tone.MidSideSplit);
5151

52-
/**
53-
* a constant signal equal to 1 / sqrt(2)
54-
* @type {Number}
55-
* @signal
56-
* @private
57-
* @static
58-
*/
59-
var sqrtTwo = null;
60-
61-
Tone._initAudioContext(function(){
62-
sqrtTwo = new Tone.Signal(1 / Math.sqrt(2));
63-
});
64-
6552
/**
6653
* clean up
6754
* @returns {Tone.MidSideSplit} this

Tone/component/Volume.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,7 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Gain"], function(Tone
2828
* @type {Decibels}
2929
* @private
3030
*/
31-
this._unmutedVolume = 0;
32-
33-
/**
34-
* if the volume is muted
35-
* @type {Boolean}
36-
* @private
37-
*/
38-
this._muted = false;
31+
this._unmutedVolume = options.volume;
3932

4033
/**
4134
* The volume control in decibels.
@@ -74,17 +67,16 @@ define(["Tone/core/Tone", "Tone/signal/Signal", "Tone/core/Gain"], function(Tone
7467
*/
7568
Object.defineProperty(Tone.Volume.prototype, "mute", {
7669
get : function(){
77-
return this._muted;
70+
return this.volume.value === -Infinity;
7871
},
7972
set : function(mute){
80-
if (!this._muted && mute){
73+
if (!this.mute && mute){
8174
this._unmutedVolume = this.volume.value;
8275
//maybe it should ramp here?
8376
this.volume.value = -Infinity;
84-
} else if (this._muted && !mute){
77+
} else if (this.mute && !mute){
8578
this.volume.value = this._unmutedVolume;
8679
}
87-
this._muted = mute;
8880
}
8981
});
9082

Tone/core/Buffer.js

Lines changed: 92 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
22

33
"use strict";
44

5+
/**
6+
* AudioBuffer.copyToChannel polyfill
7+
* @private
8+
*/
9+
if (window.AudioBuffer && !AudioBuffer.prototype.copyToChannel){
10+
AudioBuffer.prototype.copyToChannel = function(src, chanNum, start){
11+
var channel = this.getChannelData(chanNum);
12+
start = start || 0;
13+
for (var i = 0; i < channel.length; i++){
14+
channel[i+start] = src[i];
15+
}
16+
};
17+
AudioBuffer.prototype.copyFromChannel = function(dest, chanNum, start){
18+
var channel = this.getChannelData(chanNum);
19+
start = start || 0;
20+
for (var i = 0; i < channel.length; i++){
21+
dest[i] = channel[i+start];
22+
}
23+
};
24+
}
25+
526
/**
627
* @class Buffer loading and storage. Tone.Buffer is used internally by all
728
* classes that make requests for audio files such as Tone.Player,
@@ -230,17 +251,35 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
230251
array = [array];
231252
}
232253
for (var c = 0; c < channels; c++){
233-
if (this.isFunction(buffer.copyToChannel)){
234-
buffer.copyToChannel(array[c], c);
235-
} else {
236-
var channel = buffer.getChannelData(c);
237-
var channelArray = array[c];
254+
buffer.copyToChannel(array[c], c);
255+
}
256+
this._buffer = buffer;
257+
return this;
258+
};
259+
260+
/**
261+
* Sums muliple channels into 1 channel
262+
* @param {Number=} channel Optionally only copy a single channel from the array.
263+
* @return {Array}
264+
*/
265+
Tone.Buffer.prototype.toMono = function(chanNum){
266+
if (this.isNumber(chanNum)){
267+
this.fromArray(this.toArray(chanNum));
268+
} else {
269+
var outputArray = new Float32Array(this.length);
270+
var numChannels = this.numberOfChannels;
271+
for (var channel = 0; channel < numChannels; channel++){
272+
var channelArray = this.toArray(channel);
238273
for (var i = 0; i < channelArray.length; i++){
239-
channel[i] = channelArray[i];
274+
outputArray[i] += channelArray[i];
240275
}
241276
}
277+
//divide by the number of channels
278+
outputArray = outputArray.map(function(sample){
279+
return sample / numChannels;
280+
});
281+
this.fromArray(outputArray);
242282
}
243-
this._buffer = buffer;
244283
return this;
245284
};
246285

@@ -252,29 +291,27 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
252291
*/
253292
Tone.Buffer.prototype.toArray = function(channel){
254293
if (this.isNumber(channel)){
255-
return this._buffer.getChannelData(channel);
294+
return this.getChannelData(channel);
295+
} else if (this.numberOfChannels === 1){
296+
return this.toArray(0);
256297
} else {
257298
var ret = [];
258299
for (var c = 0; c < this.numberOfChannels; c++){
259-
ret[c] = new Float32Array(this.length);
260-
if (this.isFunction(this._buffer.copyFromChannel)){
261-
this._buffer.copyFromChannel(ret[c], c);
262-
} else {
263-
var channelData = this._buffer.getChannelData(c);
264-
var retArray = ret[c];
265-
for (var i = 0; i < channelData.length; i++){
266-
retArray[i] = channelData[i];
267-
}
268-
}
269-
}
270-
if (ret.length === 1){
271-
return ret[0];
272-
} else {
273-
return ret;
300+
ret[c] = this.getChannelData(c);
274301
}
302+
return ret;
275303
}
276304
};
277305

306+
/**
307+
* Returns the Float32Array representing the PCM audio data for the specific channel.
308+
* @param {Number} channel The channel number to return
309+
* @return {Float32Array} The audio as a TypedArray
310+
*/
311+
Tone.Buffer.prototype.getChannelData = function(channel){
312+
return this._buffer.getChannelData(channel);
313+
};
314+
278315
/**
279316
* Cut a subsection of the array and return a buffer of the
280317
* subsection. Does not modify the original buffer
@@ -302,8 +339,8 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
302339
*/
303340
Tone.Buffer.prototype._reverse = function(){
304341
if (this.loaded){
305-
for (var i = 0; i < this._buffer.numberOfChannels; i++){
306-
Array.prototype.reverse.call(this._buffer.getChannelData(i));
342+
for (var i = 0; i < this.numberOfChannels; i++){
343+
Array.prototype.reverse.call(this.getChannelData(i));
307344
}
308345
}
309346
return this;
@@ -370,6 +407,7 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
370407
function onError(e){
371408
if (onerror){
372409
onerror(e);
410+
Tone.Buffer.emit("error", e);
373411
} else {
374412
throw new Error(e);
375413
}
@@ -434,8 +472,9 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
434472
/**
435473
* Stop all of the downloads in progress
436474
* @return {Tone.Buffer}
475+
* @static
437476
*/
438-
Tone.Buffer.stopDownloads = function(){
477+
Tone.Buffer.cancelDownloads = function(){
439478
Tone.Buffer._downloadQueue.forEach(function(request){
440479
request.abort();
441480
});
@@ -459,5 +498,32 @@ define(["Tone/core/Tone", "Tone/core/Emitter", "Tone/type/Type"], function(Tone)
459498
return response !== "";
460499
};
461500

501+
/**
502+
* Returns a Promise which resolves when all of the buffers have loaded
503+
* @return {Promise}
504+
*/
505+
Tone.loaded = function(){
506+
var onload, onerror;
507+
function removeEvents(){
508+
//remove the events when it's resolved
509+
Tone.Buffer.off("load", onload);
510+
Tone.Buffer.off("error", onerror);
511+
}
512+
return new Promise(function(success, fail){
513+
onload = function(){
514+
success();
515+
};
516+
onerror = function(){
517+
fail();
518+
};
519+
//add the event listeners
520+
Tone.Buffer.on("load", onload);
521+
Tone.Buffer.on("error", onerror);
522+
}).then(removeEvents).catch(function(e){
523+
removeEvents();
524+
throw new Error(e);
525+
});
526+
};
527+
462528
return Tone.Buffer;
463529
});

0 commit comments

Comments
 (0)