前回は、audiocore とaudomixerでwavファイルを再生した。 引き続き、 CircuitPython で、RaspberryPi Picoから音源再生。

audiocore.WaveFile() は、wavファイルをそのまま再生するのはいいが、ちょっとeffectをかけたい場合に不便。 .wavファイルをデータイメージでloadして、 audiocore.RawSample() で再生してみる。

adafruit_wave.py

Adafruit_CircuitPython_Wave は、.wav ファイルをデータとしてloadできる

上記から、 adafruit_wave.py をもってきて、Macなら /Volumes/CIRCUITPY/lib 配下にコピーする。

bash
cp adafruit_wave.py /Volumes/CIRCUITPY/lib

配線

  • GP26(A0) とGNDをスピーカーに接続
  • GP0 - タクトスイッチ - GNDを接続

操作

起動すると、 sample.wav を再生。 タクトスイッチを押すと、再生中のデータ(0.5秒分)を繰り返す。 温泉がすきすきすきすき...

sample.wav

source code

wavfile_play.py · Gistpython
import adafruit_wave
import audiocore
import digitalio
import board
import audiobusio
import array
import time

try:
    from audioio import AudioOut
except ImportError:
    try:
        from audiopwmio import PWMAudioOut as AudioOut
    except ImportError:
        pass  # not always supported by every board!

# repeat button
button = digitalio.DigitalInOut(board.GP0)
button.switch_to_input(pull=digitalio.Pull.UP)

# Audio Out
a = AudioOut(board.A0)

# .wav open
filename = "sample.wav"
w = adafruit_wave.open(filename)

# read 0.5sec sample
sample_sec = 1/2
framerate = int(w.getframerate() / 2)

#
# main loop
#

current_channel = 0
new_c = 1 - current_channel
is_end = False

sample_data = [0, 0]
next_time = 0
while is_end is False:
    if next_time > time.monotonic_ns():
        continue

    next_time = time.monotonic_ns() + (sample_sec * 1000_000_000)
    if button.value is False:
        # repeat play
        a.stop()

        # play start
        a.play(sample_data[current_channel])
    else:
        new_c = 1 - current_channel
        if sample_data[new_c] != 0:
            a.play(sample_data[new_c])  # ready to play channel

        # read next time data from file
        data = w.readframes(framerate)
        if len(data) <= 0:
            # end of file
            is_end = True
            break
        wave = array.array("h", data)
        sample_data[current_channel] = audiocore.RawSample(wave, sample_rate=16000)
        current_channel = new_c

    print(".", end="")

print("")
print("end")

demo

制限

FileIOは重い。0.5秒単位ならまだいいが、0.2秒単位のloadにするとブツブツと雑音が混じる。