技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

Circuit Playground Express の各種機能を試す(音声周り)

マイクを使って音をサンプリングする

ということで、音のサンプリングを実行してみた。
具体的には、音量を検出して、10 個の LED (Pixcel) を段階的に光らせた。

前回のライブラリも利用し、

white-azalea.hatenablog.jp

追加で simpleio を入れた。

f:id:white-azalea:20200707210032p:plain

実際のコードはこんな感じ

import board
import math
import array
import audiobusio
import simpleio
from adafruit_circuitplayground import cp

def rms(value):
    # 音は波なので、波の振れ幅 = 音量。
    # 音の振幅の平均値(ここからの振れ幅=音量)
    dc_offset = int(sum(value) / len(value))
    # (1 サンプル毎の音量) の二乗和 (2 乗すると、マイナスがなくなるため)
    s = sum((i - dc_offset) ** 2 for i in value)
    # 二乗平均 = 分散
    m = s / len(value)
    # 標準偏差(二乗平均平方根 : root mean square)
    r = math.sqrt(m)
    return r

cp.pixels.auto_write = False
cp.pixels.brightness = 0.3

mic = audiobusio.PDMIn(
    board.MICROPHONE_CLOCK,
    board.MICROPHONE_DATA,
    sample_rate=16000, # サンプリングビットレート 16kHz
    bit_depth=16       # ビット深度 0 - 65535 の値
)

# サンプリングデータを入れるための空の 配列(長さ 80 のリスト)を作る(H は型コード)
# 16kHz, 16000 / 80 = 0.005 sec 分のサンプリング
samples = array.array('H', [0] * 80)
# samples リストの長さぶんの録音をする
mic.record(samples, len(samples))

while True:
    mic.record(samples, len(samples))
    magnitude = rms(samples)
    i = int(simpleio.map_range(int(magnitude), 0, 1000, 0, 9))  # 0-1000 までの値を 0-9 の値にマップする

    for p in range(10):
        cp.pixels[p] = (0, 5, 0) if p < i + 1 else (0, 0, 0)
    cp.pixels.show()

すると、こんな感じの光り方をする。

f:id:white-azalea:20200707210337p:plain

近くで「あー」と声を出しながら撮影

f:id:white-azalea:20200707210649p:plain

咳き込むと一瞬で上がるのだけど、その瞬間を取るわけにも行かず…大音量で音楽聞く訳にも行かなかったので断念…

スピーカーで音を鳴らす

from adafruit_circuitplayground import cp

while True:
    if cp.button_a:
        cp.start_tone(262)
    elif cp.button_b:
        cp.start_tone(294)
    else:
        cp.stop_tone()

音声の公開は難しいのでコードだけ。
ボタンを押している間だけビープ音がなります。

数字は周波数。

ちなみにトーンは、秒指定で再生もできるので

from adafruit_circuitplayground import cp

cp.play_tone(262, 1)
cp.play_tone(294, 1)

こんなんもできた