PyAudio库基本知识详解——为自制PCM音频播放器做准备
前言
结合前段时间我们做的音频编解码器,这样我们就可以将获取到的ADPCM数据,转换成PCM数据,然后播放出来,得到一个完整的音频数据,因此,接下来几篇文章中,我们想做一个播放PCM格式的音频播放器。待到音频编解码器完成,播放器完成,或许我们就能做一个语音识别功能模块,通过一个小收音器的BLE蓝牙连接,连接到电脑上,实时完成音频传输,解码,以及识别的整套流程。可以完成语音写入文本,不仅彻底解放双手,还能解放双脚,让你离开电脑桌也能输入文本(不过也是作者的美好幻想, 先挖个坑,距离实现遥遥无期,尽请期待!)
在此之前呢,我们先脚踏实地的,了解一下我们必要的第三方库,PyAudio
。
前置知识
在介绍PyAudio
库之前我们需要先了解一点点前置内容
- 采样率:采样率是指机器每秒采样的次数,是音频处理中的重要参数。如:采样率为44100,即1秒钟采样44100次,常见的采样率为44100、48000,在小型设备中,如只专注语音的识别,不在乎音质,通常会选用更小的采样率,如8000、16000等,换取硬件设备的成本优势
- 音频格式:指的是每个采样点的长度,如:
paInt16
,表示每个采样点为16比特,一次采样获取的数据为16比特,常见的采样点大小为8、16、32等。单位为比特。通常采样率与采样点大小即可确定一定时间内,采样获取的数据大小,如:当音频格式为paInt16
,采样率为8KHz,那么1s中,将采样到8000 * 16bit = 128kb
的数据。 - 通道:指的是声道,麦克风拾音的过程。分为单声道,多声道,立体声,联合立体声等。
- 块:块是指数据块,在PyAudio可以实时处理动态音频数据,也就是
音频流
,而处理音频流实际上也是将连续
的(实际上并非连续)输入以数据块的形式处理,并不是来一个字节处理一个字节,可以理解为缓冲区buffer
的概念。
稍稍理解这些概念,以便后续阅读中看懂PyAudio
的参数,如果没懂,可以返回来反复阅读。
PyAudio
PyAudio
是一个用于在 Python 中进行音频处理的库,它为我们提供了跨平台的接口,用于录音、播放和处理音频流。PyAudio
封装了 PortAudio 库,PortAudio 是一个跨平台的音频库,支持多种操作系统(如 Windows、macOS、Linux)。
PyAudio的常见用途
- 录音(Recording Audio):可以从麦克风获取音频数据。
- 播放音频(Playing Audio):可以播放 WAV 或其他格式的音频文件。
- 实时音频处理:处理音频数据流(例如,分析麦克风输入,实时音效等)。
安装 PyAudio
首先需要安装 PyAudio
。可以使用 pip
来安装:
pip install pyaudio
PyAudio的核心概念
- 流(Stream): PyAudio 的核心概念是“流”(Stream)。流是数据的一个持续流动的通道,用于音频输入或输出。你可以创建一个输入流(录音)或输出流(播放音频),然后使用流来传输音频数据。
- 音频格式和数据: PyAudio 支持多种音频格式,例如
paInt16
(16 位整数格式)和paFloat32
(32 位浮点格式)。音频数据通常是原始的字节流数据,可以通过 NumPy 数组或其他方式进行处理。 - 回调函数: 在实时音频流的场景中,通常使用回调函数来处理音频数据。回调函数会在每次采集到一块音频数据时被调用。
主要功能
-
录音示例: 以下是一个使用
PyAudio
录音的简单示例:import pyaudio import wave# 设置录音参数 FORMAT = pyaudio.paInt16 # 音频格式 CHANNELS = 1 # 单声道 RATE = 44100 # 采样率 CHUNK = 1024 # 每次读取的数据块大小 RECORD_SECONDS = 5 # 录音时长 OUTPUT_FILENAME = "output.wav" # 输出文件p = pyaudio.PyAudio()# 开启输入流 stream = p.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,frames_per_buffer=CHUNK)print("开始录音...")frames = []# 录制数据 for _ in range(0, int(RATE * RECORD_SECONDS / CHUNK)):data = stream.read(CHUNK)frames.append(data)print("录音结束...")# 停止流并关闭 stream.stop_stream() stream.close() p.terminate()# 将录音保存为WAV文件 wf = wave.open(OUTPUT_FILENAME, 'wb') wf.setnchannels(CHANNELS) wf.setsampwidth(p.get_sample_size(FORMAT)) wf.setframerate(RATE) wf.writeframes(b''.join(frames)) wf.close()
这里有值得一提的一个点:
# 录制数据 for _ in range(0, int(RATE * RECORD_SECONDS / CHUNK)):data = stream.read(CHUNK)frames.append(data)
这个循环的主要目的是从流中读取数据,并添加到
frams
列表中,可以看到RATE * RECORD_SECONDS
为采样率 * 录音时长
,这可以得到在本次录音中一共采样的次数,/ CHUNK
表明采样的数据被分块读取并写入frames
。这里其实隐式的处理了采样格式,即paInt16
。 -
播放音频示例: 以下是一个播放 WAV 文件的简单示例:
import pyaudio import wave# 打开WAV文件 wf = wave.open('output.wav', 'rb')p = pyaudio.PyAudio()# 打开输出流 stream = p.open(format=pyaudio.paInt16,channels=wf.getnchannels(),rate=wf.getframerate(),output=True)# 读取文件并播放 chunk = 1024 data = wf.readframes(chunk) while data:stream.write(data)data = wf.readframes(chunk)# 关闭流 stream.stop_stream() stream.close() p.terminate()
PyAudio的高级功能
-
回调模式(Callback Mode): PyAudio 提供了回调模式来处理音频流。在这种模式下,你可以通过定义回调函数来实时处理录制或播放的音频数据。例如,你可以实时对音频数据进行处理或应用某些效果(如滤波、增益等)。
示例:
import pyaudiodef callback(in_data, frame_count, time_info, status):# 处理音频数据print("Recording...")return (in_data, pyaudio.paContinue)p = pyaudio.PyAudio()# 打开输入流 stream = p.open(format=pyaudio.paInt16,channels=1,rate=44100,input=True,frames_per_buffer=1024,stream_callback=callback)stream.start_stream()# 等待流结束 while stream.is_active():passstream.stop_stream() stream.close() p.terminate()
PyAudio的应用场景
- 音频录制与播放:用来创建简单的音频应用程序,进行声音的录制和回放。
- 语音识别:结合其他语音识别库(如
speech_recognition
)可以实现语音识别功能。 - 实时音频处理:可以实时分析、修改或增强音频数据。
- 声音特效处理:可以在录制或播放过程中加入音效,如回声、变调等。
PyAudio与其他音频库对比
- vs. wave:
wave
模块主要用于处理静态的音频文件,而PyAudio
支持音频流,能够进行实时录音与播放。 - vs. soundfile:
soundfile
更适用于处理已保存的音频文件的读写操作,而PyAudio
更擅长实时音频流的处理。
注意事项
- 在不同平台上安装
PyAudio
可能需要额外的步骤。例如,Windows 上可能需要安装PortAudio
的依赖项。 PyAudio
并不支持直接播放 MP3 等压缩音频格式。如果需要播放其他格式的音频,可能需要使用其他库如pygame
或pydub
。
小结
总的来说,PyAudio
是一个非常强大的库,适合用于音频处理和实时音频应用,尤其在需要直接与麦克风或扬声器交互时,提供了非常简洁的接口。
stop_stream与start_stream
可能会有同学好奇,在上面的示例代码中,为什么只看见
stream.stop_stream
而没有看见stream.start_stream
呢,如果只有停止流的操作,为什么没有开启流的操作,流在哪里被开启了呢?
PyAudio
中的 stream.start_stream()
和 stream.stop_stream()
是两个重要的流控制方法,用于控制音频流的开始和停止。
在 PyAudio
的流(Stream
)中,start_stream()
和 stop_stream()
方法实际上是可选的,它们的行为是与音频流的实际使用场景有关的。让我们详细解释一下这两个方法,以及为什么在某些情况下,可能看不到显式调用 start_stream()
。
1. stream.start_stream() 的作用
start_stream()
方法用于启动音频流,开始录制或播放音频。它是用来显式告诉程序 “现在开始处理音频数据”。
2. stream.stop_stream() 的作用
stop_stream()
方法用于停止音频流,表示录制或播放过程结束。这对于需要显式控制音频流的结束时机的程序非常有用。
为什么 start_stream()
有时没被显式调用
-
回调模式(Callback Mode): 如果使用了回调模式(即通过设置
stream_callback
参数来传递回调函数),那么在调用open()
方法时,音频流已经自动开始了。回调机制会在后台处理音频数据的输入和输出。因此,在这种模式下,start_stream()
是不必要的,因为流会自动启动。例如:
import pyaudiodef callback(in_data, frame_count, time_info, status):# 处理音频数据print("Recording...")return (in_data, pyaudio.paContinue)p = pyaudio.PyAudio()# 打开输入流并设置回调函数 stream = p.open(format=pyaudio.paInt16,channels=1,rate=44100,input=True,frames_per_buffer=1024,stream_callback=callback)# 注意: 这里不需要显式调用 start_stream() stream.start_stream() # 这行可以省略,回调模式会自动启动# 等待流结束 while stream.is_active():passstream.stop_stream() stream.close() p.terminate()
在这个例子中,
start_stream()
虽然可以显式调用,但在使用回调模式时,可以省略,因为PyAudio
会在底层自动处理流的启动和停止。 -
默认自动启动(在非回调模式下): 在非回调模式(例如通过
stream.read()
或stream.write()
进行音频数据的读取和写入)中,start_stream()
也是隐式调用的。在创建音频流时,open()
方法会自动启动流,并开始数据的录制或播放。import pyaudiop = pyaudio.PyAudio()# 设置流参数 stream = p.open(format=pyaudio.paInt16,channels=1,rate=44100,input=True,frames_per_buffer=1024)# 此时,流已经自动启动 data = stream.read(1024) # 录音 stream.stop_stream() stream.close() p.terminate()
在这个例子中,
open()
已经自动启动了流,调用stream.read()
只是触发音频数据的读取过程,而不需要显式调用start_stream()
。
小结
- 回调模式:当你使用回调函数时,
PyAudio
会自动管理音频流的开始和停止。因此,通常不需要显式调用start_stream()
,而只需要设置stream_callback
并开始流的处理。 - 非回调模式:即便是非回调模式,
open()
方法有时也会自动开始音频流,尤其是在调用stream.read()
或stream.write()
时,不需要显式调用start_stream()
。
但是,在一些场景下,尤其是自定义更复杂的音频控制时,start_stream()
和 stop_stream()
还是很有用的,特别是当你需要手动控制音频流的启动与停止时。
谁开启的麦克风或扬声器
在上面的示例代码中,敏锐的读者可能会发现,似乎没有发现那里调用了麦克风或扬声器,合理猜测,直接告诉我们,应该是PyAudio库调用了硬件设备,但真是如此吗,如果是,那么又是怎么调用的呢?
我们以上面的代码为例,究竟是谁调用了麦克风,开启了录音
音频的录制是通过 pyaudio
库来实现的,调用麦克风硬件的部分是由 pyaudio
库中的 PyAudio
类和它的 open()
方法来完成的。具体的过程是这样的:
调用麦克风硬件的关键步骤:
-
pyaudio.PyAudio()
: 这个步骤创建了一个PyAudio
对象。这个对象是与音频硬件交互的主要接口,它会管理音频流(包括录音流和播放流),并负责配置音频设备。 -
p.open()
:open()
方法是用来打开一个音频流的,这个流可以是输入流(例如录音)或者输出流(例如播放音频)。在上面的代码中,p.open()
被用来打开一个输入流,用于录制音频。stream = p.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,frames_per_buffer=CHUNK)
关键参数:
format=FORMAT
:指定音频数据的格式,通常为 16 位 PCM 编码(pyaudio.paInt16
)。channels=CHANNELS
:指定录音的通道数,1 表示单声道,2 表示立体声。rate=RATE
:指定采样率,通常选择 44100 Hz,这是 CD 音质的标准采样率。input=True
:这告诉pyaudio
创建一个输入流,也就是通过麦克风录音。如果将其设置为False
,则会创建输出流,用于播放音频。frames_per_buffer=CHUNK
:指定每次读取的音频块的大小,通常是 1024 或 2048。
此时,
pyaudio
会通过系统的音频接口与麦克风硬件进行连接,并开始接收音频数据。具体而言,pyaudio
会通过操作系统调用音频驱动程序来访问麦克风硬件。操作系统(如 Windows、Linux、macOS)会提供接口给pyaudio
来处理与硬件的交互。 -
stream.read(CHUNK)
:stream.read(CHUNK)
方法是用来从音频流中读取音频数据的。这里的CHUNK
表示每次读取的音频数据的大小,也就是说它会以一定的时间间隔(根据CHUNK
的大小)从麦克风捕捉音频数据。通过连续调用
stream.read()
,程序不断地从麦克风获取音频数据,并将这些数据存储到frames
列表中。
总结:
- 谁调用了麦克风硬件?
实际上是pyaudio
库调用了麦克风硬件。pyaudio
作为一个高层的音频处理库,封装了与操作系统音频接口的交互。操作系统的音频驱动程序在幕后管理与麦克风硬件的连接和数据传输。 - 如何调用的?
- 通过
pyaudio.PyAudio()
创建的 PyAudio 实例。 - 使用
p.open()
方法创建音频输入流(input=True
),并通过该流接收来自麦克风的音频数据。 - 最终使用
stream.read()
不断地从麦克风获取音频样本。
- 通过
这样,pyaudio
库就可以通过操作系统和驱动程序,控制麦克风硬件进行录音了。
相关文章:
PyAudio库基本知识详解——为自制PCM音频播放器做准备
前言 结合前段时间我们做的音频编解码器,这样我们就可以将获取到的ADPCM数据,转换成PCM数据,然后播放出来,得到一个完整的音频数据,因此,接下来几篇文章中,我们想做一个播放PCM格式的音频播放器…...
Git如何添加子仓库
背景 项目中经常使用别人维护的模块,在git中使用子模块的功能能够大大提高开发效率。 使用子模块后,不必负责子模块的维护,只需要在必要的时候同步更新子模块即可。 本文主要讲解子模块相关的基础命令,详细使用请参考main page…...

