以前の続きです。Raspberry Piでプログラミングをして、Raspberry Pi PicoをコントロールしてLチカする実験をしましたが、次のステップとして、「音を出す」ことに挑戦したいと思います。今回もRPI 3とRPi 400を使ってやってみます。まずは、MicroPythonでできるかやってみようと思いますが、RPi 3では「Visual Studio Code」が使えなかったので、「Thonny」だけでやってみることにします。
#下準備として、PicoでMicroPythonが使えるようにするファームウェアの設定作業は、過去の拙Blogの記事を参考にしてください。公式Webサイトの情報もご確認ください。
まずは、Thonnyを起動して作業開催。既に様々な設定が終わっているので、すぐにプログラムを書き始めます。今回は、@undo0530さんの「Raspberry Pi PicoでMicroPythonでPWM信号でスピーカーでメロディー演奏」を参考にしながら、曲を演奏するMicroPythonプログラムを書きました。内容は以下のとおりですが、ファイル名は任意で決めていただいて構いません。
from machine import Pin, PWM, Timer
speaker = PWM(Pin(17, Pin.OUT))
led = Pin(25, Pin.OUT)
ahz = 440
A4 = ahz
B4 = ahz * (2 ** (2/12))
C5 = ahz * (2 ** (3/12))
D5 = ahz * (2 ** (5/12))
E5 = ahz * (2 ** (7/12))
F5 = ahz * (2 ** (8/12))
G5 = ahz * (2 ** (10/12))
A5 = ahz * 2
mspb = 400
melody = [C5,0,C5,0,G5,0,G5,0,A5,0,A5,0,G5,0,0,0,F5,0,F5,0,E5,0,E5,0,D5,0,D5,0,C5,0,0,0]
i = 0
def beat(timer):
global melody
global led
global i
global speaker
if i >= len(melody):speaker.deinit()
led.value(0)
timer.deinit()
elif int(melody[i]) == 0:speaker.duty_u16(0)
led.value(0)
else:speaker.freq(int(melody[i] + 0.5))
speaker.duty_u16(0x8000)
led.value(1)
i += 1
tim = Timer()
tim.init(period=mspb, mode=Timer.PERIODIC, callback=beat)
ScratchやMicrosoft MakeCodeのように、はじめから音階が用意されていないので、PWMで作らなければなりません。そのために、使う音名に12平均律の各音の周波数を計算して入れて、メロディとして並べて演奏するプログラムにしています。「0」は、休符です。
このプログラムを作る過程で、MicroPythonでの「べき乗」や「累乗根」の計算式の書き方を学びました。各音の周波数値を決めるために近似値を使わずに計算式で計算をさせるプログラムにしたのは、(内部処理によって計算精度が微妙に違うかもしれませんが)できるだけ「正しい12平均律」に近づけたいと思ったからでした。実験した圧電スピーカーとPicoは以下のとおりです。(Seriaで購入した小さなモニタスピーカー模型?に圧電スピーカーを仕込んであります)
プログラムを書き終えてから、PicoをUSBケーブルでRPiにつなぎ、認識された(認識がうまくいかない場合は、一度「Stop/Restert backend」ボタンをクリックすると認識される)ところでRUNボタンをクリックすると、無事にメロディが鳴ってくれました。(「きらきら星」です)RPi 400でもRPi 3でも問題なく、音程も思った通りで「楽器」としても面白いものができた感じになりました。今回取り組んだ「周波数から音階を作る」という作業は、とても面白いと思いました。一方で、もう少しスマートな書き方ができないものかと思案しています。
〈参考資料〉
- 理系のための備忘録さんの「【Python】べき乗と平方根・累乗根の計算」
- soundoffice.comさんの「十二平均律の周波数一覧表」(←PDF)
【追記】これまでのPicoでのプログラミング(フィジカル・コンピューティング)に関する拙Blogの記事もご覧ください。(2024.11.4←これからも適宜更新していきます)
0 件のコメント:
コメントを投稿