自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

手把手教你使用Python第三方庫PyAudio打造一款錄音工具

開發(fā) 后端
音頻錄制與視頻錄制相似,也是以數(shù)據(jù)幀的方式錄制保存,這次使用強大的第三方包PyAudio和內(nèi)置的wave模塊編寫主要部分代碼:pip install PyAudio

大家好,我是【🌑(這是月亮的背面)】。今天給大家分享Python使用PyAudio制作錄音工具:

最近有在使用屏幕錄制軟件錄制桌面,在用的過程中突發(fā)奇想,使用python能不能做屏幕錄制工具,也鍛煉下自己的動手能力。接下準備寫使用python如何做屏幕錄制工具的系列文章:

  • 錄制屏幕制作視頻
  • 錄制音頻
  • 合成視頻,音頻
  • 基于Pyqt5制作可視化窗口

大概上述四個部分,希望自己能夠盡快完善,上一篇文章利用opencv制作了屏幕錄制部分,接下繼續(xù)更新系列,使用python錄制音頻。

應用平臺

  • windows 10
  • python 3.7

音頻錄制部分

音頻錄制與視頻錄制相似,也是以數(shù)據(jù)幀的方式錄制保存,這次使用強大的第三方包PyAudio和內(nèi)置的wave模塊編寫主要部分代碼:pip install PyAudio

如果出現(xiàn)安裝失敗,可點擊去此處下載對應.whl文件,cp37代表python3.7環(huán)境,64代表64位操作系統(tǒng)。假如不是下載對應的whl包會導致安裝失敗,下載完成后,cmd窗口下進入whl的所在目錄,使用pip install PyAudio-xx.whl即可完成安裝。

音頻錄制主要代碼:

  1. from pyaudio import PyAudio, paInt16, paContinue, paComplete 
  2.  
  3. # 設置固定參數(shù) 
  4. chunk = 1024  # 每個緩沖區(qū)的幀數(shù) 
  5. format_sample = paInt16  # 采樣位數(shù) 
  6. channels = 2  # 聲道:1,單聲道;2,雙聲道 
  7. fps = 44100  # 采樣頻率 
  8.  
  9. # 這里采用回調(diào)的方式錄制音頻 
  10. def callback(in_data, frame_count, time_info, status): 
  11.     """錄制回調(diào)函數(shù)""" 
  12.     wf.writeframes(in_data) 
  13.     if xx:  # 當某某條件滿足時 
  14.         return in_data, paContinue 
  15.     else
  16.         return in_data, paComplete 
  17.  
  18. # 實例化PyAudio 
  19. p = PyAudio() 
  20. stream = p.open(format=format_sample, 
  21.     channels=channels, 
  22.     rate=fps, 
  23.                 frames_per_buffer=chunk, 
  24.                 input=True
  25.                 input_device_index=None,  # 輸入設備索引, None為默認設備 
  26.                 stream_callback=callback   # 回調(diào)函數(shù) 
  27.                 ) 
  28. # 開始流錄制 
  29. stream.start_stream() 
  30. # 判斷流是否活躍 
  31. while stream.is_active(): 
  32.  time.sleep(0.1)    # 0.1為靈敏度 
  33. # 錄制完成,關閉流及實例 
  34. stream.stop_stream() 
  35. stream.close() 
  36. p.terminate() 

