jjjzw 发表于 2021-8-29 03:39

【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个点)中均匀取十几个点,然后放上不同长度的矩形即可,这点计算量对电脑来说还是很轻松的。

要想把图形变得更好看一点,可以尝试带通滤波器,可以有效修饰两端不美观的部分。

jjjzw 发表于 2021-8-29 03:47

网上搜寻一番教程都是用库解决的,在此记录一下设计实现思路{:301_978:}

jjjzw 发表于 2021-9-5 14:04

xiaoyu111 发表于 2021-9-5 13:44
for循环那里应该是1:L/l-1吧,y1有两个声道,最后一次循环分析到下一个声道的第一个0.2秒了

是我疏忽了,还是大佬思维缜密{:301_973:}

吾爱石皮姐 发表于 2021-8-29 08:21

666666厉害呀

mokson 发表于 2021-8-29 08:31

chuqi26 发表于 2021-8-29 09:43

谢谢分享,很厉害

sapin 发表于 2021-8-29 10:56

做得很好看,若是合并成柱状图肯定更好看~~

twostudy 发表于 2021-8-29 11:17

的确是个好办法,可以继续研究下。

szhanyutian 发表于 2021-8-29 11:42

谢谢分享,楼主辛苦了

能活学活用matlab软件,楼主应该是学工科的吧{:1_921:}

jjjzw 发表于 2021-8-29 11:53

szhanyutian 发表于 2021-8-29 11:42
谢谢分享,楼主辛苦了

能活学活用matlab软件,楼主应该是学工科的吧

是的{:301_998:}通信学渣

zrf1980 发表于 2021-8-29 14:14

继续期待!
页: [1] 2 3
查看完整版本: 【Matlab】音乐跳动条特效分析与模仿