ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

wav音频文件的提取和分析(matlab)

2021-06-12 20:57:53  阅读:298  来源: 互联网

标签:info len 音频文件 length fprintf matlab file wav


WAV文件格式的介绍:WAV文件是计算机中最常见的存放声音的格式,其扩展名为.wav。WAV文件以RIFF(Resource interchange file format)档案的格式存储,含有不定长度的文件头(header)和数据(data),组成不定长度的区块(chunk)和子区块(sub-chunks)。
WAV文件可以分为三个子区块(chunk):

分区名称文件长度
RIFF chunk12 bytes
”fmt” sub-chunk可变长度, 16 bytes + extra
”data” sub-chunk可变长度, size of sample data

辅助函数:将wav文件中读取的16进制转为10进制。

% A表示wav文件数据
% start表示起始位
% total表示总位数
% return 得到的十进制数
function tmp = add_helper(A,start,total)
    tmp = A(start+total-1);
    for i=total-2:-1:0
        tmp = tmp*16*16+A(start+i);
    end
end

(1)采样频率:也称采样速度或采样率。定义了声音信号在“模拟-数字”转化过程中,单位时间内从连续信号中提取并组成离散信号的采样个数。它用赫兹(Hz)表示。

%法一:matlab的audioread函数返回的第二个参数即为采样频率
[~,fs] = audioread([path,file]);

%法二:直接读取wav文件的28位到25位四位数据即为采样频率
fs = add_helper(A,25,4);

(2)声道数:

%法一:matlab的audioread函数会将声道数转换为列数
channels_num = size(x,2);

%法二:直接读取wav文件的24位到23位即为声道数
channels_num = add_helper(A,23,2);%在第24和23位,24位为高位

(3)样本位数:也称采样位数,即对声音的辨析度。8位或16位,8位采样将取样信号分为256份;16位采样将取样信号分为65536份。

%法一:通过matlab的库函数audioinfo读取
info = audioinfo([path,file]);
bits_per_sample =info.BitsPerSample;
disp(['采样位数为',int2str(bits_per_sample)]);

%法二:直接读取wav文件的36位到35位两位即为样本位数
bits_per_sample = add_helper(A,35,2);

(4)求文件长:即音频文件所占用的内存空间,这里以KB为单位。

%法一:通过matlab的dir函数读取
D = dir([path,file]);
[file_length,file_length_type] = calculate_file_len(D.bytes);
fprintf('文件长为%.2f %s\n',file_length,file_length_type);

%法二:直接计算得到文件长度,简单进行单位换算
[file_length,file_length_type] = calculate_file_len(length(A));
fprintf('文件长为%.2f %s\n',file_length,file_length_type);

(5)求数据长:即WAV文件中,data子区块所包含的数据的长度,也以KB为单位。

%法一:乘以2的原因是在调用audioread函数时matlab自动将2Byte数据转化为了一个数据,实际数据长度是x长度的两倍
fprintf('数据长为%.2fKB\n',2*length(x)/1024);

%法二:直接读取WAV文件的78位到75位的四位数据即为数据部分的长度
data_length = add_helper(A,75,4);
[file_length,file_length_type] = calculate_file_len(data_length);
fprintf('数据长为%.2f %s\n',file_length,file_length_type);

(6)求数码率:表示单位时间(1秒)内传送的比特数bps(bit per second,位/秒),比特率越高质量越好,声音越饱满。码率=采样率×每次采样得到的样本位数×声道数。如果单位一般是k,码率(kbps)=码率(bps)/1000。

%波形数据传输速率(每秒平均字节数) = 采样频率 × 音频通道数 × 每次采样得到的样本位数 / 8
%比特率(kbs) = 波形数据传输速率 × 8 / 1000,除以1000是因为单位是k
kbps = fs * max_track_number * info.BitsPerSample / 8 * 8 / 1000;
fprintf('数码率为%.2f\n',kbps);

(7)求音频文件长度:音频持续的时间,可以通过数据长/采样率计算得到。

%法一:直接调用Matlab的Duration函数
fprintf('音频文件的长度为%.2f\n',info.Duration);

