やりたい事:440HzのSin波を作って鳴らしてみたけど、スピーカの特性によるのか矩形波のようなBEEP音になっていた。試しにコードの波形を作って鳴らしてみる
どうせならマイナーな、ラドミの和音の波形を作ってみる。
できたこと:和音の波形を作ってI2S制御のスピーカから再生した。
課題:和音が再生されたがノイズがひどい。また、単音の場合もi2s.write()でデータを送信する都度音が途切れる。callback方式で実装しても音が途切れる。どうやったら途切れることなく連続再生できるのか不明(Git上のサンプルコードを調べると何かわかるかも)*1
まとめ:やっぱり音のプログラムは難しい。MicroPython等のインタプリタで制御するにはハード側でcacheを持たせる等いろいろ工夫しないと、音が途切れる症状が出ると思われる。
周波数 1周期にかかるclock数(44.1KHz) -------------------------------------- # ラ A3 220.000 200 clock # ド C4 261.626 169 clock # ミ E4 329.628 134 clock
ラドミの和音による波形データを作るプログラムは以下
from math import pi from math import sin from machine import I2S from machine import Pin # code (A3_C4_E4) # A3 220.000 200 clock # C4 261.626 169 clock # E4 329.628 134 clock A3_CYCLE = 200 C4_CYCLE = 169 E4_CYCLE = 134 MAX_VOLUME = 0x7fff volume = int(MAX_VOLUME * 0.5) def dump2Bls(buf, len=128, onHex=False): for i in range(len): data = buf[i*2+1] << 8 data += buf[i*2] if onHex: print(f'{data:02x} ',end='') if data >= 0x8000: print(data - 0x10000) else: print(data) def toI16(data): if data == 0: lb = 0 ub = 0 elif (data > 0) and (data <= 0x7fff): lb = data & 0xff ub = (data >> 8) & 0xff elif (data < 0) and (data >= (0x8000 * -1)): data = 0x10000 + data lb = data & 0xff ub = (data >> 8) & 0xff else: lb = None ub = None return (ub, lb) i2s = I2S(0, sck=Pin(18), ws=Pin(19), sd=Pin(20), mode=I2S.TX, bits=16, format=I2S.MONO, rate=44100, ibuf=20_000) buffer_size = 44100 * 2 # *2 means 2byte(16bit) and 1sec buf = bytearray(buffer_size) # for i in range(int(len(buf)/2)): a3 = sin( 2 * pi * i / A3_CYCLE) c4 = sin( 2 * pi * i / C4_CYCLE) e4 = sin( 2 * pi * i / E4_CYCLE) tone = int(volume * (a3 + c4 + e4 ) / 2) i16 = toI16(tone) buf[i * 2] = i16[1] buf[i * 2 + 1] = i16[0] while True: i2s.write(buf)
ノイズがひどくて聞くに堪えない。なぜノイズが乗るのか分からない。和音の作り方がまずいのかも。Excelで波形を描画させたが特に非連続な部分は見つけられず
*1:WAVフォーマットに仕上げてPCで再生させることにより、データの問題か再生装置の問題かを切り分けられそうだ