pyqt5:python读取二进制文件(音频PCM文件)显示波形
文章目录
有个项目需要输出10-50Hz的低频信号驱动线圈,考虑使用音频功放硬件,所以做这方面的预研。
参考文章:
- 作者:很久没安静的回忆了,文章:音频 PCM 详解
- 作者:怪我冷i,文章:音视频从入门到精通——FFmpeg分离出PCM数据实战
3.作者:cuijiecheng2018,文章:windows下使用FFmpeg生成PCM音频文件并播放(通过命令的方式)
1.使用ffmpeg生成PCM文件
ffmpeg作为开源软件,应用非常广泛,这里我们借用它来把mp3转化成PCM文件。PCM文件没有文件头,帧头等信息,直接就是二进制的音频数据。播放时需要的 采样率,位深,大小端存储,通道 等信息,PCM文件也没有包含,使用ffmpeg播放时需要指定这些信息(由于PCM文件是自己生成的,所以我们知道这些信息的)。
首先选一个mp3文件,我选的源文件是一首5分钟长的歌曲,我先用格式工厂把它分割成3部分,取其中一部分,不需要太大的数据,分割后的文件大小为1.46MB,时长01:36,如下图:
把Part2.mp3放到ffmpeg目录下,打开windows shell,进入ffmpeg目录。
1.1 用 ffprobe 查看文件信息
>ffprobe -i Part2.mp3
Duration: 00:01:36.31, start: 0.025057, bitrate: 128 kb/s
Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 128 kb/s
Metadata:
encoder : Lavc59.12
1.2 用 ffmpeg 命令转换
为了方便查看数据,我选择单通道输出
>ffmpeg -i Part2.mp3 -ar 22050 -ac 1 -f s16le Part2.pcm
Stream mapping:
Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, s16le, to 'Part2.pcm':
Metadata:
title : è·ç¦» (我ä¸é
)
album : 我很忙
genre : Pop
artist : 周æ°ä¼¦
album_artist : 周æ°ä¼¦
composer : 周æ°ä¼¦
comment : ExactAudioCopy v0.99pb3
DISCID : ISCID
encoder : Lavf59.27.100
Stream #0:0: Audio: pcm_s16le, 22050 Hz, mono, s16, 352 kb/s
Metadata:
encoder : Lavc59.37.100 pcm_s16le
size= 4146kB time=00:01:36.28 bitrate= 352.8kbits/s speed= 606x
video:0kB audio:4146kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000000%
命令简单解释:
# 输入文件
-i
# 格式
-f fmt force format
#这里的参数 s16le 表示 数据格式为有符号16bit 整型,小端存储格式
#设置音频采样率
-ar rate set audio sampling rate (in Hz)
#设置音频通道数
-ac channels set number of audio channels
#最后的参数为输出文件名
1.3 用ffplay 测试播放PCM文件
ffplay -ar 22050 -ac 1 -f s16le -i Part2.pcm
可以在电脑中播放出正常的音乐,说明这个PCM文件是有效的。
2.python读取PCM文件显示波形
使用下面的代码:
import matplotlib.pyplot as plt #画图包
import numpy as np
cnt=500
# 1.设定文件的格式为小端,16bit有符号整型,小端存储
dt = np.dtype('<h')
# 2.读取二进制文件,作为y轴数据
y=np.fromfile('Part2.pcm', dtype=dt, count=cnt, sep='', offset=20000)
# 3.生成x轴数据
x=np.linspace(1, cnt,cnt, dtype=int)
print(x)
print(y)
# 4.绘制成图表
plt.plot(x,y,'bp--') #
# 5.显示图表
plt.show()
改变offset和cnt可以查看自己想看的某段数据图表。
2.1 函数numpy.fromfile
y=np.fromfile(‘Part2.pcm’, dtype=dt, count=cnt, sep=‘’, offset=20000) dt的含义详见下一节。表示以16位bit的带符号整型数据类型和小端存储格式读取文件名为“Part2.pcm”的二进制文件,从偏移量为20000个字节的位置开始读取500(cnt=500)个数据。
参数说明:
参数 | 类型 | 说明 |
---|---|---|
file | file 或 str 或 Path | 打开文件对象或文件名。 |
dtype | data-type | 可选.返回数组的数据类型。对于二进制文件,它用于确定文件中各项的大小和字节顺序。支持大多数内置数字类型,并且可能支持扩展名类型。 |
count | int | 要读取的项目数。-1表示所有项目(即完整文件)。 |
sep | str | 如果文件是文本文件,则项目之间的分隔符。空(“”)分隔符表示文件应被视为二进制文件。分隔符中的空格(“”)匹配零个或多个空格字符。仅由空格组成的分隔符必须至少匹配一个空格。 |
offset | int | 与文件当前位置的偏移量(以字节为单位)。默认值为0。仅允许用于二进制文件。 |
2.2 数据类型dtype说明
dt = np.dtype(‘<h’) 表示小端存储,16bit带符号整型。
类型 | 字符代码 |
---|---|
bool | ?, b1 |
int8 | b, i1 |
uint8 | B, u1 |
int16 | h, i2 |
uint16 | H, u2 |
int32 | i, i4 |
uint32 | I, u4 |
int64 | q, i8 |
uint64 | Q, u8 |
float16 | f2, e |
float32 | f4, f |
float64 | f8, d |
complex64 | F4, F |
complex128 | F8, D |
str | a, S(可以在S后面添加数字,表示字符串长度,比如S3表示长度为三的字符串,不写则为最大长度) |
unicode | U |
大端存储 | > |
小端 | < |
3.源码和PCM文件链接
https://gitee.com/huangweide001/py-hwd/tree/master/read_pcm_plt