オーディオ

このモジュールは micro:bit でサウンドを再生できるようにします。

デフォルトでサウンドはエッジコネクタの端子 0 と 内蔵スピーカー (V2)に出力します。端子 0 と GND に有線ヘッドフォンやスピーカーを繋いでサウンドを鳴らせます。

audio モジュールは import audio でインポートするか、 microbit モジュールの microbit.audio にアクセスすることで利用できるようになります。

audio.play() 関数を使って再生できる音源には3種類あります:

  1. 内蔵サウンド (V2): たとえば audio.play(Sound.HAPPY) など

  2. サウンド効果 (V2): パラメータ指定によりカスタムサウンドを作る方法です:

    my_effect = audio.SoundEffect(freq_start=400, freq_end=2500, duration=500)
    audio.play(my_effect)
    
  3. オーディオフレーム : AudioFrame のイテラブル(リストやジェネレータなど) - AudioFrame は 0 から 255 の値を持つ32項目のリストです:

    square_wave = audio.AudioFrame()
    for i in range(16):
        square_wave[i] = 0
        square_wave[i + 16] = 255
    audio.play([square_wave] * 64)
    

関数

audio.play(source, wait=True, pin=pin0, return_pin=None)

音源を最後まで再生します。

パラメータ:
  • source --

    There are three types of data that can be used as a source:

    • Sound: 内蔵サウンドを持った microbit モジュール。たとえば audio.play(Sound.TWINKLE) のように指定します。全一覧は 内蔵サウンド の章を参照してください。
    • SoundEffect: サウンド効果、またはサウンド効果のイテラブル。サウンド効果は audio.SoundEffect() クラスで作ります
    • AudioFrame: AudioFrame の技術詳細 の章に説明されている AudioFrame のイテラブル
  • wait -- waitTrue の場合、音源の再生が終わるまでこの関数から戻りません。
  • pin -- pin: 出力端子をデフォルトの pin0 から変えるためのオプション引数です。音を鳴らしたくない場合は pin=None を指定します。
  • return_pin -- スピーカーの2本ある線の一方を接続する先である GND を別の端子にしたい場合に使います。 V2 ではこの指定を無視します。
audio.is_playing()
戻り値:オーディオを再生中であれば True、再生していなければ False を返します。
audio.stop()

すべてのオーディオ再生を停止します。

V2 に内蔵のサウンド

以下の内蔵のサウンドは audio.play(Sound.NAME) のようにして再生できます。

  • Sound.GIGGLE
  • Sound.HAPPY
  • Sound.HELLO
  • Sound.MYSTERIOUS
  • Sound.SAD
  • Sound.SLIDE
  • Sound.SOARING
  • Sound.SPRING
  • Sound.TWINKLE
  • Sound.YAWN

サウンドのサンプルコード

from microbit import *

while True:
    if button_a.is_pressed() and button_b.is_pressed():
        # 両ボタンを押下したときはエッジコネクタを介してだけ再生
        audio.play(Sound.HELLO, pin=pin0)
    elif button_a.is_pressed():
        # Aボタンを押したときにサウンドを再生して、イメージを表示
        audio.play(Sound.HAPPY)
        display.show(Image.HAPPY)
    elif button_b.is_pressed():
        # Bボタンを押したときにサウンド再生とイメージ表示を同時に行う
        audio.play(Sound.TWINKLE, wait=False)
        display.show(Image.BUTTERFLY)

    sleep(500)
    display.clear()

サウンド効果 V2

class audio.SoundEffect(freq_start=500, freq_end=2500, duration=500, vol_start=255, vol_end=0, waveform=WAVEFORM_SQUARE, fx=FX_NONE, shape=SHAPE_LOG)

SoundEffect インスタンスはサウンド効果を表します。サウンド効果は、コンストラクタや属性で設定したパラメータのセットで構成されます。

すべてのパラメータはオプションで、デフォルト値は上記のとおりです。また、すべてのパラメータは同名の属性で変更できます。たとえば、まず my_effect =SoundEffect(duration=1000) というサウンド効果を作成した後に、 my_effect.duration = 500 で属性を変更できます。

