Matlab音频格式转换

所需前置知识
读音频 audioread
语法:
  [y,Fs] = audioread(filename);   从名为 filename 的文件中读取数据,并返回样本数据 y 以及该数据的采样率 Fs。
  
  [y,Fs] = audioread(filename,samples);   读取文件中所选范围的音频样本,其中 samples 是 [start,finish] 格式的向量。
  
  [y,Fs] = audioread(___,dataType) ;   返回数据范围内与 dataType(‘native’ 或 ‘double’)对应的采样数据,可以包含先前语法中的任何输入参数。
写音频audiowrite
语法:
  audiowrite(filename,y,Fs);  以采样率 Fs 将音频数据矩阵 y 写入名为 filename 的文件。filename 输入还指定了输出文件格式。输出数据类型取决于音频数据 y 的输出文件格式和数据类型。
  
  audiowrite(filename,y,Fs,Name,Value) ;  使用一个或多个 Name,Value 对组参数指定的其他选项。
FFT 离散傅立叶变换的快速算法:此处 FFT 只用作绘制频谱图像进行分析,并不对音频格式转换有直接的影响:
  N个采样点,经过FFT之后,就可以得到N个点的FFT结果。为了方便进行FFT运算,通常N取2的整数次方,但是这里直接取读取出来的样本数作为N。

FFT 计算公式如下:

在这里插入图片描述

Xk 长度与 N 相同。
根据奈科斯特定律,只有 f=fs/2 范围内的信号才是被采样到的有效信号,因此得到的频谱肯定是关于 N/2 对称的(就是只看前一半的波形就好)。
第k点的实际频率的计算为 f(k) = k * (fs / n) — — (横轴的频率范围为 :f = n * fs / N;)
X[0] 为直流分量 ,幅值 = 模值(X[0]) / N
X[k] 为个点的频率分量(除X[0]外),幅值 = 模值(X[k]) / (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 原始音频文件读取

读入原始音频,记得修改对应的文件名,带后缀。如果选择播放原音频,那么读取完源文件后,会从电脑喇叭播放声音。

代码片段:
 %%  原始音频文件读取  %%%%%%%%%%%
    [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

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    

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

5 生成输出音频并转码

这一步是本文的关键步骤,转码的核心就是调用 audiowrite() ,也是需要去学习使用的函数。
代码片段:
 %% 生成输出音频并转码  %%%%%%%%%%%
    y_out = resample(y_ratio,dest_FS,source_FS);              % 对即将输出的数据,进行重采样到设定的采样率
    audiowrite(outputfile,y_out,dest_FS,'BitsPerSample',bps); % 将输出数据存储为音频文件。

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

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。
3.1 例:.m4a 转 ogg
在这里插入图片描述

“萨克斯 - 莫斯科郊外的晚上 - 纯音乐.m4a” 转 .ogg,且将44.1KHz 采样率转为 48KHz采样率。
  由于上述代码中,是按照 wav 的格式来输出,audiowrite 中的 name-value 键值对对 ogg 无效,因此修改一下 audiowrite 函数的 name-value 键值对,按照帮助文档提供的设置,可以选择以下选项:
Matlab音频格式转换_第1张图片

因此修改一下 audiowrite 为:

audiowrite(outputfile,y_out,dest_FS,'Quality',100); % 将输出数据存储为音频文件。

同时修改 inputfile 与 outputfile。
运行程序后,生成下面文件
Matlab音频格式转换_第2张图片

3.2 例:.flac转 wav

按照老方法,修改一下 audiowrite 函数的 name-value 键值对,选用bps参数。
在这里插入图片描述

运行代码,
同样也生成了“张国荣-沉默是金.flac.wav”文件,显示区间显示,有需要可以通过这个地方来设置在这里插入图片描述
Matlab音频格式转换_第3张图片

完整代码

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%   功能:音频格式转换(任意格式互转)           % 
%   作者: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

————————————————
版权声明:本文为CSDN博主「Mr-Ma Technology」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_29225913/article/details/105445028

你可能感兴趣的:(Matlab音频格式转换)