EnsekiTT Blog

EnsekiTTが書くブログです。

RaspberryPiにHD Pro Webcam C920を繋いでオーディオを取得した話

こんにちは、えんせきです。
Alexaと暮らしていますが、音声で指示できるの良いですよね。なんだかんだで対応家電を増やしたくなっています。

つまりなにしたの?

ロジクールのウェブカメラ(HD Pro Webcam C920)には通話用のマイクがついているので
そのマイクのオーディオを取得してPyAudioで処理した。
今日はカメラの話はしない。

f:id:ensekitt:20180325202830j:plain

RasPiのカメラどうしたの?

昨日取り付けたディスプレイ、若干カメラつけにくくなるんですよね。
ってことで余ってたロジクールのウェブカメラをつけました。

大まかな手順

  • 依存関係のインストール
  • オーディオデバイスを確認
  • オーディオを取得して標準出力にレベルメータ的な物を表示する

依存関係のインストール

インストール直後のRaspbianを想定している。

sudo apt install libasound-dev
sudo apt install libportaudio-dev
sudo apt install portaudio19-dev

sudo apt install python3-pyaudio python-pyaudio

今回はPython3.5.2のRaspbianにデフォルトで入っている物を想定しているけど、
一応Python-pyaudio(2.x系向け)も入れた。

numpyを少し使うので

sudo apt install libatlas-base-dev

もインストール

動作確認

$ python3
>>> import pyaudio
>>> pyaudio.__version__
'0.2.11'

オーディオデバイスの確認

lsusbで認識されていることを確認する

$ lsusb
Bus 001 Device 006: ID 046d:082d Logitech, Inc. HD Pro Webcam C920

PyAudioから見えているかを確認する
入力チャンネル数が0じゃなければ入力デバイスとして確認できるのでIDと名前を表示する
(Host APIは一つしか無い(0番)という前提で進めている)

import pyaudio

p = pyaudio.PyAudio()
info = p.get_host_api_info_by_index(0)
n_dev = info.get('deviceCount')

for i in range(n_dev):
    if (p.get_device_info_by_host_api_device_index(0, i).get('maxInputChannels')):
        print("Input Device id: {0}, {1}".format(i, p.get_device_info_by_host_api_device_index(0, i).get('name')))

これで確認しておけば他のオーディオデバイスを繋いでいても選んで使うことができる

実行結果はこちら

# ALSA libのワチャワチャしたものがいっぱい出る.
# 最後あたりにInput Deviceの情報が出る
Input Device id: 2, HD Pro Webcam C920: USB Audio (hw:1,0)

オーディオを取得して標準出力にレベルメータ的な物を表示する

オーディオを取得して(callback関数内のin_data)、Int16形式に変換して、Numpyの配列にする。
その配列の中で最も大きい値÷1000個の#を表示すればレベルメータっぽくなった。

import pyaudio
import numpy as np
import time

WIDTH = 2
CHANNELS = 2
RATE = 16000

p = pyaudio.PyAudio()

def callback(in_data, frame_count, time_info, status):
  numpydata = np.fromstring(in_data, dtype=np.int16)
  print("#" * int(np.max(numpydata) / 1000))
  return (in_data, pyaudio.paContinue)

stream = p.open(format=p.get_format_from_width(WIDTH),
                channels=CHANNELS,
                rate=RATE,
                input_device_index=2,
                input=True,
                output=False,
                stream_callback=callback)

stream.start_stream()

while stream.is_active():
  time.sleep(0.1)

stream.stop_stream()
stream.close()

p.terminate()

これは実行している時に指パッチンしてみた。
f:id:ensekitt:20180325202426g:plain
ちゃんと取れているっぽい。
止める時はCtrl+c

必要に応じてCallbackのところで処理したりQueueに突っ込んで他のところで処理したりすれば、
音で遊べそう。

クリエイティブ・コモンズ・ライセンス
この 作品 は クリエイティブ・コモンズ 表示 4.0 国際 ライセンスの下に提供されています。