HTML5 Web Audio Api 先给个识别频率的demo

四月时帮朋友做毕设,用到过这个api。当时感觉很炫酷。可惜这个api的限制比较多。比如getUserMedia这个接口,在iOS中是完全不支持的(别问我为什么 我也是试验出来的)在安卓中也是有许多坑。anyway 一句话总结:这个api除了能处理声音,在移动端用处很小。

今天有点累,就不写点啥了 直接把我当初写的一个demo放上来。当然这个demo中的傅立叶快速变换不是我自己写的 

autoCorrelate函数来自于微软一个开源的项目

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <meta name="full-screen" content="yes"/>
    <meta content="telephone=no" name="format-detection" />
    <meta name="screen-orientation" content="portrait"/>
    <meta name="x5-fullscreen" content="true"/>
    <meta name="360-fullscreen" content="true"/>
    <title>监听声音</title>
    <script src="js/get-float-time-domain-data.min.js"></script>
    <style type="text/css">
        .center {
            margin-right: auto;margin-left: auto;
        }
        #button {
            width: 30%;height: 50px;background-color: cornflowerblue;text-align: center;font-size: 18px;border-radius: 10px;line-height: 50px
        }
        #canvas {
            margin-top: 10px;
        }
    </style>
</head>
<body style="text-align: center">
<h1>声音监控</h1>
<br>
<h2 id="hz">点击开始</h2>
<div οnclick="buttonClicked()" id="button" class="center">开始监听</div>
<canvas id="canvas" class="center"></canvas>
<script type="application/javascript">
    var body = document.body,
        canvas = document.getElementById("canvas"),
        ctx = canvas.getContext("2d"),
        hz = document.getElementById("hz"),
        width = 0,
        height = 0,
        button = document.getElementById("button");

    var onRecord = false,//是否在录音
        currentHz = 0, //当前频率
        historyHz = [];//用来记录历史hz (为了canvas)

    //这个是主角 WebAudio
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var audioContext = null,
        sourceNode = null,
        analyser = null,
        theBuffer = null,
        mediaStreamSource = null;

    window.onload = function(){
        canvas.width = body.clientWidth*0.5;
        canvas.height = body.clientWidth*0.5;
        width = canvas.width;
        height = canvas.height;
        ctx.fillStyle = "#B0E2FF"
        ctx.fillRect(0,0,canvas.width,canvas.height);
        initWebAudioApi();
    }

    function initWebAudioApi(){
        try {
            audioContext = new AudioContext();
        }catch(e) {
            alert("您的设备不支持Web Audi Api");
        }
    }

    function error() {
        alert('Stream generation failed.');
    }

    function buttonClicked(){
        if (!onRecord){
            onRecord = true;
            button.innerText = "停止监听";
            hz.innerText = "0Hz";
            getUserMedia(
                    {
                        "audio": {
                            "mandatory": {
                                "googEchoCancellation": "false",
                                "googAutoGainControl": "false",
                                "googNoiseSuppression": "false",
                                "googHighpassFilter": "false"
                            },
                            "optional": []
                        },
                    }, gotStream);
        }else{
            onRecord = false;
            button.innerText = "开始监听";
            hz.innerText = "点击开始";
        }
    }

    function getUserMedia(dictionary, callback) {
        try {
            navigator.getUserMedia =
                    navigator.getUserMedia ||
                    navigator.webkitGetUserMedia ||
                    navigator.mozGetUserMedia;
            navigator.getUserMedia(dictionary, callback, error);
        } catch (e) {
            //常见错误原因是因为使用了http协议 (这个接口需要https)
            console.log(e)
            alert("抱歉GetUserMedia调用失败");
        }
    }

    function gotStream(stream) {
        mediaStreamSource = audioContext.createMediaStreamSource(stream);
        analyser = audioContext.createAnalyser();
        analyser.fftSize = 2048;
        mediaStreamSource.connect( analyser );
        updatePitch();
    }

    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)
            return -1;
        var lastCorrelation=1;
        for (var offset = 0; 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);
            correlations[offset] = correlation; // store it, for the tweaking we need to do below.
            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) {
            return sampleRate/best_offset;
        }
        return -1;
    }

    var buflen = 1024,
        frequency = 0;
    var buf = new Float32Array(buflen);

    function updatePitch(){
        frequency++;
        analyser.getFloatTimeDomainData(buf);
        var ac = autoCorrelate(buf,audioContext.sampleRate);
        var current_hz = 0;
        if (ac != -1){
            pitch = ac;
            current_hz = (Math.round( pitch ));
        }
        if (historyHz.length>=canvas.width){
            historyHz.shift();
        }
        currentHz = current_hz;
        historyHz.push((current_hz>20000)?20000:current_hz);
        hz.innerText = current_hz+"Hz";
        animate()
        loop = window.requestAnimationFrame( updatePitch );
    }

    function animate(){
        //未完待续
    }

</script>
</body>
</html>

注意:这个程序需要在https中打开才能使用(或者localhost:)

get-float-time-domain-data.min.js
这个js文件可以在网上下载到

https://www.npmjs.com/package/get-float-time-domain-data

不是必须的(只有部分不支持float time的浏览器需要添加)




  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值