聲音合成理論/振盪器和波表

一個振盪器是具有基頻和峰值幅度的重複波形,它是如今大多數流行合成技術的基石。除了振盪器的頻率或音高及其幅度外,最重要的特徵之一是其波形的形狀。圖 5.1 中的時間域波形顯示了四個最常用的振盪器波形。雖然可以使用各種獨特的形狀,但這四種形狀各自服務於一系列功能,適用於一系列不同的合成技術;從正弦波的平滑、純淨的聲音到鋸齒波的富含泛音的嗡嗡聲。
振盪器通常由鍵盤合成器或 MIDI 協議裝置控制。按下鍵會產生 MIDI 音符值,該值將轉換為振盪器接受為輸入的頻率值 (Hz),並且波形週期將根據指定的頻率相應地重複。從此處,聲音可以在合成器或程式中以各種方式處理或操作,以進一步豐富或修改聲音。
請注意,以下圖表渲染不正確。x 軸應放在較低的位置,每個訊號都應在 π 弧度處穿過 y=0。
如前所述,正弦波可以被認為是最基本的聲音構建塊。生成產生這種波形的振盪器的最佳方法是利用系統中內建的庫或函式。許多程式語言都有標準數學庫,其中表示了許多三角函式。正弦波的一個週期是 弧度長,峰值幅度為 ,如圖 圖 5.2 所示。在數字系統中,生成的波將是一系列以取樣率均勻間隔的值。

以每秒 44100 個週期的取樣率,以及 1 秒的所需週期長度,需要 44100 個樣本才能從 0 到。換句話說,我們可以從週期長度確定每週期步數
其中是取樣率。因此,每一步將以以下弧度量進行
其中 ,在第二個結果中,是頻率方面相同的結果。其重要性在於它可以擴充套件成一種演算法,該演算法適用於生成使用者指定頻率和振幅的正弦波,實際上是最簡單的合成器!正弦波可以透過重複將相位值增加一定量來生成,以達到每秒所需的 長度迴圈,以取樣率。該值可以傳遞給正弦函式以建立輸出值,介於使用者指定的峰值振幅之間。
Input: Peak amplitude (A), Frequency (f)
Output: Amplitude value (y)
y = A * sin(phase)
phase = phase + ((2 * pi * f) / samplerate)
if phase > (2 * pi) then
phase = phase - (2 * pi)
關於此演算法最重要的是,當相位值超過 時,它將減去一個完整週期。這樣做是為了確保函式“迴繞”到正確的位置,而不是直接返回到 0;如果相位增量 *越過* 並重置為 0,則會出現不希望有的不連續性,導致振盪聲音的諧波失真。
方波
[edit | edit source]方波不能輕易地從數學函式庫中生成,但演算法非常直接,因為它是由直線段構建的。與正弦波不同,方波在其 *基頻* 以上具有許多諧波,並且具有更明亮、更尖銳的音色。在檢查了許多不同的波形之後,人們會開始意識到,具有陡峭邊緣和/或突然變化和不連續性的波形通常富含諧波。
(請注意,以下方波、鋸齒波和三角波函式是“天真的”;它們等效於在對理想數學函式進行帶限處理之前對它們進行取樣。換句話說,奈奎斯特頻率以上的所有諧波都將被混疊回可聽範圍。當將其中一個波形掃到高頻時,這一點最為明顯。混疊的諧波將上下移動頻譜,在背景中發出“收音機調諧”的聲音。一種更好的方法是使用加法合成或類似 MinBLEPs 的方法來生成音訊波形。一個正確帶限的波形在接近不連續點時將有“鋸齒”,而不是分段直線。)

方波的構建方式與正弦波非常相似,我們使用相同的方法,透過一個具有相位變數的模式迴圈,並在超過 弧度後重置。
Input: Peak amplitude (A), Frequency (f)
Output: Amplitude value (y)
if phase < pi then
y = A
else
y = -A
phase = phase + ((2 * pi * f) / samplerate)
if phase > (2 * pi) then
phase = phase - (2 * pi)
很明顯,它不依賴於外部函式,方波可以透過簡單的算術來定義,因為它本質上是在每個週期內在兩個值之間切換。可以透過引入一個新的變數來擴充套件它,該變數控制在週期中初始值切換到其符號值的點;這種波形被稱為 *脈衝波*。脈衝波與方波類似,但能夠調製切換點提供了更大的聲音潛力。
鋸齒波
[edit | edit source]
鋸齒波的聲音更像方波,儘管它具有諧波衰減和適當的“嗡嗡”音色。它由對角線斜線段構成,因此演算法中需要直線梯度方程。數學形式為
其中 代表振幅, 是相位。這可以併入演算法形式,如下所示
Input: Peak amplitude (A), Frequency (f)
Output: Amplitude value (y)
y = A - (A / pi * phase)
phase = phase + ((2 * pi * f) / samplerate)
if phase > (2 * pi) then
phase = phase - (2 * pi)
三角波
[edit | edit source]
三角波與鋸齒波有許多幾何相似之處,只是它有兩個斜線段。代數略微複雜,程式設計師可能希望考慮將直線生成合併到一個新函式中,以方便閱讀。三角波僅包含基頻的奇數諧波,並且比方波或鋸齒波具有更柔和的音色,更接近正弦波。兩個線段的數學形式為
對於 到 弧度
對於 到 弧度
然後,該演算法與之前的示例類似,但將梯度方程合併到其中。在本示例中提供的演算法中,很明顯可以設計出各種不同的波形,但也要認識到這些形狀只能描述為數學函式。由於更復雜的數學表示式,複雜形狀可能會變得非常費力,因為需要更大的處理能力。
Input: Peak amplitude (A), Frequency (f)
Output: Amplitude value (y)
if phase < pi then
y = -A + (2 * A / pi) * phase
else
y = 3A - (2 * A / pi) * phase
phase = phase + ((2 * pi * f) / samplerate)
if phase > (2 * pi) then
phase = phase - (2 * pi)
波表
[edit | edit source]可能存在一種情況,或者人們可能希望擺脫使用數學公式或線段定義振盪波形的限制或複雜性。如前所述,這可能是對處理能力的擔憂,或者僅僅是透過直觀的圖形介面指定形狀會更容易。在這樣的情況下,音樂家和工程師可能會使用波表作為他們的源振盪器。波表在數字合成應用中很受歡迎,因為訪問記憶體塊在計算上比使用數學運算計算值更快。

