大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是语音处理工具pzh-py-speech诞生之音频录播实现

  音频录播是pzh-py-speech的主要功能,pzh-py-speech借助的是Python自带wave库以及第三方PyAudio库来实现的音频播放和录制功能,今天痞子衡为大家介绍音频录播在pzh-py-speech中是如何实现的。

一、wave简介

  wave是python标准库,其可以实现wav音频文件的读写,并且能解析wav音频的参数。pzh-py-speech借助wave库来读写wav文件,播放音频时借助wave库来读取wav文件并获取音频参数(通道,采样宽度,采样率),录制音频时借助wave库来设置音频参数并保存成wav文件。下面列举了pzh-py-speech所用到的全部API:

wave.open()

# wav音频读API
Wave_read.getnchannels() # 获取音频通道数
Wave_read.getsampwidth() # 获取音频采样宽度
Wave_read.getframerate() # 获取音频采样率
Wave_read.getnframes() # 获取音频总帧数
Wave_read.readframes(n) # 读取音频帧数据
Wave_read.tell() # 获取已读取的音频帧数
Wave_read.close() # wav音频写API
Wave_write.setnchannels(n) # 设置音频通道数
Wave_write.setsampwidth(n) # 设置音频采样宽度
Wave_write.setframerate(n) # 设置音频采样率
Wave_write.writeframes(data) # 写入音频帧数据
Wave_write.close()

二、PyAudio简介

  PyAudio是开源跨平台音频库PortAudio的python封装,PyAudio库的维护者是Hubert Pham,该库从2006年开始推出,一直持续更新至今,pzh-py-speech使用的是PyAudio 0.2.11。

  pzh-py-speech借助PyAudio库来实现音频数据流控制(包括从PC麦克风获取音频流,将音频流输出给PC扬声器),如果说wave库实现的是对wav文件的单纯操作,那么PyAudio库则实现的是音频相关硬件设备的交互。

  PyAudio项目的官方主页如下:

  PyAudio对音频流的控制有两种,一种是阻塞式的,另一种是非阻塞式的(callback),前者一般用于确定的音频控制(比如单纯播放一个本地音频文件,并且中途不会有暂停/继续等操作),后者一般用于灵活的音频控制(比如录制一段音频,但是要等待一个事件响应才会结束)。pzh-py-speech用的是后者。下面是两种方式的音频播放使用示例:

import pyaudio
import wave CHUNK = 1024 wf = wave.open(“test.wav”, 'rb')
p = pyaudio.PyAudio() ##########################################################
# 此为阻塞式,循环读取1024个byte音频数据去播放,直到test.wav文件数据被全部读出
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
data = wf.readframes(CHUNK)
while data != '':
stream.write(data)
data = wf.readframes(CHUNK)
##########################################################
# 此为非阻塞式的(callback),系统会自动读取test.wav文件里的音频帧,直到播放完毕
def callback(in_data, frame_count, time_info, status):
data = wf.readframes(frame_count)
return (data, pyaudio.paContinue)
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True,
stream_callback=callback)
stream.start_stream()
while stream.is_active():
time.sleep(0.1)
########################################################## stream.stop_stream()
stream.close()
p.terminate()

三、pzh-py-speech音频录播实现

3.1 播放实现

  播放功能本身实现不算复杂,但pzh-py-speech里实现的是播放按钮的五种状态Start -> Play -> Pause -> Resume -> End控制,即播放中途实现了暂停和恢复,因此代码要稍微复杂一些。此处的重点是playAudioCallback()函数里的else分支,如果在暂停状态下,必须还是要给PyAudio返回一段空数据:

import wave
import pyaudio AUDIO_PLAY_STATE_START = 0
AUDIO_PLAY_STATE_PLAY = 1
AUDIO_PLAY_STATE_PAUSE = 2
AUDIO_PLAY_STATE_RESUME = 3
AUDIO_PLAY_STATE_END = 4 class mainWin(win.speech_win): def __init__(self, parent):
# ...
# Start -> Play -> Pause -> Resume -> End
self.playState = AUDIO_PLAY_STATE_START def viewAudio( self, event ):
self.wavPath = self.m_genericDirCtrl_audioDir.GetFilePath()
if self.playState != AUDIO_PLAY_STATE_START:
self.playState = AUDIO_PLAY_STATE_END
self.m_button_play.SetLabel('Play Start') def playAudioCallback(self, in_data, frame_count, time_info, status):
if self.playState == AUDIO_PLAY_STATE_PLAY or self.playState == AUDIO_PLAY_STATE_RESUME:
data = self.wavFile.readframes(frame_count)
if self.wavFile.getnframes() == self.wavFile.tell():
status = pyaudio.paComplete
self.playState = AUDIO_PLAY_STATE_END
self.m_button_play.SetLabel('Play Start')
else:
status = pyaudio.paContinue
return (data, status)
else:
# Note!!!:
data = numpy.zeros(frame_count*self.wavFile.getnchannels()).tostring()
return (data, pyaudio.paContinue) def playAudio( self, event ):
if os.path.isfile(self.wavPath):
if self.playState == AUDIO_PLAY_STATE_END:
self.playState = AUDIO_PLAY_STATE_START
self.wavStream.stop_stream()
self.wavStream.close()
self.wavPyaudio.terminate()
self.wavFile.close()
if self.playState == AUDIO_PLAY_STATE_START:
self.playState = AUDIO_PLAY_STATE_PLAY
self.m_button_play.SetLabel('Play Pause')
self.wavFile = wave.open(self.wavPath, "rb")
self.wavPyaudio = pyaudio.PyAudio()
self.wavStream = self.wavPyaudio.open(format=self.wavPyaudio.get_format_from_width(self.wavFile.getsampwidth()),
channels=self.wavFile.getnchannels(),
rate=self.wavFile.getframerate(),
output=True,
stream_callback=self.playAudioCallback)
self.wavStream.start_stream()
elif self.playState == AUDIO_PLAY_STATE_PLAY or self.playState == AUDIO_PLAY_STATE_RESUME:
self.playState = AUDIO_PLAY_STATE_PAUSE
self.m_button_play.SetLabel('Play Resume')
elif self.playState == AUDIO_PLAY_STATE_PAUSE:
self.playState = AUDIO_PLAY_STATE_RESUME
self.m_button_play.SetLabel('Play Pause')
else:
pass

