0

ピアノの録音で周波数を検出する MATLAB コードを書いています。

キーボードを使用して録音した C スケールのオーディオ ファイルを使用しました (C4 D4 E4 F4 G4 A4 B4 C5)

単純にFFTを実行すると(ウィンドウに侵入せずに)、基本周波数の振幅が大きくなり、完全に問題ありません。

しかし、より正確にするために、次の手順を実行しました。2. ピーク検出アルゴリズムを実装して、ノートの始まりを見つけます。3. 各オンセットを取得して、各音符の FFT を取得するために、それぞれに FFT を実行しました。ただし、上記のオーディオ ファイルに対してこれを行うと、間違った結果が得られます。ハーモニクスの振幅が 1 番目よりも高い場合があります。

clear all;
clear max;
clc;

%% create 5s sample at 10kHz with tone from 1s to 2s
FS = 10000; % 10kHz
N=5*FS;
song =  randn(N,2)/10;
song(FS:2*FS,:)=10*repmat(sin(261*pi*2*(0:FS)/FS)',1,2)+song(FS:2*FS,:);

P = 2000;   
t=0:1/FS:(N-1)/FS;                  % define time period


song = sum(song,2);                        
song=abs(song);


%----------------------Finding the envelope of the signal-----------------%
% Gaussian Filter
x = linspace( -1, 1, P);                      % create a vector of P values between -1 and 1 inclusive
sigma = 0.335;                                % standard deviation used in Gaussian formula
myFilter = -x .* exp( -(x.^2)/(2*sigma.^2));  % compute first derivative, but leave constants out
myFilter = myFilter / sum( abs( myFilter ) ); % normalize


% fft convolution
myFilter = myFilter(:);                         % create a column vector
song(length(song)+length(myFilter)-1) = 0;      %zero pad song
myFilter(length(song)) = 0;                     %zero pad myFilter
edges =ifft(fft(song).*fft(myFilter));

tedges=edges(P:N+P-1);                      % shift by P/2 so peaks line up w/ edges
tedges=tedges/max(abs(tedges));                 % normalize

%---------------------------Onset Detection-------------------------------%
% This section does the peak picking algorithm
max_col = maxtab(:,1);
peaks_det = max_col/FS;
No_of_peaks = length(peaks_det);

%---------------------------Performing FFT--------------------------------

    song_seg = song(max_col(1):max_col(2)-1);
    L = length(song_seg);    
    NFFT = 2^nextpow2(L); % Next power of 2 from length of y

    seg_fft = fft(song_seg,NFFT);%/L;

    f = FS/2*linspace(0,1,NFFT/2+1);
    seg_fft2 = 2*abs(seg_fft(1:NFFT/2+1));
    L5 = length(song_seg);

    fmin = 60;
    fmax = 1000;
    region_of_interest = fmax>f & f>fmin;
    froi = f(region_of_interest);

    [p_max,loc] = max(seg_fft2(region_of_interest));

    % index into froi to find the frequency of the peaks
    p_max;


     f_p_max = froi(loc);

     [points, locatn] = findpeaks(seg_fft2(region_of_interest));        
     aboveMax = points > 0.4*p_max;

        if any(aboveMax)
            peak_points = points(aboveMax)
        f_peak = froi(locatn(aboveMax))

    end

 end

ここで何が間違っているのですか?ここで本当に本当に助けが必要です......

ここに画像の説明を入力

D4 の f0 はまったく検出されていませんが、C4 と E4 の f0 は高調波に比べて振幅が小さいことがわかります。

4

3 に答える 3

1

FFT を使用して、周波数領域のピークを見つけました。運が良ければ、これは基音に対応するかもしれません。そうでなければ、これは一般的に第 1 高調波かもしれません。

ピークが基音にあるのか第 1 高調波にあるのかわかりません。私の仕事はこれを見つけることです。

私がしたことは...

  1. FFT でピークが発生する周波数に対応する "max_user_freq" 変数があります。注: "Spectrum[]" はマグニチュード スペック変数です。

  2. スペクトル [m] の最大値を計算します。ここで、m は周波数の範囲です。注 : 周波数は m にスケーリングする必要があります。私の場合: m=freq*length(fraw)/22050;

  3. 完全なコード:

    f1=(最大周波数/2)-0.05*最大周波数;

    f1=ラウンド(f1); f2=(最大周波数/2)+0.05*最大周波数; f2=ラウンド(f2); m=[]; spec_index_fund_note=m; spec_fund_max=spectrum(f1*length(fraw)/22050;

    m=f1:f2 の場合、spec_index_fund_note(m)=m*length(fraw)/22050; if(spectrum(spec_index_fund_note(m))>spec_fund_max) spec_fund_max=spectrum(spec_index_fund_note(m)); 終わり

    終わり

    if((spectrum(max_freq_index)-specval_fund_note)/spectrum(max_freq_index)>) display('1次高調波が基本波を超えました、リトライ'); 終わり

于 2014-04-02T09:46:23.010 に答える
0

私は matlab でコーディングし、ミュージシャンに役立つアプリケーションを開発しています。私自身はミュージシャンです。だから、私は自分のアルゴリズムを実行する音楽理論を知っています。私は、あなたがピアノを弾いている正確なスケールを教えてくれるアルゴリズムをmatlabで開発しました。見てみる

MATLAB ミュージシャンのブログ

于 2014-06-21T14:13:48.877 に答える