_runtimePath_ "../runtime" _runtimeStart_ &h7FFF _arraysStart_ &h7FFF const X_POS = 34 const Y_POS = 46 const VU_LEVELS = 64 'frequency sweep const F_LUT=&h0500 def word(F_LUT, y, 0.0, 360.0, 256) = sin(y)*2000.0 + 5000.0 'volume sweep const V_LUT=&h08A0 const V_SIZ=64 def byte(V_LUT, y, 0.0, 360.0, V_SIZ) = 63.0 - (cos(y)*0.5 + 0.5)*55.0 'extinction function, (modelled in Desmos), used to control attack and decay for crash sound 'don't use variable names that clash with functions, i.e. 'x' and 'exp' const D_LUT=&h09A0 const D_SIZ=64 def byte(D_LUT, y, 0.0, 0.5, D_SIZ) = 63.0 - exp(-y)*(1.0-exp(-2.0*y))*2.5*58.0 const T_LUT=&h09E0 const T_SIZ=8 def byte(T_LUT, y, 0.0, 3.0, T_SIZ) = 63.0 - 1.398*exp(-y)*(1.0-exp(-10.0*y))*63.0 _spriteStripeChunks_ 32, &h0400, ascending load sprite, ../../res/image/VUerase.tga, 0 load sprite, ../../res/image/VUdraw.tga, 1, FlipY t = 0 : f = t : v = 0 'audio fix for ROMv5a poke &h21, peek(&h21) OR 3 sound off set FGBG_COLOUR, &h3C00 cls mode 2 at 33,2 : print "Keys: <1> to <0>" at 33 : print " to " dim volume%(4) = 127 dim ypos%(4) = 1 kk = 255 state = 0 init midiv loop: 'wait set SOUND_TIMER, 2 gosub vuMeter k = get("SERIAL_RAW") if kk &&= 255 then gosub k gosub state kk = k goto &loop midiOff: set MIDI_STREAM, &h0000 sound off return 1: gosub siren return 2: gosub crash return 3: gosub beep return 4: gosub tictoc return 5: gosub pucDeath return 6: gosub ghostMove return 7: gosub invaderMove return 8: gosub invaderShoot return 9: gosub saucerMove return 10: gosub invaderExplode return 11: gosub testSfx return 12: gosub saucerExplode return 13: gosub playerExplode return 14: if get("MIDI_STREAM") &= &h0000 play midiv, &h0AA0, 2 else tick midiv endif return 48: state = 14 return 49: t = 0 state = 1 gosub midiOff return 50: t = 0 state = 2 gosub midiOff return 51: t = 0 state = 3 gosub midiOff return 52: t = 0 state = 4 gosub midiOff return 53: t = 0 state = 5 gosub midiOff return 54: t = 0 state = 6 gosub midiOff return 55: t = 0 f = 0 vv = 63 state = 7 gosub midiOff return 56: t = 0 state = 8 gosub midiOff return 57: t = 0 f = 0 vv = 63 state = 9 gosub midiOff return 113:t = 0 f = 0 vv = 63 state = 10 gosub midiOff return 119:t = 0 f = 0 vv = 63 state = 11 gosub midiOff return 101:t = 0 f = 0 vv = 60 state = 12 gosub midiOff return 114:t = 0 f = 0 vv = 63 state = 13 gosub midiOff return vuMeter: for i=1 to 4 i8 = i LSL 8 v = peek(i8 + &h00FA) vol = volume(i) y = ypos(i) if v &>= VU_LEVELS i4 = (i LSL 4) + X_POS if deek(i8 + &h00FC) &= 0 then goto decay 'if frequency is 0, (i.e. note off), then decay if v &< vol y = ((VU_LEVELS-1) - (v - VU_LEVELS)) LSR 1 'transform 127->64 to 0->63 vol = v else decay: dec y inc vol if y &< 1 inc y dec vol endif endif 'erase led sprite noFlip, 0, i4, (Y_POS + 32) - (y + 1) 'adjust height of led bar lut = (y LSL 2) + y + y + get("SPRITE_LUT", 1) save = peek(lut) poke lut, -1 sprite flipY, 1, i4, Y_POS sprite flipY, 1, i4 + 6, Y_POS poke lut, save endif volume(i) = vol ypos(i) = y next i return siren: v_lut = peek(V_LUT + (t AND (V_SIZ - 1))) f_lut = deek(F_LUT + (t LSL 1)) sound on, 1, f_lut , v_lut, 2 sound on, 2, f_lut+100, v_lut, 2 sound on, 3, f_lut+200, v_lut, 2 sound on, 4, f_lut+300, v_lut, 2 inc t if t &= 64 t = 0 state = 0 sound off endif return crash: d_lut = peek(D_LUT + (t AND (D_SIZ - 1))) f_lut = deek(F_LUT + ((t AND 1) LSL 1)) sound on, 1, f_lut , d_lut, 0 sound on, 2, f_lut+100, d_lut, 0 sound on, 3, f_lut+200, d_lut, 0 sound on, 4, f_lut+300, d_lut, 0 inc t if t &= 64 t = 0 state = 0 sound off endif return beep: sound on, 1, 8000, 63, 1 inc t if t &= 3 t = 0 state = 0 sound off endif return tictoc: t_lut = peek(T_LUT + (t AND (T_SIZ - 1))) sound on, 1, t_lut LSL 4, t_lut, 0 inc t if t &= T_SIZ-2 t = 0 state = 0 sound off endif return dim pnotes%(15) = 74, 72, 71, 69, 67, 65, 64, 62, 60, 62, 64, 65, 67, 69, 71, 72 def byte(&h0701, x, 0.0, 1.0, 64, 4) = sin(pow(x + 1.8, 3.13)*57.2957795)*31.0 + 32.0 'def byte(&h0701, y, 0.0, 1.0, 64, 4) = (sin(pow(y + 1.8, 3.13)*57.2957795)*exp(-1.5*y)*1.2)*31.0 + 32.0 'def byte(&h0701, y, 0.0, 1.0, 64, 4) = sin(pow(y + 1.8, 3.13)*57.2957795)*(1-y)*31.0 + 32.0 pucDeath: n = get("MIDI_NOTE", peek(@pnotes + (t AND 15))) sound on, 1, n - f, 63 - (t LSR 2), 1 inc t if (t AND 7) &= 0 f = f + 200 endif if t &= 128 t = 0 f = 0 state = 0 sound off endif return dim gnotes%(15) = 60, 62, 64, 65, 67, 69, 71, 72, 74, 72, 71, 69, 67, 65, 64, 62 ghostMove: n = get("MIDI_NOTE", peek(@gnotes + (t AND 15)) + 10) sound on, 1, n, 63, 2 inc t if t &= 128 t = 0 state = 0 sound off endif return 'overwrite waveform 0 in audio memory, (invader move) 'load wave, ../../res/audio/Invader/IMove.gtwav, &h0702, 4 dim inotes%(3) = 40, 38, 36, 34 vv = 0 invaderMove: n = get("MIDI_NOTE", peek(@inotes + (f AND 3))) sound on, 1, n, vv, 3 inc t if t &= 25 t = 0 vv = 63 inc f if f &= 4 f = 0 state = 0 sound off endif elseif t &= 4 vv = 0 endif return const I_LUT=&h6EA0 const IF_LUT=&h6DA0 const I_SIZ=32 'def word(I_LUT, y, 0.0, 1.0, I_SIZ) = (10.0*exp(-15.0*y)*(1.0-exp(-9.75*(y-0.015)))*0.343 + 0.25)*25000.0 def byte(I_LUT, y, 0.0, 1.0, I_SIZ) = exp(-5.0*pow(y, 3.0))*32.0 'def byte(I_LUT, y, 0.0, 10.0, I_SIZ) = exp(-0.2*y)*(sin(15.0*y/6.28*360.0)*0.25 + 0.75)*32.0 def word(IF_LUT, y, 0.0, 1.0, I_SIZ) = exp(-3.0*y)*6000.0 + 14000.0 invaderShootOld: ff = max(25000 - f, 13000) sound on, 1, ff, vv, 2 'sound on, 1, deek(I_LUT + (t AND 31)), vv, 2 inc t vv = vv - 2 if vv &<= 0 t = 0 vv = 63 state = 0 sound off endif return invaderShoot: ff = deek(IF_LUT + ((t AND 31) LSL 1)) vvv = peek(I_LUT + (t AND 31)) sound on, 1, ff, vvv, 3 sound on, 2, ff, vvv, 0 inc t if t &= 32 t = 0 state = 0 sound off endif return const SF_LUT=&h6CA0 const SF_SIZ=12 'def word(SF_LUT, y, 0.0, 360.0, SF_SIZ) = (sin(y)*0.5 + 0.5) * 5000.0 'def word(SF_LUT, y, 0.5, 1.5, SF_SIZ) = sin(exp(-pow(4.0*y - 4.0, 2.0))/6.28*360) * 5000.0 'def word(SF_LUT, y, 0.0, 180.0, SF_SIZ) = sin(y) * sin(y) * 2121.0 + 2121.0 def word(SF_LUT, y, 0.0, SF_SIZ, SF_SIZ) = (y % (SF_SIZ/2)) * 300.0 + 3000.0 'def word(SF_LUT, y, 0.0, 360, SF_SIZ) = (asin(cos(y))/90.0*0.5 + 0.5) * 300.0 + 3000.0 'def byte(&h0702, x, 0.0, 360.0, 64, 4) = sin(x)*31.0 + 32.0 saucerMove: ff = deek(SF_LUT + (t LSL 1)) sound on, 1, ff, 32, 2 inc t if t &= SF_SIZ t = 0 endif return const IE_LUT=&h6BA0 const IE_SIZ=3 'def word(IE_LUT, y, 0.0, 1.0, IE_SIZ) = exp(-3.0*y)*5000.0 'def word(IE_LUT, y, 0.0, 720.0, IE_SIZ) = sin(y) * sin(y) * 1000.0 + 500 'def word(IE_LUT, y, 0.0, 360, IE_SIZ) = (asin(cos(y))/90.0*0.5 + 0.5) * 3000.0 + 3000.0 def word(IE_LUT, y, 0.0, IE_SIZ, IE_SIZ) = 6000.0*(1 - exp(-0.5*y)) 'def byte(&h0702, x, 0.0, 720.0, 64, 4) = sin(x)*31.0 + 32.0 invaderExplode: sound on, 1, deek(IE_LUT + (t LSL 1)), vv, 2 inc t if t &= IE_SIZ then t = 0 vv = vv - 2 if vv &<= 0 t = 0 vv = 60 state = 0 sound off endif return testSfx: ff = 16384 - (vv LSL 8) + f sound on, 1, ff, vv, 2 inc t vv = vv - 8 if vv &<= 0 t = 0 vv = 63 f = f + 1000 if f &= 4000 f = 0 state = 0 sound off endif endif return const SEF_LUT=&h69A0 const SEF_SIZ=12 'def word(SEF_LUT, y, 0.0, 180.0, SEF_SIZ) = sin(y) * sin(y) * 2121.0 + 2121.0 def word(SEF_LUT, y, 0.0, SEF_SIZ, SEF_SIZ) = (y % (SEF_SIZ/2)) * 300.0 + 3000.0 saucerExplode: m = min(vv + 10, 63) ff = deek(SEF_LUT + (t LSL 1)) - f sound on, 1, ff, vv, 2 sound on, 2, ff LSR 4, vv, 0 inc t if t &= SEF_SIZ t = 0 f = f + 600 vv = vv - 15 if vv &<= 0 f = 0 vv = 60 state = 0 sound off endif endif return const PEF_LUT=&h6AA0 const PEF_SIZ=32 'def word(PEF_LUT, y, 0.0, 180.0, PEF_SIZ) = sin(y) * sin(y) * 2121.0 + 2121.0 'def word(PEF_LUT, y, 0.0, PEF_SIZ, PEF_SIZ) = (y % (PEF_SIZ/2)) * 300.0 + 3000.0 'def word(PEF_LUT, y, 0.0, 360, PEF_SIZ) = (asin(cos(y))/90.0*0.5 + 0.5) * 300.0 + 300.0 'def word(PEF_LUT, y, 0.0, PEF_SIZ, PEF_SIZ) = 900.0*(exp(-1.125*y)) + 300.0 def word(PEF_LUT, 0.0, PEF_SIZ, PEF_SIZ) = rand(PEF_SIZ) / PEF_SIZ * 300.0 playerExplode: f = deek(PEF_LUT + (t LSL 1)) sound on, 1, f, vv, 0 sound on, 2, f, vv, 0 sound on, 3, f, vv, 0 sound on, 4, f, vv, 0 inc t if t &= PEF_SIZ then t = 0 vv = vv - 1 if vv &<= 0 t = 0 vv = 60 state = 0 sound off endif return module "MidiFx.i"