【问题标题】:custom wave forms in web audio APIWeb 音频 API 中的自定义波形
【发布时间】:2015-08-18 08:12:22
【问题描述】:

我正在阅读这篇很棒的文章:https://jackschaedler.github.io/circles-sines-signals/dft_introduction.html

我想使用 Web Audio API 的 PeriodicWave 对象来实现这个演示:

但是,当我使用这些设置设置周期波时:

 var real = new Float32Array([0,0,1,0,1]);
 var imag = new Float32Array(real.length);
 var customWave = context.createPeriodicWave(real,imag);
 osc.setPeriodicWave(customWave);

我输出的波形是这样的:

这是完整代码:http://jsbin.com/zaqojavixo/4/edit 要查看波形,请按几次播放声音。

我认为这些应该匹配,所以这是我的问题:

  1. 我是在这里遗漏了一些关于理论的基本知识,还是我只是错误地实施了它? PeriodicWave 对象是否应该与文章中说明的相同?
  2. 如果我采用了错误的方法,我将如何在 Web Audio API 中实现此图?通过将两个不同频率的不同正弦波连接到同一个增益节点,我已经能够在下面进行匹配 - 这与使用 PeriodicWave 对象有何不同?
  3. 我是 DSP 和 Web 音频 API 的新手 - 任何建议阅读都将不胜感激!
  4. 其次,在我的示例中,我必须按几次“播放声音”按钮,然后才能将正确的数据绘制到画布上 - 分析仪似乎位于振荡器后面,即使 analyser.getFloatTimeDomainData() 是在我启动振荡器后调用了关于这里发生了什么的任何想法?

编辑:如 cmets 中所述,我的图表是颠倒的(在画布上,0,0 是左上角)。

【问题讨论】:

    标签: javascript audio signal-processing web-audio-api


    【解决方案1】:

    请注意,第一个数组定义余弦项,第二个数组定义正弦项:

    real 参数表示 余弦项 的数组(传统上 A 条款)。在音频术语中,第一个元素(索引 0)是 周期波形的直流偏移。第二个元素(索引 1) 表示基频。第三个元素代表 第一泛音,以此类推。第一个元素被忽略并且 实现必须在内部将其设置为零。

    imag 参数表示一组正弦项(传统上 B 项)。第一个元素(索引 0)应设置为零(并且 将被忽略),因为该项在傅里叶级数中不存在。 第二个元素(索引 1)代表基频。这 第三个元素代表第一泛音,以此类推。

    Source

    你会看到你得到了预期的波形,但“颠倒了”(由于@Julian 在他的回答中指出了这一点,将其颠倒绘制 - 固定如下):

    (我在这里用交换的数组内联了您的代码:)
    更新修复了原始代码中的绘图问题

    //setup audio context
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    var context = new window.AudioContext();
    
    //create nodes
    var osc; //create in event listener so we can press the button more than once
    var masterGain = context.createGain();
    var analyser = context.createAnalyser();
    
    //routing
    masterGain.connect(analyser);
    analyser.connect(context.destination);
    
    var isPlaying = false;
    
    //draw function for canvas
    function drawWave(analyser, ctx) {
      
      var buffer = new Float32Array(1024),
          w = ctx.canvas.width;
      
      ctx.strokeStyle = "#777";
      ctx.setTransform(1,0,0,-1,0,100.5); // flip y-axis and translate to center
      ctx.lineWidth = 2;
      
      (function loop() {
        analyser.getFloatTimeDomainData(buffer);
        
        ctx.clearRect(0, -100, w, ctx.canvas.height);
    
        ctx.beginPath();
        ctx.moveTo(0, buffer[0] * 90);
        for (var x = 2; x < w; x += 2) ctx.lineTo(x, buffer[x] * 90);
        ctx.stroke();
        
        if (isPlaying) requestAnimationFrame(loop)
      })();
    }
    
    //button trigger
    $(function() {  
      var c = document.getElementById('scope'),
          ctx = c.getContext("2d");
      
      c.height = 200;
      c.width = 600;
      
      // make 0-line permanent as background
      ctx.moveTo(0, 100.5);
      ctx.lineTo(c.width, 100.5);
      ctx.stroke();
      c.style.backgroundImage = "url(" + c.toDataURL() + ")";
      
      $('button').on('mousedown', function() {
        osc = context.createOscillator();
        //osc settings
        osc.frequency.value = 220;
        var imag= new Float32Array([0,0,1,0,1]);   // sine
        var real = new Float32Array(imag.length);  // cos
        var customWave = context.createPeriodicWave(real, imag);  // cos,sine
        osc.setPeriodicWave(customWave);
    
        osc.connect(masterGain);
        osc.start();
        isPlaying = true;
        
        drawWave(analyser, ctx);
      });
    
      $('button').on('mouseup', function() {
        isPlaying = false;
        osc.stop();
      }); 
    });
    button {position:fixed;left:10px;top:10px}
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <button>Play the sound</button>
    <canvas id='scope'></canvas>

    【讨论】:

    • 感谢分享这个漂亮的波浪渲染!
    【解决方案2】:

    演示和您的输出之间的唯一区别是两种音调之间的相位关系。演示是y=sin(x) + sin(2x),你的是y=sin(x) + sin(2x + pi/2)。我不清楚这种相移是从哪里来的,但我不认为这是你所做的任何事情。

    以下是来自 wolfram alpha 的一些图:

    y=sin(x) + sin(2x)

    y=sin(x) + sin(2x + pi/2)

    【讨论】:

      【解决方案3】:

      createPeriodicWave 中,real 数组是余弦部分(或 a 项),而 imag 数组(b 项)是正弦部分部分。

      见:http://en.wikipedia.org/wiki/Fourier_series

      我认为你只是颠倒了两者。文章中说:

      其中 Ai 是第 i 个正弦波的幅度,fi 是第 i 个正弦波的频率 第 i 个正弦。

      所以你的 imag 数组(正弦部分)应该是 [0,0,1,0,1] 而你的真实数组应该是 [0,0,0,0,0]。

      像这样:

      var imag = new Float32Array([0,0,1,0,1]);
       var real = new Float32Array(real.length);
      

      在你的 jsbin 中尝试它,它会起作用,只是它会被反转,因为你正在绘制负数(意味着 0 坐标是顶部,而不是底部)。要获得文章中的内容,请反向绘制或让您的 imag 数组如下所示:[0,0,-1,0,-1]。

      如果你想用不同的imagreal 配置玩一下看看结果,你可以看这里:http://themusictoolbox.net/waves/

      【讨论】:

        猜你喜欢
        • 2019-07-02
        • 1970-01-01
        • 2011-04-30
        • 2012-03-19
        • 1970-01-01
        • 2016-12-09
        • 2017-07-08
        • 2015-04-12
        • 1970-01-01
        相关资源
        最近更新 更多