Tweaking audio
This commit is contained in:
parent
f1873abed7
commit
c5407266eb
|
@ -0,0 +1,111 @@
|
|||
local love = love
|
||||
local passChimes = {}
|
||||
local failChimes = {}
|
||||
local drones = {}
|
||||
local N = 8
|
||||
|
||||
local function StartDrones()
|
||||
love.audio.setEffect( "droneReverb", {
|
||||
type = "reverb",
|
||||
volume = 1.0, }
|
||||
|
||||
)
|
||||
|
||||
drones.bass = love.audio.newSource("sounds/drone.flac", "stream")
|
||||
drones.alto = love.audio.newSource("sounds/drone.flac", "stream")
|
||||
drones.bass:setVolume( 0 )
|
||||
drones.bass:setPitch( 0.25 )
|
||||
drones.alto:setVolume( 0 )
|
||||
drones.bass:setPitch( 0.5 )
|
||||
drones.bass:setEffect( "droneReverb", true )
|
||||
|
||||
love.audio.play( drones.bass )
|
||||
love.audio.play( drones.alto )
|
||||
end
|
||||
|
||||
love.audio.setEffect( "passChimeReverb", {
|
||||
type = "reverb",
|
||||
volume = 1.0, } )
|
||||
|
||||
local passChime = love.audio.newSource("sounds/chimeb.flac", "static")
|
||||
passChime:setEffect( "passChimeReverb", true )
|
||||
local failChime = love.audio.newSource("sounds/chime.flac", "static")
|
||||
failChime:setEffect( "passChimeReverb", true )
|
||||
|
||||
for i = 1, N do
|
||||
passChimes[i] = passChime:clone()
|
||||
failChimes[i] = failChime:clone()
|
||||
end
|
||||
|
||||
local idxNextPassChime = 1
|
||||
local idxNextFailChime = 1
|
||||
local function GetNextPassChime( pass )
|
||||
idxNextPassChime = idxNextPassChime % N + 1
|
||||
return passChimes[ idxNextPassChime ]
|
||||
end
|
||||
|
||||
local function GetNextFailChime( pass )
|
||||
idxNextFailChime = idxNextFailChime % N + 1
|
||||
return failChimes[ idxNextFailChime ]
|
||||
end
|
||||
|
||||
local pitches =
|
||||
{
|
||||
1,
|
||||
2/3,
|
||||
3/2,
|
||||
9/8,
|
||||
27/16,
|
||||
81/64,
|
||||
243/128,
|
||||
2 --Safety
|
||||
}
|
||||
|
||||
local function GetPitch( th )
|
||||
th = 0.5 + 0.5 * th / math.pi
|
||||
return pitches[ 1 + math.floor( th * 7 )]
|
||||
end
|
||||
|
||||
local function OnImpact( impact, score, pass, level )
|
||||
|
||||
--
|
||||
if not pass then
|
||||
--drones.bass:seek( level )
|
||||
-- drones.alto:seek( level )
|
||||
end
|
||||
|
||||
local th = impact.th
|
||||
local r = impact.r
|
||||
|
||||
-- Chimes
|
||||
local chime = pass and GetNextPassChime() or GetNextFailChime()
|
||||
chime:setPitch( GetPitch( th ) )
|
||||
chime:setPosition( r * math.cos( th ), r * math.sin( th ) )
|
||||
local highgain = math.max( 0, math.min( score, 1.0 ) - (pass and 0.0 or 0.5))
|
||||
chime:setFilter{
|
||||
type = "lowpass",
|
||||
volume = 0.5 * impact.speed,
|
||||
highgain = highgain,
|
||||
}
|
||||
love.audio.stop( chime )
|
||||
love.audio.play( chime )
|
||||
|
||||
end
|
||||
|
||||
--score is the hypothetical "beat score" that would be attained
|
||||
--if an impact took place at this instant.
|
||||
local function Update( score )
|
||||
drones.bass:setVolume( 0.5 * math.sqrt( score ) )
|
||||
--drones.alto:setVolume( 0.3 * score )
|
||||
end
|
||||
|
||||
local function Reset( )
|
||||
for i = 1, N do
|
||||
love.audio.stop( passChimes[i] )
|
||||
love.audio.stop( failChimes[i] )
|
||||
end
|
||||
StartDrones()
|
||||
end
|
||||
|
||||
Reset()
|
||||
return { OnImpact = OnImpact, Update = Update, Reset = Reset}
|
133
main.lua
133
main.lua
|
@ -4,12 +4,12 @@ local sitelenpona
|
|||
local text
|
||||
local marble
|
||||
local wave
|
||||
local particles
|
||||
local audio
|
||||
local recorder
|
||||
local DetectCollision
|
||||
|
||||
local sounds = {
|
||||
|
||||
|
||||
}
|
||||
local OnImpact
|
||||
local OnVictory
|
||||
|
||||
|
||||
local state
|
||||
|
@ -52,17 +52,52 @@ function love.load()
|
|||
|
||||
love.graphics.setBackgroundColor( 245 / 255, 169 / 255, 184 / 255 ) --Trans pink.
|
||||
--love.graphics.setBackgroundColor( 91 / 255, 206 / 255, 250 / 255 ) --Trans blue.
|
||||
sounds.goodPing = love.audio.newSource("sounds/soundTest.ogg", "static")
|
||||
sounds.badPing = love.audio.newSource("sounds/chime8.ogg", "static")
|
||||
|
||||
do--particle system setup
|
||||
particles = love.graphics.newParticleSystem(
|
||||
love.graphics.newImage( "prideflag.png" ),
|
||||
1024)
|
||||
|
||||
particles:setSizes( 0.00015, 0.0001, 0.00018 )
|
||||
particles:setSizeVariation( 1 )
|
||||
particles:setRadialAcceleration( 0, 0.5 )
|
||||
particles:setSpeed( 0.2, 1 )
|
||||
particles:setLinearDamping( 1, 10 )
|
||||
particles:setRelativeRotation( true )
|
||||
particles:setEmitterLifetime( -1 )
|
||||
particles:setParticleLifetime( 0, 15 )
|
||||
particles:setSpread( 0.05 )
|
||||
particles:setColors(
|
||||
1, 1, 1, 1,
|
||||
91 / 255, 206 / 255, 250 / 255, 1,
|
||||
245 / 255, 169 / 255, 184 / 255, 1,
|
||||
1,1,1,0
|
||||
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
sitelenpona = assert( require "sitelenpona" )
|
||||
text = assert( require "text" )
|
||||
marble = assert( require "marble" )
|
||||
wave = assert( require "wave" )
|
||||
DetectCollision = assert ( require "collision" )
|
||||
audio = assert( require "audio" )
|
||||
recorder = assert( require "recorder" )
|
||||
return state.Reset()
|
||||
|
||||
end
|
||||
|
||||
local function ExtrapolateBeatScore( )
|
||||
local t = love.timer.getTime()
|
||||
local beat = state.beat
|
||||
if not beat.t then return 2.0 end
|
||||
if not beat.mu then return 2.0 end
|
||||
if beat.mu < 0.001 then return 2.0 end
|
||||
|
||||
t = 1.1 * math.sin( math.pi * ( t - beat.t ) / beat.mu )
|
||||
return t * t * t * t
|
||||
end
|
||||
|
||||
local function BeatScore( t )
|
||||
local beat = state.beat
|
||||
|
@ -82,63 +117,61 @@ local function BeatScore( t )
|
|||
return 2.0
|
||||
end
|
||||
|
||||
local score = 1.1 * math.sin( math.pi * dt / beat.mu )
|
||||
score = score * score * score * score
|
||||
|
||||
--General case: update average beat length.
|
||||
local WEIGHT = 0.25 --High number makes the last beat more significant.
|
||||
if dt > 0.2 then
|
||||
|
||||
local WEIGHT = 0.85 --High number makes the last beat more significant.
|
||||
local mu = ( 1.0 - WEIGHT ) * beat.mu + WEIGHT * dt
|
||||
beat.mu = mu
|
||||
|
||||
--Safety: avoid a dbz.
|
||||
if mu < 0.001 or dt < 0.001 then
|
||||
return 0.0
|
||||
--error( "DBZ! Beat length too small." )
|
||||
end
|
||||
|
||||
--Calculate beat score.
|
||||
local score = dt * dt / ( mu * mu )
|
||||
local TOLERANCE = 1.04
|
||||
if dt < mu then
|
||||
return TOLERANCE * score
|
||||
else
|
||||
return TOLERANCE / score
|
||||
end
|
||||
|
||||
return score
|
||||
end
|
||||
|
||||
local function OnVictory()
|
||||
|
||||
end
|
||||
|
||||
local function OnImpact( impact )
|
||||
OnImpact = function( impact )
|
||||
if not impact then return end
|
||||
local score = BeatScore( impact.t )
|
||||
--DEBUG
|
||||
state.lastBeatScore = score
|
||||
local pass = false
|
||||
|
||||
local sound
|
||||
if score > state.beatScoreThreshold then
|
||||
sound = sounds.goodPing
|
||||
if score > 1.0 then
|
||||
|
||||
state.beatScoreThreshold = 1.0
|
||||
pass = true
|
||||
state.currentBeat = state.currentBeat + 1
|
||||
if state.currentBeat >= 120 then
|
||||
return OnVictory()
|
||||
end
|
||||
|
||||
|
||||
else
|
||||
|
||||
sound = sounds.badPing
|
||||
state.beatScoreThreshold = state.beatScoreThreshold - 0.05
|
||||
|
||||
end
|
||||
|
||||
love.audio.play( sound )
|
||||
|
||||
local x, y = math.cos(impact.th), math.sin(impact.th)
|
||||
particles:setPosition( impact.r * x, impact.r * y )
|
||||
particles:setEmissionArea( "normal", 0.1, 0.2, impact.th, true )
|
||||
particles:emit( 50 * score * score )
|
||||
|
||||
audio.OnImpact( impact, score, pass, state.currentBeat )
|
||||
marble.OnImpact( impact )
|
||||
wave.OnImpact( impact )
|
||||
end
|
||||
local _OnImpact = OnImpact
|
||||
|
||||
|
||||
local function NewGame()
|
||||
OnImpact = _OnImpact
|
||||
state.Reset()
|
||||
marble.Reset()
|
||||
wave.Reset()
|
||||
end
|
||||
|
||||
|
||||
OnVictory = function()
|
||||
OnImpact = function() end
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
|
||||
|
@ -149,13 +182,19 @@ function love.draw()
|
|||
love.graphics.print( state.beatScoreThreshold, 0, 20)
|
||||
love.graphics.print( state.lastBeatScore, 0, 30 )]]
|
||||
|
||||
|
||||
local score = ExtrapolateBeatScore()
|
||||
|
||||
love.graphics.push( "transform" )
|
||||
love.graphics.applyTransform( transform )
|
||||
wave.Draw()
|
||||
|
||||
if debugRenderImpact then
|
||||
|
||||
|
||||
wave.Draw( score )
|
||||
|
||||
love.graphics.setColor( 1.0, 1.0, 1.0, 1.0 )
|
||||
love.graphics.draw(particles, 0, 0)
|
||||
|
||||
--[[if debugRenderImpact then
|
||||
|
||||
love.graphics.setLineWidth( 0.01 )
|
||||
love.graphics.setColor( 1, 0, 0, 0.5 ) --Red: Incoming
|
||||
|
@ -177,7 +216,7 @@ function love.draw()
|
|||
debugRenderImpact.vxout,
|
||||
debugRenderImpact.vyout)
|
||||
|
||||
end
|
||||
end]]
|
||||
|
||||
love.graphics.pop()
|
||||
|
||||
|
@ -191,8 +230,15 @@ end
|
|||
|
||||
|
||||
function love.update( dt )
|
||||
|
||||
audio.Update( ExtrapolateBeatScore() )
|
||||
particles:update( dt )
|
||||
dt = dt + state.timeToSimulate
|
||||
|
||||
--Physics tick.
|
||||
while dt > step do
|
||||
recorder.Update( marble.GetAcceleration() ) --For savegames.
|
||||
|
||||
marble.Integrate( step )
|
||||
wave.Integrate( step )
|
||||
|
||||
|
@ -211,7 +257,8 @@ end
|
|||
|
||||
function love.keypressed( key, code, isRepeat )
|
||||
if key == "escape" then return love.event.quit() end
|
||||
if key == "return" then return OnImpact{ t = love.timer.getTime() } end
|
||||
if key == "return" then return OnVictory() end
|
||||
if key == "space" then return NewGame() end
|
||||
return marble.OnKey()
|
||||
end
|
||||
|
||||
|
|
15
marble.lua
15
marble.lua
|
@ -4,14 +4,18 @@ local oldBuffer = love.graphics.newCanvas()
|
|||
local newBuffer = love.graphics.newCanvas()
|
||||
local oldState, curState, newState
|
||||
|
||||
local FRICTION = 0.01
|
||||
local MAXSPEED = 5.0
|
||||
local FRICTION = 0.05
|
||||
local MAXSPEED = 4
|
||||
local ddx, ddy = 0.0, 0.0
|
||||
|
||||
local function State( )
|
||||
return { t = 0, x = 0, y = 0, dx = 0, dy = 0 }
|
||||
end
|
||||
|
||||
local function GetAcceleration( )
|
||||
return ddx, ddy
|
||||
end
|
||||
|
||||
local function Current() return curState end
|
||||
local function Next() return newState end
|
||||
|
||||
|
@ -60,13 +64,13 @@ local function OnImpact( impact )
|
|||
inward * (- math.sin(impact.th) ) - (1.0 - inward) * ( x * s + vy * c )
|
||||
|
||||
curState.x, curState.y = x, y
|
||||
curState.dx, curState.dy = 0.5 * vxout, 0.5 * vyout
|
||||
curState.dx, curState.dy = vxout, vyout
|
||||
|
||||
debugRenderImpact = { xi = x, yi = y, xf = x - vx, yf = y - vy,
|
||||
xn = 0.2 * unx + x, yn = 0.2 * uny + y,
|
||||
vxout = x + vxout, vyout = y + vyout}
|
||||
|
||||
return Integrate( math.max( impact.dt , 1 / 60 ) ) --Hmm! Maybe this should be a fixed step instead for stability's sake.
|
||||
return Integrate( math.max( impact.dt , 1 / 120 ) ) --Hmm! Maybe this should be a fixed step instead for stability's sake.
|
||||
end
|
||||
|
||||
local function Update()
|
||||
|
@ -120,7 +124,7 @@ local function Draw()
|
|||
love.graphics.draw( newBuffer )
|
||||
love.graphics.setColor( 1, 1, 1, 1.0 ) --White.
|
||||
love.graphics.setLineWidth( 1.0 )
|
||||
love.graphics.circle( "line", xn, yn, 4 )
|
||||
--love.graphics.circle( "line", xn, yn, 4 )
|
||||
|
||||
oldBuffer, newBuffer = newBuffer, oldBuffer
|
||||
|
||||
|
@ -159,4 +163,5 @@ return {
|
|||
Resize = Resize,
|
||||
Current = Current,
|
||||
Next = Next,
|
||||
GetAcceleration = GetAcceleration,
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,32 @@
|
|||
--Record demos.
|
||||
local love = love
|
||||
local recorder = {}
|
||||
recorder.isLoaded = false
|
||||
local i = 0
|
||||
|
||||
local function Reset()
|
||||
i = 0
|
||||
end
|
||||
|
||||
function recorder.Update( ddx, ddy )
|
||||
local byte = 0
|
||||
if ddx > 0.5 then byte = byte + 1 end
|
||||
if ddy > 0.5 then byte = byte + 2 end
|
||||
if ddx < -0.5 then byte = byte + 4 end
|
||||
if ddy < -0.5 then byte = byte + 8 end
|
||||
|
||||
i = i + 1
|
||||
recorder[i] = string.char( byte )
|
||||
end
|
||||
|
||||
function recorder.Load( )
|
||||
local s = love.filesystem.read( "demo" )
|
||||
|
||||
recorder.isLoaded = true
|
||||
end
|
||||
|
||||
function recorder.Save( )
|
||||
assert( love.filesystem.write( "demo", table.concat( recorder ) ) )
|
||||
end
|
||||
|
||||
return recorder
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
20
wave.lua
20
wave.lua
|
@ -2,7 +2,7 @@
|
|||
local love = love
|
||||
local N = 33
|
||||
local SOUNDSPEED = 0.5
|
||||
local IMPULSESIZE = 20
|
||||
local IMPULSESIZE = 5
|
||||
local DAMPING = 0.01
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ local shader = love.graphics.newShader([[
|
|||
|
||||
uniform float re[33];
|
||||
uniform float im[33];
|
||||
uniform float score;
|
||||
|
||||
//Slow IDFT
|
||||
float r( float x )
|
||||
|
@ -47,7 +48,7 @@ local shader = love.graphics.newShader([[
|
|||
|
||||
float r = r( atan(p.y, p.x) ) - length( p );
|
||||
|
||||
return vec4(color.x, color.y, color.z, (r > -0.01)) ;
|
||||
return vec4( (1.0 + float(score > 1.0) * r * 0.1) * color.xyz, float(r > -0.01)) ;
|
||||
}
|
||||
]])
|
||||
|
||||
|
@ -175,8 +176,6 @@ local function Wave( )
|
|||
local t = {
|
||||
--radii[k] = radius of point on curve at angle (k - 1) / N
|
||||
radii = {},
|
||||
--TIME derivative of radius
|
||||
vrad = {},
|
||||
|
||||
--SPACE DFT of radius function (which is periodic)
|
||||
dftre = {},
|
||||
|
@ -184,21 +183,21 @@ local function Wave( )
|
|||
}
|
||||
|
||||
for i = 1, N do
|
||||
t.radii[i] = 1.0 + 0.05 * ( i/N + math.sin( i * 2.0 * math.pi / N ))
|
||||
t.vrad[i] = 0.0
|
||||
t.radii[i] = 1.0
|
||||
end
|
||||
DFT( t )
|
||||
|
||||
return setmetatable(t, mt)
|
||||
end
|
||||
|
||||
local function Draw()
|
||||
local function Draw( score )
|
||||
|
||||
-- Blue circle.
|
||||
love.graphics.setColor( 91 / 255, 206 / 255, 250 / 255 )
|
||||
|
||||
shader:send( "re", unpack( cur.dftre ) )
|
||||
shader:send( "im", unpack( cur.dftim ) )
|
||||
shader:send( "score", score )
|
||||
love.graphics.setShader( shader )
|
||||
love.graphics.circle("fill", 0, 0, 1.5)
|
||||
local t = love.timer.getTime()
|
||||
|
@ -253,7 +252,7 @@ local function Draw()
|
|||
end
|
||||
|
||||
|
||||
local function Update()
|
||||
local function Update( )
|
||||
|
||||
--Deep copy of current state to old state.
|
||||
for name, t in pairs( cur ) do
|
||||
|
@ -290,6 +289,11 @@ local function DetectCollision( px, py, vpx, vpy )
|
|||
end
|
||||
|
||||
local function Reset()
|
||||
|
||||
SOUNDSPEED = 0.5
|
||||
IMPULSESIZE = 5
|
||||
DAMPING = 0.02
|
||||
|
||||
old = Wave()
|
||||
cur = Wave()
|
||||
new = Wave()
|
||||
|
|
Loading…
Reference in New Issue