%直接计算,单声道数据长度除以采样率即为音频文件长度
info.music_length = roundn(info.real_length/info.fs,-2);

(8)显示李萨如图形:(8)将两个声道的数据分别加至示波器的Y轴输入端和x轴输入端,将出现一个合成图形,这个图形就是李沙育图形。
李沙育图形随两个输入信号的频率、相位、幅度不同,所呈现的波形也不同。当两个信号相位差为90°时,合成图形为正椭圆,此时若两个信号的振幅相同的话,合成图形为圆;当两个信号相位差为0°时,合成图形为直线,此时若两个信号振幅相同则为与x轴成45°的直线 。

%因为李萨如图形是将信号以左声道作为x轴数据,以右声道数据作为y轴数据,因此至少要双声道
if channels_num >= 2
    figure('Name','李萨如图形','NumberTitle','off');
    plot(x(:,1),x(:,2));
    title('李萨图图形','FontSize',20);
end

(9)实现音频播放功能:

choice = input('请选择使用左声道1播放还是右声道2:');
%法一:通过audioplayer函数实现播放
player = audioplayer(x(:,choice),fs);
play(player)%该函数既可以实现播放
pause(player)%该函数既可以实现暂停播放
resume(player)%该函数可以实现暂停后恢复播放
stop(player)%该函数可以实现停止播放

%法二:通过sound函数实现播放
sound(x(choice),fs);

(10)绘制波形图:

%法一:matlab的audioread函数会将声道数转换为列数
channels_num = size(x,2);
figure('Name','波形图形','NumberTitle','off');
for i = 1:track_number
    subplot(track_number,1,i);
    %横坐标表示序号,纵坐标表示归一化的频率值
    plot(x(:,i));
    title(['\fontsize{16}第',int2str(i),'声道']);
end

具体代码:
代码一:这个函数基本是通过调用matlab库函数实现的。
可以实现播放.wav文件;
可以选择文件;
显示波形图(单声道,双声道);
在波形图上显示声道数、采样频率、样本位数、文件长、数据长、数码率及音频文件长度等参数;
显示李沙育波形图;
可以选择声道播放。

clc;
clear;
close all;

%这里请自己设置路径,这里是以打开文件夹自己选择文件的方式
[file,path] = uigetfile('语音素材/wav_file.wav','*.wav');
if isequal(file,0)
    disp('没有选择文件')
else
    disp(['选择了文件',file])
end
%fs为采样率
info = audioinfo([path,file]);
[x,fs] = audioread([path,file]);

%最大声道数
channels_num = size(x,2);
choice = input('请选择使用左声道1播放还是右声道2还是双声道3:');
if choice == 1
    sound(x(:,1),fs);
elseif choice == 2
    sound(x(:,2),fs);
else
    sound(x(:,1:2),fs);
end

%选择声道数
track_number = input(['总声道数为',int2str(channels_num),'请输入需要的声道数:']);
while track_number>channels_num
    disp(['超出范围',int2str(channels_num),'请重新输入']);
    track_number = input('请输入需要的声道数:');
end

figure('Name','波形图形','NumberTitle','off');
for i = 1:track_number
    subplot(track_number,1,i);
    %横坐标表示序号,纵坐标表示归一化的频率值
    plot(x(:,i));
    title(['\fontsize{16}第',int2str(i),'声道']);
end

if channels_num >= 2
    figure('Name','李萨如图形','NumberTitle','off');
    plot(x(:,1),x(:,2));
    title('李萨图图形','FontSize',20);
end

%%
%获取相关信息
disp(['采样率为',int2str(fs)]);

disp(['声道数为',int2str(channels_num)]);

%需要获取文件本身的内容
%typec = class(x);
%fprintf(['采样位数为',typec(1,4:end),'\n']);
disp(['采样位数为',int2str(info.BitsPerSample)]);

%fprintf('音频文件的长度为%.2f\n',size(x,1)/fs);
fprintf('音频文件的长度为%.2f\n',info.Duration);

D = dir([path,file]);
fprintf('文件长为%dKB\n',round(D.bytes/1024));

