|
89 | 89 | * }
|
90 | 90 | * </code></div>
|
91 | 91 | */
|
92 |
| -p5.PeakDetect = function (freq1, freq2, threshold, _framesPerPeak) { |
| 92 | +class PeakDetect { |
93 | 93 | // framesPerPeak determines how often to look for a beat.
|
94 | 94 | // If a beat is provided, try to look for a beat based on bpm
|
95 |
| - this.framesPerPeak = _framesPerPeak || 20; |
96 |
| - this.framesSinceLastPeak = 0; |
97 |
| - this.decayRate = 0.95; |
| 95 | + constructor(freq1, freq2, threshold, _framesPerPeak) { |
| 96 | + this.framesPerPeak = _framesPerPeak || 20; |
| 97 | + this.framesSinceLastPeak = 0; |
| 98 | + this.decayRate = 0.95; |
98 | 99 |
|
99 |
| - this.threshold = threshold || 0.35; |
100 |
| - this.cutoff = 0; |
| 100 | + this.threshold = threshold || 0.35; |
| 101 | + this.cutoff = 0; |
101 | 102 |
|
102 |
| - // how much to increase the cutoff |
103 |
| - // TO DO: document this / figure out how to make it accessible |
104 |
| - this.cutoffMult = 1.5; |
| 103 | + // how much to increase the cutoff |
| 104 | + // TO DO: document this / figure out how to make it accessible |
| 105 | + this.cutoffMult = 1.5; |
105 | 106 |
|
106 |
| - this.energy = 0; |
107 |
| - this.penergy = 0; |
| 107 | + this.energy = 0; |
| 108 | + this.penergy = 0; |
108 | 109 |
|
109 |
| - // TO DO: document this property / figure out how to make it accessible |
110 |
| - this.currentValue = 0; |
| 110 | + // TO DO: document this property / figure out how to make it accessible |
| 111 | + this.currentValue = 0; |
111 | 112 |
|
112 |
| - /** |
113 |
| - * isDetected is set to true when a peak is detected. |
114 |
| - * |
115 |
| - * @attribute isDetected {Boolean} |
116 |
| - * @default false |
117 |
| - */ |
118 |
| - this.isDetected = false; |
| 113 | + /** |
| 114 | + * isDetected is set to true when a peak is detected. |
| 115 | + * |
| 116 | + * @attribute isDetected {Boolean} |
| 117 | + * @default false |
| 118 | + */ |
| 119 | + this.isDetected = false; |
119 | 120 |
|
120 |
| - this.f1 = freq1 || 40; |
121 |
| - this.f2 = freq2 || 20000; |
| 121 | + this.f1 = freq1 || 40; |
| 122 | + this.f2 = freq2 || 20000; |
122 | 123 |
|
123 |
| - // function to call when a peak is detected |
124 |
| - this._onPeak = function () {}; |
125 |
| -}; |
| 124 | + // function to call when a peak is detected |
| 125 | + this._onPeak = function () {}; |
| 126 | + } |
126 | 127 |
|
127 |
| -/** |
128 |
| - * The update method is run in the draw loop. |
129 |
| - * |
130 |
| - * Accepts an FFT object. You must call .analyze() |
131 |
| - * on the FFT object prior to updating the peakDetect |
132 |
| - * because it relies on a completed FFT analysis. |
133 |
| - * |
134 |
| - * @method update |
135 |
| - * @param {p5.FFT} fftObject A p5.FFT object |
136 |
| - */ |
137 |
| -p5.PeakDetect.prototype.update = function (fftObject) { |
138 |
| - var nrg = (this.energy = fftObject.getEnergy(this.f1, this.f2) / 255); |
139 |
| - if (nrg > this.cutoff && nrg > this.threshold && nrg - this.penergy > 0) { |
140 |
| - // trigger callback |
141 |
| - this._onPeak(); |
142 |
| - this.isDetected = true; |
| 128 | + /** |
| 129 | + * The update method is run in the draw loop. |
| 130 | + * |
| 131 | + * Accepts an FFT object. You must call .analyze() |
| 132 | + * on the FFT object prior to updating the peakDetect |
| 133 | + * because it relies on a completed FFT analysis. |
| 134 | + * |
| 135 | + * @method update |
| 136 | + * @param {p5.FFT} fftObject A p5.FFT object |
| 137 | + */ |
| 138 | + update(fftObject) { |
| 139 | + var nrg = (this.energy = fftObject.getEnergy(this.f1, this.f2) / 255); |
| 140 | + if (nrg > this.cutoff && nrg > this.threshold && nrg - this.penergy > 0) { |
| 141 | + // trigger callback |
| 142 | + this._onPeak(); |
| 143 | + this.isDetected = true; |
143 | 144 |
|
144 |
| - // debounce |
145 |
| - this.cutoff = nrg * this.cutoffMult; |
146 |
| - this.framesSinceLastPeak = 0; |
147 |
| - } else { |
148 |
| - this.isDetected = false; |
149 |
| - if (this.framesSinceLastPeak <= this.framesPerPeak) { |
150 |
| - this.framesSinceLastPeak++; |
| 145 | + // debounce |
| 146 | + this.cutoff = nrg * this.cutoffMult; |
| 147 | + this.framesSinceLastPeak = 0; |
151 | 148 | } else {
|
152 |
| - this.cutoff *= this.decayRate; |
153 |
| - this.cutoff = Math.max(this.cutoff, this.threshold); |
| 149 | + this.isDetected = false; |
| 150 | + if (this.framesSinceLastPeak <= this.framesPerPeak) { |
| 151 | + this.framesSinceLastPeak++; |
| 152 | + } else { |
| 153 | + this.cutoff *= this.decayRate; |
| 154 | + this.cutoff = Math.max(this.cutoff, this.threshold); |
| 155 | + } |
154 | 156 | }
|
| 157 | + |
| 158 | + this.currentValue = nrg; |
| 159 | + this.penergy = nrg; |
155 | 160 | }
|
156 | 161 |
|
157 |
| - this.currentValue = nrg; |
158 |
| - this.penergy = nrg; |
159 |
| -}; |
| 162 | + /** |
| 163 | + * onPeak accepts two arguments: a function to call when |
| 164 | + * a peak is detected. The value of the peak, |
| 165 | + * between 0.0 and 1.0, is passed to the callback. |
| 166 | + * |
| 167 | + * @method onPeak |
| 168 | + * @param {Function} callback Name of a function that will |
| 169 | + * be called when a peak is |
| 170 | + * detected. |
| 171 | + * @param {Object} [val] Optional value to pass |
| 172 | + * into the function when |
| 173 | + * a peak is detected. |
| 174 | + * @example |
| 175 | + * <div><code> |
| 176 | + * var cnv, soundFile, fft, peakDetect; |
| 177 | + * var ellipseWidth = 0; |
| 178 | + * |
| 179 | + * function preload() { |
| 180 | + * soundFile = loadSound('assets/beat.mp3'); |
| 181 | + * } |
| 182 | + * |
| 183 | + * function setup() { |
| 184 | + * cnv = createCanvas(100,100); |
| 185 | + * textAlign(CENTER); |
| 186 | + * |
| 187 | + * fft = new p5.FFT(); |
| 188 | + * peakDetect = new p5.PeakDetect(); |
| 189 | + * |
| 190 | + * setupSound(); |
| 191 | + * |
| 192 | + * // when a beat is detected, call triggerBeat() |
| 193 | + * peakDetect.onPeak(triggerBeat); |
| 194 | + * } |
| 195 | + * |
| 196 | + * function draw() { |
| 197 | + * background(0); |
| 198 | + * fill(255); |
| 199 | + * text('click to play', width/2, height/2); |
| 200 | + * |
| 201 | + * fft.analyze(); |
| 202 | + * peakDetect.update(fft); |
| 203 | + * |
| 204 | + * ellipseWidth *= 0.95; |
| 205 | + * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); |
| 206 | + * } |
| 207 | + * |
| 208 | + * // this function is called by peakDetect.onPeak |
| 209 | + * function triggerBeat() { |
| 210 | + * ellipseWidth = 50; |
| 211 | + * } |
| 212 | + * |
| 213 | + * // mouseclick starts/stops sound |
| 214 | + * function setupSound() { |
| 215 | + * cnv.mouseClicked( function() { |
| 216 | + * if (soundFile.isPlaying() ) { |
| 217 | + * soundFile.stop(); |
| 218 | + * } else { |
| 219 | + * soundFile.play(); |
| 220 | + * } |
| 221 | + * }); |
| 222 | + * } |
| 223 | + * </code></div> |
| 224 | + */ |
| 225 | + onPeak(callback, val) { |
| 226 | + var self = this; |
160 | 227 |
|
161 |
| -/** |
162 |
| - * onPeak accepts two arguments: a function to call when |
163 |
| - * a peak is detected. The value of the peak, |
164 |
| - * between 0.0 and 1.0, is passed to the callback. |
165 |
| - * |
166 |
| - * @method onPeak |
167 |
| - * @param {Function} callback Name of a function that will |
168 |
| - * be called when a peak is |
169 |
| - * detected. |
170 |
| - * @param {Object} [val] Optional value to pass |
171 |
| - * into the function when |
172 |
| - * a peak is detected. |
173 |
| - * @example |
174 |
| - * <div><code> |
175 |
| - * var cnv, soundFile, fft, peakDetect; |
176 |
| - * var ellipseWidth = 0; |
177 |
| - * |
178 |
| - * function preload() { |
179 |
| - * soundFile = loadSound('assets/beat.mp3'); |
180 |
| - * } |
181 |
| - * |
182 |
| - * function setup() { |
183 |
| - * cnv = createCanvas(100,100); |
184 |
| - * textAlign(CENTER); |
185 |
| - * |
186 |
| - * fft = new p5.FFT(); |
187 |
| - * peakDetect = new p5.PeakDetect(); |
188 |
| - * |
189 |
| - * setupSound(); |
190 |
| - * |
191 |
| - * // when a beat is detected, call triggerBeat() |
192 |
| - * peakDetect.onPeak(triggerBeat); |
193 |
| - * } |
194 |
| - * |
195 |
| - * function draw() { |
196 |
| - * background(0); |
197 |
| - * fill(255); |
198 |
| - * text('click to play', width/2, height/2); |
199 |
| - * |
200 |
| - * fft.analyze(); |
201 |
| - * peakDetect.update(fft); |
202 |
| - * |
203 |
| - * ellipseWidth *= 0.95; |
204 |
| - * ellipse(width/2, height/2, ellipseWidth, ellipseWidth); |
205 |
| - * } |
206 |
| - * |
207 |
| - * // this function is called by peakDetect.onPeak |
208 |
| - * function triggerBeat() { |
209 |
| - * ellipseWidth = 50; |
210 |
| - * } |
211 |
| - * |
212 |
| - * // mouseclick starts/stops sound |
213 |
| - * function setupSound() { |
214 |
| - * cnv.mouseClicked( function() { |
215 |
| - * if (soundFile.isPlaying() ) { |
216 |
| - * soundFile.stop(); |
217 |
| - * } else { |
218 |
| - * soundFile.play(); |
219 |
| - * } |
220 |
| - * }); |
221 |
| - * } |
222 |
| - * </code></div> |
223 |
| - */ |
224 |
| -p5.PeakDetect.prototype.onPeak = function (callback, val) { |
225 |
| - var self = this; |
| 228 | + self._onPeak = function () { |
| 229 | + callback(self.energy, val); |
| 230 | + }; |
| 231 | + } |
| 232 | +} |
226 | 233 |
|
227 |
| - self._onPeak = function () { |
228 |
| - callback(self.energy, val); |
229 |
| - }; |
230 |
| -}; |
| 234 | +export default PeakDetect; |
0 commit comments