【解説】M5stickVのPythonプログラミング ~オーディオ編~

【M5stickV】wav

こんにちは、けいです。
今回は、M5stickVで音を出す方法について解説していきます。
今回でPart4となります。
以前の記事を読んでいない方は下のリンクより、ぜひ読んでみて下さい。

音を出す方法

ハードウェア

M5stack公式より

回路図が上の写真のようになっています。
M5stack社らしいポップな回路図ですね!

今回使用するデバイスは画像右下のMAX98357です。
データシートを一応載せておきます。

MAX98357とはI2S通信を用いて通信するみたいです。

I2S(Inter-IC Sound、アイ・スクウェアード・エス)は、4本のデジタル信号線でステレオ音声をシリアル伝送する規格。通常はデジタルオーディオ機器内部でDACなどのIC間をつなぐ目的で利用されるが、これを外部機器との通信に利用することで、より「生」に近い信号にしようという狙いだ。

出典

サンプルコード

今回使用するサンプルコードはM5stickVが起動時に顔認証を行う、boot.pyの必要な部分を抜き取った以下のコードを用います。
boot.pyはスイッチサイエンスさんのページに記載されております。

import lcd
import image
import time
import uos

lcd.init()
lcd.rotation(2) #Rotate the lcd 180deg

try:
    img = image.Image("/sd/picture3.jpg") 
    lcd.display(img) 
except:
    lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find start.jpg", lcd.WHITE, lcd.RED)   

from Maix import I2S, GPIO
import audio
from fpioa_manager import *

fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
spk_sd.value(1) #Enable the SPK output

fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)

wav_dev = I2S(I2S.DEVICE_0)

try:
    player = audio.Audio(path = "/sd/test.wav")
    player.volume(100)
    wav_info = player.play_process(wav_dev)
    wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT, align_mode = I2S.STANDARD_MODE)
    wav_dev.set_sample_rate(wav_info[1])
    while True:
        ret = player.play()
        if ret == None:
            break
        elif ret==0:
            break
    player.finish()
except:
    pass

一つ目のtryの中の”/sd/picture3.jpg”の部分と、二つ目のtry の中の”/sd/test.wav”の部分は自分で設定する必要があります。
wavファイルを使用するので、SDカードに予め保存する必要があります。
私のSDカードのファイル構造はこのようになっています。
SDカードのルートディレクトリ?である/sdの直下にpicture3.jpg、test.wavファイルを置きます。
bootファイルに上のpythonファイルを書きます。
起動時に自動的にSDカード内のboot.pyを実行します。

解説

先ほどのサンプルコードを見ながら進めていきます。
一つ目のtryまでは、画像を表示するsdカード内の画像を表示するコードで、以前に解説したのでそちらの記事を見てみて下さい。

一つ目のtry後から解説します。

from Maix import I2S, GPIO
import audio
from fpioa_manager import *

ここはpythonのお決まりの他のファイルからのインポートの記述です。
Maixモジュールからオーディオとの通信方法であるI2SとGPIOクラスをインポートします。
wavファイルを読み込んで出力を制御するaudioモジュールをインポートします。
audioモジュールについては公式のドキュメントが現在はないため、詳しくご説明することができませんが、ご了承ください。
fpioa_managerモジュールからすべての要素をインポートします。
*を記述した場合、例えばfpioa_managerモジュールにfunc()という関数があった場合に、そのままfunc()と記述するだけで関数を呼び出すことができます。
もし、*を書かない場合はfpioa_manager.func()で毎回呼び出す必要があります。
fpioa_managerモジュールにはfmというグローバル変数が記述されていて、それを用いて、Fpioa_Managerクラスを使用することができます。
詳しくプログラムを見たい方は、以下のリンクより参照してみて下さい。

https://github.com/sipeed/MaixPy

fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
spk_sd.value(1) #Enable the SPK output

fm.register()はFpioa_Managerクラスのregister関数を呼び出しています。
fm.registerの第一引数はピン番号、第二引数はチップの関数とします。
fpioa_managerモジュールでboard_infoモジュールをインポートしてるので、board_infoモジュールを自分でインポートしなくても大丈夫です。
board_infoの中にはピン番号が格納された変数がたくさんあり、その中の一つがSPK_SDです。
board_infoモジュールの中で、self.SPK_SD=25と記述されていて、先ほどの回路図の番号と一致していることが分かります。

ピン25をGPIOの0番と定義して、spk_sdにGPIOクラスのインスタンスを生成します。

次に、GPIOクラスのvalue関数を呼び出して、たぶんgpio0をHIGHにしています。

fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)

先ほどと同じようにfm.registerでピンの割り当てを行います。
今回は残りの3つの線を登録しています。

audioモジュールについての記載が見当たらないので分かる範囲で書いていきます。tryの中の、

player = audio.Audio(path = "/sd/test.wav")
player.volume(100)

audioモジュールのAudioクラスのインスタンスをplayerに生成します。
Audioクラスのvolume関数を用いてボリューム調整をすることができます。

while文でwavファイルの出力が完了するまで、オーディオ出力を続けます。

wavファイルの生成

今回使用するソフトは、私の通う名古屋工業大学が中心となって開発したオープンソースの『Open Jtalk』をつかいます。
テキストを入力するだけでwavファイルを生成してくれる優れものなので、ぜひ使ってみて下さい。

http://open-jtalk.sp.nitech.ac.jp/

結果

正確に音声を出力できていますね。
ちなみにこの声は、名工大の入ってすぐのところでも聞くことができます。

参考にさせて頂いたサイト

他のモジュールの解説を行っているのでぜひ読んでみて下さい。