3.2 录制实现

  相比播放功能,录制功能就简单了些,因为录制按钮状态就两种Start -> End,暂不支持中断后继续录制。这里的重点主要是音频三大参数(采样宽度,采样率,通道数)设置的支持:

import wave
import pyaudio class mainWin(win.speech_win): def recordAudioCallback(self, in_data, frame_count, time_info, status):
if not self.isRecording:
status = pyaudio.paComplete
else:
self.wavFrames.append(in_data)
status = pyaudio.paContinue
return (in_data, status) def recordAudio( self, event ):
if not self.isRecording:
self.isRecording = True
self.m_button_record.SetLabel('Record Stop')
# Get the wave parameter from user settings
fileName = self.m_textCtrl_recFileName.GetLineText(0)
if fileName == '':
fileName = 'rec_untitled1.wav'
self.wavPath = os.path.join(os.path.dirname(os.path.abspath(os.path.dirname(__file__))), 'conv', 'rec', fileName)
self.wavSampRate = int(self.m_choice_sampRate.GetString(self.m_choice_sampRate.GetSelection()))
channels = self.m_choice_channels.GetString(self.m_choice_channels.GetSelection())
if channels == 'Mono':
self.wavChannels = 1
else: #if channels == 'Stereo':
self.wavChannels = 2
bitDepth = int(self.m_choice_bitDepth.GetString(self.m_choice_bitDepth.GetSelection()))
if bitDepth == 8:
self.wavBitFormat = pyaudio.paInt8
elif bitDepth == 24:
self.wavBitFormat = pyaudio.paInt24
elif bitDepth == 32:
self.wavBitFormat = pyaudio.paFloat32
else:
self.wavBitFormat = pyaudio.paInt16
# Record audio according to wave parameters
self.wavFrames = []
self.wavPyaudio = pyaudio.PyAudio()
self.wavStream = self.wavPyaudio.open(format=self.wavBitFormat,
channels=self.wavChannels,
rate=self.wavSampRate,
input=True,
frames_per_buffer=AUDIO_CHUNK_SIZE,
stream_callback=self.recordAudioCallback)
self.wavStream.start_stream()
else:
self.isRecording = False
self.m_button_record.SetLabel('Record Start')
self.wavStream.stop_stream()
self.wavStream.close()
self.wavPyaudio.terminate()
# Save the wave data into file
wavFile = wave.open(self.wavPath, 'wb')
wavFile.setnchannels(self.wavChannels)
wavFile.setsampwidth(self.wavPyaudio.get_sample_size(self.wavBitFormat))
wavFile.setframerate(self.wavSampRate)
wavFile.writeframes(b''.join(self.wavFrames))
wavFile.close()

  至此,语音处理工具pzh-py-speech诞生之音频录播实现痞子衡便介绍完毕了,掌声在哪里~~~

参考文档

  1. Python解析Wav文件并绘制波形的方法

欢迎订阅

文章会同时发布到我的 博客园主页CSDN主页微信公众号 平台上。

微信搜索"痞子衡嵌入式"或者扫描下面二维码,就可以在手机上第一时间看了哦。