パラメータ:
  • freq_start -- 開始周波数をヘルツ(Hz)で指定します: デフォルトは 500
  • freq_end -- 終了周波数をヘルツ(Hz)で指定します: デフォルトは 2500
  • duration -- サウンドの長さをミリ秒(ms)で指定します: デフォルトは 500
  • vol_start -- 開始音量を 0-255 の範囲で指定します。デフォルトは 255
  • vol_end -- 終了音量を 0-255 の範囲で指定します。デフォルトは 0
  • waveform -- 波形の種類。次の値のいずれかを指定します: WAVEFORM_SINE, WAVEFORM_SAWTOOTH, WAVEFORM_TRIANGLE, WAVEFORM_SQUARE, WAVEFORM_NOISE (ランダムに生成したノイズ)。デフォルトは WAVEFORM_SQUARE です。
  • fx -- サウンドに追加する効果。次の値のいずれかを指定します: FX_TREMOLO, FX_VIBRATO, FX_WARBLE, FX_NONE 。デフォルトは FX_NONE です。
  • shape -- 開始周波数と終了周波数の補間曲線の種類で、波形の違いにより周波数の変化率が異なります。次の値のうちのいずれかを指定します: SHAPE_LINEAR, SHAPE_CURVE, SHAPE_LOG 。デフォルトは SHAPE_LOG です。
copy()
戻り値:SoundEffect のコピー。
freq_start

開始周波数。単位はヘルツ(Hz)で、 0 から 9999 の範囲の数値です。

freq_end

終了周波数。単位はヘルツ(Hz)で、 0 から 9999 の範囲の数値です。

duration

サウンドの長さ。 0 から 9999 の範囲の数値です。

vol_start

開始音量。 0 から 255 の範囲の数値です。

vol_end

終了音量。 0 から 255 の範囲の数値です。

waveform

波形の種類。次の値のいずれか: WAVEFORM_SINE, WAVEFORM_SAWTOOTH, WAVEFORM_TRIANGLE, WAVEFORM_SQUARE, WAVEFORM_NOISE (ランダムに生成したノイズ)。

fx

サウンドに追加する効果。次の値のいずれか: FX_TREMOLO, FX_VIBRATO, FX_WARBLE, FX_NONE

shape

開始周波数と終了周波数の補間曲線の種類で、波形の違いにより周波数の変化率が異なります。次の値のうちのいずれか: SHAPE_LINEAR, SHAPE_CURVE, SHAPE_LOG

サウンド効果の作成に使った引数は、サウンド効果のインスタンス属性を見るか、インスタンスを文字列に変換することで調べることができます(文字列への変換は str() 関数、または print() のように自動的に変換する関数を使ってできます)

たとえば REPL を使うと、デフォルトの SoundEffects を調べられます:

>>> print(audio.SoundEffect())
SoundEffect(freq_start=500, freq_end=2500, duration=500, vol_start=255, vol_end=0, waveform=WAVE_SQUARE, fx=FX_NONE, shape=SHAPE_LOG)

このフォーマット「human readable」、つまり私たちが読みやすいもので、そのサウンド効果を作るために必要なコードと非常に似ていますが、ちょっと違います。 repr() 関数は保存や転送が可能な Python コードの文字列を作成するために使えます(micro:bit の無線機能でサウンドを送信できます!)。この文字列は eval() 関数で実行できます::

>>> from audio import SoundEffect
>>> sound_code = repr(SoundEffect())
>>> print(sound_code)
SoundEffect(500, 2500, 500, 255, 0, 3, 0, 18)
>>> eval("audio.play({})".format(sound_code))

サウンド効果のサンプルコード

from microbit import *

# Play the default Sound Effect
audio.play(audio.SoundEffect())

# Create a new Sound Effect and immediately play it
audio.play(audio.SoundEffect(
    freq_start=400,
    freq_end=2000,
    duration=500,
    vol_start=100,
    vol_end=255,
    waveform=audio.SoundEffect.WAVEFORM_TRIANGLE,
    fx=audio.SoundEffect.FX_VIBRATO,
    shape=audio.SoundEffect.SHAPE_LOG
))

# Play a Sound Effect instance, modify an attribute, and play it again
my_effect = audio.SoundEffect(
    freq_start=400,
    freq_end=2000,
)
audio.play(my_effect)
my_effect.duration = 1000
audio.play(my_effect)

# You can also create a new effect based on an existing one, and modify
# any of its characteristics via arguments
my_modified_effect = my_effect.copy()
my_modified_effect.waveform = audio.SoundEffect.WAVEFORM_NOISE
audio.play(my_modified_effect)

