479 lines
9.7 KiB
Plaintext
479 lines
9.7 KiB
Plaintext
_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 " <q> to <r>"
|
|
|
|
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"
|