-- title: wavetestfm -- author: mieki256 -- desc: SFX wave maker. add like FM. -- script: lua WAVADR=0x0ffe4 waveid=4 vol=1.0 adjust_enable=false maxi=false oct=4 likefm=false fr_synth=true mode=0 playing=true setwave=false t=0 freqtbl={ {fs=1,mul=1.0,sft=0,kind=0}, {fs=2,mul=0.0,sft=0,kind=0}, {fs=3,mul=0.0,sft=0,kind=0}, {fs=4,mul=0.0,sft=0,kind=0}, {fs=5,mul=0.0,sft=0,kind=0}, {fs=6,mul=0.0,sft=0,kind=0}, {fs=7,mul=0.0,sft=0,kind=0}, {fs=8,mul=0.0,sft=0,kind=0}, {fs=9,mul=0.0,sft=0,kind=0}, {fs=10,mul=0.0,sft=0,kind=0}, } function makeWaveArray(p) local dt={} local ang,v,fs for i=0,31 do ang = i * 360 / 32 v = 0 for j,d in ipairs(freqtbl) do fs = d.fs * p if d.kind==0 then v = v + getSin(ang, d.mul, fs, d.sft) elseif d.kind==1 then v = v + getSquare(ang, d.mul, fs, d.sft) elseif d.kind==2 then v = v + getSaw(ang, d.mul, fs, d.sft) elseif d.kind==3 then v = v + getTri(ang, d.mul, fs, d.sft) else v = v + getSin(ang, d.mul, fs, d.sft) end end v = vol * v table.insert(dt,v) end return dt end function makeFMwaveArray(p) local mv0,mv1,mv2,mf0,mf1,mf2,ms0,ms1,ms2 local dt={} mv0=freqtbl[1].mul mf0=freqtbl[1].fs*p ms0=freqtbl[1].sft mv1=freqtbl[2].mul+1.0 mf1=freqtbl[3].mul+1.0 mv2=freqtbl[4].mul+1.0 mf2=freqtbl[5].mul+1.0 ms1=freqtbl[2].sft ms2=freqtbl[3].sft for i=0,34 do local a,a2,a1,v a=i*360/32 a2=180*getSin(a,mv2,mf2,ms2) a1=180*getSin(a,mv1,mf1,ms1+a2) v=vol*getSin(a,mv0,mf0,ms0+a1) table.insert(dt,v) end if fr_synth then dt[1]=0.25*dt[1]+0.75*dt[33] dt[2]=0.50*dt[2]+0.50*dt[34] dt[3]=0.75*dt[3]+0.25*dt[35] end table.remove(dt,35) table.remove(dt,34) table.remove(dt,33) return dt end function makeWave() if likefm then return makeFMwaveArray(1.0) end return makeWaveArray(1.0) end function getSin(a,m,fs,sft) return m*math.sin(math.rad(fs*a+sft)) end function getSquare(ang, m, fs, sft) local a = (fs * ang + sft) % 360 return m * ((a < 180) and 1.0 or -1.0) end function getSaw(ang, m, fs, sft) local v = (((fs * ang + sft) % 360) / 180) - 1.0 return m * v end function getTri(ang, m, fs, sft) local v = (fs * ang + sft) % 360 if v < 180 then v = (v % 180) / 90 - 1.0 else v = (2.0 - (v % 180) / 90) - 1.0 end return m * v end function resetFreqtbl() if not likefm then for i,d in ipairs(freqtbl) do d.mul=0.0 d.sft=0 d.kind=0 end freqtbl[1].mul=1.0 vol=1.0 else for i=1,5 do freqtbl[i].mul=-1.0 freqtbl[i].sft=0 end freqtbl[1].mul=1.0 vol=1.0 end end function clamp(v,min,max) if v<=min then v=min end if max<=v then v=max end return v end function writeWave(id,dt) -- adjust if id < 0 or id > 15 then return end if #dt>32 then return end if not adjust_enable then for i=1,#dt do dt[i] = math.floor(15 * (0.5 * dt[i] + 0.5) + 0.5) dt[i]=clamp(dt[i],0,15) end else -- adjust enable local vmax,vmin=0,0 for i=1,#dt do if dt[i]>vmax then vmax=dt[i] end if dt[i]>4)&0x0f) end -- draw wave local bx,by,w,h if maxi then bx,by,w,h=24,12,6,6 else bx,by,w,h=24,12,4,4 end 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 Button={} Button.new=function() local o={} o.lst={ {id=0,x=8*6, y=0, w=6,h=6,on=false,sts=false,str="<"}, {id=1,x=11*6,y=0, w=6,h=6,on=false,sts=false,str=">"}, {id=2,x=13*6,y=0, w=6*4,h=6,on=false,sts=false,str="READ"}, {id=3,x=18*6,y=0, w=6*4,h=6,on=false,sts=false,str="MAKE"}, {id=4,x=23*6,y=0, w=6*4,h=6,on=false,sts=false,str="PLAY"}, {id=5,x=28*6,y=0, w=6*4,h=6,on=false,sts=false,str="STOP"}, {id=6,x=33*6,y=0, w=6*4,h=6,on=false,sts=false,str="Sync"}, {id=7,x=0,y=6*19, w=6*4,h=6,on=false,sts=false,str="RSET"}, {id=8,x=6*0, y=6*14, w=6,h=6,on=false,sts=false,str="<"}, {id=9,x=6*2, y=6*14, w=6,h=6,on=false,sts=false,str=">"}, {id=10,x=0,y=6*17, w=6*4,h=6,on=false,sts=false,str="AJST"}, {id=11,x=0,y=6*2, w=6*4,h=6,on=false,sts=false,str="MAXI"}, {id=12,x=0,y=6*4, w=6*2,h=6,on=false,sts=false,str="FM"}, {id=13,x=0,y=6*6, w=6*2,h=6,on=false,sts=false,str="FSYN"}, } return setmetatable(o,{__index=Button}) end Button.update=function(self) local mx,my,md=mouse() local ret=-1 for i,d in ipairs(self.lst) do if d.x <= mx and mx <= d.x+d.w and d.y <= my and my <= d.y+d.h then d.on=true if d.sts then if not md then d.sts = false end else if md then ret=d.id d.sts=true end end else d.on=false d.sts=false end end return ret end Button.draw=function(self) local fg for i,d in ipairs(self.lst) do fg=7 if d.id==2 or d.id==3 then fg = (mode==(d.id-2)) and 15 or 7 elseif d.id==4 and playing==true then fg=15 elseif d.id==5 and playing==false then fg=15 elseif d.id==10 and adjust_enable then fg=15 elseif d.id==11 and maxi then fg=15 elseif d.id==12 and likefm then fg=15 elseif d.id==13 and likefm and fr_synth then fg=15 end if d.on then fg=10 end print(d.str,d.x,d.y,fg,true) end end Freq={} Freq.new=function() local o={} local y,bh,wy -- y,bh,wy = 12+6*16+1,20,136-5 y,bh,wy=12+4*16+4,41,136-5 wy=y+bh+4+1 o.tbl={ {bx=24+6*2,by=y,w=6,h=bh}, {bx=24+6*2+6*10+8,by=y,w=6,h=bh}, {bx=24+6*2,by=wy,w=6,h=6}, {bx=24+6*0,by=y,w=6,h=bh}, } o.kindsts={} for i=1,#freqtbl do table.insert(o.kindsts, false) end o.value=0 return setmetatable(o,{__index=Freq}) end Freq.chkBar=function(self,x,y,w,h,mx,my,ml,mm,mr) local k=0 local v=0.0 if x<=mx and mx<=x+w-2 and y<=my and my<=y+h-1 then if ml then local hh=(h-1)/2 v=(y+hh-my)/hh k=1 elseif mm then v=0.0 k=2 end end return k,v end Freq.update=function(self) local setfg=false local x,mx,my,ml,mm,mr,k,v mx,my,ml,mm,mr=mouse() for mode,d in ipairs(self.tbl) do if mode==4 then x=d.bx k,v = self:chkBar(x,d.by,d.w,d.h,mx,my,ml,mm,mr) if k>0 then vol=v+1.0; self.value=vol; setfg=true; break end else local l=#freqtbl if likefm then if mode==1 then l=5 elseif mode==2 then l=3 end end local dd for i=1,l do dd=freqtbl[i] x = d.bx + d.w * (i-1) if mode==1 then k,v = self:chkBar(x,d.by,d.w,d.h,mx,my,ml,mm,mr) if k>0 then dd.mul=v setfg=true if likefm then self.value=v+1.0 else self.value=v end break end elseif mode==2 then k,v = self:chkBar(x,d.by,d.w,d.h,mx,my,ml,mm,mr) if k>0 then dd.sft=180*v; self.value=dd.sft; setfg=true; break end elseif mode==3 then k,v = self:chkBar(x,d.by,d.w,d.h,mx,my,ml,mm,mr) if k<=0 then self.kindsts[i]=false else if not self.kindsts[i] then self.kindsts[i]=true dd.kind=(dd.kind+1)%4; setfg=true; break end end end end end end return setfg end Freq.drawBar=function(self,x,y,w,h,v) rect(x,y,w-1,h,7) local hh=(h-1)/2 local ly=y+hh local vy=y+hh-hh*v line(x,ly,x+w-2,ly,8) line(x,vy,x+w-2,vy,15) end Freq.drawWaveKind=function(self,bx,by,w) if likefm then return end for i,dd in ipairs(freqtbl) do local x=bx+w*(i-1) spr(32+dd.kind,x,by,0,1,0,0,1,1) end end Freq.drawFreqBar=function(self,bx,by,w,h) local l=(likefm==true) and 5 or (#freqtbl) for i=1,l do local dd=freqtbl[i] local x=bx+w*(i-1) self:drawBar(x,by,w,h,dd.mul) end end Freq.drawSftBar=function(self,bx,by,w,h) local l=(likefm==true) and 3 or (#freqtbl) for i=1,l do local dd=freqtbl[i] local x=bx+w*(i-1) self:drawBar(x,by,w,h,dd.sft/180) end end Freq.draw=function(self) for mode,d in ipairs(self.tbl) do if mode==1 then self:drawFreqBar(d.bx,d.by,d.w,d.h) elseif mode==2 then self:drawSftBar(d.bx,d.by,d.w,d.h) elseif mode==3 then self:drawWaveKind(d.bx,d.by,d.w) elseif mode==4 then self:drawBar(d.bx,d.by,d.w,d.h,vol-1.0) end end local s="Value:"..string.format("%.3f",self.value) local sw=print(s,0,-6) print(s,240-sw,136-6) end SyncDispObj={} SyncDispObj.new=function() local o={step=0,t=0,y=136,str="SFX Sync"} return setmetatable(o,{__index=SyncDispObj}) end SyncDispObj.update=function(self) local ct=15 if self.step==0 then return end if self.step==1 then self.y=136-8*(self.t/ct) if self.t>=ct then self.t=0; self.step=self.step+1 end elseif self.step==2 then if self.t>=60 then self.t=0; self.step=self.step+1 end elseif self.step==3 then self.y=136-8+8*(self.t/ct) if self.t>=ct then self.t=0; self.step=self.step+1 end elseif self.step==4 then self.y=136 self.t=0; self.step=0 end self.t=self.t+1 end SyncDispObj.draw=function(self) if self.step==0 then return end rect(0,self.y,240,8,6) local w=print(self.str,0,-6,15,true) print(self.str,(240-w)/2,self.y+1,15,true) end SyncDispObj.display=function(self,_str) self.step=1 self.t=0 self.str=_str end function setMakeMode() if waveid<4 then syncdisp:display("WAVE ID 0-3 can not be changed") else mode=1; setwave=true end end syncdisp=SyncDispObj.new() btn=Button.new() freq=Freq.new() function TIC() setwave=false local r = btn:update() if r==0 then waveid=(waveid-1) % 16; mode=0 elseif r==1 then waveid=(waveid+1) % 16; mode=0 elseif r==2 then mode=0 elseif r==3 then setMakeMode() elseif r==4 then playing=true; t=0 elseif r==5 then playing=false elseif r==6 then -- write to cart sync(1<<3,0,true) syncdisp:display("Sync SFX") elseif r==7 then -- reset freqtbl resetFreqtbl() setMakeMode() elseif r==8 then oct=((oct-1-1)%8)+1 elseif r==9 then oct=((oct-1+1)%8)+1 elseif r==10 then adjust_enable = not adjust_enable; setwave=true elseif r==11 then maxi = not maxi elseif r==12 then likefm = not likefm; setwave=true elseif r==13 then fr_synth = not fr_synth; setwave=true end if freq:update() then if mode==0 then setMakeMode() else setwave=true end end if setwave and waveid >=4 then writeWave(waveid,makeWave()) end if t%60==0 and playing then sfx(waveid,"A-"..oct,45,0) end syncdisp:update() cls(0) freq:draw() btn:draw() drawWave(waveid) local s="" s=s.."WAVE ID: "..string.format("%02d",waveid) print(s,0,0,15,true) print("OCT",0,6*13-2) print(oct,6,6*14,15,true) syncdisp:draw() t=t+1 end