语音频谱基频的提取

泛音列

所有谐波震荡中频率最小者称为基本频率(基频),而基频高低决定了乐器弹奏此音符的音高。几乎所有乐器除了可发出基频音以外亦会伴随着较高频的声音,称为泛音

理论上,泛音的频率分别为基频的2、3、4、5、6、…等倍。

根据对不同音色的音频进行频域分析时发现. 不同的音色最大振幅对应的频率也会发生变化. 但是有一个固定的规律是最大振幅对应的频率不是基频就是泛音, 也就是说最大振幅对应的频率基频的整数倍.

WZK的频谱图:

frequency_wzk

HMD的频谱图:

frequency_hmd

算法的目标是找到最大振幅对应的频率基频的多少倍.

基频提取流程

  1. 从data(f)中找到最大振幅对应的频率frequency_max(此时 倍数 可能的取值为 1, 2, ..., frequency_max).
  2. 取步长step = frequency_max / i(i为猜测的倍数) 使data_sum(i) = sum(data(step : step : frequency_max)) * step.
  3. change(i) = data_sum(i) - data_sum(i + 1).
  4. change_sum(i) = change(i : i : length(change)) * i, i = 1 : length(change).
  5. 找到change_sum中最大值对应的i值即为需要提取的倍数.
  6. frequency_base = ceil(frequency_max / change_sum_max).

编程实现

<!-- lang: js -->
function main()
    %傅立叶变换到频域
    [stream, sample_rate] = audioread('hmd.wma');
    stream = stream(1 : length(stream), 1);
    frequency = abs(fft(stream, sample_rate));
    len = floor(length(frequency) / 2); 
    frequency = frequency(1 : len) / max(frequency);

    figure(1);
    plot(frequency);

    %找到最大振幅对应的频率
    [~, frequency_max] = max(frequency);
    frequency_sum = zeros(frequency_max);

    %取不同倍数对应的步长.对频率求和
    for i = 1 : frequency_max
        step = frequency_max / i;
        index = ceil(step : step : frequency_max);
        frequency_sum(i) = sum(frequency(index)) * step;
    end
    figure(2);
    plot(frequency_sum);

    %change(i) = frequency_sum(i)  - frequency_sum(i + 1);
    change = zeros(1, frequency_max);
    for i = 1 : length(frequency_sum) - 1
       change(i) = frequency_sum(i)  - frequency_sum(i + 1);
    end

    figure(3);
    plot(change)


    change_sum = zeros(1, length(frequency_sum));
    for i = 1 : length(change_sum)
        index = i : i : length(change_sum);
        change_sum(i) = sum(change(index)) * i;
    end
    figure(4);
    plot(change_sum);

    %change_sum_max 为需要的倍数
    [~, change_sum_max] = max(change_sum);

    %基频
    frequency_base = ceil(frequency_max / change_sum_max);
    disp(change_sum_max);
    disp(frequency_base);
end

运行结果

取了4个同学及自己的一段a---音进行测试, 都能准确的得出基频 但是样本量较小.不能很好说明问题.
wzk.wmahmd.wma的频域图在上方.
运行结果分别为:

1, 120

6, 128

你可能感兴趣的:(matlab,音频,基频,泛音列)