001__VMware软件和ubuntu系统安装(镜像)
[ 基本难度系数 ]:★☆☆☆☆ 一、Vmware软件和Ubuntu系统说明: a、Vmware软件的说明: 官网: 历史版本: 如何下载? b、Ubuntu系统的说明: 4、linux系统的其他版本:红旗(redhat)、dibian、cent…...

在国产电脑上运行PDFSAM软件使用pdf分割合并交替混合处理pdf文档
软件下载地址: https://sourceforge.net/projects/pdfsam/files/ 需要注意事项,系统需要java环境,确认系统有java环境,根据软件版本需求安装对应的java运行环境。 下载pdfsam-4.3.4-linux.tar.gz安装包,解压,将runt…...

STM32完全学习——FATFS0.15移植SD卡
一、下载FATFS源码 大家都知道使用CubMAX可以很快的将,FATFS文件管理系统移植到单片机上,但是别的芯片没有这么好用的工具,就需要自己从官网下载源码进行移植。我们首先解决SD卡的驱动问题,然后再移植FATFS文件管理系统。 二、SD…...

Linux -- 生产消费模型之环形队列、信号量
目录 前言 环形队列 如何用环形队列实现生产消费模型? 信号量 sem_t sem_init(初始化信号量) sem_destroy(销毁信号量) 什么是PV操作? sem_wait(P操作,减少信号量ÿ…...

Ashy的考研游记
文章目录 摘要12.1112.2012.21 DAY1(政治/英语)政治英语 12.22 DAY2(数学/专业课)数学专业课 结束估分 摘要 在24年的12月里,Ashy完成了他的考研冲刺,顺利的结束了他本年度的考研之旅。 在十二月里&#…...

MySQL线上事故:使用`WHERE`条件`!=xxx`无法查询到NULL数据
前言 在一次 MySQL 的线上查询操作中,因为 ! 的特性导致未能正确查询到为 NULL 的数据,险些引发严重后果。本文将详细解析 NULL 在 SQL 中的行为,如何避免类似问题,并提供实际操作建议。 1. 为什么NULL会查询不到? 在…...

vue3学习笔记(11)-组件通信
1.props 父传子 子传夫 父传子 接收用defineProps([]) 空字符串也是假 2.自定义事件 $event:事件对象 ref定义的数据在模板里面引用的时候可以不用.value 3.子传父 宏函数 触发事件 声明事件 defineEmits() 挂载之后3s钟触发 4.命名 肉串命名 5.任意组件通信 mitt pubs…...

【PDF物流单据提取明细】批量PDF提取多个区域内容导出表格或用区域内容对文件改名,批量提取PDF物流单据单号及明细导出表格并改名的技术难点及小节
相关阅读及下载: PDF电子物流单据: 批量PDF提取多个区域局部内容重命名PDF或者将PDF多个局部内容导出表格,具体使用步骤教程和实际应用场景的说明演示https://mp.weixin.qq.com/s/uCvqHAzKglfr40YPO_SyNg?token720634989&langzh_CN扫描…...
张量与数据类型
Pytorch最基本的操作对象——张量(tensor),张量是Pytorch中重要的数据结构,可认为是一个高维数组。一般的,标量(scalar)是只有大小没有方向的量,如1、2、3等;向量&#x…...
torchvision.utils.make_grid 解释下
torchvision.utils.make_grid 是 PyTorch 中 torchvision 库提供的一个实用函数,用于将多个图像拼接成一个网格,方便进行可视化。 主要功能 make_grid 将一批图片组织成一个网格形式,输出一个单一的张量,便于使用可视化工具(如 Matplotlib)查看图像。 参数解释 torchvi…...
Android原生Widget使用步骤
需要创建三个XML文件以及一个Class文件 三个XML文件分别是 Widget布局文件 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_p…...
实验八 指针2
7-1 利用指针返回多个函数值 分数 30 全屏浏览 切换布局 作者 陈晓梅 单位 广东外语外贸大学 读入n个整数,调用max_min()函数求这n个数中的最大值和最小值。 输入格式: 输入有两行: 第一行是n值; 第二行是n个数。 输出格式: 输出最大…...

1 数据库(下):多表设计 、多表查询 + SQL中的with查询语法(MySQL8.0以后版本才支持这种新语法)+ 数据库优化(索引优化)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、多表设计1 多表设计-概述2 三种多表关系一对多(多对一)(1)无外键约束(逻辑外键)&…...
什么是.net framework,什么是.net core,什么是.net5~8,版本对应关系
我不知道有多少人和我一样,没学习过.netCore,想要学习,但是版本号太多就蒙了,不知道学什么了,这里解释下各个版本的关系 我们一般开始学习微软的时候,都是开始学习的.netframework,常用的就是4…...

vulhub-wordpress靶场
一.主题上传漏洞 来到靶场点击主题选择add new 这里有一个上传主题的地方 我们可以去网上找到wordpress主题下载一个 wordpress模板 网页设计模板 免费 免费下载 - 爱给网 下载完成后对我们有用的东西只有这一个目录,把它拖出来 点开moban目录后,创建…...
安装与配置
《PHP Libxml》是一个在PHP中处理XML和HTML文档的重要库。它提供了丰富的API,支持DOM、SimpleXML和XMLReader等多种解析方式,广泛应用于各种编程语言和项目中。 安装与配置 安装: 在PHP中,libxml扩展通常是默认启用的。如果你需要手动安装&…...
斗鱼Android面试题及参考答案
常用的图片框架有哪些? Glide:是一个快速高效的 Android 图片加载库,专注于平滑滚动。它支持多种图片格式,包括 GIF,具有高效的缓存策略,能自动管理图片的生命周期,避免内存泄漏和 OOM 错误。其 API 简洁易用,可轻松实现图片的加载、显示和缓存等功能,如一行代码即可实…...

Could not install Gradle distribution from 的解决办法
在安装完成AndroidStudio之后,运行工程出现如下错误 Could not install Gradle distribution from https://services.gradle.org/distributions/gradle-6.5-bin.zip. 错误原因是:对应版本的Gradle文件下载失败了,我这里是gradle-6.5-bin.zip,不同版本的android studio也可…...

网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...

力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...