2012-03-06 71 views
3

我正在看這example about sound generation on iOS,因爲我需要做類似的事情,但有些部分我不明白,我希望有人能幫助我。iOS tone generation

在這部分代碼:

double theta_increment = 2.0 * M_PI * viewController->frequency/viewController->sampleRate; 
    // Generate the samples 
    for (UInt32 frame = 0; frame < inNumberFrames; frame++) 
    { 
     buffer[frame] = sin(theta) * amplitude; 

     theta += theta_increment; 
     if (theta > 2.0 * M_PI) 
     { 
      theta -= 2.0 * M_PI; 
     } 
    } 

我真的不明白theta += theta_increment;部分是什麼。對我來說,在for循環中做這樣的事情更有意義:

buffer[frame] = sin(theta_increment * frame); 

任何想法爲什麼不行?此外,我不知道代碼的這一部分是什麼:if (theta > 2.0 * M_PI)因此對此的任何解釋都會非常受歡迎。

回答

1

您的方法可用於創建相同的結果,表達方式不同。但是,theta += theta_increment;將比您提出的更簡單的表達式(計算)。

階段的域被包裝爲sin'的邏輯參數域。對於短樣本來說,這一步並不是必須的。由於浮點存儲的限制,您的頻率最終可能會變化,並且如果值未被打包,則最終不會增加,這取決於您生成的樣本數量以及是否使用floatdouble。想想這樣:如果你有一個巨大的正浮點數(你的相位累加器的值),並且你試圖增加0.000004它會發生什麼?浮點錯誤會將其舍入到浮點數或雙精度浮點數中,並且錯誤將導致相位並最終導致音調不穩定。對於短樣品(例如某些循環),在這種情況下不需要纏繞,但是對於很多很多循環來說,它隨着時間的推移穩定了螺距和相位累加器。

最後,theta將被用來存儲相位斜坡的最後一個值,以便在下一個渲染調用中停止生成。沒有這一點,輸出將在渲染調用邊界處從0重新開始,產生非常令人不快的噪聲和錯誤的頻率。

所有事情都考慮到了:這可能是因爲它是一個簡單的演示,並且是在這種情況下生成正弦的快速方法。你的方法有一些「昂貴」的轉換,但它是無分支的 - 它可能比原來的更快,尤其是對於更高的頻率。

1

我想象它會工作得很好的方式(但不要忘記幅度乘以):

buffer[frame] = sin(theta_increment * frame) * amplitude; 

就在表達着同一個數學的不同方式。看起來像寫了原始代碼的人想要保持0 < = theta < 2pi,但這可能不是必需的(除非sin()調用以我不知道的方式奇怪)。此外,他們可能希望保持獨立於框架變量的「數學」部分,以防其他循環中出現相同片段,但這只是推測。