2018/11/23(金) [n年前の日記]
#2 [tic80] TIC-80の波形メモリ音源について試行錯誤中
TIC-80のサウンド機能は、いわゆる波形メモリ音源タイプとして実装されているのだけれど。
この、波形メモリ音源、一見すると波形を描いていけばいいだけだから簡単そうに思えてくるけれど、実際にやってみるとイイ感じの音がさっぱり鳴らないというアレな感じの音源タイプで。
もうちょっとどうにかならんのか、と思えてきたので、試しに、sin値等で一周期分の波形データを作って、ソレを波形メモリに書き込んで鳴らすプログラムを書いてみたり。
ブラウザでプレイするなら以下。
_wavetest.tic.html
cart(.tic)は以下。
_wavetest.tic.zip
この、波形メモリ音源、一見すると波形を描いていけばいいだけだから簡単そうに思えてくるけれど、実際にやってみるとイイ感じの音がさっぱり鳴らないというアレな感じの音源タイプで。
もうちょっとどうにかならんのか、と思えてきたので、試しに、sin値等で一周期分の波形データを作って、ソレを波形メモリに書き込んで鳴らすプログラムを書いてみたり。
ブラウザでプレイするなら以下。
_wavetest.tic.html
- Nキーで、表示されてる波形が鳴る。
- ESCキーを押して、CLOSE GAME を選んで Zキーで決定すると入力待ち画面になる。
- 入力待ち画面でF1キー、もしくは edit と打つとエディタが開く。
- ソースを弄ってから Ctrl + R を叩けば実行されて波形が変わる。
- F4キーで、SFXエディタ(効果音エディタ)が開く。
cart(.tic)は以下。
_wavetest.tic.zip
- ローカル環境で動かした場合は、Xキーで、表示されてる波形が、波形メモリ(cart)に記録できる。
◎ ソース。 :
ソースは以下。無駄に長いけど、makeWave() の中だけ弄れば波形が変わるので…。長さ32個の配列さえ作れば、中の各値を音量16段階(4bit)に切り詰めて波形メモリに書き込んでくれる。
_wavetest.lua
_wavetest.lua
-- title: wavetest -- author: mieki256 -- desc: short description -- script: lua waveid=4 WAVADR=0x0ffe4 function makeWave() dt={} for i=0,31 do local v=0 -- multiplier, speed, shift v=v+getSin(i, 1.0, 1.0, 0) v=v+getSin(i, 1.5, 0.5, 0) v=v+getSin(i, 1.5, 2.0, 0) v=v+getSin(i, 0.5, 3.0, 90) --[[ v=v+getSin(i, 0.5, 3.0, 0) v=v+getSin(i, 0.25, 4.0, 0) --]] table.insert(dt,v) end return dt end function getSin(i,m,spd,sft) return m*math.sin(math.rad(spd*i*360/32+sft)) end function writeWave(id,dt) -- adjust if id<0 or id>15 then return end if #dt>32 then return end local vmax,vmin vmax=0 vmin=0 for i=1,#dt do if dt[i]>vmax then vmax=dt[i] end if dt[i]<vmin then vmin=dt[i] end end local range=vmax-vmin for i=1,#dt do dt[i]=math.floor(15*(dt[i]-vmin)/range) end -- write wave local addr=WAVADR+id*16 for i=1,#dt,2 do local v=0 v = v | ((dt[i+1] & 0x0f)<<4) v = v | (dt[i] & 0x0f) poke(addr+((i-1)//2),v) end end function drawGuide(bx,by,w,h) local x0,y0,x1,y1 local c=3 x0,x1=bx,bx+w*32-2 y0=by+h*8-1 line(x0,y0,x1,y0,c) y0=by+h*4-1 line(x0,y0,x1,y0,c) y0=by+h*12-1 line(x0,y0,x1,y0,c) x0=bx+w*16-1 y0,y1=by,by+h*16-2 line(x0,y0,x0,y1,c) x0=bx+w*8-1 line(x0,y0,x0,y1,c) x0=bx+w*24-1 line(x0,y0,x0,y1,c) end function drawWave(id) -- read wave local addr=WAVADR+id*16 local dt={} for i=0,15 do local v=peek(addr+i) local v1=v&0x0f local v2=(v>>4)&0x0f table.insert(dt,v1) table.insert(dt,v2) end -- draw wave local bx,by=24,12 local w,h=6,6 local x,y for ix=0,31 do x = ix * w + bx for iy=0,15 do y = iy * h + by rect(x,y,w,h,0) rect(x,y,w-1,h-1,1) end y=(15-dt[ix+1])*h+by rect(x,y,w-1,h-1,6) end drawGuide(bx,by,w,h) end dt=makeWave() writeWave(waveid,dt) t=0 function TIC() if keyp(14) then sfx(0,"A-4",30,0) end if keyp(25) then sfx(1,"A-4",30,0) end if btnp(5) then -- write to cart sync(1<<3,0,true) end cls(0) drawWave(waveid) print("WAVE ID: "..waveid, 2,120) print("Play: N or Y / Write: X", 2,128) t=t+1 end
◎ 少し解説。 :
TIC-80上で波形データがどこに記録されているかは、以下のページで説明されてる。
_RAM - nesbox/TIC-80 Wiki
_poke - nesbox/TIC-80 Wiki
書き込む1byteのうち、下位4bitが0番目の音量、上位4bitが1番目の音量、となっている模様。
せっかく波形メモリを書き換えても、プログラムを終了してしまうと、波形メモリの内容はデフォルト値でリセットされてしまう。できれば cart.tic に保存・記録しておきたい。そんな時は、sync() を使う。
_sync - nesbox/TIC-80 Wiki
とりあえず、sync(1<<3, 0, true) を呼び出せば、現在のSFXデータ(効果音データ)を、cart.tic に記憶させられる。と言っても、その段階ではファイルとして保存されてない気配がするので、更に Ctrl+S を叩いてファイルとして上書き保存したほうがいいのかもしれず。
_RAM - nesbox/TIC-80 Wiki
| 0FFE4 | WAVEFORMS | 256 | 16 waveforms, each 32 x 4bit valuesというのがソレ。
- 0x0FFE4番地から、256byteほど確保してあって、16種類の波形が記録されてる。
- 1つの波形につき、4bitの音量が32個並んでる。つまり、16byteで一つの波形になる。
_poke - nesbox/TIC-80 Wiki
書き込む1byteのうち、下位4bitが0番目の音量、上位4bitが1番目の音量、となっている模様。
bytes : 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, ... wave memory : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, ...
せっかく波形メモリを書き換えても、プログラムを終了してしまうと、波形メモリの内容はデフォルト値でリセットされてしまう。できれば cart.tic に保存・記録しておきたい。そんな時は、sync() を使う。
_sync - nesbox/TIC-80 Wiki
とりあえず、sync(1<<3, 0, true) を呼び出せば、現在のSFXデータ(効果音データ)を、cart.tic に記憶させられる。と言っても、その段階ではファイルとして保存されてない気配がするので、更に Ctrl+S を叩いてファイルとして上書き保存したほうがいいのかもしれず。
◎ 課題。 :
一々ソースを書き換えて波形を変えていくのは面倒なので、実行画面上でパラメータを弄ればその場で変化するようにしたいのだけど。しかし、どういった波形ソース、及び、パラメータを用意しておけばいいのかで悩んだり。
sin波をいくつか合成するだけでではそんなに変化が出ないだろうし…。矩形波、三角波、ノコギリ波も加算できるようにしたほうがいいのかな…。
sin波をいくつか合成するだけでではそんなに変化が出ないだろうし…。矩形波、三角波、ノコギリ波も加算できるようにしたほうがいいのかな…。
[ ツッコむ ]
以上です。