采取流式并用回調(diào)函數(shù)錄制,需要先定義保存音頻文件,用wave新建音頻二進制文件:

  1. import wave 
  2. wf = wave.open('test.wav''wb'
  3. wf.setnchannels(channels) 
  4. wf.setsampwidth(p.get_sample_size(format_sample)) 
  5. wf.setframerate(fps) 

為了后續(xù)代碼可以很好的與之結合復用,將上面的代碼包裝成類

  1. from pyaudio import PyAudio 
  2.  
  3. class AudioRecord(PyAudio): 
  4.  
  5.     def __init__(self,): 

源碼于文末補充。

音頻播放部分

播放部分代碼與錄制部分代碼相差不大,核心部分:

  1. wf = wave.open('test.wav''rb'
  2. def callback(in_data, frame_count, time_info, status): 
  3.  data = wf.readframes(frame_count) 
  4.  return data, paContinue 
  5.  
  6. stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), 
  7.     channels=wf.getnchannels(), 
  8.                 rate=wf.getframerate(), 
  9.     output=True
  10.     output_device_index=output_device_index,  # 輸入設備索引 
  11.     stream_callback=callback  # 輸出用回調(diào)函數(shù) 
  12.                 ) 
  13. stream.start_stream() 
  14. while stream.is_active(): 
  15.  time.sleep(0.1) 

目前暫時測試了.wav和.mp3格式可以正常錄制及播放,其它類型格式音頻可以自行調(diào)用代碼進行測試。

GUI窗口所需屬性值代碼部分

