欢迎转载,但请一定要给出原文链接,标注出处,支持原创! 谢谢~
https://blog.csdn.net/qq_29225913/article/details/105445028
在本文,有两个核心的函数需要掌握,方可实现功能,具体可以在命令行 help 查看,或者点击链接进入中文帮助中心。
1.1 读音频 audioreadaudioread
语法:
[y,Fs] = audioread(filename); 从名为 filename 的文件中读取数据,并返回样本数据 y 以及该数据的采样率 Fs。
[y,Fs] = audioread(filename,samples); 读取文件中所选范围的音频样本,其中 samples 是 [start,finish] 格式的向量。
[y,Fs] = audioread(___,dataType) ; 返回数据范围内与 dataType(‘native’ 或 ‘double’)对应的采样数据,可以包含先前语法中的任何输入参数。
1.2 写音频audiowriteaudiowrite
语法:
audiowrite(filename,y,Fs); 以采样率 Fs 将音频数据矩阵 y 写入名为 filename 的文件。filename 输入还指定了输出文件格式。输出数据类型取决于音频数据 y 的输出文件格式和数据类型。
audiowrite(filename,y,Fs,Name,Value) ; 使用一个或多个 Name,Value 对组参数指定的其他选项。
1.3 FFT 离散傅立叶变换的快速算法FFT 的详细使用参考我的另一篇单独分析 FFT 的博文 Matlab 计算 FFT 的方法及幅值问题
截取部分关键内容在这里(此处 FFT 只用作绘制频谱图像进行分析,并不对音频格式转换有直接的影响,因此属于扩展阅读内容):
N个采样点,经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N取2的整数次方,但是这里直接取读取出来的样本数作为N。
备注:在本文发布后,对绘图部分有小部分修改,暂时没时间对本章的图片及内容进行修改,本章节的内容已经过验证,能够实现 音频格式转换 功能,因此也可以使用本章节的代码,第四章-完整代码 已做了更新。
2.1 参数定义 能够修改的参数,放在这个部分来定义。%% 参数定义 %%%%%%%%%%%
% 音频文件参数
% source_FS = 16000; %原采样率(该值弃用,从文件读取)
dest_FS = 8000; %目标采样率
bps = 16; %位深 (查看帮助文档可以获取支持的 bps)
Tfile = 0; %声音片段的总时长s (0为不修改)
% 音频通道
stereo = 'mono'; % 输出音频通道 'mono':单声道,'stereo':立体声
audio_ch = 'left'; % 立体声输入,单声道输出时,选用哪一通道? 'left','right','both'
Left_channel_ratio = 0.5; % 左声道占比
% 文件
inputfile = ('connected_CN.mp3'); % 输入文件名
outputfile = [inputfile,'.wav']; % 输出文件名
AudioInfo = audioinfo(inputfile) % 打印输入音频文件的信息(不加分号)
%播放设置
isplay = 1; % 0:播放原音频 1:播放生成音频
2.2 原始音频文件读取
读入原始音频,记得修改对应的文件名,带后缀。如果选择播放原音频,那么读取完源文件后,会从电脑喇叭播放声音。%% 原始音频文件读取 %%%%%%%%%%%
[y_input,source_FS]=audioread(inputfile); % 将 WAV 文件转换成变量
fs_str = ['(Fs:',num2str(source_FS/1000),'KHz)']; % fs 的字符串,在图上显示文件 fs
whos y_input % 打印y的信息
if isplay == 0 % 如果选择播放原音频
if source_FS < 192000 % 电脑小于 192K 采样率才能播放
sound(y_input,source_FS) % 调用可以播放声音的函数 sound()
end
end
2.3 打印输入波形图像
这一步将 audioread 读取出来的原音频数据,通过图像展示出来,原音频文件解码后,会得到一个列表,根据源文件的通道数n来区分,常用的通道是双通道,即2声道立体声,还有有其他的如:2.1声道、4声道、5.1声道、7.1声道等,对应的n会不同,此处我只对2声道的立体声做处理,有需要其他声道的,可以在此基础上,增加不同 n 值处理的方法。%% 打印输入波形图像 %%%%%%%%%%%
figure('Name','输入文件波形','NumberTitle','off');
[m,n] = size(y_input); % 计算文件的长度与声道数量
if n==1 % 单声道
y1 = y_input(:,1); % 提取声道数据
subplot(2,1,1);
plot(y1); % 描绘左声道图像
title(['单声道原始波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,1,2);
Y_fft = fft(y1,4096); % 计算 FFT
plot(abs(Y_fft)); % 描绘 FFT 图像
title('单声道原始波形频谱')
else % 立体声
y1 = y_input(:,1); % 提取左声道数据
y2 = y_input(:,2); % 提取右声道数据
subplot(2,2,1);
plot(y1); % 描绘左声道图像
title(['左声道原始波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,2,2);
plot(y2); % 描绘右声道图像
title(['右声道原始波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,2,3);
Y_fft1 = fft(y1,4096); % 左声道 FFT 计算
plot(abs(Y_fft1)); % 描绘左声道 FFT 图像
title('左声道原始波形频谱')
subplot(2,2,4);
Y_fft2 = fft(y2,4096); % 右声道 FFT 计算
plot(abs(Y_fft2)); % 描绘右声道 FFT 图像
title('右声道原始波形频谱')
end
2.4 输出参数设置
这一个步骤是根据 2.1 设置的参数来去对读取出来的声道列表进行计算,可以根据需求来这里增加对音频序列的操作,但是本文的目标是转码,不做音频处理,因此,此处不对音频数据进行过多的处理。%% 输出参数设置 %%%%%%%%%%%
if strcmp(stereo,'mono') % 输出选项为单声道
if n == 1 % 如果输入文件是单声道文件
y_ratio = y1; % 那么输出文件的数据与输入文件的数据一致
else % 如果输入是立体声文件
if strcmp(audio_ch,'left') % 输出通道选择 左声道
y_ratio = y1; % 将左声道的数据作为输出数据
elseif strcmp(audio_ch,'right') % 输出通道选择 右声道
y_ratio = y2; % 将右声道的数据作为输出数据
else % 输出通道选择其他选项(both)
y_ratio = y1*Left_channel_ratio + y2*(1-Left_channel_ratio); % 就将左声道数据与右声道数据,按照设定的比例来混合。
end
end
else % 如果输出选项为立体声
if n == 1 % 输入文件是单声道
y_ratio(:,1) = y1; % 那么左右声道都用输入的数据
y_ratio(:,2) = y1;
else % 输入文件是立体声
y_ratio = y_input; % 那么输出文件的数据与输入文件的数据一致
end
end
2.5 生成输出音频并转码
这一步是本文的关键步骤,转码的核心就是调用 audiowrite() ,也是需要去学习使用的函数。%% 生成输出音频并转码 %%%%%%%%%%%
y_out = resample(y_ratio,dest_FS,source_FS); % 对即将输出的数据,进行重采样到设定的采样率
audiowrite(outputfile,y_out,dest_FS,'BitsPerSample',bps); % 将输出数据存储为音频文件。
2.6 输出音频文件读取
这一步将刚才生成的音频文件再重新读入进来,用于检查格式转换后的效果。如果选择播放生成音频,那么读取完源文件后,会从电脑喇叭播放声音。%% 输出音频文件读取 %%%%%%%%%%%
figure('Name','输出文件波形','NumberTitle','off'); % 打开第2个figure
[y_output,dest_FS]=audioread(outputfile); % 将上一步生成的文件读取出来保存为变量
fs_str = ['(Fs:',num2str(dest_FS/1000),'KHz)']; % 采样率字符串
if isplay == 1 % 如果选择播放生成音频
if dest_FS < 192000 % 电脑小于 192K 采样率才能播放
sound(y_output,dest_FS) % 调用可以播放声音的函数 sound()
end
end
2.7 打印输出波形图像
这一步将 audioread 读取出来的转码后的音频数据,通过图像展示出来,操作方式与原文件的读取并打印波形类似。%% 打印输出波形图像 (跟打印输入波形图像类似,由于后续复用性较低,就不单独编写函数了) %%%%%%%%%%%
[m,n] = size(y_output); % 计算文件的长度与声道数量
if n==1 % 单声道
y1 = y_output(:,1); % 提取声道数据
subplot(2,1,1);
plot(y1); % 描绘左声道图像
title(['单声道生成波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,1,2);
Y_fft = fft(y1,4096); % 计算 FFT
plot(abs(Y_fft)); % 描绘 FFT 图像
title('单声道生成波形频谱');
else %立体声
y1 = y_output(:,1); % 提取左声道数据
y2 = y_output(:,2); % 提取右声道数据
subplot(2,2,1);
plot(y1); % 描绘左声道图像
title(['左声道生成波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,2,2);
plot(y2); % 描绘右声道图像
title(['右声道生成波形 ',fs_str]);
legend(fs_str); % 显示图例
subplot(2,2,3);
Y_fft1 = fft(y1,4096); % 左声道 FFT 计算
plot(abs(Y_fft1)); % 描绘左声道 FFT 图像
title('左声道生成波形频谱')
subplot(2,2,4);
Y_fft2 = fft(y2,4096); % 右声道 FFT 计算
plot(abs(Y_fft2)); % 描绘右声道 FFT 图像
title('右声道生成波形频谱')
end
3、运行图片
先准备两首歌,用于测试。分别将 .m4a 转成 .ogg,将 .flac 转成 .wav。
“萨克斯 - 莫斯科郊外的晚上 - 纯音乐.m4a” 转 .ogg,且将44.1KHz 采样率转为 48KHz采样率。
由于上述代码中,是按照 wav 的格式来输出,audiowrite 中的 name-value 键值对对 ogg 无效,因此修改一下 audiowrite 函数的 name-value 键值对,按照帮助文档提供的设置,可以选择以下选项:
因此修改一下 audiowrite 为:
audiowrite(outputfile,y_out,dest_FS,'Quality',100); % 将输出数据存储为音频文件。
同时修改 inputfile 与 outputfile。
运行程序后,生成下面文件
按照老方法,修改一下 audiowrite 函数的 name-value 键值对,选用bps参数。
运行代码,
同样也生成了“张国荣-沉默是金.flac.wav”文件,显示区间显示,有需要可以通过这个地方来设置
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 功能:音频格式转换(任意格式互转) %
% 作者:Mr-Ma Technology(马健维) %
% 时间:2020.04.09 %
% 转载请注明出处 %
% https://blog.csdn.net/qq_29225913/article/details/105445028
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 支持的转换格式 %%%%%%%%%%%
% |-----------------------------------------------------|
% | 格式 | 输入 | 输出 |
% |-----------------------------------------------------|
% |WAVE (.wav) | 支持 | 支持 |
% |OGG (.ogg) | 支持 | 支持 |
% |FLAC (.flac) | 支持 | 支持 |
% |AU (.au) | 支持 | 不支持 |
% |AIFF(.aiff/.aif) | 支持 | 不支持 |
% |AIFC (.aifc) | 支持 | 不支持 |
% |MP3 (.mp3) (注意电脑版本) | 支持 | 不支持 |
% |MPEG-4 AAC(.m4a/.mp4)(注意电脑版本) | 支持 | 支持 |
% |-----------------------------------------------------|
% 更多详细信息,请参考 Matlab 相关描述(通道数、比特率、位深)
% audioread :https://ww2.mathworks.cn/help/matlab/ref/audioread.html
% audiowrite :https://ww2.mathworks.cn/help/matlab/ref/audiowrite.html?ue&s_tid=gn_loc_dropp
%% 清空内存里的变量 %%%%%%%%%%%
clear;
close all;
clc;
%% 参数定义 %%%%%%%%%%%
% 音频文件参数
% source_FS = 16000; %原采样率(该值弃用,从文件读取)
dest_FS = 48000; % 目标采样率
bps = 16; % 位深 -audiowrite 参数(适用于输出 .wav/.flac 文件)
qlt = 80; % Quality -audiowrite 参数(适用于输出 .ogg 文件)
br = 0; % BitRate -audiowrite 参数(适用于输出 .m4a/.mp4 文件)
% Tfile = 0; % 声音片段的总时长s (0为不修改) 暂时没用这个参数
% 音频通道
stereo = 'stereo'; % 输出音频通道 'mono':单声道,'stereo':立体声
audio_ch = 'left'; % 立体声输入,单声道输出时,选用哪一通道? 'left','right','both'
Left_channel_ratio = 0.5; % 左声道占比
% 文件
inputfile = ('张国荣-沉默是金.flac'); % 输入文件名
outputfile = [inputfile,'.wav']; % 输出文件名
AudioInfo = audioinfo(inputfile) % 打印输入音频文件的信息(不加分号)
%播放设置
isplay = 1; % 0:播放原音频 1:播放生成音频
% 绘图
isdraw = 1; % 1:打开绘图, 0:关闭绘图, 计算 FFT 需要消耗时间
t_axis = [-1 1]; % 时域图显示区域(纵坐标),按实际来改
f_axis = [0 20000 0 0.002]; % 频域图显示区域,按实际来改
%% 原始音频文件读取 %%%%%%%%%%%
[y_input,source_FS]=audioread(inputfile); % 将 WAV 文件转换成变量
fs_str = ['(Fs:',num2str(source_FS/1000),'KHz)']; % fs 的字符串,在图上显示文件 fs
whos y_input % 打印y的信息
if isplay == 0 % 如果选择播放原音频
if source_FS < 192000 % 电脑小于 192K 采样率才能播放
sound(y_input,source_FS) % 调用可以播放声音的函数 sound()
end
end
%% 打印输入波形图像 %%%%%%%%%%%
if isdraw == 1
figure('Name','输入文件波形','NumberTitle','off');
[N,n] = size(y_input); % 计算文件的长度与声道数量
if n==1 % 单声道
y1 = y_input(:,1); % 提取声道数据
subplot(2,1,1);
plot(y1); % 描绘左声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['单声道原始波形 ',fs_str]);
subplot(2,1,2);
NFFT = source_FS * floor(N / source_FS); % FFT 点数取 fs 的倍数
Y_fft = abs(fft(y1,NFFT)); % 左声道 FFT 计算
A_FFT1 = Y_fft * 2 / NFFT; % 转换为幅值
A_FFT1(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * source_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT1(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('单声道原始波形频谱')
else % 立体声
y1 = y_input(:,1); % 提取左声道数据
y2 = y_input(:,2); % 提取右声道数据
subplot(2,2,1);
plot(y1); % 描绘左声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['左声道原始波形 ',fs_str]);
subplot(2,2,2);
plot(y2); % 描绘右声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['右声道原始波形 ',fs_str]);
subplot(2,2,3);
NFFT = source_FS * floor(N / source_FS); % FFT 点数取 fs 的倍数
Y_fft1 = abs(fft(y1,NFFT)); % 左声道 FFT 计算
A_FFT1 = Y_fft1 * 2 / NFFT; % 转换为幅值
A_FFT1(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * source_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT1(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('左声道原始波形频谱')
subplot(2,2,4);
NFFT = source_FS * floor(N / source_FS); % FFT 点数取 fs 的倍数
Y_fft2 = abs(fft(y2,NFFT)); % 左声道 FFT 计算
A_FFT2 = Y_fft2 * 2 / NFFT; % 转换为幅值
A_FFT2(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * source_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT2(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('右声道原始波形频谱')
end
end
%% 输出参数设置 %%%%%%%%%%%
if strcmp(stereo,'mono') % 输出选项为单声道
if n == 1 % 如果输入文件是单声道文件
y_ratio = y1; % 那么输出文件的数据与输入文件的数据一致
else % 如果输入是立体声文件
if strcmp(audio_ch,'left') % 输出通道选择 左声道
y_ratio = y1; % 将左声道的数据作为输出数据
elseif strcmp(audio_ch,'right') % 输出通道选择 右声道
y_ratio = y2; % 将右声道的数据作为输出数据
else % 输出通道选择其他选项(both)
y_ratio = y1*Left_channel_ratio + y2*(1-Left_channel_ratio); % 就将左声道数据与右声道数据,按照设定的比例来混合。
end
end
else % 如果输出选项为立体声
if n == 1 % 输入文件是单声道
y_ratio(:,1) = y1; % 那么左右声道都用输入的数据
y_ratio(:,2) = y1;
else % 输入文件是立体声
y_ratio = y_input; % 那么输出文件的数据与输入文件的数据一致
end
end
%% 生成输出音频并转码 %%%%%%%%%%%
y_out = resample(y_ratio,dest_FS,source_FS); % 对即将输出的数据,进行重采样到设定的采样率
audiowrite(outputfile,y_out,dest_FS,'BitsPerSample',bps); % 将输出数据存储为音频文件。
%audiowrite(outputfile,y_out,dest_FS,'Quality',qlt); % 将输出数据存储为音频文件。
%% 输出音频文件读取 %%%%%%%%%%%
[y_output,dest_FS]=audioread(outputfile); % 将上一步生成的文件读取出来保存为变量
fs_str = ['(Fs:',num2str(dest_FS/1000),'KHz)']; % 采样率字符串
if isplay == 1 % 如果选择播放生成音频
if dest_FS < 192000 % 电脑小于 192K 采样率才能播放
sound(y_output,dest_FS) % 调用可以播放声音的函数 sound()
end
end
%% 打印输出波形图像 (跟打印输入波形图像类似,由于后续复用性较低,就不单独编写函数了) %%%%%%%%%%%
if isdraw == 1
figure('Name','输出文件波形','NumberTitle','off'); % 打开第2个figure
[N,n] = size(y_output); % 计算文件的长度与声道数量
if n==1 % 单声道
y1 = y_output(:,1); % 提取声道数据
subplot(2,1,1);
plot(y1); % 描绘左声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['单声道生成波形 ',fs_str]);
subplot(2,1,2);
NFFT = dest_FS * floor(N / dest_FS); % FFT 点数取 fs 的倍数
Y_fft = abs(fft(y1,NFFT)); % 左声道 FFT 计算
A_FFT1 = Y_fft * 2 / NFFT; % 转换为幅值
A_FFT1(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * dest_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT1(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('单声道生成波形频谱');
else % 立体声
y1 = y_output(:,1); % 提取左声道数据
y2 = y_output(:,2); % 提取右声道数据
subplot(2,2,1);
plot(y1); % 描绘左声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['左声道生成波形 ',fs_str]);
subplot(2,2,2);
plot(y2); % 描绘右声道图像
axis([0 N t_axis]); % 根据实际情况,限制可显示区间
xlabel('采样点');ylabel('幅度');
title(['右声道生成波形 ',fs_str]);
subplot(2,2,3);
NFFT = dest_FS * floor(N / dest_FS); % FFT 点数取 fs 的倍数
Y_fft1 = abs(fft(y1,NFFT)); % 左声道 FFT 计算
A_FFT1 = Y_fft1 * 2 / NFFT; % 转换为幅值
A_FFT1(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * dest_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT1(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('左声道生成波形频谱')
subplot(2,2,4);
NFFT = dest_FS * floor(N / dest_FS); % FFT 点数取 fs 的倍数
Y_fft2 = abs(fft(y2,NFFT)); % 左声道 FFT 计算
A_FFT2 = Y_fft2 * 2 / NFFT; % 转换为幅值
A_FFT2(1) = 0; % 忽略直流分量的影响
f = (0:(NFFT/2)) * dest_FS / NFFT; % 频率范围,横坐标(半边谱)
plot(f ,A_FFT2(1:NFFT/2 +1)); % 描绘 FFT 图像
axis(f_axis); % 根据实际情况,限制可显示区间
xlabel('频率/Hz');ylabel('振幅');
title('右声道生成波形频谱')
end
end