用matlab识别声音的音高

时间:2013-07-24 16:18:20

标签: matlab signal-processing spectrogram

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

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

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

或者我走错了路?

提前致谢!

2 个答案:

答案 0 :(得分:3)

你在正确的轨道上,但这不是一个简单的问题。我建议调查的是一种称为色度图的东西。这将使用您从频谱图中收集的信息并将其“bin”到钢琴音符频率中。这将给出歌曲谐波内容的近似值。尽管由于音符谐波中的剩余能量,这可能不完全准确,但它是一个开始。

要意识到你正在做的转录是一项非常艰巨的任务,并且尚未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

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

当然可以优化它。

答案 1 :(得分:3)

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

1)限制时间。程序实际上很难确定笔记何时发生变化!如果您尝试将声乐与乐器分开,或者例如当两个和弦按顺序播放时,尤其如此,但它们之间的一个音符保持不变。因此,通过约束时间意味着找出每个音乐块的发生时间,因此在您的情况下,将轨道分成四个轨道,每个音轨一个轨道。您可能能够利用每个音符的攻击来自动检测攻击,作为要测试的新段的开头。

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

这是对问题的粗略解释,但相信我,你可以对这种分析施加的限制越多越好。