微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript – 网络音频:Karplus强字符串合成

编辑:清除代码和播放器(在 Github上),以便更容易设置频率

我是使用Karplus Strong string synthesis算法的trying to synthesize字符串,但我无法正确调整字符串.有谁有想法吗?

如上所述,代码在Github上:https://github.com/achalddave/Audio-API-Frequency-Generator(相关位在strings.js中).

Wiki有以下图表:

基本上,我生成噪声,然后输出并同时发送到延迟滤波器.延迟滤波器连接到低通滤波器,然后与输出混合.根据维基百科,延迟应该是N个样本,其中N是采样频率除以基频(N = f_s / f_0).

摘自我的代码

生成噪音(bufferSize是2048,但这不应该太重要)

var buffer = context.createBuffer(1,bufferSize,context.sampleRate);
var bufferSource = context.createBufferSource();
bufferSource.buffer = buffer;

var bufferData = buffer.getChannelData(0);
for (var i = 0; i < delaySamples+1; i++) {
    bufferData[i] = 2*(Math.random()-0.5); // random noise from -1 to 1
}

创建延迟节点

var delayNode = context.createDelayNode();

我们需要延迟f_s / f_0样本.但是,延迟节点以秒为单位进行延迟,因此我们需要将其除以每秒采样数,得到(f_s / f_0)/ f_s,它只是1 / f_0.

var delaySeconds = 1/(frequency);
delayNode.delayTime.value = delaySeconds;

创建低通滤波器(据我所知,频率截止,不应该影响频率,更重要的是字符串“听起来”自然):

var lowpassFilter = context.createBiquadFilter();
lowpassFilter.type = lowpassFilter.LOWPASS; // explicitly set type
lowpassFilter.frequency.value = 20000; // make things sound better

将噪声连接到输出和延迟节点(destination = context.destination并在前面定义):

bufferSource.connect(destination);
bufferSource.connect(delayNode);

将延迟连接到低通滤波器:

delayNode.connect(lowpassFilter);

将低通连接到输出并返回延迟*:

lowpassFilter.connect(destination);
lowpassFilter.connect(delayNode);

有没有人有任何想法?我无法弄清楚问题是我的代码,我对算法的解释,我对API的理解,或者(虽然这是最不可能的)API本身的问题.

*请注意,在Github上,低通和输出之间实际上有一个增益节点,但这并没有真正对输出产生很大的影响.

解决方法

这就是我认为的问题.我不认为DelayNode实现旨在处理这种紧密的反馈循环.例如,对于441 Hz音调,这只是100个延迟样本,并且DelayNode实现可能以128或更多的块处理其输入. (delayTime属性是“k-rate”,意味着对它的更改仅在128个样本的块中处理.这不能证明我的观点,但它暗示了它.)所以反馈来得太晚,或者只是部分反馈,或者其他的东西.

编辑/更新:正如我在下面的评论中所述,实际问题是循环中的DelayNode在输出和输入之间添加了128个样本帧,因此观察到的延迟比指定的延迟长128 / sampleRate秒.

我的建议(以及我开始做的)是在JavaScriptNode(现在称为scriptprocessorNode)中实现整个Karplus-Strong,包括你自己的延迟线.这并不难,一旦我摆脱了一个不可能存在但又不知道的烦人的bug,我会发布我的代码.

顺便说一句,你(和我)得到的延迟时间为1/440(应该是A)的音调似乎是G,两个半音低于它应该的位置.频率加倍将其提高到B,四个半音更高. (我可能会被一个或两个八度音 – 很难说.)可能有人可以从这样的几个数据点中找出(数学上)正在发生的事情,但我不会打扰.

编辑:这是我的代码,经过认证无错误.

var context = new webkitaudiocontext();

var frequency = 440;
var impulse = 0.001 * context.sampleRate;

var node = context.createJavaScriptNode(4096,1);
var N = Math.round(context.sampleRate / frequency);
var y = new Float32Array(N);
var n = 0;
node.onaudioprocess = function (e) {
  var output = e.outputBuffer.getChannelData(0);
  for (var i = 0; i < e.outputBuffer.length; ++i) {
    var xn = (--impulse >= 0) ? Math.random()-0.5 : 0;
    output[i] = y[n] = xn + (y[n] + y[(n + 1) % N]) / 2;
    if (++n >= N) n = 0;
  }
}

node.connect(context.destination);

原文地址:https://www.jb51.cc/js/158932.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