在MATLAB2014a中先对音乐信号进行归一化再通过恒q变换实现对一个12s的音乐信号的音阶提取,但不使用MATLAB自带的CQT函数,绘制出音阶图并给出详细代码及注释
时间: 2024-02-15 07:02:48 浏览: 143
基于MATLAB的音乐信号处理
5星 · 资源好评率100%
好的,以下是一个用 MATLAB 实现归一化和 CQT 变换的示例代码:
```matlab
% 读取音频文件
[y, fs] = audioread('music.wav');
% 归一化处理
y = y / max(abs(y));
% 设置 CQT 变换参数
fmin = 32.7; % 最低频率为 C1
n = 12*24; % 一共变换 12 个八度,每个八度取 24 个半音
bins_per_octave = 24; % 每个八度取 24 个半音
Q = 1/(2^(1/bins_per_octave)-1); % Q 值的计算公式
fmax = fs/2; % 最高频率为采样率的一半
hop_length = 256; % 帧移
win_length = hop_length*4; % 窗长
% 计算 CQT
C = zeros(n, length(y)/hop_length);
for i = 1:n
f = fmin*2^((i-1)/bins_per_octave);
fft_len = ceil(Q*fs/f);
% 计算每一帧的 CQT
frame_start = (i-1)*bins_per_octave + 1;
frame_end = i*bins_per_octave;
for j = 1:length(y)/hop_length-win_length/hop_length+1
frame = y((j-1)*hop_length+1:(j-1)*hop_length+win_length).*hanning(win_length);
X = fft(frame, fft_len);
X = X(1:fft_len/2+1);
Y = zeros(bins_per_octave, 1);
for k = 1:bins_per_octave
f1 = fmin*2^((frame_start-1+k-0.5)/bins_per_octave);
f2 = fmin*2^((frame_start-1+k+0.5)/bins_per_octave);
idx1 = ceil(f1/Q/f);
idx2 = floor(f2/Q/f);
if idx1 <= idx2
Y(k) = sum(abs(X(idx1:idx2)).^2);
end
end
C(frame_start:frame_end, j) = Y;
end
end
% 绘制音阶图
imagesc(log(C+eps));
colormap(jet);
set(gca, 'YDir', 'normal');
```
代码解释:
1. `audioread` 函数用于读取音频文件,并返回音频数据 `y` 和采样率 `fs`。
2. 归一化处理可以使音频信号的幅值范围在 -1 到 1 之间,方便后续处理。
3. CQT 变换的参数包括:最低频率 `fmin`、变换个数 `n`、每个八度取的半音数 `bins_per_octave`、Q 值 `Q`、最高频率 `fmax`、帧移 `hop_length`、窗长 `win_length`。这些参数的设置需要根据具体的需求进行调整。
4. 在计算 CQT 变换时,使用了循环计算每个帧的 CQT。对于每个帧,根据变换的频率范围计算 FFT 长度 `fft_len`,然后对帧进行加窗和 FFT 变换得到频谱 `X`,再根据每个八度取的半音数 `bins_per_octave`,计算对应的 CQT 频带能量。最后将每个帧的 CQT 频带能量填充到 CQT 矩阵 `C` 中。
5. 绘制音阶图时,使用了 MATLAB 的 `imagesc` 函数。将 CQT 矩阵取对数是为了使音阶图更易于观察,使用了 `log` 函数。`colormap` 函数用于设置颜色映射,`set(gca, 'YDir', 'normal')` 函数用于将纵轴方向翻转,使得低频在下,高频在上。
请注意,这份代码的运行效率可能会比较低,需要一定的计算资源和时间。
阅读全文