python錄制系統聲音


轉載:python開發的錄音機(一)錄制聲卡播放的聲音(內錄)

環境准備

python

  • wave
  • pyaudio

wave 可以通過pip直接install,在安裝pyaudio時,通過正常的pip install 直接安裝一直處於報錯階段,后來想到可以通過輪子直接安裝。

pypi提供的安裝包中有對應的安裝包,注意,不僅僅是python2python3的區別,python3的小版本也有點差別。可杯具的是,小主電腦里裝的是python3.8,后來想到還有一個網站可以安裝pythonlibs,找到對應的版本后,下載下來。直接在文件所在目錄,或者在安裝中指定文件目錄中執行安裝

pip install /c/Users/root/Downloads/PyAudio-0.2.11-cp38-cp38-win_amd64.whl

代碼和運行

def audio_record(out_file, rec_time):
    CHUNK = 1024
    FORMAT = pyaudio.paInt16  # 16bit編碼格式
    CHANNELS = 1  # 單聲道
    RATE = 16000  # 16000采樣頻率
    p = pyaudio.PyAudio()
    # 創建音頻流
    dev_idx = findInternalRecordingDevice(p)
    stream = p.open(format=FORMAT,  # 音頻流wav格式
                    channels=CHANNELS,  # 單聲道
                    rate=RATE,  # 采樣率16000
                    input=True,
                    input_device_index=dev_idx, # 指定內錄設備的id,可以不寫,使用win的默認錄音設備
                    frames_per_buffer=CHUNK)
    print("Start Recording...")
    frames = []  # 錄制的音頻流
    # 錄制音頻數據
    for i in range(0, int(RATE / CHUNK * rec_time)): # 控制錄音時間
        data = stream.read(CHUNK)
        frames.append(data)
    # 錄制完成
    stream.stop_stream()
    stream.close()
    p.terminate()
    print("Recording Done...")
    # 保存音頻文件
    wf = wave.open(out_file, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

在使用默認錄音設備時,發現是話筒錄音,效果並不是太理想,所以就去查查能不能直接錄系統的聲音。

def findInternalRecordingDevice(p):
    # 要找查的設備名稱中的關鍵字
    target = '立體聲混音'
    # 逐一查找聲音設備
    for i in range(p.get_device_count()):
        devInfo = p.get_device_info_by_index(i)
        print(devInfo)
        if devInfo['name'].find(target) >= 0 and devInfo['hostApi'] == 0:
            # print('已找到內錄設備,序號是 ',i)
            return i
    print('無法找到內錄設備!')
    return -1

可以使用p.get_device_info_by_index()去查看系統有關聲音的設備,通過設置為立體聲混音就可以錄制系統聲音。

保存聲音

def save(fileName):
    # 創建pyAudio對象
    p = pyaudio.PyAudio()
    # 打開用於保存數據的文件
    wf = wave.open(fileName, 'wb')
    # 設置音頻參數
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    # 寫入數據
    wf.writeframes(b''.join(_frames))
    # 關閉文件
    wf.close()
    # 結束pyaudio
    p.terminate()

保存聲音是通過上述代碼進行保存,此處的_frames是個list,是通過每錄一個chunk(數據流塊),就把這一塊的數據添加進去

然后只需要重新創建PyAudio對象,把這個list轉為字節串保存到文件中就可以了

問題

上述一般可以錄到系統聲音,但在執行的時候發現,並不能。

原因是:win的輸入設備中沒有配置立體聲混音

設置步驟:

  • 在win的聲音調節出,右擊打開聲音設置
  • 找到管理聲音設備
  • 在輸入設備處啟用立體聲混音

就此,就完成了錄制系統聲音的需求

注意

上述操作,可以外放,可以插入3.5mm耳機,但系統靜音tpye-c耳機插入的時候不能錄到聲音

完整代碼

import os
import pyaudio
import threading
import wave
import time
from datetime import datetime

# 需要系統打開立體聲混音

# 錄音類
class Recorder():
    def __init__(self, chunk=1024, channels=2, rate=44100):
        self.CHUNK = chunk
        self.FORMAT = pyaudio.paInt16
        self.CHANNELS = channels
        self.RATE = rate
        self._running = True
        self._frames = []

    # 獲取內錄設備序號,在windows操作系統上測試通過,hostAPI = 0 表明是MME設備
    def findInternalRecordingDevice(self, p):
        # 要找查的設備名稱中的關鍵字
        target = '立體聲混音'
        # 逐一查找聲音設備
        for i in range(p.get_device_count()):
            devInfo = p.get_device_info_by_index(i)
            # print(devInfo)
            if devInfo['name'].find(target) >= 0 and devInfo['hostApi'] == 0:
                # print('已找到內錄設備,序號是 ',i)
                return i
        print('無法找到內錄設備!')
        return -1

    # 開始錄音,開啟一個新線程進行錄音操作
    def start(self):
        threading._start_new_thread(self.__record, ())

    # 執行錄音的線程函數
    def __record(self):
        self._running = True
        self._frames = []

        p = pyaudio.PyAudio()
        # 查找內錄設備
        dev_idx = self.findInternalRecordingDevice(p)
        if dev_idx < 0:
            return
        # 在打開輸入流時指定輸入設備
        stream = p.open(input_device_index=dev_idx,
                        format=self.FORMAT,
                        channels=self.CHANNELS,
                        rate=self.RATE,
                        input=True,
                        frames_per_buffer=self.CHUNK)
        # 循環讀取輸入流
        while (self._running):
            data = stream.read(self.CHUNK)
            self._frames.append(data)

        # 停止讀取輸入流
        stream.stop_stream()
        # 關閉輸入流
        stream.close()
        # 結束pyaudio
        p.terminate()
        return

    # 停止錄音
    def stop(self):
        self._running = False

    # 保存到文件
    def save(self, fileName):
        # 創建pyAudio對象
        p = pyaudio.PyAudio()
        # 打開用於保存數據的文件
        wf = wave.open(fileName, 'wb')
        # 設置音頻參數
        wf.setnchannels(self.CHANNELS)
        wf.setsampwidth(p.get_sample_size(self.FORMAT))
        wf.setframerate(self.RATE)
        # 寫入數據
        wf.writeframes(b''.join(self._frames))
        # 關閉文件
        wf.close()
        # 結束pyaudio
        p.terminate()


if __name__ == "__main__":

    # 檢測當前目錄下是否有record子目錄
    if not os.path.exists('record'):
        os.makedirs('record')

    print("\npython 錄音機 ....\n")
    print("提示:按 r 鍵並回車 開始錄音\n")

    i = input('請輸入操作碼:')
    if i == 'r':
        rec = Recorder()
        begin = time.time()

        print("\n開始錄音,按 s 鍵並回車 停止錄音,自動保存到 record 子目錄\n")
        rec.start()

        running = True
        while running:
            i = input("請輸入操作碼:")
            if i == 's':
                running = False
                print("錄音已停止")
                rec.stop()
                t = time.time() - begin
                print('錄音時間為%ds' % t)
                # 以當前時間為關鍵字保存wav文件
                rec.save("record/rec_" + datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + ".wav")


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM