5-4 Pitch (?喲?)

「音高」(Pitch)是另一個音訊裡面很重要的特徵,直覺地說,音高代表聲音頻率的高低,而此頻率指的是「基本頻率」(Fundamental Frequency),也就是「基本週期」(Fundamental Period)的倒數。

若直接觀察音訊的波形,只要聲音穩定,我們並不難直接看到基本週期的存在,以一個 3 秒的音叉聲音來說,我們可以取一個 256 點的音框,將此音框畫出來後,就可以很明顯地看到基本週期,請見下列範例:

Example 1: pitchSoundFork01.mclose all waveFile='soundFork01.wav'; au=myAudioRead(waveFile); y=au.signal; fs=au.fs index1=11000; frameSize=226; index2=index1+frameSize-1; segment=y(index1:index2); subplot(2,1,1); plot(y); grid on title(waveFile); set(gca, 'xlim', [0, length(y)]); limit=axis; line(index1*[1 1], limit(3:4), 'color', 'r'); line(index2*[1 1], limit(3:4), 'color', 'r'); subplot(2,1,2); plot(segment, '.-'); set(gca, 'xlim', [1, index2-index1+1]); point=[7, 189]; line(point, segment(point), 'marker', 'o', 'color', 'red'); periodCount=5; fp=((point(2)-point(1))/periodCount)/fs; ff=fs/((point(2)-point(1))/periodCount); pitch=69+12*log2(ff/440); fprintf('Fundamental period = %g second\n', fp); fprintf('Fundamental frequency = %g Hertz\n', ff); fprintf('Pitch = %g semitone\n', pitch);

在上述範例中,上圖紅線的位置代表音框的位置,下圖即是 256 點的音框,其中紅線部分包含了 5 個基本週期,總共佔掉了 182 單位點,因此對應的基本頻率是 fs/(182/5) = 16000/(182/5) = 439.56 Hz,相當於 68.9827 半音(Semitone),其中由基本頻率至半音的轉換公式如下:
semitone = 69 + 12*log2(frequency/440)
換句話說,當基本頻率是 440 Hz 時,對應到的半音差是 69,這就是鋼琴的「中央 La」或是「A4」,請見下圖。

Hint
一般音叉的震動頻率非常接近 440 Hz,因此我們常用音叉來校正鋼琴的音準。

上述公式所轉換出來的半音差,也是 MIDI 音樂檔案所用的標準。從上述公式也可以看出:

音叉的聲音非常乾淨,整個波形非常接近弦波,所以基本週期顯而易見。若以我的聲音「清華大學資訊系」來說,我們可以將「華」的部分放大,也可以明顯地看到基本週期,請見下列範例:

Example 2: framePitchDisp4speech01.mwaveFile='csNthu.wav'; au=myAudioRead(waveFile); y=au.signal; fs=au.fs; index1=11050; frameSize=512; index2=index1+frameSize-1; frame=y(index1:index2); subplot(2,1,1); plot(y); grid on xlabel('Sample index'); ylabel('Amplitude'); title(['Waveform of ', waveFile]); axis([1, length(y), -1 1]); subplot(2,1,2); plot(frame, '.-'); grid on xlabel('Sample index within frame'); ylabel('Amplitude'); point=[83, 485]; % Peaks point=[75, 477]; % Valleys axis([1, length(frame), -1 1]); periodCount=3; fp=((point(2)-point(1))/periodCount); % fundamental period ff=fs/fp; % fundamental frequency pitch=69+12*log2(ff/440); fprintf('Fundamental period (fp) = (%g-%g)/%g = %g points\n', point(2), point(1), periodCount, fp); fprintf('Fundamental frequency (ff) = %g/%g = %g Hz\n', fs, fp, ff); fprintf('Pitch = %g semitone\n', pitch); % === For plotting arrows, etc % ====== Frame boundary subplot(211); line(index1*[1 1], [-1 1], 'color', 'r', 'linewidth', 1); line(index2*[1 1], [-1 1], 'color', 'r', 'linewidth', 1); % ====== FP coverage subplot(212); line(point, frame(point), 'marker', 'o', 'color', 'red'); % ====== Axis locations subplot(211); loc1=get(gca, 'position'); subplot(212); loc2=get(gca, 'position'); % ====== arrow 1 x1=[loc1(1)+(index1(1)-1)/(length(y)-1)*loc1(3), loc2(1)]; y1=[loc1(2), loc2(2)+loc2(4)]; ah=annotation('arrow', x1, y1, 'color', 'r', 'linewidth', 1); % ======= arrow 2 x2=[loc1(1)+(index2-1)/(length(y)-1)*loc1(3), loc2(1)+loc2(3)]; y2=[loc1(2), loc2(2)+loc2(4)]; ah=annotation('arrow', x2, y2, 'color', 'r', 'linewidth', 1); % ====== Texts indicating start/end indices h1=text(point(1), frame(point(1)), [' \leftarrow index=', int2str(point(1))], 'rotation', -10); h2=text(point(2), frame(point(2)), [' \leftarrow index=', int2str(point(2))], 'rotation', -10); Fundamental period (fp) = (477-75)/3 = 134 points Fundamental frequency (ff) = 16000/134 = 119.403 Hz Pitch = 46.42 semitone

上列範例的下圖,是從「華」的韻母附近抓出來的 512 點的音框,其中紅線部分包含了 6 個基本週期,總共佔掉了 757 單位點,因此對應的基本頻率是 fs/(757/6) = 16000/(757/6) = 126.816 Hz,相當於 47.463 半音,與「中央 La」差了 21.5 個半音,接近但還不到兩個全音階(24 個半音)。

在觀察音訊波形時,每一個基本週期的開始點,我們稱為「音高基準點」(Pitch Marks,簡稱 PM),PM 大部分是波形的局部最大點或最小點,例如在上述音叉的範例中,我們抓取的兩個 PM 是局部最大點,而在我的聲音的範例中,由於 PM 在局部最大點並不明顯,因此我們抓取了兩個局部最小點的 PM 來計算音高。PM 通常用來調節一段聲音的音高,在語音合成方面很重要。

由於生理構造不同,男女生的音高範圍並不相同,一般而言:

但是我們分辨男女的聲並不是只憑音高,而還是依照音色(共振峰),詳見後續說明。

使用「觀察法」來算出音高,並不是太難的事,但是若要電腦自動算出音高,就需要更深入的研究。有關音高追蹤的各種方法,會在後續章節詳細介紹。


Audio Signal Processing and Recognition (音訊處理與辨識)