我正在阅读这篇很棒的文章: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 要查看波形,请按播放声音几次。
我相信这些应该匹配,所以这是我的问题:
编辑:如评论中所述,我的图表是颠倒的(画布上 0,0 是左上角)。
请注意,第一个数组定义余弦项,第二个数组定义正弦项:
参数表示一组余弦项(传统上 A 项)。在音频术语中,第一个元素(索引 0)是 周期波形的直流偏移。第二个元素(索引 1) 代表基频。第三个元素代表 第一泛音,等等。第一个元素被忽略并且 实现必须在内部将其设置为零。real
参数表示一组正弦项(传统上 B 项)。第一个元素(索引 0)应设置为零(并且 将被忽略),因为该术语在傅里叶级数中不存在。 第二个元素(索引 1)表示基频。这 第三个元素代表第一个泛音,依此类推。imag
你会看到你得到了预期的波形,但是“颠倒了”(颠倒绘制,感谢@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>
演示和输出之间的唯一区别是两个音调之间的相位关系。该演示是
y=sin(x) + sin(2x)
,您的是 y=sin(x) + sin(2x + pi/2)
。我不清楚这个相移从何而来,但我不认为这是你所做的任何事情。
以下是 Wolfram alpha 的一些图:
在
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]。