痞子衡嵌入式:语音处理工具pzh-speech诞生记(4)- 音频录播实现(PyAudio)的更多相关文章

  1. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(1)- 环境搭建(Python2.7.14 + pySerial3.4 + wxPython4.0.3)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之环境搭建. 在写Jays-PyCOM时需要先搭好开发和调试环境,下表列出了开发过程中会用到的所有软 ...

  2. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(2)- 界面构建(wxFormBuilder3.8.0)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之界面构建. 一个软件的UI界面是非常重要的,这是软件与用户交互的接口,软件功能即使再强大,但如果没 ...

  3. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(6)- 打包发布(PyInstaller3.3.1)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之打包发布. 经过上一篇软件优化之后,Jays-PyCOM已经初长成,该到了出去历练的时候了,只有经 ...

  4. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(3)- 串口功能实现(pySerial)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之串口功能实现. 串口调试助手是最核心的当然是串口数据收发与显示的功能,Jays-PyCOM借助的是 ...

  5. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(5)- 软件优化

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之软件优化. 前面痞子衡已经初步实现了Jays-PyCOM的串口功能,并且通过了最基本的测试,但目前 ...

  6. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记 - 索引

    大家好,我是痞子衡,是正经搞技术的痞子.本系列痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生. 串口调试助手是嵌入式开发里非常常用的小工具,市面上有非常多流行的串口调试工具,比如TeraTe ...

  7. 痞子衡嵌入式:串口调试工具Jays-PyCOM诞生记(4)- 联合调试(vspd, sscom, PyCharm2018.2)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是串口调试工具Jays-PyCOM诞生之联合调试. 软件开发离不开调试,调试手段分两种:一是黑盒调试,即直接从输入/输出角度测试软件功能是 ...

  8. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(1)- 环境搭建(Python2.7.14 + PyAudio0.2.11 + Matplotlib2.2.3 + SpeechRecognition3.8.1 + pyttsx3 2.7)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是语音处理工具Jays-PySPEECH诞生之环境搭建. 在写Jays-PySPEECH时需要先搭好开发环境,下表列出了开发过程中会用到的 ...

  9. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(5)- 语音识别实现(SpeechRecognition, PocketSphinx0.1.15)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是语音处理工具Jays-PySPEECH诞生之语音识别实现. 语音识别是Jays-PySPEECH的核心功能,Jays-PySPEECH借 ...

  10. 痞子衡嵌入式:语音处理工具Jays-PySPEECH诞生记(6)- 文语合成实现(pyttsx3, eSpeak1.48.04)

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是语音处理工具Jays-PySPEECH诞生之文语合成实现. 文语合成是Jays-PySPEECH的核心功能,Jays-PySPEECH借 ...

随机推荐

  1. Linux 内核usb_bulk_msg 接口

    usb_bulk_msg 创建一个 USB 块 urb 并且发送它到特定的设备, 接着在返回到调用者之 前等待完成. 它定义为: int usb_bulk_msg(struct usb_device ...

  2. android权限申请执行过程

    弹出的授权对口窗口实际上是一个activity(隐式intent启动上图第二个方块里)(com.android.packageinstaller.permission.ui.Grantpermissi ...

  3. Team Foundation Server 2015使用教程【6】:新增权限为读取器的团队

  4. 【温故知新】Java web 开发(三)Form表单与上传下载文件

    简介:在一和二的基础之上,这次来记录下如何在页面提交表单数据,以及文件的上传和下载整个流程,请求也不仅限于GET了,也有POST了. 1. 为了方便,在 webapp 下直接新建一个 index.ht ...

  5. 精选腾讯技术干货200+篇,云加社区全年沙龙PPT免费下载!

    2019年已经过去,小编为大家整理了这一年以来云加社区发布的 200多篇腾讯干货,点击文章标题即可跳转到原文,请速速收藏哦~ 看腾讯技术: 腾讯成本优化黑科技:整机CPU利用率最高提升至90%: 腾讯 ...

  6. $Noip2013/Luogu1966$ 火柴排队 贪心+离散化+逆序对

    $Luogu$ $Description$ 给定等长的$a,b$两个序列.每次可以交换一个序列中相邻两个数.求最小的交换次数使得$\sum(a_i-b_i)^2$最小. $Sol$ 交换后的序列一定满 ...

  7. 什么是Ceph存储?什么是分布式存储?简单明了带你学Ceph--<1>

    Ceph存储介绍 为什么要用Ceph Ceph是当前非常流行的开源分布式存储系统,具有高扩展性.高性能.高可靠性等优点,同时提供块存储服务(rbd).对象存储服务(rgw)以及文件系统存储服务(cep ...

  8. 浅谈Java的默认和静态方法

    目录 浅谈Java的默认和静态方法 Java新增默认方法有啥用 Java新增的静态方法有啥用 浅谈Java的默认和静态方法 允许在接口中声明默认方法和静态方法,是JDK1.8新增的特性.存在即合理,两 ...

  9. 2017 ACM-ICPC亚洲区域赛北京站J题 Pangu and Stones 题解 区间DP

    题目链接:http://www.hihocoder.com/problemset/problem/1636 题目描述 在中国古代神话中,盘古是时间第一个人并且开天辟地,它从混沌中醒来并把混沌分为天地. ...

  10. 2019年终总结&小半年流媒体服务器开发经验总结

    目录 2019年终总结&小半年流媒体服务器开发经验总结 19年开发小结 流媒体服务框架设计 登录服开发 ffmpeg音视频服务开发 音视频控制 流媒体服务开发小结 rtp处理 视频的合成&am ...