【问题标题】:Recognizing the pitch of a sound with matlab用matlab识别声音的音高
【发布时间】:2013-07-24 06:08:12
【问题描述】:

我正在尝试做一个项目,该项目使用 MATLAB 读取包含一系列音符的 WAV 文件。例如,我的 WAV 文件可能包含一系列 C-D-C-E。将此文件输入我的程序会打印出“C D C E”。

我尝试使用 WAVREAD 将文件转换为矢量,然后 使用采样对其进行下采样并制作成单通道文件。 然后我就能够提出在某些频率处具有“峰值”的频谱图。

从这里,我想获得有关如何使 MATLAB 识别峰值频率的帮助,从而使我能够打印出注释。

还是我走错了路?

提前致谢!

【问题讨论】:

    标签: matlab signal-processing spectrogram


    【解决方案1】:

    您在正确的轨道上,但这不是一个简单的问题。我建议研究的是一种叫做色谱图的东西。这将使用您从频谱图中收集的信息并将其“分箱”成钢琴音符频率。这将给出歌曲谐波内容的近似值。这可能并不完全准确,因为音符的谐波中有残余能量,但这是一个开始。

    请注意,您正在做的转录是一项非常艰巨的任务,尚未 100% 解决。直到今天,人们仍在研究这个。我有生成色度的代码,但我必须挖掘它。

    编辑

    这里是一些色度的代码

    clc; close all; clear all;
    % didn't have wav file, but simply replace this with the following
    % [audio,fs] = wavread('audioFile.wav')
    audio = rand(1,10000);
    fs = 44100; % temp sampling frequency, will depend on audio input
    NFFT = 1024; % feel free to change FFT size
    hamWin = hamming(NFFT); % window your audio signal to avoid fft edge effects
    
    % get spectral content
    S = spectrogram(audio,hamWin,NFFT/2,NFFT,fs);
    
    % Start at center lowest piano note
    A0 = 27.5;
    % all 88 keys
    keys = 0:87;
    center = A0*2.^((keys)/12); % set filter center frequencies
    left = A0*2.^((keys-1)/12); % define left frequency
    left = (left+center)/2.0;
    right = A0*2.^((keys+1)/12); % define right frequency
    right = (right+center)/2;
    
    % Construct a filter bank
    filter = zeros(numel(center),NFFT/2+1); % place holder
    freqs = linspace(0,fs/2,NFFT/2+1); % array of frequencies in spectrogram
    for i = 1:numel(center)
        xTemp = [0,left(i),center(i),right(i),fs/2]; % create points for filter bounds
        yTemp = [0,0,1,0,0]; % set magnitudes at each filter point
        filter(i,:) = interp1(xTemp,yTemp,freqs); % use interpolation to get values for   frequencies
    end
    
    % multiply filter by spectrogram to get chroma values.
    chroma = filter*abs(S);
    
    %Put into 12 bin chroma
    chroma12 = zeros(12,size(chroma,2));
    for i = 1:size(chroma,1)
        bin = mod(i,12)+1; % get modded index
        chroma12(bin,:) = chroma12(bin,:) + chroma(i,:); % add octaves together
    end
    

    这应该可以解决问题。这可能不是最快的解决方案,但应该可以完成工作。

    当然可以优化。

    【讨论】:

    • 谢谢!我会查一下色谱图是什么。但是有没有办法从生成的频谱图中正确访问数据?
    • S=spectrogram(x,window,noverlap,nfft,fs)
    • 这似乎是一个值得赏金的答案!
    • 请注意,这是我在大学时研究的主题:)
    • @MZimmerman6 嗨,我一直在阅读您的答案,但我迷失在代码中。你如何选择NFFT?(有一些规则吗?)。 S告诉你什么?在你开始构建过滤器之后,我迷路了。能否请您详细说明一下?
    【解决方案2】:

    作为 MZimmerman6,这是一个非常复杂的问题。峰峰值测量可能会成功,但如果音乐变得更复杂,肯定不会成功。我以前解决过这个问题,也看到其他人也尝试过,我见过的同行中最成功的项目包括以下内容:

    1) 限制时间。实际上,程序可能很难确定音符何时发生变化!如果您试图将人声与乐器分开,或者例如当两个和弦按顺序播放但它们之间有一个保持相同的音符时,尤其如此。因此,通过限制时间意味着找出每段音乐发生的时间,因此在您的情况下,将曲目分为四个曲目,每个音符一个。您可以利用每个音符的攻击来发挥自己的优势,自动将攻击检测为要测试的新片段的开始。

    2) 限制频率。您必须使用您所知道的,否则您将需要进行特征模态比较。奇异值分解在这个领域是有效的。但是,如果您以某种方式让钢琴演奏单独的音符(单独),并且您有钢琴演奏歌曲的录音,那么您可以做的是对每个片段进行快速傅立叶变换(参见上面的时间限制),消除噪音,然后比较它们。然后,您使用减法或其他指标来确定每个音符的最佳“拟合”。

    这是对这些问题的粗略解释,但相信我,对此类分析施加的限制越多越好。

    【讨论】:

    • 是的,我绝对需要这些约束,因为这是我的第一个项目。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    • 1970-01-01
    • 2012-12-28
    • 1970-01-01
    • 2011-05-05
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多