考慮到GUI窗口能較為人性化的輸出及輸入值,編寫該部分代碼,內(nèi)容含音頻時長及獲取輸入設備及輸出設備。

  1. # 音頻時長 
  2. duration = wf.getnframes() / wf.getframerate() 
  1. # 獲取系統(tǒng)目前已安裝的輸入輸出設備 
  2. dev_info = self.get_device_info_by_index(i) 
  3. default_rate = int(dev_info['defaultSampleRate']) 
  4. if not dev_info['hostApi'and default_rate == fps and '映射器' not in dev_info['name']: 
  5.  if dev_info['maxInputChannels']: 
  6.   print('輸入設備:', dev_info['name']) 
  7.  elif dev_info['maxOutputChannels']: 
  8.   print('輸出設備:', dev_info['name']) 

pynput監(jiān)聽鍵盤

在這部分代碼也暫時使用pynput監(jiān)聽鍵盤來對錄音做中斷處理。可以調(diào)用上一篇文章中的鍵盤監(jiān)聽代碼。

  1. def hotkey(self): 
  2.     """熱鍵監(jiān)聽""" 
  3.     with keyboard.Listener(on_press=self.on_press) as listener: 
  4.         listener.join() 
  5.  
  6. def on_press(self, key): 
  7.     try: 
  8.         if key.char == 't':  # t鍵,錄制結束,保存音頻 
  9.             self.flag = True 
  10.         elif key.char == 'k':  # k鍵,錄制中止,刪除文件 
  11.             self.flag = True 
  12.             self.kill = True 
  13.     except Exception as e: 
  14.         print(e) 

功能與上一篇類似,不再贅述。

總結

大家好,我是【🌑(這是月亮的背面)】。以上就是使用PyAudio調(diào)用windows的音頻設備進行錄制及播放的內(nèi)容了,這篇文章帶大家整體學習了使用類及其繼承相關知識,用法在這只是展示了冰山一角,還有更多的知識等待著我們一起去探索!

源碼:

  1. import wave 
  2. import time 
  3. from pathlib import Path 
  4. from threading import Thread 
  5. from pyaudio import PyAudio, paInt16, paContinue, paComplete 
  6. from pynput import keyboard  # pip install pynput 
  7.  
  8.  
  9. class AudioRecord(PyAudio): 
  10.  
  11.     def __init__(self, channels=2): 
  12.         super().__init__() 
  13.         self.chunk = 1024  # 每個緩沖區(qū)的幀數(shù) 
  14.         self.format_sample = paInt16  # 采樣位數(shù) 
  15.         self.channels = channels  # 聲道:1,單聲道;2,雙聲道 
  16.         self.fps = 44100  # 采樣頻率 
  17.         self.input_dict = None 
  18.         self.output_dict = None 
  19.         self.stream = None 
  20.         self.filename = '~test.wav' 
  21.         self.duration = 0   # 音頻時長 
  22.         self.flag = False 
  23.         self.kill = False 
  24.  
  25.     def __call__(self, filename): 
  26.         """重載文件名""" 
  27.         self.filename = filename 
  28.  
  29.     def callback_input(self, in_data, frame_count, time_info, status): 
  30.         """錄制回調(diào)函數(shù)""" 
  31.         self.wf.writeframes(in_data) 
  32.         if not self.flag: 
  33.             return in_data, paContinue 
  34.         else
  35.             return in_data, paComplete 
  36.  
  37.     def callback_output(self, in_data, frame_count, time_info, status): 
  38.         """播放回調(diào)函數(shù)""" 
  39.         data = self.wf.readframes(frame_count) 
  40.         return data, paContinue 
  41.  
  42.     def open_stream(self, name): 
  43.         """打開錄制流""" 
  44.         input_device_index = self.get_device_index(nameTrue) if name else None 
  45.         return self.open(format=self.format_sample, 
  46.                          channels=self.channels, 
  47.                          rate=self.fps, 
  48.                          frames_per_buffer=self.chunk, 
  49.                          input=True
  50.                          input_device_index=input_device_index,  # 輸入設備索引 
  51.                          stream_callback=self.callback_input 
  52.                          ) 
  53.  
  54.     def audio_record_run(self, name=None): 
  55.         """音頻錄制""" 
  56.         self.wf = self.save_audio_file(self.filename) 
  57.         self.stream = self.open_stream(name
  58.         self.stream.start_stream() 
  59.         while self.stream.is_active(): 
  60.             time.sleep(0.1) 
  61.         self.wf.close() 
  62.         if self.kill: 
  63.             Path(self.filename).unlink() 
  64.         self.duration = self.get_duration(self.wf) 
  65.         print(self.duration) 
  66.         self.terminate_run() 
  67.  
  68.     def run(self, filename=None, name=None, record=True): 
  69.         """音頻錄制線程""" 
  70.         thread_1 = Thread(target=self.hotkey, daemon=True
  71.         if record: 
  72.             # 錄制 
  73.             if filename: 
  74.                 self.filename = filename 
  75.             thread_2 = Thread(target=self.audio_record_run, args=(name,)) 
  76.         else
  77.             # 播放 
  78.             if not filename: 
  79.                 raise Exception('未輸入音頻文件名,不能播放,請輸入后再試!'
  80.             thread_2 = Thread(target=self.read_audio, args=(filename, name,)) 
  81.         thread_1.start() 
  82.         thread_2.start() 
  83.  
  84.     def read_audio(self, filename, name=None): 
  85.         """音頻播放""" 
  86.         output_device_index = self.get_device_index(nameFalse) if name else None 
  87.         with wave.open(filename, 'rb'as self.wf: 
  88.             self.duration = self.get_duration(self.wf) 
  89.             self.stream = self.open(format=self.get_format_from_width(self.wf.getsampwidth()), 
  90.                                     channels=self.wf.getnchannels(), 
  91.                                     rate=self.wf.getframerate(), 
  92.                                     output=True
  93.                                     output_device_index=output_device_index,  # 輸出設備索引 
  94.                                     stream_callback=self.callback_output 
  95.                                     ) 
  96.             self.stream.start_stream() 
  97.             while self.stream.is_active(): 
  98.                 time.sleep(0.1) 
  99.         print(self.duration) 
  100.         self.terminate_run() 
  101.  
  102.     @staticmethod 
  103.     def get_duration(wf): 
  104.         """獲取音頻時長""" 
  105.         return round(wf.getnframes() / wf.getframerate(), 2) 
  106.  
  107.     def get_in_out_devices(self): 
  108.         """獲取系統(tǒng)輸入輸出設備""" 
  109.         self.input_dict = {} 
  110.         self.output_dict = {} 
  111.         for i in range(self.get_device_count()): 
  112.             dev_info = self.get_device_info_by_index(i) 
  113.             default_rate = int(dev_info['defaultSampleRate']) 
  114.             if not dev_info['hostApi'and default_rate == self.fps and '映射器' not in dev_info['name']: 
  115.                 if dev_info['maxInputChannels']: 
  116.                     self.input_dict[dev_info['name']] = i 
  117.                 elif dev_info['maxOutputChannels']: 
  118.                     self.output_dict[dev_info['name']] = i 
  119.  
  120.     def get_device_index(self, name, input_in=True): 
  121.         """獲取選定設備索引""" 
  122.         if input_in and self.input_dict: 
  123.             return self.input_dict.get(name, -1) 
  124.         elif not input_in and self.output_dict: 
  125.             return self.output_dict.get(name, -1) 
  126.  
  127.     def save_audio_file(self, filename): 
  128.         """音頻文件保存""" 
  129.         wf = wave.open(filename, 'wb'
  130.         wf.setnchannels(self.channels) 
  131.         wf.setsampwidth(self.get_sample_size(self.format_sample)) 
  132.         wf.setframerate(self.fps) 
  133.         return wf 
  134.  
  135.     def terminate_run(self): 
  136.         """結束流錄制或流播放""" 
  137.         if self.stream: 
  138.             self.stream.stop_stream() 
  139.             self.stream.close() 
  140.         self.terminate() 
  141.  
  142.     def hotkey(self): 
  143.         """熱鍵監(jiān)聽""" 
  144.         with keyboard.Listener(on_press=self.on_press) as listener: 
  145.             listener.join() 
  146.  
  147.     def on_press(self, key): 
  148.         try: 
  149.             if key.char == 't':  # t鍵,錄制結束,保存音頻 
  150.                 self.flag = True 
  151.             elif key.char == 'k':  # k鍵,錄制中止,刪除文件 
  152.                 self.flag = True 
  153.                 self.kill = True 
  154.         except Exception as e: 
  155.             print(e) 
  156.  
  157.  
  158. if __name__ == '__main__'
  159.     audio_record = AudioRecord() 
  160.     audio_record.get_in_out_devices() 
  161.     # 錄制 
  162.     print(audio_record.input_dict) 
  163.     audio_record.run('test.mp3'
  164.     # 播放 
  165.     print(audio_record.output_dict) 
  166.     audio_record.run('test.mp3', record=False

 小伙伴們,快快用實踐一下吧!

 

責任編輯:姜華 來源: Python爬蟲與數(shù)據(jù)挖掘
相關推薦

2021-12-30 08:56:57

Python摸魚倒計界面Python基礎

2022-02-17 10:26:17

JavaScript掃雷游戲前端

2021-11-01 10:26:07

CanvasAPI畫布技術HTML5

2022-01-24 11:02:27

PySimpleGUPython計算器

2023-05-22 10:04:24

2021-02-01 08:41:06

Java考試系統(tǒng)

2017-09-14 09:09:04

php應用LibreOfficeWord轉HTML

2021-02-04 15:52:46

Java考試系統(tǒng)

2021-01-04 09:55:26

Java移動互聯(lián)網(wǎng)

2021-01-05 09:04:20

Javatxt文件

2021-06-10 07:49:28

Python詞云圖wordcloud

2021-07-14 09:00:00

JavaFX開發(fā)應用

2010-05-25 11:09:31

SVN工具

2014-07-22 10:56:45

Android Stu第三方類庫

2021-06-24 10:52:35

JDBC數(shù)據(jù)庫圖書管理系統(tǒng)

2018-09-09 15:38:55

SD-WAN網(wǎng)絡WAN

2021-01-10 08:14:01

Go語言TCP掃描器

2021-01-13 09:03:48

Java游戲函數(shù)

2016-11-01 09:46:04

2021-01-12 05:05:15

Java對碰游戲
點贊
收藏

51CTO技術棧公眾號