Rewriting the SoundMeter class to be RMS and be encapsulated differently
This CL changes the SoundMeter to be root-mean-square. It also changes the interface between the meter and the display to be based on the display calling down to the meter rather than the meter calling up to the display. A graphic display of the results is also added. BUG= R=cwilso@google.com, dutton@google.com, henrika@webrtc.org, juberti@webrtc.org Review URL: https://webrtc-codereview.appspot.com/5439004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5256 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
77507eff4f
commit
c4038d795d
@ -77,13 +77,17 @@ if (navigator.mozGetUserMedia) {
|
||||
};
|
||||
|
||||
// Fake get{Video,Audio}Tracks
|
||||
MediaStream.prototype.getVideoTracks = function() {
|
||||
return [];
|
||||
};
|
||||
if (!MediaStream.prototype.getVideoTracks) {
|
||||
MediaStream.prototype.getVideoTracks = function() {
|
||||
return [];
|
||||
};
|
||||
}
|
||||
|
||||
MediaStream.prototype.getAudioTracks = function() {
|
||||
return [];
|
||||
};
|
||||
if (!MediaStream.prototype.getAudioTracks) {
|
||||
MediaStream.prototype.getAudioTracks = function() {
|
||||
return [];
|
||||
};
|
||||
}
|
||||
} else if (navigator.webkitGetUserMedia) {
|
||||
console.log("This appears to be Chrome");
|
||||
|
||||
|
@ -9,7 +9,52 @@
|
||||
var buttonStart;
|
||||
var buttonStop;
|
||||
var localStream;
|
||||
var soundMeter;
|
||||
var reporter;
|
||||
var audioContext;
|
||||
|
||||
// Meter class that generates a number correlated to audio volume.
|
||||
// The meter class itself displays nothing, but it makes the
|
||||
// instantaneous and time-decaying volumes available for inspection.
|
||||
// It also reports on the fraction of samples that were at or near
|
||||
// the top of the measurement range.
|
||||
function SoundMeter(context) {
|
||||
this.context = context
|
||||
this.volume = 0.0;
|
||||
this.slow_volume = 0.0;
|
||||
this.clip = 0.0;
|
||||
this.script = context.createScriptProcessor(2048, 1, 1);
|
||||
that = this;
|
||||
this.script.onaudioprocess = function(event) {
|
||||
var input = event.inputBuffer.getChannelData(0);
|
||||
var i;
|
||||
var sum = 0.0;
|
||||
var clipcount = 0;
|
||||
for (i = 0; i < input.length; ++i) {
|
||||
sum += input[i] * input[i];
|
||||
if (Math.abs(input[i]) > 0.99) {
|
||||
clipcount += 1
|
||||
}
|
||||
}
|
||||
that.volume = Math.sqrt(sum / input.length);
|
||||
that.slow_volume = 0.95 * that.slow_volume + 0.05 * that.volume;
|
||||
that.clip = clipcount / input.length;
|
||||
}
|
||||
}
|
||||
|
||||
SoundMeter.prototype.connectToSource = function(stream) {
|
||||
console.log('SoundMeter connecting');
|
||||
this.mic = this.context.createMediaStreamSource(stream);
|
||||
this.mic.connect(this.script);
|
||||
// Necessary to make sample run, but should not be.
|
||||
this.script.connect(this.context.destination);
|
||||
}
|
||||
|
||||
SoundMeter.prototype.stop = function() {
|
||||
this.mic.disconnect();
|
||||
this.script.disconnect();
|
||||
}
|
||||
|
||||
// End of SoundMeter class.
|
||||
|
||||
$ = function(id) {
|
||||
return document.getElementById(id);
|
||||
@ -26,11 +71,13 @@
|
||||
buttonStart.enabled = true;
|
||||
buttonStop.enabled = false;
|
||||
localStream.stop();
|
||||
clearInterval(reporter);
|
||||
soundMeter.stop();
|
||||
}
|
||||
|
||||
function gotStream(stream) {
|
||||
videoTracks = stream.getVideoTracks();
|
||||
audioTracks = stream.getAudioTracks();
|
||||
var videoTracks = stream.getVideoTracks();
|
||||
var audioTracks = stream.getAudioTracks();
|
||||
if (audioTracks.length == 1 && videoTracks.length == 0) {
|
||||
console.log('gotStream({audio:true, video:false})');
|
||||
console.log('Using audio device: ' + audioTracks[0].label);
|
||||
@ -42,18 +89,25 @@
|
||||
};
|
||||
|
||||
localStream = stream;
|
||||
soundMeter = new SoundMeter()
|
||||
meter = $('volume');
|
||||
decaying_meter = $('decaying_volume');
|
||||
decaying_volume = 0.0;
|
||||
soundMeter.showVolume = function(volume) {
|
||||
meter.innerHTML = volume.toFixed(2);
|
||||
decaying_volume = volume * 0.05 + decaying_volume * 0.95;
|
||||
decaying_meter.innerHTML = decaying_volume.toFixed(2);
|
||||
}
|
||||
soundMeter.connect(stream)
|
||||
var soundMeter = new SoundMeter(audioContext);
|
||||
soundMeter.connectToSource(stream);
|
||||
|
||||
// Set up reporting of the volume every 0.2 seconds.
|
||||
var meter = $('volume');
|
||||
var decaying_meter = $('decaying_volume');
|
||||
var meter_canvas = $('graphic_volume').getContext('2d');
|
||||
var meter_slow = $('graphic_slow').getContext('2d');
|
||||
var meter_clip = $('graphic_clip').getContext('2d');
|
||||
reporter = setInterval(function() {
|
||||
meter.textContent = soundMeter.volume.toFixed(2);
|
||||
decaying_meter.textContent = soundMeter.slow_volume.toFixed(2);
|
||||
paintMeter(meter_canvas, soundMeter.volume);
|
||||
paintMeter(meter_slow, soundMeter.slow_volume);
|
||||
paintMeter(meter_clip, soundMeter.clip);
|
||||
}, 200);
|
||||
} else {
|
||||
alert('The media stream contains an invalid amount of audio tracks.');
|
||||
alert('The media stream contains an invalid amount of tracks:'
|
||||
+ audioTracks.length + ' audio ' + videoTracks.length + ' video');
|
||||
stream.stop();
|
||||
}
|
||||
}
|
||||
@ -65,6 +119,12 @@
|
||||
}
|
||||
|
||||
function onload() {
|
||||
try {
|
||||
window.AudioContext = window.AudioContext || window.webkitAudioContext;
|
||||
audioContext = new AudioContext();
|
||||
} catch(e) {
|
||||
alert('Web Audio API not found');
|
||||
}
|
||||
audioElement = $('audio');
|
||||
buttonStart = $('start');
|
||||
buttonStop = $('stop');
|
||||
@ -72,37 +132,22 @@
|
||||
buttonStop.disabled = true;
|
||||
}
|
||||
|
||||
// Meter class that generates a number.
|
||||
function SoundMeter() {
|
||||
this.context = new webkitAudioContext();
|
||||
this.volume = 0.0;
|
||||
}
|
||||
|
||||
SoundMeter.prototype.connect = function(stream) {
|
||||
console.log('SoundMeter connecting');
|
||||
this.mic = this.context.createMediaStreamSource(stream);
|
||||
this.script = this.context.createScriptProcessor(1024, 1, 1);
|
||||
that = this;
|
||||
this.script.onaudioprocess = function(event) {
|
||||
var input = event.inputBuffer.getChannelData(0);
|
||||
var i;
|
||||
var sum = 0.0;
|
||||
for (i = 0; i < input.length; ++i) {
|
||||
sum += Math.abs(input[i]);
|
||||
}
|
||||
that.showVolume(sum / input.length);
|
||||
}
|
||||
console.log('Buffer size ' + this.script.bufferSize);
|
||||
this.mic.connect(this.script);
|
||||
// Necessary to make sample run, but should not be.
|
||||
this.script.connect(this.context.destination)
|
||||
}
|
||||
|
||||
SoundMeter.prototype.showVolume = function(volume) {
|
||||
alert('Dummy showVolume called')
|
||||
function paintMeter(context, number) {
|
||||
context.clearRect(0, 0, 400, 20);
|
||||
context.fillStyle = 'red';
|
||||
context.fillRect(0, 0, number * 400, 20);
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
button {
|
||||
font: 14px sans-serif;
|
||||
padding: 8px;
|
||||
}
|
||||
canvas {
|
||||
border:1px solid #000000;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="onload()">
|
||||
@ -111,16 +156,16 @@
|
||||
using WebAudio.<br>
|
||||
Press Start, select a microphone, listen to your own voice in loopback,
|
||||
and see the numbers change as you speak.</p>
|
||||
<style>
|
||||
button {
|
||||
font: 14px sans-serif;
|
||||
padding: 8px;
|
||||
}
|
||||
</style>
|
||||
The "instant" volume changes approximately every 50 ms; the "slow"
|
||||
volume approximates the average volume over about a second.
|
||||
<audio id="audio" autoplay="autoplay" controls="controls"></audio><br><br>
|
||||
<button id="start" onclick="start()">Start</button>
|
||||
<button id="stop" onclick="stop()">Stop</button><br><br>
|
||||
Volume (instant): <span id="volume">Not set</span><br>
|
||||
Volume (slow): <span id="decaying_volume">Not set</span>
|
||||
Volume (slow): <span id="decaying_volume">Not set</span><br>
|
||||
<canvas id="graphic_volume" width="400" height="20"></canvas> Volume<br>
|
||||
<canvas id="graphic_slow" width="400" height="20"></canvas> Slow<br>
|
||||
<canvas id="graphic_clip" width="400" height="20"></canvas> Clipping
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user