mirror of
https://github.com/Tonejs/Tone.js
synced 2024-11-16 08:38:00 +00:00
3d1202043a
simplifies deep references to individual files
162 lines
4.7 KiB
JavaScript
162 lines
4.7 KiB
JavaScript
define(["../core/Tone", "../event/Part", "../core/Transport"], function(Tone){
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* @class A sequence is an alternate notation of a part. Instead
|
|
* of passing in an array of [time, event] pairs, pass
|
|
* in an array of events which will be spaced at the
|
|
* given subdivision. Sub-arrays will subdivide that beat
|
|
* by the number of items are in the array.
|
|
* Sequence notation inspiration from [Tidal](http://yaxu.org/tidal/)
|
|
* @param {Function} callback The callback to invoke with every note
|
|
* @param {Array} events The sequence
|
|
* @param {Time} subdivision The subdivision between which events are placed.
|
|
* @extends {Tone.Part}
|
|
* @example
|
|
* var seq = new Tone.Sequence(function(time, note){
|
|
* console.log(note);
|
|
* //straight quater notes
|
|
* }, ["C4", "E4", "G4", "A4"], "4n");
|
|
* @example
|
|
* var seq = new Tone.Sequence(function(time, note){
|
|
* console.log(note);
|
|
* //subdivisions are given as subarrays
|
|
* }, ["C4", ["E4", "D4", "E4"], "G4", ["A4", "G4"]]);
|
|
*/
|
|
Tone.Sequence = function(){
|
|
|
|
var options = Tone.defaults(arguments, ["callback", "events", "subdivision"], Tone.Sequence);
|
|
|
|
//remove the events
|
|
var events = options.events;
|
|
delete options.events;
|
|
|
|
Tone.Part.call(this, options);
|
|
|
|
/**
|
|
* The subdivison of each note
|
|
* @type {Ticks}
|
|
* @private
|
|
*/
|
|
this._subdivision = this.toTicks(options.subdivision);
|
|
|
|
//if no time was passed in, the loop end is the end of the cycle
|
|
if (Tone.isUndef(options.loopEnd) && Tone.isDefined(events)){
|
|
this._loopEnd = (events.length * this._subdivision);
|
|
}
|
|
//defaults to looping
|
|
this._loop = true;
|
|
|
|
//add all of the events
|
|
if (Tone.isDefined(events)){
|
|
for (var i = 0; i < events.length; i++){
|
|
this.add(i, events[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
Tone.extend(Tone.Sequence, Tone.Part);
|
|
|
|
/**
|
|
* The default values.
|
|
* @type {Object}
|
|
*/
|
|
Tone.Sequence.defaults = {
|
|
"subdivision" : "4n",
|
|
};
|
|
|
|
/**
|
|
* The subdivision of the sequence. This can only be
|
|
* set in the constructor. The subdivision is the
|
|
* interval between successive steps.
|
|
* @type {Time}
|
|
* @memberOf Tone.Sequence#
|
|
* @name subdivision
|
|
* @readOnly
|
|
*/
|
|
Object.defineProperty(Tone.Sequence.prototype, "subdivision", {
|
|
get : function(){
|
|
return Tone.Ticks(this._subdivision).toSeconds();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Get/Set an index of the sequence. If the index contains a subarray,
|
|
* a Tone.Sequence representing that sub-array will be returned.
|
|
* @example
|
|
* var sequence = new Tone.Sequence(playNote, ["E4", "C4", "F#4", ["A4", "Bb3"]])
|
|
* sequence.at(0)// => returns "E4"
|
|
* //set a value
|
|
* sequence.at(0, "G3");
|
|
* //get a nested sequence
|
|
* sequence.at(3).at(1)// => returns "Bb3"
|
|
* @param {Positive} index The index to get or set
|
|
* @param {*} value Optionally pass in the value to set at the given index.
|
|
*/
|
|
Tone.Sequence.prototype.at = function(index, value){
|
|
//if the value is an array,
|
|
if (Tone.isArray(value)){
|
|
//remove the current event at that index
|
|
this.remove(index);
|
|
}
|
|
//call the parent's method
|
|
return Tone.Part.prototype.at.call(this, this._indexTime(index), value);
|
|
};
|
|
|
|
/**
|
|
* Add an event at an index, if there's already something
|
|
* at that index, overwrite it. If `value` is an array,
|
|
* it will be parsed as a subsequence.
|
|
* @param {Number} index The index to add the event to
|
|
* @param {*} value The value to add at that index
|
|
* @returns {Tone.Sequence} this
|
|
*/
|
|
Tone.Sequence.prototype.add = function(index, value){
|
|
if (value === null){
|
|
return this;
|
|
}
|
|
if (Tone.isArray(value)){
|
|
//make a subsequence and add that to the sequence
|
|
var subSubdivision = Math.round(this._subdivision / value.length);
|
|
value = new Tone.Sequence(this._tick.bind(this), value, Tone.Ticks(subSubdivision));
|
|
}
|
|
Tone.Part.prototype.add.call(this, this._indexTime(index), value);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Remove a value from the sequence by index
|
|
* @param {Number} index The index of the event to remove
|
|
* @returns {Tone.Sequence} this
|
|
*/
|
|
Tone.Sequence.prototype.remove = function(index, value){
|
|
Tone.Part.prototype.remove.call(this, this._indexTime(index), value);
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Get the time of the index given the Sequence's subdivision
|
|
* @param {Number} index
|
|
* @return {Time} The time of that index
|
|
* @private
|
|
*/
|
|
Tone.Sequence.prototype._indexTime = function(index){
|
|
if (index instanceof Tone.TransportTime){
|
|
return index;
|
|
} else {
|
|
return Tone.Ticks(index * this._subdivision + this.startOffset).toSeconds();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clean up.
|
|
* @return {Tone.Sequence} this
|
|
*/
|
|
Tone.Sequence.prototype.dispose = function(){
|
|
Tone.Part.prototype.dispose.call(this);
|
|
return this;
|
|
};
|
|
|
|
return Tone.Sequence;
|
|
});
|