波表本質上是一個包含N個值的陣列,值 1 到 N 代表振盪器的一個完整週期。每個值代表週期中某個點的幅度。波表通常以圖形方式顯示,使用者可以選擇繪製他們所需的波形,因此它代表了一個非常強大的工具。還可以載入預先錄製好的波形;但請注意,波表振盪器只是一個波形週期的參考表,它與取樣器不同。波表與其關聯的讀指標一起,以所需的速率迴圈遍歷表,並按順序輸出每個幅度值,以便將波形重新建立為數字值的流。當指標到達表陣列中的最後一個值時,它將重置為指向 1 並開始一個新的週期。
使用波表
[edit | edit source]波表的大小和系統的取樣率決定了波表振盪器的基頻。如果我們有一個包含1024個單獨值的波表,並且取樣率為44.1 kHz,則需要
秒才能完成一個週期。如前所示,頻率可以從 中確定,從而得出基頻為
因此,很明顯,為了改變振盪器的頻率,我們必須改變波表的大小或系統的取樣率。這兩種方法都存在一些實際問題。
- 改變波表大小意味著切換到具有相同更新波形的不同大小的波表。這將需要數十個、數百個甚至數千個單獨的波表,每個音調一個,這顯然是完全低效且佔用記憶體的。
- 數字系統,尤其是將多個合成或錄製訊號組合在一起的混音器,被設計為以固定的取樣率工作,突然改變它再次效率低下並且非常難以程式設計。
- 以可接受的精度播放高頻所需的取樣率變得非常高,對系統提出了很高的要求。
最實用且使用最廣泛的以不同頻率播放波表振盪器的方法之一是改變讀指標遍歷表的“步長”大小。與之前的示例一樣,我們的 1024 值波表在輸出表中的每個點時具有 43.5 Hz 的基頻。現在,如果我們每隔5個值遍歷表,我們將擁有
由此可以得出用於計算給定頻率f所需的步長大小S的通用公式
其中N是波表的大小,而 是取樣率。需要注意的是,由於步長正在改變,讀指標可能不會準確地落在最後一個表值N上,因此它必須像之前部分中函式生成的波形一樣“環繞”。這可以透過從當前指標值中減去表的大小來實現,如果它超過 N;其演算法形式可以很容易地從上面的示例中獲得。
頻率精度和插值
[edit | edit source]我們必須考慮到,某些頻率值可能會產生具有小數部分的步長;也就是說,它不是整數,而是一個有理數。在這種情況下,我們發現讀指標將嘗試步進到波表陣列中不存在的位置,因為陣列的每個成員都具有整數值索引。位置 50 可能存在一個值,但位置 50.5 呢?如果我們希望播放使用小數步長的頻率,我們必須考慮如何適應它。
- 截斷和舍入。透過刪除小數點後的分數,我們將步長縮減為整數——這就是截斷。例如,1.3 變為 1,4.98 變為 4。舍入類似,但選擇最接近的整數——3.49 變為 3,8.67 變為 9。對於簡單的舍入,如果小數點後的值小於 5,我們向下舍入(截斷),否則我們向上舍入到下一個整數。舍入可以在處理器中免費支援,或者可以透過將 0.5 加到原始值然後截斷為整數來完成。對於波表合成,截斷和舍入之間的唯一區別是輸出中恆定的 0.5 個樣本相位偏移。由於這不可檢測——既不是改進也不是損害——截斷和舍入之間的決定歸結為哪一個更方便或更快。
- 線性插值。這是在步長位置周圍的兩個整數值之間繪製一條直線,並使用這兩個點的值生成在它們之間插值的振幅值的方法。這是一個計算量更大的過程,但會帶來更高的精度。
- 高階插值。將線性插值視為一階插值(並將截斷和舍入視為零階插值),存在許多常用的高階形式——三次埃爾米特、拉格朗日等等。正如線性插值需要兩個點進行計算一樣,高階需要更多的波表點用於計算,但會產生更準確、更低失真的結果。Sinc 插值可以任意接近完美,但以計算時間為代價。
透過增加波表的大小,上述過程的精度會更高,並將更接近理想的、預期的曲線。當然,更大的波表大小會導致更大的記憶體需求。一些波表合成器硬體設計更喜歡 2 的冪的表大小(128、256、512、1024、2048 等),因為利用了數字記憶體構建方式(二進位制)的捷徑。