Tone.Pattern iterates through an array of events in a number of patterns

This commit is contained in:
Yotam Mann 2015-11-03 19:15:40 -05:00
parent 89f4e738fc
commit d6d9c397de
2 changed files with 132 additions and 161 deletions

132
Tone/event/Pattern.js Normal file
View file

@ -0,0 +1,132 @@
define(["Tone/core/Tone", "Tone/event/Loop", "Tone/control/CtrlPattern"], function (Tone) {
/**
* @class Tone.Pattern arpeggiates between the given notes
* in a number of patterns.
* @extends {Tone.Loop}
* @param {Function} callback The callback to invoke with the
* event.
* @param {Array} events The events to arpeggiate over.
*/
Tone.Pattern = function(){
var options = this.optionsObject(arguments, ["callback", "events", "pattern"], Tone.Pattern.defaults);
Tone.Loop.call(this, options);
/**
* The pattern manager
* @type {Tone.CtrlPattern}
* @private
*/
this._pattern = new Tone.CtrlPattern({
"values" : options.events,
"type" : options.pattern,
"index" : options.index
});
};
Tone.extend(Tone.Pattern, Tone.Loop);
/**
* The defaults
* @const
* @type {Object}
*/
Tone.Pattern.defaults = {
"pattern" : Tone.CtrlPattern.Type.Up,
"events" : [],
};
/**
* Internal function called when the notes should be called
* @param {Number} time The time the event occurs
* @private
*/
Tone.Pattern.prototype._tick = function(time){
this.callback(time, this._pattern.value);
this._pattern.next();
};
/**
* The current index in the events array.
* @memberOf Tone.Pattern#
* @type {Time}
* @name index
*/
Object.defineProperty(Tone.Pattern.prototype, "index", {
get : function(){
return this._pattern.index;
},
set : function(i){
this._pattern.index = i;
}
});
/**
* The array of events.
* @memberOf Tone.Pattern#
* @type {Time}
* @name events
*/
Object.defineProperty(Tone.Pattern.prototype, "events", {
get : function(){
return this._pattern.values;
},
set : function(vals){
this._pattern.values = vals;
}
});
/**
* The current value of the pattern.
* @memberOf Tone.Pattern#
* @type {Time}
* @name value
*/
Object.defineProperty(Tone.Pattern.prototype, "value", {
get : function(){
return this._pattern.value;
},
set : function(val){
this._pattern.value = val;
}
});
/**
* The pattern type.
* "up" - cycles upward
* "down" - cycles downward
* "upDown" - up then and down
* "downUp" - cycles down then and up
* "alternateUp" - jump up two and down one
* "alternateDown" - jump down two and up one
* "random" - randomly select an index
* "randomWalk" - randomly moves one index away from the current position
* "randomOnce" - randomly select an index without repeating until all values have been chosen.
* @memberOf Tone.Pattern#
* @type {Time}
* @name pattern
*/
Object.defineProperty(Tone.Pattern.prototype, "pattern", {
get : function(){
return this._pattern.type;
},
set : function(pattern){
this._pattern.type = pattern;
}
});
/**
* Clean up
* @return {Tone.Pattern} this
*/
Tone.Pattern.prototype.dispose = function(){
Tone.Loop.prototype.dispose.call(this);
this._pattern.dispose();
this._pattern = null;
};
return Tone.Pattern;
});

View file

@ -1,161 +0,0 @@
define(["Tone/core/Tone", "Tone/structure/Note", "Tone/structure/Part"], function (Tone) {
/**
* @class Tone.Pattern arpeggiates between the given notes
* in a number of patterns.
* @extends {Tone}
* @param {Function} callback The callback to invoke with the
* event.
* @param {Array} notes The notes to arpeggiate over.
*/
Tone.Pattern = function(callback, notes){
/**
* Called back with the current event
* @private
* @type {Function}
*/
this._callback = callback;
/**
* The notes to arpeggiate
* @type {Array}
*/
this.notes = notes;
/**
* The event index
* @type {Array}
* @private
*/
this._eventIndex = -1;
/**
* The note which schedules the notes
* @type {Tone.Note}
* @private
*/
this._note = new Tone.Note(this._tick.bind(this));
this._note.loop = true;
this._note.loopEnd = "4n";
/**
* The stepping direction of the notes
* @type {Number}
* @private
*/
this._arpDirection = 1;
};
Tone.extend(Tone.Pattern);
/**
* Start the arpeggio at the given time.
* @param {Time=} time When to start the Arpeggio
* @return {Tone.Pattern} this
*/
Tone.Pattern.prototype.start = function(time){
this._note.start(time);
return this;
};
/**
* Stop the arpeggio at the given time.
* @param {Time=} time When to stop the Arpeggio
* @return {Tone.Pattern} this
*/
Tone.Pattern.prototype.stop = function(time){
this._note.stop(time);
return this;
};
/**
* Internal function called when the notes should be called
* @param {Number} time The time the event occurs
* @private
*/
Tone.Pattern.prototype._tick = function(time){
if (this._pattern === Tone.Pattern.Type.Random){
this._eventIndex = Math.floor(Math.random() * this.notes.length);
} else {
this._eventIndex += this._arpDirection;
if (this._pattern === Tone.Pattern.Type.Alternate){
if (this._eventIndex === 0){
this._arpDirection = 1;
} else if (this._eventIndex === this.notes.length - 1){
this._arpDirection = -1;
}
} else if (this._eventIndex < 0){
this._eventIndex = this.notes.length - 1;
} else if (this._eventIndex >= this.notes.length){
this._eventIndex = 0;
}
}
this._callback(time, this.notes[this._eventIndex]);
};
/**
* The interval of the notes
* @memberOf Tone.Pattern#
* @type {Time}
* @name interval
*/
Object.defineProperty(Tone.Pattern.prototype, "interval", {
get : function(){
return this._note.loopEnd;
},
set : function(interval){
this._note.loopEnd = interval;
}
});
/**
* @memberOf Tone.Pattern#
* @type {Time}
* @name pattern
*/
Object.defineProperty(Tone.Pattern.prototype, "pattern", {
get : function(){
return this._pattern;
},
set : function(pattern){
switch(pattern){
case Tone.Pattern.Type.Forward :
this._arpDirection = 1;
break;
case Tone.Pattern.Type.Reverse :
this._arpDirection = -1;
break;
}
var hasType = false;
for (var pattr in Tone.Pattern.Type){
if (pattern === Tone.Pattern.Type[pattr]){
hasType = true;
break;
}
}
if (!hasType){
throw new Error("Invalid pattern: "+pattern);
}
this._pattern = pattern;
}
});
/**
* The arpeggiation patterns
* @type {Object}
* @enum {String}
*/
Tone.Pattern.Type = {
Forward : "forward",
Reverse : "reverse",
Alternate : "alternate",
Drunk : "drunk",
Converge : "converge",
Diverge : "diverge",
RandomOnce : "randomOnce",
Random : "random"
};
return Tone.Pattern;
});