@@ -6,18 +6,19 @@ define(function (require) {
66 var TimelineSignal = require ( 'Tone/signal/TimelineSignal' ) ;
77 require ( 'sndcore' ) ;
88
9+
910 /**
1011 * An AudioVoice is used as a single voice for sound synthesis.
1112 * The PolySynth class holds an array of AudioVoice, and deals
1213 * with voices allocations, with setting notes to be played, and
13- * parameters to be set.
14+ * parameters to be set.
1415 *
1516 * @class p5.PolySynth
1617 * @constructor
17- *
18+ *
1819 * @param {Number } [synthVoice] A monophonic synth voice inheriting
1920 * the AudioVoice class. Defaults to p5.MonoSynth
20- * @param {Number } [polyValue ] Number of voices, defaults to 8;
21+ * @param {Number } [maxVoices ] Number of voices, defaults to 8;
2122 *
2223 *
2324 * @example
@@ -32,19 +33,19 @@ define(function (require) {
3233 * polysynth.play(74,1,0,3);
3334 * }
3435 * </code></div>
35- *
36+ *
3637 **/
37- p5 . PolySynth = function ( audioVoice , polyValue ) {
38- //audiovoices will contain polyValue many monophonic synths
38+ p5 . PolySynth = function ( audioVoice , maxVoices ) {
39+ //audiovoices will contain maxVoices many monophonic synths
3940 this . audiovoices = [ ] ;
4041
4142 /**
42- * An object that holds information about which notes have been played and
43+ * An object that holds information about which notes have been played and
4344 * which notes are currently being played. New notes are added as keys
4445 * on the fly. While a note has been attacked, but not released, the value of the
4546 * key is the audiovoice which is generating that note. When notes are released,
46- * the value of the key becomes undefined.
47- * @property notes
47+ * the value of the key becomes undefined.
48+ * @property notes
4849 */
4950 this . notes = { } ;
5051
@@ -56,7 +57,7 @@ define(function (require) {
5657 * A PolySynth must have at least 1 voice, defaults to 8
5758 * @property polyvalue
5859 */
59- this . polyValue = polyValue || 8 ;
60+ this . maxVoices = maxVoices || 8 ;
6061
6162 /**
6263 * Monosynth that generates the sound for each note that is triggered. The
@@ -87,7 +88,7 @@ define(function (require) {
8788 * @method _allocateVoices
8889 */
8990 p5 . PolySynth . prototype . _allocateVoices = function ( ) {
90- for ( var i = 0 ; i < this . polyValue ; i ++ ) {
91+ for ( var i = 0 ; i < this . maxVoices ; i ++ ) {
9192 this . audiovoices . push ( new this . AudioVoice ( ) ) ;
9293 this . audiovoices [ i ] . disconnect ( ) ;
9394 this . audiovoices [ i ] . connect ( this . output ) ;
@@ -96,7 +97,7 @@ define(function (require) {
9697
9798 /**
9899 * Play a note by triggering noteAttack and noteRelease with sustain time
99- *
100+ *
100101 * @method play
101102 * @param {Number } [note] midi note to play (ranging from 0 to 127 - 60 being a middle C)
102103 * @param {Number } [velocity] velocity of the note to play (ranging from 0 to 1)
@@ -110,12 +111,12 @@ define(function (require) {
110111 } ;
111112
112113
113- /**
114+ /**
114115 * noteADSR sets the envelope for a specific note that has just been triggered.
115116 * Using this method modifies the envelope of whichever audiovoice is being used
116117 * to play the desired note. The envelope should be reset before noteRelease is called
117118 * in order to prevent the modified envelope from being used on other notes.
118- *
119+ *
119120 * @method noteADSR
120121 * @param {Number } [note] Midi note on which ADSR should be set.
121122 * @param {Number } [attackTime] Time (in seconds before envelope
@@ -141,10 +142,10 @@ define(function (require) {
141142 } ;
142143
143144
144- /**
145+ /**
145146 * Set the PolySynths global envelope. This method modifies the envelopes of each
146147 * monosynth so that all notes are played with this envelope.
147- *
148+ *
148149 * @method setADSR
149150 * @param {Number } [note] Midi note on which ADSR should be set.
150151 * @param {Number } [attackTime] Time (in seconds before envelope
@@ -170,14 +171,14 @@ define(function (require) {
170171 /**
171172 * Trigger the Attack, and Decay portion of a MonoSynth.
172173 * Similar to holding down a key on a piano, but it will
173- * hold the sustain level until you let go.
174+ * hold the sustain level until you let go.
174175 *
175176 * @method noteAttack
176177 * @param {Number } [note] midi note on which attack should be triggered.
177178 * @param {Number } [velocity] velocity of the note to play (ranging from 0 to 1)/
178179 * @param {Number } [secondsFromNow] time from now (in seconds)
179- *
180- */
180+ *
181+ */
181182 p5 . PolySynth . prototype . noteAttack = function ( _note , _velocity , secondsFromNow ) {
182183 var now = p5sound . audiocontext . currentTime ;
183184
@@ -201,8 +202,8 @@ define(function (require) {
201202 }
202203
203204 //Check to see how many voices are in use at the time the note will start
204- if ( this . _voicesInUse . getValueAtTime ( t ) < this . polyValue ) {
205- currentVoice = this . _voicesInUse . getValueAtTime ( t ) ;
205+ if ( this . _voicesInUse . getValueAtTime ( t ) < this . maxVoices ) {
206+ currentVoice = Math . max ( ~ ~ this . _voicesInUse . getValueAtTime ( t ) , 0 ) ;
206207 }
207208 //If we are exceeding the polyvalue, bump off the oldest notes and replace
208209 //with a new note
@@ -211,12 +212,11 @@ define(function (require) {
211212
212213 var oldestNote = p5 . prototype . freqToMidi ( this . audiovoices [ this . _oldest ] . oscillator . freq ( ) . value ) ;
213214 this . noteRelease ( oldestNote ) ;
214- this . _oldest = ( this . _oldest + 1 ) % ( this . polyValue - 1 ) ;
215+ this . _oldest = ( this . _oldest + 1 ) % ( this . maxVoices - 1 ) ;
215216 }
216217
217- //Overrite the entry in the notes object. A note (frequency value)
218+ //Overrite the entry in the notes object. A note (frequency value)
218219 //corresponds to the index of the audiovoice that is playing it
219-
220220 this . notes [ note ] = new TimelineSignal ( ) ;
221221 this . notes [ note ] . setValueAtTime ( currentVoice , t ) ;
222222
@@ -229,7 +229,6 @@ define(function (require) {
229229 this . _updateAfter ( t , 1 ) ;
230230
231231 this . _newest = currentVoice ;
232-
233232 //The audiovoice handles the actual scheduling of the note
234233 if ( typeof velocity === 'number' ) {
235234 var maxRange = 1 / this . _voicesInUse . getValueAtTime ( t ) * 2 ;
@@ -241,7 +240,7 @@ define(function (require) {
241240 /**
242241 * Private method to ensure accurate values of this._voicesInUse
243242 * Any time a new value is scheduled, it is necessary to increment all subsequent
244- * scheduledValues after attack, and decrement all subsequent
243+ * scheduledValues after attack, and decrement all subsequent
245244 * scheduledValues after release
246245 *
247246 * @private
@@ -250,7 +249,6 @@ define(function (require) {
250249 * @return {[type] } [description]
251250 */
252251 p5 . PolySynth . prototype . _updateAfter = function ( time , value ) {
253-
254252 if ( this . _voicesInUse . _searchAfter ( time ) === null ) {
255253 return ;
256254 } else {
@@ -265,12 +263,12 @@ define(function (require) {
265263 * Trigger the Release of an AudioVoice note. This is similar to releasing
266264 * the key on a piano and letting the sound fade according to the
267265 * release level and release time.
268- *
266+ *
269267 * @method noteRelease
270268 * @param {Number } [note] midi note on which attack should be triggered.
271269 * @param {Number } [secondsFromNow] time to trigger the release
272- *
273- */
270+ *
271+ */
274272
275273 p5 . PolySynth . prototype . noteRelease = function ( _note , secondsFromNow ) {
276274 //Make sure note is in frequency inorder to query the this.notes object
@@ -281,24 +279,25 @@ define(function (require) {
281279 var tFromNow = secondsFromNow || 0 ;
282280 var t = now + tFromNow ;
283281
284-
282+
285283 if ( this . notes [ note ] . getValueAtTime ( t ) === null ) {
286284 console . warn ( 'Cannot release a note that is not already playing' ) ;
287285 } else {
288-
286+
289287
290288 //Find the scheduled change in this._voicesInUse that will be previous to this new note
291289 //subtract 1 and schedule this value at time 't', when this note will stop playing
292- var previousVal = this . _voicesInUse . _searchBefore ( t ) === null ? 0 : this . _voicesInUse . _searchBefore ( t ) . value ;
290+ var previousVal = Math . max ( ~ ~ this . _voicesInUse . getValueAtTime ( t ) . value , 1 ) ;
293291 this . _voicesInUse . setValueAtTime ( previousVal - 1 , t ) ;
294- //Then update all scheduled values that follow to decrease by 1
295- this . _updateAfter ( t , - 1 ) ;
292+ //Then update all scheduled values that follow to decrease by 1 but never go below 0
293+ if ( previousVal > 0 ) {
294+ this . _updateAfter ( t , - 1 ) ;
295+ }
296296
297297 this . audiovoices [ this . notes [ note ] . getValueAtTime ( t ) ] . triggerRelease ( tFromNow ) ;
298-
299298 this . notes [ note ] . setValueAtTime ( null , t ) ;
300299
301- this . _newest = this . _newest === 0 ? 0 : ( this . _newest - 1 ) % ( this . polyValue - 1 ) ;
300+ this . _newest = this . _newest === 0 ? 0 : ( this . _newest - 1 ) % ( this . maxVoices - 1 ) ;
302301 }
303302
304303 } ;
0 commit comments