2017-08-27 21:50:31 +00:00
|
|
|
define(["Tone/core/Tone", "Tone/component/Analyser", "Tone/core/AudioNode"], function(Tone){
|
2014-03-11 23:27:46 +00:00
|
|
|
|
2014-09-04 04:41:40 +00:00
|
|
|
"use strict";
|
|
|
|
|
2014-06-16 01:18:29 +00:00
|
|
|
/**
|
2018-05-16 14:41:02 +00:00
|
|
|
* @class Tone.Meter gets the Peak or [RMS](https://en.wikipedia.org/wiki/Root_mean_square)
|
2017-08-27 21:50:31 +00:00
|
|
|
* of an input signal with some averaging applied. It can also get the raw
|
2016-05-18 01:26:57 +00:00
|
|
|
* value of the input signal.
|
2014-06-16 01:18:29 +00:00
|
|
|
*
|
|
|
|
* @constructor
|
2017-08-27 21:50:31 +00:00
|
|
|
* @extends {Tone.AudioNode}
|
2016-05-18 01:26:57 +00:00
|
|
|
* @param {Number} smoothing The amount of smoothing applied between frames.
|
2018-05-16 14:41:02 +00:00
|
|
|
* @param {'rms' | 'peak'} type Calculation method of dB value, defaults to RMS
|
2015-07-02 00:19:58 +00:00
|
|
|
* @example
|
|
|
|
* var meter = new Tone.Meter();
|
2017-04-20 19:12:16 +00:00
|
|
|
* var mic = new Tone.UserMedia().open();
|
2015-07-02 00:19:58 +00:00
|
|
|
* //connect mic to the meter
|
|
|
|
* mic.connect(meter);
|
2017-08-31 14:56:19 +00:00
|
|
|
* //the current level of the mic input in decibels
|
|
|
|
* var level = meter.getValue();
|
2014-06-16 01:18:29 +00:00
|
|
|
*/
|
2015-08-28 22:32:20 +00:00
|
|
|
Tone.Meter = function(){
|
|
|
|
|
2017-08-31 14:56:19 +00:00
|
|
|
var options = Tone.defaults(arguments, ["smoothing"], Tone.Meter);
|
2017-08-27 21:50:31 +00:00
|
|
|
Tone.AudioNode.call(this);
|
|
|
|
|
2016-05-14 23:13:50 +00:00
|
|
|
/**
|
|
|
|
* The analyser node which computes the levels.
|
2014-06-16 01:18:29 +00:00
|
|
|
* @private
|
2016-05-14 23:13:50 +00:00
|
|
|
* @type {Tone.Analyser}
|
2014-06-16 01:18:29 +00:00
|
|
|
*/
|
2017-08-31 14:56:19 +00:00
|
|
|
this.input = this.output = this._analyser = new Tone.Analyser("waveform", 1024);
|
2014-03-11 23:27:46 +00:00
|
|
|
|
2018-04-09 17:24:10 +00:00
|
|
|
//set the smoothing initially
|
2016-05-14 23:13:50 +00:00
|
|
|
this.smoothing = options.smoothing;
|
2018-05-16 14:41:02 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Calculation method used to get the dB value
|
|
|
|
* @type {'rms' | 'peak'}
|
|
|
|
*/
|
|
|
|
this.type = options.type;
|
2014-06-15 22:19:05 +00:00
|
|
|
};
|
2014-03-11 23:27:46 +00:00
|
|
|
|
2017-08-27 21:50:31 +00:00
|
|
|
Tone.extend(Tone.Meter, Tone.AudioNode);
|
2014-03-11 23:27:46 +00:00
|
|
|
|
2018-05-16 14:41:02 +00:00
|
|
|
/**
|
|
|
|
* Calculation methods available for dB value, default is RMS
|
|
|
|
* @enum {String}
|
|
|
|
*/
|
|
|
|
Tone.Meter.Type = {
|
|
|
|
RMS : "rms",
|
|
|
|
Peak : "peak"
|
|
|
|
};
|
|
|
|
|
2015-08-28 22:32:20 +00:00
|
|
|
/**
|
|
|
|
* The defaults
|
|
|
|
* @type {Object}
|
|
|
|
* @static
|
|
|
|
* @const
|
|
|
|
*/
|
|
|
|
Tone.Meter.defaults = {
|
2018-05-16 14:41:02 +00:00
|
|
|
"smoothing" : 0.8,
|
|
|
|
"type" : Tone.Meter.Type.RMS
|
2017-08-31 14:56:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current decibel value of the incoming signal
|
|
|
|
* @returns {Decibels}
|
|
|
|
*/
|
|
|
|
Tone.Meter.prototype.getLevel = function(){
|
|
|
|
var values = this._analyser.getValue();
|
2018-05-16 14:41:02 +00:00
|
|
|
|
|
|
|
switch (this.type){
|
|
|
|
case Tone.Meter.Type.RMS:
|
|
|
|
var rmsFloatValue = this.getRmsFloatValue(values);
|
|
|
|
return Tone.gainToDb(rmsFloatValue);
|
|
|
|
case Tone.Meter.Type.Peak:
|
|
|
|
var peakFloatValue = this.getPeakFloatValue(values);
|
|
|
|
return Tone.gainToDb(peakFloatValue);
|
|
|
|
default:
|
|
|
|
// Sanity check, should have thrown while setting type
|
|
|
|
throw new TypeError("Tone.Meter: invalid type: " + this.type);
|
|
|
|
}
|
2015-08-28 22:32:20 +00:00
|
|
|
};
|
|
|
|
|
2014-06-16 01:18:29 +00:00
|
|
|
/**
|
2017-08-31 14:56:19 +00:00
|
|
|
* Get the signal value of the incoming signal
|
|
|
|
* @returns {Number}
|
|
|
|
*/
|
|
|
|
Tone.Meter.prototype.getValue = function(){
|
|
|
|
var value = this._analyser.getValue();
|
|
|
|
return value[0];
|
|
|
|
};
|
|
|
|
|
2018-05-16 14:41:02 +00:00
|
|
|
/**
|
|
|
|
* Gets the peak value from a Float32Array, uses absolute values so
|
|
|
|
* negative values are counted towards the peak.
|
|
|
|
*
|
|
|
|
* @param {Float32Array} values Float32Array with amplitude ratio readings
|
|
|
|
* @returns {Number}
|
|
|
|
*/
|
|
|
|
Tone.Meter.prototype.getPeakFloatValue = function(values){
|
|
|
|
var peak = 0;
|
|
|
|
for (var i = 0; i < values.length; i++){
|
|
|
|
var value = Math.abs(values[i]);
|
|
|
|
if (value > peak){
|
|
|
|
peak = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return peak;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Gets the [RMS](https://en.wikipedia.org/wiki/Root_mean_square) value from a Float32Array
|
|
|
|
*
|
|
|
|
* @param {Float32Array} values Float32Array with amplitude ratio readings
|
|
|
|
* @returns {Number}
|
|
|
|
*/
|
|
|
|
Tone.Meter.prototype.getRmsFloatValue = function(values){
|
|
|
|
var totalSquared = 0;
|
|
|
|
for (var i = 0; i < values.length; i++){
|
|
|
|
var value = values[i];
|
|
|
|
totalSquared += value * value;
|
|
|
|
}
|
|
|
|
return Math.sqrt(totalSquared / values.length);
|
|
|
|
};
|
|
|
|
|
2017-08-31 14:56:19 +00:00
|
|
|
/**
|
|
|
|
* A value from 0 -> 1 where 0 represents no time averaging with the last analysis frame.
|
2016-05-14 23:13:50 +00:00
|
|
|
* @memberOf Tone.Meter#
|
|
|
|
* @type {Number}
|
2017-08-31 14:56:19 +00:00
|
|
|
* @name smoothing
|
2016-05-14 23:13:50 +00:00
|
|
|
* @readOnly
|
2015-02-02 17:49:13 +00:00
|
|
|
*/
|
2017-08-31 14:56:19 +00:00
|
|
|
Object.defineProperty(Tone.Meter.prototype, "smoothing", {
|
2016-05-14 23:13:50 +00:00
|
|
|
get : function(){
|
2017-08-31 14:56:19 +00:00
|
|
|
return this._analyser.smoothing;
|
|
|
|
},
|
|
|
|
set : function(val){
|
|
|
|
this._analyser.smoothing = val;
|
2018-05-16 14:41:02 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Either 'rms' or 'peak', determines calculation method of getValue
|
|
|
|
* @memberOf Tone.Meter#
|
|
|
|
* @type {'rms' | 'peak'}
|
|
|
|
* @name type
|
|
|
|
*/
|
|
|
|
Object.defineProperty(Tone.Meter.prototype, "type", {
|
|
|
|
get : function(){
|
|
|
|
return this._type;
|
2016-05-14 23:13:50 +00:00
|
|
|
},
|
2018-05-16 14:41:02 +00:00
|
|
|
set : function(type){
|
|
|
|
if (type !== Tone.Meter.Type.RMS && type !== Tone.Meter.Type.Peak){
|
|
|
|
throw new TypeError("Tone.Meter: invalid type: " + type);
|
|
|
|
}
|
|
|
|
this._type = type;
|
|
|
|
}
|
2016-05-14 23:13:50 +00:00
|
|
|
});
|
2014-04-05 22:05:42 +00:00
|
|
|
|
2014-06-19 02:35:31 +00:00
|
|
|
/**
|
2015-06-20 23:25:49 +00:00
|
|
|
* Clean up.
|
2015-06-14 00:54:29 +00:00
|
|
|
* @returns {Tone.Meter} this
|
2014-06-19 02:35:31 +00:00
|
|
|
*/
|
|
|
|
Tone.Meter.prototype.dispose = function(){
|
2017-08-27 21:50:31 +00:00
|
|
|
Tone.AudioNode.prototype.dispose.call(this);
|
2016-05-14 23:13:50 +00:00
|
|
|
this._analyser.dispose();
|
|
|
|
this._analyser = null;
|
2015-02-02 17:49:13 +00:00
|
|
|
return this;
|
2014-06-19 02:35:31 +00:00
|
|
|
};
|
|
|
|
|
2014-04-05 22:05:42 +00:00
|
|
|
return Tone.Meter;
|
2017-08-27 21:50:31 +00:00
|
|
|
});
|