window.AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext = null;
var isPlaying = false;
var sourceNode = null;
var analyser = null;
var theBuffer = null;
var DEBUGCANVAS = null;
var mediaStreamSource = null;
var detectorElem,
pitchElem ;
var testdelay = null;
window.onload = function() {
audioContext = new AudioContext();
//test delay
//testdelay = audioContext.createDelay(5.0);
//testdelay.delayTime.value = 3.0;
MAX_SIZE = Math.max(4,Math.floor(audioContext.sampleRate/5000)); // corresponds to a 5kHz signal
var request = new XMLHttpRequest();
request.open("GET", "../sounds/whistling3.ogg", true);
request.responseType = "arraybuffer";
request.onload = function() {
audioContext.decodeAudioData( request.response, function(buffer) {
theBuffer = buffer;
} );
}
request.send();
detectorElem = document.getElementById( "detector" );
pitchElem = document.getElementById( "pitch" );
detectorElem.ondragenter = function () {
this.classList.add("droptarget");
return false; };
detectorElem.ondragleave = function () { this.classList.remove("droptarget"); return false; };
detectorElem.ondrop = function (e) {
this.classList.remove("droptarget");
e.preventDefault();
theBuffer = null;
var reader = new FileReader();
reader.onload = function (event) {
audioContext.decodeAudioData( event.target.result, function(buffer) {
theBuffer = buffer;
}, function(){alert("error loading!");} );
};
reader.onerror = function (event) {
alert("Error: " + reader.error );
};
reader.readAsArrayBuffer(e.dataTransfer.files[0]);
return false;
};
}
function error() {
alert('Stream generation failed.');
}
function getUserMedia(dictionary, callback) {
try {
navigator.getUserMedia =
navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia;
navigator.getUserMedia(dictionary, callback, error);
} catch (e) {
alert('getUserMedia threw exception :' + e);
}
}
function gotStream(stream) {
// Create an AudioNode from the stream.
mediaStreamSource = audioContext.createMediaStreamSource(stream);
// Connect it to the destination.
analyser = audioContext.createAnalyser();
//test delay
//testdelay = audioContext.createDelay(5.0);
//testdelay.delayTime.value = 3.0;
//analyser.smoothingTimeConstant = 0.8;
analyser.fftSize = 8192;
mediaStreamSource.connect( analyser );
updatePitch();
}
function toggleLiveInput() {
if (isPlaying) {
//stop playing and return
sourceNode.stop( 0 );
sourceNode = null;
analyser = null;
isPlaying = false;
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
window.cancelAnimationFrame( rafID );
}
getUserMedia(
{
"audio": {
"mandatory": {
"googEchoCancellation": "false",
"googAutoGainControl": "false",
"googNoiseSuppression": "false",
"googHighpassFilter": "false"
},
"optional": []
},
}, gotStream);
}
var buf = new Float32Array( 1024 );
var MIN_SAMPLES = 0; // will be initialized when AudioContext is created.
function autoCorrelate( buf, sampleRate ) {
var SIZE = buf.length;
var MAX_SAMPLES = Math.floor(SIZE/2);
var best_offset = -1;
var best_correlation = 0;
var rms = 0;
var foundGoodCorrelation = false;
var correlations = new Array(MAX_SAMPLES);
for (var i=0;i<SIZE;i++) {
var val = buf[i];
rms += val*val;
}
rms = Math.sqrt(rms/SIZE);
if (rms<0.01) // not enough signal
return -1;
var lastCorrelation=1;
for (var offset = MIN_SAMPLES; offset < MAX_SAMPLES; offset++) {
var correlation = 0;
for (var i=0; i<MAX_SAMPLES; i++) {
correlation += Math.abs((buf[i])-(buf[i+offset]));
}
correlation = 1 - (correlation/MAX_SAMPLES);
// store it, for the tweaking we need to do below.
correlations[offset] = correlation;
if ((correlation>0.9) && (correlation > lastCorrelation)) {
foundGoodCorrelation = true;
if (correlation > best_correlation) {
best_correlation = correlation;
best_offset = offset;
}
} else if (foundGoodCorrelation) {
var shift = (correlations[best_offset+1] - correlations[best_offset-1])/correlations[best_offset];
return sampleRate/(best_offset+(8*shift));
}
lastCorrelation = correlation;
}
if (best_correlation > 0.01) {
// console.log("f = " + sampleRate/best_offset + "Hz (rms: " + rms + " confidence: " + best_correlation + ")")
return sampleRate/best_offset;
}
return -1;
// var best_frequency = sampleRate/best_offset;
}
//Fungsi untuk melakukan Update/perubahan data frequensi
function updatePitch( time ) {
var cycles = new Array;
analyser.getFloatTimeDomainData( buf );
analyser.smoothingTimeConstant = 0.8;
var ac = autoCorrelate( buf, audioContext.sampleRate );
//menampilkan data pada form
//jika tidak ditemukanya gelombang maka data akan kosong, dan warna tampilan akan abu2
if (ac == -1) {
detectorElem.className = "vague";
pitchElem.innerText = "";
//jika ditemukanya gelombang maka data akan kosong, dan warna tampilan akan hitam dan data akan ditampilkan
} else {
detectorElem.className = "confident";
pitch = ac;
//menampilkan data "pitch" (--Hz) pada halaman Web
pitchElem.innerText = Math.round( pitch ) ;
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = window.webkitRequestAnimationFrame;
rafID = window.requestAnimationFrame( updatePitch );
}
&#13;
<!doctype html>
<html>
<head>
<title>Pitch Detector</title>
<link href='http://fonts.googleapis.com/css?family=Alike' rel='stylesheet' type='text/css'>
<style>
body { font: 14pt 'Alike', sans-serif;}
#note { font-size: 164px; }
.droptarget { background-color: #348781}
div.confident { color: black; }
div.vague { color: lightgrey; }
#note { display: inline-block; height:180px; text-align: left;}
#detector { width: 300px; height: 300px; border: 4px solid gray; border-radius: 8px; text-align: center; padding-top: 10px;}
#output { width: 300px; height: 42px; }
#flat { display: none; }
#sharp { display: none; }
.flat #flat { display: inline; }
.sharp #sharp { display: inline; }
</style>
</head>
<body>
<script src="js/pitchdetect.js"></script>
<!-- <button onclick="this.innerText = togglePlayback()">use demo audio</button> -->
<center>
<button onclick="toggleLiveInput()">use live input</button>
<!--<button onclick="updatePitch(0);">sample</button>-->
<div id="detector" class="vague">
<div class="pitch"><span id="pitch">--</span>Hz</div>
<div class="note"><span id="note">--</span></div>
<canvas id="output" width=300 height=42></canvas>
<div id="detune"><span id="detune_amt">--</span><span id="flat">cents ♭</span><span id="sharp">cents ♯</span></div>
</div>
<!-- just used for debugging
<canvas id="waveform" width="512" height="256"></canvas>
-->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-35593052-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</center>
</body>
</html>
&#13;
有没有人有使用麦克风在网上制作实时频率计(php,javascript)的经验?
我有一个制作在线实时频率计的项目。显示频率编号,以便我们记录产品是否良好。 但频率数字运行得太快..
任何人都可以帮助我,如何跳过一些updatePicht()或某种方式来延迟显示,以便更容易看? 或平滑价值的方式......
答案 0 :(得分:0)
我认为你基本上必须平滑你自己从updatePitch()获得的频率估计。要么不那么频繁地调用updatePitch,这可能不是你想要的,也不是对updatePitch返回的值进行某种运行平均。