【问题标题】:Multiple instances in web audio网络音频中的多个实例
【发布时间】:2020-03-04 17:20:13
【问题描述】:

我正在尝试使用 HTML 和 JavaScript 制作一个简单的钢琴软件,它可以只用键盘琴键演奏一个八度音阶。按键布局差不多是这样的:

虽然声音不像钢琴,但我稍后会考虑这部分。我写了这段代码:

<html>

<body onkeydown="play(event)" onkeyup="stop(event)">
    <span style="font-size:10em;">Piano</span>
    <script>
        var context, o, g;

        function play(event) {
            context = new AudioContext();
            o = context.createOscillator();
            var key = event.which || event.keyCode;
            if (key == 49) o.frequency.value = 116.54;
            if (key == 81) o.frequency.value = 123.47;
            if (key == 87) o.frequency.value = 130.81;
            if (key == 51) o.frequency.value = 138.59;
            if (key == 69) o.frequency.value = 146.83;
            if (key == 52) o.frequency.value = 155.56;
            if (key == 82) o.frequency.value = 164.81;
            if (key == 84) o.frequency.value = 174.61;
            if (key == 54) o.frequency.value = 185.00;
            if (key == 89) o.frequency.value = 196.00;
            if (key == 55) o.frequency.value = 207.65;
            if (key == 85) o.frequency.value = 220.00;
            if (key == 56) o.frequency.value = 233.08;
            if (key == 73) o.frequency.value = 246.94;
            if (key == 79) o.frequency.value = 261.63;
            if (key == 48) o.frequency.value = 277.18;
            if (key == 80) o.frequency.value = 293.66;
            if (key == 189) o.frequency.value = 311.13;
            if (key == 219) o.frequency.value = 329.63;
            if (key == 221) o.frequency.value = 349.23;
            g = context.createGain();
            o.connect(g);
            g.connect(context.destination);
            o.start(0);
        }

        function stop(event) {
            g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
            o.disconnect(context.destination);
        }
    </script>
</body>

</html>

现在,问题是,如果我按住一个键,就会有多个该特定频率的实例。因此,我不能同时按下多个键。为了克服这个问题,我稍微修改了代码:



var context, o, g;

    function play(event) {
        context = new AudioContext();
        o = context.createOscillator();
        var key = event.which || event.keyCode;
        if (key == 49) o.frequency.value = 116.54;
        if (key == 81) o.frequency.value = 123.47;
        if (key == 87) o.frequency.value = 130.81;
        if (key == 51) o.frequency.value = 138.59;
        if (key == 69) o.frequency.value = 146.83;
        if (key == 52) o.frequency.value = 155.56;
        if (key == 82) o.frequency.value = 164.81;
        if (key == 84) o.frequency.value = 174.61;
        if (key == 54) o.frequency.value = 185.00;
        if (key == 89) o.frequency.value = 196.00;
        if (key == 55) o.frequency.value = 207.65;
        if (key == 85) o.frequency.value = 220.00;
        if (key == 56) o.frequency.value = 233.08;
        if (key == 73) o.frequency.value = 246.94;
        if (key == 79) o.frequency.value = 261.63;
        if (key == 48) o.frequency.value = 277.18;
        if (key == 80) o.frequency.value = 293.66;
        if (key == 189) o.frequency.value = 311.13;
        if (key == 219) o.frequency.value = 329.63;
        if (key == 221) o.frequency.value = 349.23;
        g = context.createGain();
        o.connect(g);
        g.connect(context.destination);
        o.start(0);
        document.body.removeEventListener("keydown", play(event)); //Added this part
    }

    function stop(event) {
        g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
        o.disconnect(context.destination);
        document.body.addEventListener("keydown", play(event)); //Added this part
    }

现在,如果我在 Chrome 浏览器中加载它并按一个键,浏览器和我的 Ubuntu 操作系统就会挂起!!!为什么会发生这种情况,我怎样才能实现我想要的?

【问题讨论】:

    标签: javascript html ubuntu audio


    【解决方案1】:

    考虑将逻辑与其操作的数据分离:

    <html>
    
    <body onkeydown="play(event)" onkeyup="stop(event)">
        <span style="font-size:10em;">Piano</span>
        <script>
    
            const keyToFrequencyMap = {
                49: 116.54,
                81: 123.47,
                87: 130.81,
                51: 138.59,
                69: 146.83,
                52: 155.56,
                82: 164.81,
                84: 174.61,
                54: 185.00,
                89: 196.00,
                55: 207.65,
                85: 220.00,
                56: 233.08,
                73: 246.94,
                79: 261.63,
                48: 277.18,
                80: 293.66,
                189: 311.13,
                219: 329.63,
                221: 349.23
            }
            var context, o, g;
    
            function play(event) {
                context = new AudioContext();
                o = context.createOscillator();
                var key = event.which || event.keyCode;
                o.frequency.value = keyToFrequencyMap[key]
                console.log(`Playing ${o.frequency.value}`)
                g = context.createGain();
                o.connect(g);
                g.connect(context.destination);
                o.start(0);
            }
    
            function stop(event) {
                g.gain.exponentialRampToValueAtTime(0.00001, context.currentTime + 0.1);
                console.log('Disconnecting')
                o.disconnect(context.destination);
            }
        </script>
    </body>
    
    </html>
    

    console.log 是你的朋友。正在播放多个音符,或者音符在您认为应该停止时没有停止。

    【讨论】:

    • 感谢您的建议。但是,如果我从play(event)stop(event) 中删除(event) 它根本不起作用,即使我使用onkeypress 而不是onkeydown 我得到相同的结果——音频的多个实例!!!
    • 添加了 console.log 进行调试。
    • 每当我按下一个键时,我都会在控制台中收到此错误:Uncaught DOMException: Failed to execute 'disconnect' on 'AudioNode': the given destination is not connected. at stop (&lt;anonymous&gt;:42:15) at HTMLBodyElement.onkeyup。我做错了什么?
    • 嗯,你是g.connect,然后是o.disconnect——应该是g.disconnect吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多