【Matlab】音乐跳动条特效分析与模仿
本帖最后由 jjjzw 于 2021-9-5 14:05 编辑### 一、频谱图分析
无意中在b站看到有up在某项目中实现了常见的音乐跳动特效,想到这就是音频的频谱图,于是想试着分析并模仿这种特效的制作。
!(https://i.loli.net/2021/08/29/UOlSIhLEtv4dNXR.png)
所谓频谱图,即以横轴纵轴的波纹方式,记录画出信号在各种频率的图形资料。横轴为频率,纵轴为强度,即信号在这个频率的能量是多还是少。符合认知的是,当观察音乐特效时,高音部分出现后右边的音乐条会变高,左边会变低,是不同频率强度不同导致的。
因此要得到会变化的特效图,只要不断地画频谱图即可。因为同步和计算力的原因,我设计每次画出0.2秒信号的频谱图,0.2秒更新一次。
为了得到0.2秒的频谱,我使用快速傅立叶变换(FFT)。
!(https://i.loli.net/2021/08/29/apD7wqcToGnKErZ.png)
### 二、Matlab实现
(随便下载一首歌"汪苏泷 - 年轮.mp3")
```matlab
%% begin
clc;
clear;
close all;
%% settings
div = 0.2; % 设置间隔
%% read file
= audioread("汪苏泷 - 年轮.mp3");
T = 1/Fs;
L = length(y)-mod(length(y),2); % 防止索引报错
t = (0:L-1)*T;
l = div*Fs;
%% play music
sound(y,Fs);
%% FFT
for i=1:L/(l-1)
t1 = clock; % 计时
x = y(i*l:(i+1)*l);
FFT(x,l,Fs); % 变换、绘画
t2 = etime(clock,t1); % 计时
pause(div-t2); % 确保0.2秒同步,同时给电脑绘画的时间
end
function [] = FFT(x,l,Fs) % 对0.2秒信号进行FFT
Y = fft(x);
P2 = abs(Y/l);
P1 = P2(1:l/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f = Fs*(0:(l/2))/l;
plot(f,P1); % 绘画频谱图
axis();
end
```
效果:
!(https://i.loli.net/2021/08/29/QPgAl5Rhz4jo7sJ.png)
看得出来不是很好,原因在于低频太多,强度太大,因此用高通滤波器滤掉这部分。用工具设计一个巴特沃斯高通滤波器,滤掉0-1500Hz左右的频率。
!(https://i.loli.net/2021/08/29/zGQPTodkqnajBIi.png)
```matlab
function Hd = btw
%BTW 返回离散时间滤波器对象。
% MATLAB Code
% Generated by MATLAB(R) 9.8 and Signal Processing Toolbox 8.4.
% Generated on: 29-Aug-2021 01:48:30
% Butterworth Highpass filter designed using FDESIGN.HIGHPASS.
% All frequency values are in Hz.
Fs = 44100;% Sampling Frequency
Fstop = 1000; % Stopband Frequency
Fpass = 2000; % Passband Frequency
Astop = 80; % Stopband Attenuation (dB)
Apass = 1; % Passband Ripple (dB)
match = 'stopband';% Band to match exactly
% Construct an FDESIGN object and call its BUTTER method.
h= fdesign.highpass(Fstop, Fpass, Astop, Apass, Fs);
Hd = design(h, 'butter', 'MatchExactly', match);
%
```
在源代码中添加:
```matlab
%% HPF
Hlp = btw;
y1 = filtfilt(Hlp.sosMatrix, 1, y);
```
效果图:
!(https://i.loli.net/2021/08/29/Lh7KlJTFNGDucZQ.png)
这次就好看很多。完整代码:
```matlab
%% begin
clc;
clear;
close all;
%% settings
div = 0.2;
%% read file
= audioread("汪苏泷 - 年轮.mp3");
T = 1/Fs;
L = length(y)-mod(length(y),2);
t = (0:L-1)*T;
l = div*Fs;
%% HPF
Hlp = btw;
y1 = filtfilt(Hlp.sosMatrix, 1, y);
%% play music
sound(y,Fs);
%% FFT
for i=1:L/(l-1)
t1 = clock;
x = y1(i*l:(i+1)*l);
FFT(x,l,Fs);
t2 = etime(clock,t1);
pause(div-t2);
end
function [] = FFT(x,l,Fs)
Y = fft(x);
P2 = abs(Y/l);
P1 = P2(1:l/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f = Fs*(0:(l/2))/l;
plot(f,P1);
%axis();
end
```
运行代码:
!(https://i.loli.net/2021/08/29/Uxpnjcf7N2uAyXh.gif)
### 三、进阶
到这里就只剩下采样和上色等事情了,不是Matlab需要做的(笑),要实现音乐条,只需要从FFT的横坐标(共20000个点)中均匀取十几个点,然后放上不同长度的矩形即可,这点计算量对电脑来说还是很轻松的。
要想把图形变得更好看一点,可以尝试带通滤波器,可以有效修饰两端不美观的部分。
网上搜寻一番教程都是用库解决的,在此记录一下设计实现思路{:301_978:} xiaoyu111 发表于 2021-9-5 13:44
for循环那里应该是1:L/l-1吧,y1有两个声道,最后一次循环分析到下一个声道的第一个0.2秒了
是我疏忽了,还是大佬思维缜密{:301_973:} 666666厉害呀 谢谢分享,很厉害 做得很好看,若是合并成柱状图肯定更好看~~ 的确是个好办法,可以继续研究下。 谢谢分享,楼主辛苦了
能活学活用matlab软件,楼主应该是学工科的吧{:1_921:} szhanyutian 发表于 2021-8-29 11:42
谢谢分享,楼主辛苦了
能活学活用matlab软件,楼主应该是学工科的吧
是的{:301_998:}通信学渣 继续期待!