完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
今天给大家介绍的是语音处理工具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诞生之音频录播实现便介绍完毕了,掌声在哪里~~~ |
|
|
|
只有小组成员才能发言,加入小组>>
793 浏览 0 评论
1152 浏览 1 评论
2528 浏览 5 评论
2861 浏览 9 评论
移植了freeRTOS到STMf103之后显示没有定义的原因?
2711 浏览 6 评论
keil5中manage run-time environment怎么是灰色,不可以操作吗?
1071浏览 3评论
194浏览 2评论
456浏览 2评论
369浏览 2评论
M0518 PWM的电压输出只有2V左右,没有3.3V是怎么回事?
454浏览 1评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 20:12 , Processed in 1.140750 second(s), Total 79, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号