pyqt5:python读取二进制文件(音频PCM文件)显示波形

有个项目需要输出10-50Hz的低频信号驱动线圈,考虑使用音频功放硬件,所以做这方面的预研。
参考文章:

  1. 作者:很久没安静的回忆了,文章:音频 PCM 详解
  2. 作者:怪我冷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()

改变offsetcnt可以查看自己想看的某段数据图表。
在这里插入图片描述

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)个数据。
参数说明:

参数类型说明
filefile 或 str 或 Path打开文件对象或文件名。
dtypedata-type可选.返回数组的数据类型。对于二进制文件,它用于确定文件中各项的大小和字节顺序。支持大多数内置数字类型,并且可能支持扩展名类型。
countint要读取的项目数。-1表示所有项目(即完整文件)。
sepstr如果文件是文本文件,则项目之间的分隔符。空(“”)分隔符表示文件应被视为二进制文件。分隔符中的空格(“”)匹配零个或多个空格字符。仅由空格组成的分隔符必须至少匹配一个空格。
offsetint与文件当前位置的偏移量(以字节为单位)。默认值为0。仅允许用于二进制文件。

2.2 数据类型dtype说明

dt = np.dtype(‘<h’) 表示小端存储,16bit带符号整型。

类型字符代码
bool?, b1
int8b, i1
uint8B, u1
int16h, i2
uint16H, u2
int32i, i4
uint32I, u4
int64q, i8
uint64Q, u8
float16f2, e
float32f4, f
float64f8, d
complex64F4, F
complex128F8, D
stra, S(可以在S后面添加数字,表示字符串长度,比如S3表示长度为三的字符串,不写则为最大长度)
unicodeU
大端存储>
小端<

3.源码和PCM文件链接

https://gitee.com/huangweide001/py-hwd/tree/master/read_pcm_plt

### 音频信号的傅里叶变换实现 在 Qt 中实现音频信号的傅里叶变换 (FFT),可以通过多种方式完成,具体取决于使用的工具库和技术栈。以下是详细的说明: #### 使用 OpenCV 库 OpenCV 是一种强大的计算机视觉库,同时也支持基本的数值运算操作,比如傅里叶变换。虽然其主要用途不是针对音频处理,但在某些情况下也可以用于简单场景中的频谱分析。 以下是一个利用 OpenCV 的示例代码片段,展示如何加载数据并执行 FFT 变换: ```cpp #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> void performFourierTransform(const std::vector<float>& audioData, cv::Mat& fftResult) { // 将输入数据转换为 Mat 类型 cv::Mat data(audioData.size(), 1, CV_32F, &audioData[0]); // 执行离散傅里叶变换 cv::dft(data, fftResult, cv::DFT_COMPLEX_OUTPUT); } ``` 此方法适用于已经具备 OpenCV 开发环境的情况[^3]。 --- #### 使用 FFTW 库 FFTW(Fastest Fourier Transform in the West)是一种高效的开源 FFT 计算库,在 C/C++ 编程领域广泛使用。为了将其集成到 Qt 工程中,需按照如下步骤配置项目文件和源码逻辑: ##### 步骤概述 1. **下载 FFTW**:访问官方站点获取适合目标平台的预编译二进制包或自行构建。 2. **创建 lib 文件**:将动态链接库 (.dll 或 .so) 转化成静态库形式以便于跨平台移植。 3. **Qt Creator 设置**:修改 `.pro` 文件以引入外部依赖项。 例如,`.pro` 文件可能包含这样的条目: ```plaintext LIBS += -L$$PWD/libs/ -lfftw3f INCLUDEPATH += $$PWD/include DEPENDPATH += $$PWD/include ``` 随后可以在程序内部调用 FFT 函数计算频谱分量: ```cpp #include <fftw3.h> void computeFFT(float* inputSignal, size_t length, float* outputReal, float* outputImaginary) { fftwf_plan plan = fftwf_plan_dft_r2c_1d(length, inputSignal, reinterpret_cast<fftwf_complex*>(outputReal), FFTW_ESTIMATE); fftwf_execute(plan); // Perform FFT computation fftwf_destroy_plan(plan); // Clean up resources after use } ``` 上述函数实现了单精度浮点数类型的快速傅里叶正向变换[^5]。 --- #### 数学基础与注意事项 当讨论采样频率 \( F_s \) 和样本数量 \( N \) 对应关系时,应当注意以下几个方面: - 每个索引位置代表特定范围内的实际物理频率值; \[ f_n = \frac{(n-1)}{N} \cdot F_s \quad (\text{n=1,...,N})\] - 幅度归一化的必要性在于消除因窗口大小变化带来的误差影响; - 如果违反奈奎斯特准则,则可能发生混叠现象导致错误解读原始波形特征[^4]。 --- #### Python 结合 PyQt 实现方案 除了纯 C++ 外壳封装外,还可以考虑混合编程模式——即借助 Python 解析音轨帧序列后再传递给 GUI 层面渲染图表视图组件。这种方法的优势在于开发周期短且易于维护扩展新特性。 典型流程包括但不限于读取 PCM 数据流、应用 NumPy 完成核心算法部分以及最终绘制成像效果呈现给用户界面交互体验优化等方面工作内容[^2]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值