リアルタイムにサウンドを生成・再生する
Mk-Synth、サウンドの再生にwaveOut系のAPIを使っているのだけど、スクリプトがHSPTV部門用に詰めてて自分でも分かりにくいので、再生部分だけでも分かりやすくなるようにサンプル書いた。
実行するといきなり音が鳴るので音量注意!マウス左ボタンで波形の形を変えれる。
; HSP3.5b4 #include "winmm.as" ; 基になる波形の準備 bwsize = 100 ; 一周期の長さ ddim bwbuf, bwsize repeat bwsize if (cnt < bwsize / 2) { bwbuf(cnt) = 0.2 } else { bwbuf(cnt) = -0.2 } loop bwpos = 0 boxsize = 3 asprate = 0.5 winsx = bwsize * boxsize winsy = asprate * winsx screen 0, winsx, winsy gosub *drawBaseWave channels = 1 bits = 16 samples = 44100 blockalign = channels * bits / 8 wbufnum = 5 wbufblock = 1000 wbufsize = wbufblock * blockalign ; 小さい程反応が早いが音が途切れやすい dim wfx, 4 ; WAVEFORMATEX wfx(0) = 1 | (channels << 16) ; WAVE_FORMAT_PCM wfx(1) = samples wfx(2) = samples * blockalign wfx(3) = blockalign | (bits << 16) ; デバイス オープン dim hwo waveOutOpen varptr(hwo), $ffffffff, varptr(wfx), 0, 0, 0 ; WAVE_MAPPER if stat { dialog "デバイスのオープンに失敗しました" end } ; マルチバッファリング用のバッファ準備 sdim wavBuf, wbufsize * wbufnum dim whd, 8, wbufnum ; WAVEHDR ptwhd = varptr(whd) repeat wbufnum whd(0, cnt) = varptr(wavBuf) + wbufsize * cnt, wbufsize pt = ptwhd + cnt * 32 waveOutPrepareHeader hwo, pt, 32 waveOutWrite hwo, pt, 32 loop nowbuf = 0 onexit goto *bye *mainLoop await 1 stick key, 256 if (key & 256) { ; マウス左ボタン bwbuf(mousex / boxsize) = double((mousey - winsy / 2) / boxsize) * boxsize / winsy * 2 gosub *drawBaseWave } if (whd(4, nowbuf) & 1) { ; WHDR_DONE(1): バッファの再生が終了している gosub *writeWave } goto *mainLoop *drawBaseWave redraw 0 color 255, 255, 255 boxf color 0, 0, 0 repeat bwsize x = cnt * boxsize y = (bwbuf(cnt) + 1) / 2 * winsy boxf x, y, x + boxsize - 1, y + boxsize - 1 loop redraw 1 return *writeWave p = nowbuf * wbufsize repeat wbufblock wpoke wavBuf, cnt * 2 + p, int(bwbuf(bwpos) * $7fff) bwpos = (bwpos + 1) \ bwsize loop waveOutWrite hwo, ptwhd + nowbuf * 32, 32 nowbuf = (nowbuf + 1) \ wbufnum return *bye waveOutReset hwo repeat wbufnum waveOutUnprepareHeader hwo, ptwhd + cnt * 32, 32 loop waveOutClose hwo end end
サウンドのバッファを複数用意しておいて再生が終わったバッファに波形を書くの繰り返し。再生が終わったのを知るのは oncmd で MM_WOM_DONE を受け取る方法もある(こっちが普通?)けど、今回は WAVEHDR構造体 の dwFlags をループでチェックしてる。
波形の作り方で色々音が変わるのが結構楽しい。キーマニ専コンで弾きたかった(Win10に更新したら動かなくなった…