2012-10-31 17 views
7

編輯: - 清理代碼和播放器(在Github上)一點,所以它更容易設定頻率網絡音頻:Karplus組強大的字符串合成

我使用Karplus Strong string synthesis算法trying to synthesize字符串,但我可以」讓字符串調整正確。有人有什麼主意嗎?

如上面鏈接,代碼在Github上:https://github.com/achalddave/Audio-API-Frequency-Generator(相關位在strings.js)。

維基下圖:

Karplus Strong String Synthesis diagram

所以基本上,我生成噪聲,然後獲取輸出,並且同時發送到延遲濾波器。延遲濾波器連接到低通濾波器,然後與輸出混合。根據維基百科,延遲應該是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上,實際上是低通和輸出之間的增益節點,但這並不能真正使輸出有很大的區別。

+0

我只是擺弄這個,我真的不知道我在做什麼。但嘗試將頻率設置爲241.在我的Mac上創建了一些奇怪的噪音。也許這會告訴你什麼?你對數學和理論看起來更加熟練。 :) –

+0

嗯,這很有趣。說實話,除了一門EE課程外,我對這個理論也不太熟悉,其中很多東西都是拼湊在一起,四處詢問。儘管如此,感謝您的幫助,如果我更多地瞭解,這可能會提供一些見解。 –

+0

這可能不是問題,因爲我認爲低通是默認的,但你應該在代碼中明確地設置你的過濾器類型......像'lowpassFilter.type = lowpassFilter.LOWPASS'。 –

回答

6

這是我認爲的問題。我不認爲DelayNode實現的目的是處理這種嚴格的反饋循環。例如,對於441 Hz音調,這隻有100個延遲採樣,並且DelayNode實現可能會以128或更多的塊處理其輸入。 delayTime屬性爲「k-rate」,意味着對它的更改只能在128個樣本的塊中處理。這並不證明我的觀點,但它暗示了它。)所以反饋來得太晚,或者只是部分或某事。

EDIT/UPDATE:正如我在下面註釋的狀態,實際的問題是,在一個循環的DelayNode增加了輸出和輸入之間128個樣本幀,因此所觀察到的延遲小於指定的時間更長128/sampleRate秒。

我的建議(以及我已經開始做的)是在JavaScriptNode(現在稱爲ScriptProcessorNode)中實現整個Karplus-Strong,包括您自己的延遲線。這並不難,我會在我擺脫一個不可能存在但不知何故的令人討厭的bug時發佈我的代碼。順便說一句,你(和我)用delayTime1/440(它應該是A)得到的音調似乎是一個G,低於它應該在的兩個半音。將頻率加倍會提高到B,高出四個半音。 (我可能會被一個八度音階或兩個 - 很難說)。也許人們可以從這樣的更多數據點中找出(數學上的)發生了什麼,但我不會打擾。

編輯:這是我的代碼,認證無錯。

var context = new webkitAudioContext(); 

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

var node = context.createJavaScriptNode(4096, 0, 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); 
+0

這工作?我明天會嘗試。如果是這樣,我不能誇大那是多麼可怕(以及我多麼感激這種幫助)。我曾考慮過將它作爲JavascriptNode實現,但是我最後一次嘗試使用另一個實驗時遇到了性能問題。 –

+0

另外,什麼是「不可能存在的錯誤」?第二,DelayNode實施問題錯誤報告值得嗎?如果是這樣,我會報告你(我自己,但你似乎更好地理解它),並在這裏發佈鏈接。 –

+0

它的工作原理 - 真的!無論如何,對我來說。 – Grumdrig