# Use sensor data to modify and play an existing Sound Effect instance
my_effect.duration = 600
while True:
    # int() might be temporarily needed: https://github.com/microbit-foundation/micropython-microbit-v2/issues/121
    my_effect.freq_start = int(scale(accelerometer.get_x(), from_=(-2000, 2000), to=(0, 9999)))
    my_effect.freq_end = int(scale(accelerometer.get_y(), from_=(-2000, 2000), to=(0, 9999)))
    audio.play(my_effect)

    if button_a.is_pressed():
        # Button A silences the micro:bit
        speaker.off()
        display.show(Image("09090:00000:00900:09990:00900"))
        sleep(500)
    elif button_b.is_pressed():
        # Button B re-enables the speaker & plays an effect while showing an image
        speaker.on()
        audio.play(audio.SoundEffect(), wait=False)
        display.show(Image.MUSIC_QUAVER)
        sleep(500)

    sleep(150)

AudioFrame

class audio.AudioFrame

AudioFrame オブジェクトは32項目のリストです。各項目の値は符号なしバイト(0と255の間の整数)です。

1フレームを再生するのには4ミリ秒以上かかります。

copyfrom(other)

この AudioFrame のデータを、別の AudioFrame インスタンスのデータで上書きします。

パラメータ:other -- コピーするデータを持つ AudioFrame インスタンス。

技術的な詳細

注釈

audio モジュールを使うのにこのセクションを理解する必要はありません。このモジュールがどのように機能するのか知りたい方のためにあります。

audio モジュールは AudioFrame インスタンスのイテラブル(リストやタプルなどのシーケンス、またはジェネレータ)を巡回し、各回 7812.5 Hz で 32 項目を採取し、線形補間を使用して 32.5 kHz の PWM 信号を出力します。これにより、許容できる音質が得られます。

関数 play は、次のフレームを得るのに next() 呼び出す前に、 各 AudioFrame からすべてのデータを完全にコピーするので、音源は同じ AudioFrame を繰り返し使用できます。

audio モジュールには64個のサンプルバッファがあり、そこからサンプルを読み取ります。読み取りがバッファの開始点または中間点に達すると、次の AudioFrame を取り込むコールバックをトリガして、バッファにコピーします。これは、音源が次の AudioFrame を処理するのは 4ms 以下であり、信頼できる操作のために 2ms 以下である必要があります(micro:bit V1 では 32000 サイクル、V2 では 128000 サイクルなので十分です)。

AudioFrame のサンプルコード

from microbit import display, sleep, button_a
import audio
import math

def repeated_frame(frame, count):
    for i in range(count):
        yield frame

# 次の波形に行くには A ボタンを押します。
def show_wave(name, frame, duration=1500):
    display.scroll(name + " wave", wait=False,delay=100)
    audio.play(repeated_frame(frame, duration),wait=False)
    for i in range(75):
        sleep(100)
        if button_a.is_pressed():
            display.clear()
            audio.stop()
            break

frame = audio.AudioFrame()

for i in range(len(frame)):
    frame[i] = int(math.sin(math.pi*i/16)*124+128.5)
show_wave("Sine", frame)

triangle = audio.AudioFrame()

QUARTER = len(triangle)//4
for i in range(QUARTER):
    triangle[i] = i*15
    triangle[i+QUARTER] = 248-i*15
    triangle[i+QUARTER*2] = 128-i*15
    triangle[i+QUARTER*3] = i*15+8
show_wave("Triangle", triangle)

square = audio.AudioFrame()

HALF = len(square)//2
for i in range(HALF):
    square[i] = 8
    square[i+HALF] = 248
show_wave("Square", square)
sleep(1000)

for i in range(len(frame)):
    frame[i] = 252-i*8
show_wave("Sawtooth", frame)

del frame

#三角波から方形波になる波形を、適度になめらかに生成。
frames = [ None ] * 32
for i in range(32):
    frames[i] = frame = audio.AudioFrame()
    for j in range(len(triangle)):
        frame[j] = (triangle[j]*(32-i) + square[j]*i)>>5

def repeated_frames(frames, count):
    for frame in frames:
        for i in range(count):
            yield frame


display.scroll("Ascending wave", wait=False)
audio.play(repeated_frames(frames, 60))