由于matlab这款科学计算软件本身庞大略显笨重,执行代码的速度受当前系统影响,很难做到严格定时仿真(造成音画不同步),因此高帧率版本的音画同步需要调整:
for i = 1:floor(fs/75):length(data)
if i+0.1*fs<length(data)
X = data(i:floor(i+0.1*fs),1);
中fs/75
的步长数值,以及0.1
*fs窗移步长权重,根据经验调参出适合本地系统的同步效果。
clc,clear,close all;
[data, fs]=audioread('see u again.wav');
player = audioplayer(data,fs);
play(player);
figure('Name', 'The Chainsmokers - See You Again');
subplot(121)
wallpaper = imread('see u again.jpg');
imshow(wallpaper);
axis off
for i = 1:floor(fs/75):length(data)
if i+0.1*fs<length(data)
X = data(i:floor(i+0.1*fs),1);
else
break
end
L = length(X);
Y = fft(X); %Y为复数
P1 = abs(Y/L); %取模
freq1 = fs*(0:L-1)/L; %频域范围
P3 = P1(1:floor(L/2)+1); %索引必须从1开始
freq3 = fs*(0:floor(L/2))/L;
nbins = 256; %将频域波分nbins份
window = floor(length(freq3)/nbins);
%平滑数据
P4 = smooth(P3, window);
P5 = P4(1:window:end);
freq4 = freq3(1:window:end);
subplot(122)
bar3(freq4,P5);
view(290,45)
axis off
drawnow
end
通过使用matlab定时器,实现严格的帧刷新效果;
缺点是比较卡顿。
具体教程参考:江流不染 - matlab音乐频谱动画
clc,clear,close all;
%全局句柄
global music;
%Fs为每秒采样点数44100
[data, Fs] = audioread('see u again.wav');
% 音频长度
total_frame = size(data,1);
% 更新音乐播放器
music = audioplayer(data, Fs);
% 初始化画布
figure('Name', 'The Chainsmokers - See You Again')
subplot(121)
wallpaper = imread('see u again.jpg');
imshow(wallpaper);
axis off
subplot(122)
bar3(0, 0);
% 限制Y轴显示范围
ylim([0, 0.2]);
% 视角
view(290,45)
% 创建一个定时器。
t = timer('Period', 0.1, 'TimerFcn', {@timer_callback,data,Fs,total_frame},'ExecutionMode','fixedSpacing');
% 启动定时器,每隔Period调用一帧动画
start(t);
% 进行播放
play(music);
%定时器回调函数
function timer_callback(object, eventdata, data,Fs,total_frame)% 前两个参数不能省略,必填,其中第一个参数代表定时器本身
global music;
Current = music.CurrentSample;
%确定取样范围
half_space = floor(0.1*Fs/2);
left = Current - half_space;
if left<1
left = 1;
end
right = Current + half_space;
if right>total_frame
right = total_frame;
end
X = data(left:right,:);
% 将音频左右声道合并
X = sum(X, 2);
L = length(X);
% 快速傅里叶fft
Y = fft(X);
P1 = abs(Y/L);
% 合并,乘以2。
P2 = 2*P1(1:floor(L/2)+1);
freq2 = Fs*(0:floor(L/2))/L;
P2 = P2(freq2>20&freq2<12000);
freq2 = freq2(freq2>20&freq2<12000);
% 分为nbins份
nbins = 128;
% 每一份的宽度
window = floor(length(freq2)/nbins);
% 平滑数据
P3 = smooth(P2, window);
P4 = P3(1:window:end);
freq3 = freq2(1:window:end);
%更新句柄属性
bar3(freq3, P4);
axis off;
end
用Matlab听音乐 - 钱斯莫克 & ILLENIUM/Carlie Hanson - See You Again
clc,clear,close all;
%全局句柄
global music;
%Fs为每秒采样点数44100
[data, Fs] = audioread('selfds.mp3');
% 音频长度
total_frame = size(data,1);
% 更新音乐播放器
music = audioplayer(data, Fs);
% 初始化画布
figure('Name', 'The Chainsmokers - Self Destruction Mode')
subplot(121)
wallpaper = imread('self destruction mode.jpg');
imshow(wallpaper);
axis off
subplot(122)
axis off;
% 创建一个定时器。
t = timer('Period', 0.01, 'TimerFcn', {@timer_callback2,data,Fs,total_frame},'ExecutionMode','fixedSpacing');
% 启动定时器,每隔Period调用一帧动画
start(t);
% 进行播放
play(music);
%定时器回调函数
function timer_callback2(object, eventdata, data,Fs,total_frame)% 前两个参数不能省略,必填,其中第一个参数代表定时器本身
global music;
Current = music.CurrentSample;
%确定取样范围
half_space = floor(0.1*Fs/2);
left = Current - half_space;
if left<1
left = 1;
end
right = Current + half_space;
if right>total_frame
right = total_frame;
end
X = data(left:right,:);
% 将音频左右声道合并
X = sum(X, 2);
L = length(X);
% 快速傅里叶fft
Y = fft(X);
P1 = abs(Y/L);
% 合并,乘以2。
P2 = 2*P1(1:floor(L/2)+1);
freq2 = Fs*(0:floor(L/2))/L;
P2 = P2(freq2>20&freq2<12000);
freq2 = freq2(freq2>20&freq2<12000);
% 分为nbins份
nbins = 128;
% 每一份的宽度
window = floor(length(freq2)/nbins);
% 平滑数据
P3 = smooth(P2, window);
P4 = P3(1:window:end);
freq3 = freq2(1:window:end);
%更新句柄属性
r = linspace(0,2*pi,length(freq3));
s = linspace(0,pi,length(freq3));
[u,v] = meshgrid(r,s);
x = (2+cos(v)).*cos(u);
y = (2+cos(v)).*sin(u);
z = 128*P4.*sin(u);
mesh(x,y,z);
colormap hot;
axis equal;
axis off;
end
用Matlab听音乐 -钱斯莫克 - Self Destruction Mode