%乘以2的原因是length(x)并不是真正数据的长度因为一个采样是需要16位,占两个byte
%而wav文件中给出的也是占用的byte数,而非通过audioread函数将16位数据自动换算为float
fprintf('数据长为%.2fKB\n',4*length(x)/1024);

%波形数据传输速率(每秒平均字节数) = 采样频率 × 音频通道数 × 每次采样得到的样本位数 / 8
%比特率(kbs) = 波形数据传输速率 × 8 / 1000,除以1000是因为单位是k
kbps = fs * channels_num * info.BitsPerSample / 8 * 8 / 1000;
fprintf('数码率为%.2f\n',kbps);

双声道图像

李萨如图形

代码二:代码二的bug是数据长度这里,因为不同的文件数据长度在wav文件中不一定是从75开始的4位数据。只是对当前文件适用,暂时没找到确定数据长度位置的方法。

clc;
clear;
close all;

%获得数据长度
filepath = 'speaking.wav';%这里请自己设置路径
fileID = fopen(filepath);
A = fread(fileID);

%声道数
info.channels_num = add_helper(A,23,2);%在第24和23位,24位为高位
fprintf('声道数为%d位\n',info.channels_num);
%采样频率
info.fs = add_helper(A,25,4);%从25位开始,持续4位
fprintf('采样频率为%d位\n',info.fs);
%取样位数
info.bits_per_sample = add_helper(A,35,2);
fprintf('取样位数为%d位\n',info.bits_per_sample);
%数据长度,因为这里有一个数据类型转换两个byte才被视为一个数据值
data_length = add_helper(A,75,4);
[info.data_length,info.data_length_type] = calculate_file_len(data_length);
fprintf('数据长为%.2f %s\n',info.data_length,info.data_length_type);
%文件长
[info.file_length,info.file_length_type] = calculate_file_len(length(A));
fprintf('文件长为%.2f %s\n',info.file_length,info.file_length_type);
%因为是将两字节数据视为1个数据,所以要除以2,因为只取一个声道故需要处理声道数
info.real_length = data_length/info.channels_num/2;
%音频长度
info.music_length = roundn(info.real_length/info.fs,-2);
fprintf('音频文件长度为%.2f s\n',info.music_length);
%与采样位数有关,多少Byte合成一位
val = info.bits_per_sample/8;
%左声道数据
left_wav = zeros(info.real_length/2/val,1);
%右声道数据
right_wav = zeros(info.real_length/2/val,1);

for i = 0:info.real_length-1
    left_wav(i+1) = add_helper(A,79+i*4,2);
    right_wav(i+1) = add_helper(A,79+i*4+val,2);
end

[x,fs] = audioread(filepath,'double');

% figure;
% subplot(2,1,1)
% plot(left_wav);
% subplot(2,1,2)
% plot(right_wav);

Hex_A = dec2hex(A);

% A表示wav文件数据
% start表示起始位
% total表示总位数
% return 得到的十进制数据
function tmp = add_helper(A,start,total)
    tmp = A(start+total-1);
    for i=total-2:-1:0
        tmp = tmp*16*16+A(start+i);
    end
end

% A表示wav文件数据
% return file_length表示文件长度
% return len_type表示长度对应类型,有B,KB,MB,GB
function [len,len_type]=calculate_file_len(native_A)
    len = native_A;
    len_index = 1;
    len_list = {'B','KB','MB','GB'};
    while len >= 1024
        len = len/1024;
        len_index = len_index+1;
    end
    %保留两位小数
    len = roundn(len,-2);
    len_type = len_list{len_index};
end

代码三:
gui格式较为完整。
可以实现的功能如下:
1.数据部分显示音频文件的各项数据。
选择声道
2.其他选项部分可以选择声道显示波形图异或是李萨如图形。
李萨如图形
3.播放选项部分可以跟随动态显示图像。
动态显示1
动态显示2
已上传到我的资源。
有不足之处欢迎指出。

标签:info,len,音频文件,length,fprintf,matlab,file,wav
来源: https://blog.csdn.net/qq_43650421/article/details/117855008

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有