|
|
<!--
|
|
|
CO_OP_TRANSLATOR_METADATA:
|
|
|
{
|
|
|
"original_hash": "0ac0afcfb40cb5970ef4cb74f01c32e9",
|
|
|
"translation_date": "2025-08-26T15:33:13+00:00",
|
|
|
"source_file": "6-consumer/lessons/1-speech-recognition/pi-audio.md",
|
|
|
"language_code": "hk"
|
|
|
}
|
|
|
-->
|
|
|
# 捕捉音訊 - Raspberry Pi
|
|
|
|
|
|
在這部分課程中,你將撰寫程式碼以在 Raspberry Pi 上捕捉音訊。音訊捕捉將由按鈕控制。
|
|
|
|
|
|
## 硬件
|
|
|
|
|
|
Raspberry Pi 需要一個按鈕來控制音訊捕捉。
|
|
|
|
|
|
你將使用的是 Grove 按鈕。這是一種數字感測器,可以開啟或關閉信號。這些按鈕可以配置為在按下時發送高信號,未按下時發送低信號,或者按下時發送低信號,未按下時發送高信號。
|
|
|
|
|
|
如果你使用的是 ReSpeaker 2-Mics Pi HAT 作為麥克風,那麼不需要額外連接按鈕,因為這個 HAT 已經配備了一個按鈕。直接跳到下一部分。
|
|
|
|
|
|
### 連接按鈕
|
|
|
|
|
|
按鈕可以連接到 Grove 基座 HAT。
|
|
|
|
|
|
#### 任務 - 連接按鈕
|
|
|
|
|
|

|
|
|
|
|
|
1. 將 Grove 電纜的一端插入按鈕模組上的插座。它只能以一種方式插入。
|
|
|
|
|
|
1. 在 Raspberry Pi 關機的情況下,將 Grove 電纜的另一端連接到 Grove 基座 HAT 上標記為 **D5** 的數字插座。這個插座位於 GPIO 引腳旁邊的一排插座中,從左數第二個。
|
|
|
|
|
|

|
|
|
|
|
|
## 捕捉音訊
|
|
|
|
|
|
你可以使用 Python 程式碼從麥克風捕捉音訊。
|
|
|
|
|
|
### 任務 - 捕捉音訊
|
|
|
|
|
|
1. 啟動 Raspberry Pi,並等待其完成啟動。
|
|
|
|
|
|
1. 啟動 VS Code,可以直接在 Raspberry Pi 上操作,或者通過 Remote SSH 擴展連接。
|
|
|
|
|
|
1. PyAudio Pip 套件提供了錄製和播放音訊的功能。此套件依賴於一些音訊庫,需先安裝這些庫。在終端中執行以下命令進行安裝:
|
|
|
|
|
|
```sh
|
|
|
sudo apt update
|
|
|
sudo apt install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev libasound2-plugins --yes
|
|
|
```
|
|
|
|
|
|
1. 安裝 PyAudio Pip 套件。
|
|
|
|
|
|
```sh
|
|
|
pip3 install pyaudio
|
|
|
```
|
|
|
|
|
|
1. 建立一個名為 `smart-timer` 的新資料夾,並在此資料夾中新增一個名為 `app.py` 的檔案。
|
|
|
|
|
|
1. 在檔案的頂部新增以下導入:
|
|
|
|
|
|
```python
|
|
|
import io
|
|
|
import pyaudio
|
|
|
import time
|
|
|
import wave
|
|
|
|
|
|
from grove.factory import Factory
|
|
|
```
|
|
|
|
|
|
這會導入 `pyaudio` 模組、一些處理 WAV 檔案的標準 Python 模組,以及 `grove.factory` 模組以導入 `Factory` 來建立按鈕類別。
|
|
|
|
|
|
1. 在此之下,新增程式碼以建立 Grove 按鈕。
|
|
|
|
|
|
如果你使用的是 ReSpeaker 2-Mics Pi HAT,請使用以下程式碼:
|
|
|
|
|
|
```python
|
|
|
# The button on the ReSpeaker 2-Mics Pi HAT
|
|
|
button = Factory.getButton("GPIO-LOW", 17)
|
|
|
```
|
|
|
|
|
|
這會在 **D17** 埠上建立一個按鈕,該埠連接到 ReSpeaker 2-Mics Pi HAT 上的按鈕。此按鈕設定為在按下時發送低信號。
|
|
|
|
|
|
如果你未使用 ReSpeaker 2-Mics Pi HAT,而是使用連接到基座 HAT 的 Grove 按鈕,請使用以下程式碼:
|
|
|
|
|
|
```python
|
|
|
button = Factory.getButton("GPIO-HIGH", 5)
|
|
|
```
|
|
|
|
|
|
這會在 **D5** 埠上建立一個按鈕,該按鈕設定為在按下時發送高信號。
|
|
|
|
|
|
1. 在此之下,建立一個 PyAudio 類別的實例以處理音訊:
|
|
|
|
|
|
```python
|
|
|
audio = pyaudio.PyAudio()
|
|
|
```
|
|
|
|
|
|
1. 宣告麥克風和揚聲器的硬件卡號。這將是你在本課程中早些時候執行 `arecord -l` 和 `aplay -l` 時找到的卡號。
|
|
|
|
|
|
```python
|
|
|
microphone_card_number = <microphone card number>
|
|
|
speaker_card_number = <speaker card number>
|
|
|
```
|
|
|
|
|
|
將 `<microphone card number>` 替換為你的麥克風卡號。
|
|
|
|
|
|
將 `<speaker card number>` 替換為你的揚聲器卡號,與你在 `alsa.conf` 檔案中設定的卡號相同。
|
|
|
|
|
|
1. 在此之下,宣告用於音訊捕捉和播放的採樣率。根據你使用的硬件可能需要更改此值。
|
|
|
|
|
|
```python
|
|
|
rate = 48000 #48KHz
|
|
|
```
|
|
|
|
|
|
如果稍後執行此程式碼時出現採樣率錯誤,將此值更改為 `44100` 或 `16000`。值越高,音質越好。
|
|
|
|
|
|
1. 在此之下,建立一個名為 `capture_audio` 的新函數。此函數將用於從麥克風捕捉音訊:
|
|
|
|
|
|
```python
|
|
|
def capture_audio():
|
|
|
```
|
|
|
|
|
|
1. 在此函數內,新增以下程式碼以捕捉音訊:
|
|
|
|
|
|
```python
|
|
|
stream = audio.open(format = pyaudio.paInt16,
|
|
|
rate = rate,
|
|
|
channels = 1,
|
|
|
input_device_index = microphone_card_number,
|
|
|
input = True,
|
|
|
frames_per_buffer = 4096)
|
|
|
|
|
|
frames = []
|
|
|
|
|
|
while button.is_pressed():
|
|
|
frames.append(stream.read(4096))
|
|
|
|
|
|
stream.stop_stream()
|
|
|
stream.close()
|
|
|
```
|
|
|
|
|
|
此程式碼使用 PyAudio 物件開啟音訊輸入流。該流將以 16KHz 的速率從麥克風捕捉音訊,每次捕捉 4096 字節大小的緩衝區。
|
|
|
|
|
|
程式碼會在 Grove 按鈕被按下時進行迴圈,每次將這些 4096 字節的緩衝區讀入一個陣列。
|
|
|
|
|
|
> 💁 你可以在 [PyAudio 文件](https://people.csail.mit.edu/hubert/pyaudio/docs/) 中了解更多關於傳遞給 `open` 方法的選項。
|
|
|
|
|
|
一旦按鈕被釋放,流將停止並關閉。
|
|
|
|
|
|
1. 在此函數的末尾新增以下程式碼:
|
|
|
|
|
|
```python
|
|
|
wav_buffer = io.BytesIO()
|
|
|
with wave.open(wav_buffer, 'wb') as wavefile:
|
|
|
wavefile.setnchannels(1)
|
|
|
wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16))
|
|
|
wavefile.setframerate(rate)
|
|
|
wavefile.writeframes(b''.join(frames))
|
|
|
wav_buffer.seek(0)
|
|
|
|
|
|
return wav_buffer
|
|
|
```
|
|
|
|
|
|
此程式碼建立一個二進制緩衝區,並將所有捕捉的音訊以 [WAV 檔案](https://wikipedia.org/wiki/WAV) 的形式寫入其中。這是一種將未壓縮音訊寫入檔案的標準方式。然後返回此緩衝區。
|
|
|
|
|
|
1. 新增以下 `play_audio` 函數以播放音訊緩衝區:
|
|
|
|
|
|
```python
|
|
|
def play_audio(buffer):
|
|
|
stream = audio.open(format = pyaudio.paInt16,
|
|
|
rate = rate,
|
|
|
channels = 1,
|
|
|
output_device_index = speaker_card_number,
|
|
|
output = True)
|
|
|
|
|
|
with wave.open(buffer, 'rb') as wf:
|
|
|
data = wf.readframes(4096)
|
|
|
|
|
|
while len(data) > 0:
|
|
|
stream.write(data)
|
|
|
data = wf.readframes(4096)
|
|
|
|
|
|
stream.close()
|
|
|
```
|
|
|
|
|
|
此函數開啟另一個音訊流,這次是輸出流,用於播放音訊。它使用與輸入流相同的設定。緩衝區被打開為 WAV 檔案,並以 4096 字節的塊寫入輸出流,播放音訊。然後關閉流。
|
|
|
|
|
|
1. 在 `capture_audio` 函數下方新增以下程式碼以迴圈直到按鈕被按下。一旦按鈕被按下,音訊將被捕捉並播放。
|
|
|
|
|
|
```python
|
|
|
while True:
|
|
|
while not button.is_pressed():
|
|
|
time.sleep(.1)
|
|
|
|
|
|
buffer = capture_audio()
|
|
|
play_audio(buffer)
|
|
|
```
|
|
|
|
|
|
1. 執行程式碼。按下按鈕並對著麥克風說話。完成後釋放按鈕,你將聽到錄音。
|
|
|
|
|
|
在建立 PyAudio 實例時,你可能會遇到一些 ALSA 錯誤。這是由於 Raspberry Pi 上的音訊設備配置問題,你可以忽略這些錯誤。
|
|
|
|
|
|
```output
|
|
|
pi@raspberrypi:~/smart-timer $ python3 app.py
|
|
|
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front
|
|
|
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
|
|
|
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
|
|
|
ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
|
|
|
```
|
|
|
|
|
|
如果你遇到以下錯誤:
|
|
|
|
|
|
```output
|
|
|
OSError: [Errno -9997] Invalid sample rate
|
|
|
```
|
|
|
|
|
|
那麼請將 `rate` 更改為 `44100` 或 `16000`。
|
|
|
|
|
|
> 💁 你可以在 [code-record/pi](../../../../../6-consumer/lessons/1-speech-recognition/code-record/pi) 資料夾中找到此程式碼。
|
|
|
|
|
|
😀 你的音訊錄製程式成功了!
|
|
|
|
|
|
---
|
|
|
|
|
|
**免責聲明**:
|
|
|
此文件已使用人工智能翻譯服務 [Co-op Translator](https://github.com/Azure/co-op-translator) 翻譯。我們致力於提供準確的翻譯,但請注意,自動翻譯可能包含錯誤或不準確之處。應以原始語言的文件作為權威來源。對於關鍵資訊,建議尋求專業人工翻譯。我們對因使用此翻譯而引起的任何誤解或錯誤解讀概不負責。 |