From 64a5f76daf90ff041bde00b66307e386f3da280d Mon Sep 17 00:00:00 2001 From: GuglioIsStupid Date: Mon, 6 May 2024 16:12:06 -0400 Subject: [PATCH] ABOT Viz --- src/love/images/png/weekend1/aBotViz.png | Bin 0 -> 16006 bytes src/love/lib/fft/complex.lua | 385 +++++++++++++++++++++++ src/love/lib/fft/ffthread.lua | 24 ++ src/love/lib/fft/lovefft.lua | 105 +++++++ src/love/lib/fft/luafft.lua | 360 +++++++++++++++++++++ src/love/main.lua | 3 + src/love/modules/util.lua | 16 +- src/love/sprites/weekend1/abotViz.lua | 106 +++++++ src/love/stages/streets.lua | 46 +++ src/love/weeks/weekend1.lua | 12 +- 10 files changed, 1053 insertions(+), 4 deletions(-) create mode 100644 src/love/images/png/weekend1/aBotViz.png create mode 100644 src/love/lib/fft/complex.lua create mode 100644 src/love/lib/fft/ffthread.lua create mode 100644 src/love/lib/fft/lovefft.lua create mode 100644 src/love/lib/fft/luafft.lua create mode 100644 src/love/sprites/weekend1/abotViz.lua diff --git a/src/love/images/png/weekend1/aBotViz.png b/src/love/images/png/weekend1/aBotViz.png new file mode 100644 index 0000000000000000000000000000000000000000..046333ef756ce1128e7fb6e3744db7ebcd02f65c GIT binary patch literal 16006 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 z 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 JWj8FI{2x%Gk<$PG literal 0 HcmV?d00001 diff --git a/src/love/lib/fft/complex.lua b/src/love/lib/fft/complex.lua new file mode 100644 index 00000000..ee287a28 --- /dev/null +++ b/src/love/lib/fft/complex.lua @@ -0,0 +1,385 @@ +-- complex 0.3.0 +-- Lua 5.1 + +-- 'complex' provides common tasks with complex numbers + +-- function complex.to( arg ); complex( arg ) +-- returns a complex number on success, nil on failure +-- arg := number or { number,number } or ( "(-)" and/or "(+/-)i" ) +-- e.g. 5; {2,3}; "2", "2+i", "-2i", "2^2*3+1/3i" +-- note: 'i' is always in the numerator, spaces are not allowed + +-- a complex number is defined as carthesic complex number +-- complex number := { real_part, imaginary_part } +-- this gives fast access to both parts of the number for calculation +-- the access is faster than in a hash table +-- the metatable is just a add on, when it comes to speed, one is faster using a direct function call + +-- http://luaforge.net/projects/LuaMatrix +-- http://lua-users.org/wiki/ComplexNumbers + +-- Licensed under the same terms as Lua itself. + +--/////////////-- +--// complex //-- +--/////////////-- + +-- link to complex table +local complex = {} + +-- link to complex metatable +local complex_meta = {} + +-- complex.to( arg ) +-- return a complex number on success +-- return nil on failure +local _retone = function() return 1 end +local _retminusone = function() return -1 end +function complex.to( num ) + -- check for table type + if type( num ) == "table" then + -- check for a complex number + if getmetatable( num ) == complex_meta then + return num + end + local real,imag = tonumber( num[1] ),tonumber( num[2] ) + if real and imag then + return setmetatable( { real,imag }, complex_meta ) + end + return + end + -- check for number + local isnum = tonumber( num ) + if isnum then + return setmetatable( { isnum,0 }, complex_meta ) + end + if type( num ) == "string" then + -- check for real and complex + -- number chars [%-%+%*%^%d%./Ee] + local real,sign,imag = string.match( num, "^([%-%+%*%^%d%./Ee]*%d)([%+%-])([%-%+%*%^%d%./Ee]*)i$" ) + if real then + if string.lower(string.sub(real,1,1)) == "e" + or string.lower(string.sub(imag,1,1)) == "e" then + return + end + if imag == "" then + if sign == "+" then + imag = _retone + else + imag = _retminusone + end + elseif sign == "+" then + imag = loadstring("return tonumber("..imag..")") + else + imag = loadstring("return tonumber("..sign..imag..")") + end + real = loadstring("return tonumber("..real..")") + if real and imag then + return setmetatable( { real(),imag() }, complex_meta ) + end + return + end + -- check for complex + local imag = string.match( num,"^([%-%+%*%^%d%./Ee]*)i$" ) + if imag then + if imag == "" then + return setmetatable( { 0,1 }, complex_meta ) + elseif imag == "-" then + return setmetatable( { 0,-1 }, complex_meta ) + end + if string.lower(string.sub(imag,1,1)) ~= "e" then + imag = loadstring("return tonumber("..imag..")") + if imag then + return setmetatable( { 0,imag() }, complex_meta ) + end + end + return + end + -- should be real + local real = string.match( num,"^(%-*[%d%.][%-%+%*%^%d%./Ee]*)$" ) + if real then + real = loadstring( "return tonumber("..real..")" ) + if real then + return setmetatable( { real(),0 }, complex_meta ) + end + end + end +end + +-- complex( arg ) +-- same as complex.to( arg ) +-- set __call behaviour of complex +setmetatable( complex, { __call = function( _,num ) return complex.to( num ) end } ) + +-- complex.new( real, complex ) +-- fast function to get a complex number, not invoking any checks +function complex.new( ... ) + return setmetatable( { ... }, complex_meta ) +end + +-- complex.type( arg ) +-- is argument of type complex +function complex.type( arg ) + if getmetatable( arg ) == complex_meta then + return "complex" + end +end + +-- complex.convpolar( r, phi ) +-- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number +-- r (radius) is a number +-- phi (angle) must be in radians; e.g. [0 - 2pi] +function complex.convpolar( radius, phi ) + return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta ) +end + +-- complex.convpolardeg( r, phi ) +-- convert polar coordinates ( r*e^(i*phi) ) to carthesic complex number +-- r (radius) is a number +-- phi must be in degrees; e.g. [0° - 360°] +function complex.convpolardeg( radius, phi ) + phi = phi/180 * math.pi + return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta ) +end + +--// complex number functions only + +-- complex.tostring( cx [, formatstr] ) +-- to string or real number +-- takes a complex number and returns its string value or real number value +function complex.tostring( cx,formatstr ) + local real,imag = cx[1],cx[2] + if formatstr then + if imag == 0 then + return string.format( formatstr, real ) + elseif real == 0 then + return string.format( formatstr, imag ).."i" + elseif imag > 0 then + return string.format( formatstr, real ).."+"..string.format( formatstr, imag ).."i" + end + return string.format( formatstr, real )..string.format( formatstr, imag ).."i" + end + if imag == 0 then + return real + elseif real == 0 then + return ((imag==1 and "") or (imag==-1 and "-") or imag).."i" + elseif imag > 0 then + return real.."+"..(imag==1 and "" or imag).."i" + end + return real..(imag==-1 and "-" or imag).."i" +end + +-- complex.print( cx [, formatstr] ) +-- print a complex number +function complex.print( ... ) + print( complex.tostring( ... ) ) +end + +-- complex.polar( cx ) +-- from complex number to polar coordinates +-- output in radians; [-pi,+pi] +-- returns r (radius), phi (angle) +function complex.polar( cx ) + return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) +end + +-- complex.polardeg( cx ) +-- from complex number to polar coordinates +-- output in degrees; [-180°,180°] +-- returns r (radius), phi (angle) +function complex.polardeg( cx ) + return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) / math.pi * 180 +end + +-- complex.mulconjugate( cx ) +-- multiply with conjugate, function returning a number +function complex.mulconjugate( cx ) + return cx[1]^2 + cx[2]^2 +end + +-- complex.abs( cx ) +-- get the absolute value of a complex number +function complex.abs( cx ) + return math.sqrt( cx[1]^2 + cx[2]^2 ) +end + +-- complex.get( cx ) +-- returns real_part, imaginary_part +function complex.get( cx ) + return cx[1],cx[2] +end + +-- complex.set( cx, real, imag ) +-- sets real_part = real and imaginary_part = imag +function complex.set( cx,real,imag ) + cx[1],cx[2] = real,imag +end + +-- complex.is( cx, real, imag ) +-- returns true if, real_part = real and imaginary_part = imag +-- else returns false +function complex.is( cx,real,imag ) + if cx[1] == real and cx[2] == imag then + return true + end + return false +end + +--// functions returning a new complex number + +-- complex.copy( cx ) +-- copy complex number +function complex.copy( cx ) + return setmetatable( { cx[1],cx[2] }, complex_meta ) +end + +-- complex.add( cx1, cx2 ) +-- add two numbers; cx1 + cx2 +function complex.add( cx1,cx2 ) + return setmetatable( { cx1[1]+cx2[1], cx1[2]+cx2[2] }, complex_meta ) +end + +-- complex.sub( cx1, cx2 ) +-- subtract two numbers; cx1 - cx2 +function complex.sub( cx1,cx2 ) + return setmetatable( { cx1[1]-cx2[1], cx1[2]-cx2[2] }, complex_meta ) +end + +-- complex.mul( cx1, cx2 ) +-- multiply two numbers; cx1 * cx2 +function complex.mul( cx1,cx2 ) + return setmetatable( { cx1[1]*cx2[1] - cx1[2]*cx2[2],cx1[1]*cx2[2] + cx1[2]*cx2[1] }, complex_meta ) +end + +-- complex.mulnum( cx, num ) +-- multiply complex with number; cx1 * num +function complex.mulnum( cx,num ) + return setmetatable( { cx[1]*num,cx[2]*num }, complex_meta ) +end + +-- complex.div( cx1, cx2 ) +-- divide 2 numbers; cx1 / cx2 +function complex.div( cx1,cx2 ) + -- get complex value + local val = cx2[1]^2 + cx2[2]^2 + -- multiply cx1 with conjugate complex of cx2 and divide through val + return setmetatable( { (cx1[1]*cx2[1]+cx1[2]*cx2[2])/val,(cx1[2]*cx2[1]-cx1[1]*cx2[2])/val }, complex_meta ) +end + +-- complex.divnum( cx, num ) +-- divide through a number +function complex.divnum( cx,num ) + return setmetatable( { cx[1]/num,cx[2]/num }, complex_meta ) +end + +-- complex.pow( cx, num ) +-- get the power of a complex number +function complex.pow( cx,num ) + if math.floor( num ) == num then + if num < 0 then + local val = cx[1]^2 + cx[2]^2 + cx = { cx[1]/val,-cx[2]/val } + num = -num + end + local real,imag = cx[1],cx[2] + for i = 2,num do + real,imag = real*cx[1] - imag*cx[2],real*cx[2] + imag*cx[1] + end + return setmetatable( { real,imag }, complex_meta ) + end + -- we calculate the polar complex number now + -- since then we have the versatility to calc any potenz of the complex number + -- then we convert it back to a carthesic complex number, we loose precision here + local length,phi = math.sqrt( cx[1]^2 + cx[2]^2 )^num, math.atan2( cx[2], cx[1] )*num + return setmetatable( { length * math.cos( phi ), length * math.sin( phi ) }, complex_meta ) +end + +-- complex.sqrt( cx ) +-- get the first squareroot of a complex number, more accurate than cx^.5 +function complex.sqrt( cx ) + local len = math.sqrt( cx[1]^2+cx[2]^2 ) + local sign = (cx[2]<0 and -1) or 1 + return setmetatable( { math.sqrt((cx[1]+len)/2), sign*math.sqrt((len-cx[1])/2) }, complex_meta ) +end + +-- complex.ln( cx ) +-- natural logarithm of cx +function complex.ln( cx ) + return setmetatable( { math.log(math.sqrt( cx[1]^2 + cx[2]^2 )), + math.atan2( cx[2], cx[1] ) }, complex_meta ) +end + +-- complex.exp( cx ) +-- exponent of cx (e^cx) +function complex.exp( cx ) + local expreal = math.exp(cx[1]) + return setmetatable( { expreal*math.cos(cx[2]), expreal*math.sin(cx[2]) }, complex_meta ) +end + +-- complex.conjugate( cx ) +-- get conjugate complex of number +function complex.conjugate( cx ) + return setmetatable( { cx[1], -cx[2] }, complex_meta ) +end + +-- complex.round( cx [,idp] ) +-- round complex numbers, by default to 0 decimal points +function complex.round( cx,idp ) + local mult = 10^( idp or 0 ) + return setmetatable( { math.floor( cx[1] * mult + 0.5 ) / mult, + math.floor( cx[2] * mult + 0.5 ) / mult }, complex_meta ) +end + +--// metatable functions + +complex_meta.__add = function( cx1,cx2 ) + local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 ) + return complex.add( cx1,cx2 ) +end +complex_meta.__sub = function( cx1,cx2 ) + local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 ) + return complex.sub( cx1,cx2 ) +end +complex_meta.__mul = function( cx1,cx2 ) + local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 ) + return complex.mul( cx1,cx2 ) +end +complex_meta.__div = function( cx1,cx2 ) + local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 ) + return complex.div( cx1,cx2 ) +end +complex_meta.__pow = function( cx,num ) + if num == "*" then + return complex.conjugate( cx ) + end + return complex.pow( cx,num ) +end +complex_meta.__unm = function( cx ) + return setmetatable( { -cx[1], -cx[2] }, complex_meta ) +end +complex_meta.__eq = function( cx1,cx2 ) + if cx1[1] == cx2[1] and cx1[2] == cx2[2] then + return true + end + return false +end +complex_meta.__tostring = function( cx ) + return tostring( complex.tostring( cx ) ) +end +complex_meta.__concat = function( cx,cx2 ) + return tostring(cx)..tostring(cx2) +end +-- cx( cx, formatstr ) +complex_meta.__call = function( ... ) + print( complex.tostring( ... ) ) +end +complex_meta.__index = {} +for k,v in pairs( complex ) do + complex_meta.__index[k] = v +end + +return complex + +--///////////////-- +--// chillcode //-- +--///////////////-- \ No newline at end of file diff --git a/src/love/lib/fft/ffthread.lua b/src/love/lib/fft/ffthread.lua new file mode 100644 index 00000000..5f3d101d --- /dev/null +++ b/src/love/lib/fft/ffthread.lua @@ -0,0 +1,24 @@ +local fftSize = ... +local fft = require("lib.fft.luafft") +local inChannel = love.thread.getChannel("toFFT") + +local fftSizeInv = 1 / fftSize -- Because multiplication is slightly faster +local function postprocess(x) + return x * fftSizeInv * 0.5 -- Normalization +end + +while true do + if inChannel:getCount() > 0 then + -- Get input + local toFFT = inChannel:pop() + -- Perform FFT + local res = fft.fft(toFFT, false) + -- Process the results to build an intuitive FFT result + local fftArray = {} + for i = 1, fftSize / 2 do + fftArray[i] = postprocess(res[i]:abs() + res[#res-i+1]:abs()) + end + -- Send the result to the main thread + love.thread.getChannel("fft"):push(fftArray) + end +end \ No newline at end of file diff --git a/src/love/lib/fft/lovefft.lua b/src/love/lib/fft/lovefft.lua new file mode 100644 index 00000000..8888621b --- /dev/null +++ b/src/love/lib/fft/lovefft.lua @@ -0,0 +1,105 @@ +--[[ + A simple FFT module for LÖVE. +]] + +local loveFFT = {} + +function loveFFT:init(fftSize) -- The number of samples used to calculate FFT, must be a power of 2 + if fftSize == nil then + fftSize = 2048 + end + local fftArray = {} + for i = 1, fftSize/2 do fftArray[i] = 0 end + self.fftSize = fftSize + self.fftArray = fftArray + self.threadFFT = love.thread.newThread("lib/fft/ffthread.lua") + self.threadFFT:start(fftSize) + self.channelFFT = love.thread.getChannel("fft") + self.channelToFFT = love.thread.getChannel("toFFT") +end + +function loveFFT:setFFTSize(fftSize) -- Usually, avoid setting FFTSize in run time to save you from chores + self.threadFFT:release() + self.threadFFT = love.thread.newThread("li/fft/ffthread.lua") + self.threadFFT:start(fftSize) + self.channelFFT:clear() + self.channelToFFT:clear() +end + +function loveFFT:getFFTSize() + return self.fftSize +end + +function loveFFT:getFFTArray() + return self.fftArray +end + +function loveFFT:setSoundData(soundDataOrPath) -- The sound data or path to the sound data + if type(soundDataOrPath) == "string" then + self.soundData = love.sound.newSoundData(soundDataOrPath) + elseif type(soundDataOrPath) == "userdata" and soundDataOrPath:typeOf("SoundData") then + self.soundData = soundDataOrPath + else + error("Invalid sound data or path.\n\nWhen you use setSoundData, you should provide a path to the audio file or a SoundData object that is created using love.sound.newSoundData.") + end + self.sampleRate = self.soundData:getSampleRate() + self.bitDepth = self.soundData:getBitDepth() + self.channelCount = self.soundData:getChannelCount() +end + +function loveFFT:getSoundData() + return self.soundData +end + +function loveFFT:updatePlayTime(time) -- Sync with audio playback position and start an FFT computation in a separate thread + self.playPosition = time + self:push() + local err = self.threadFFT:getError() + if err then + error(err) + end +end + +function loveFFT:setPlayPosition(time) -- Set the audio playback position but does not start an FFT computation + self.playPosition = time +end + +function loveFFT:getPlayPosition() -- Why do you need this? Getting playback position from the Audio object is better + return self.playPosition +end + +function loveFFT:push() -- Launch a new FFT computation in a separate thread using self.playPosition. Set the position using self.updatePlayTime or self.setPlayPosition + local sample = self.playPosition * self.sampleRate + local toFFT = {} + for i = 1, self.fftSize do + toFFT[i] = 0 + for j = 1, self.channelCount do + toFFT[i] = toFFT[i] + self.soundData:getSample(sample + i - 1, j) + end + end + -- Send to thread + self.channelToFFT:push(toFFT) +end + +function loveFFT:get() -- Gets the result of an FFT computation. This function promises a non-blocking call and yields a valid list + -- Get from thread + if self.channelFFT:getCount() > 0 then + self.fftArray = self.channelFFT:pop() + return self.fftArray, true + else + return self.fftArray, false + end +end + +function loveFFT:release() -- Releases the thread and clears the channel. According to LOVE documentation, this is necessary on Android platforms. But based on my personal experience, it is always unnecessary to call this function + self.threadFFT:release() + self.channelFFT:clear() + self.channelToFFT:clear() +end + +-- Aliases +loveFFT.pop = loveFFT.get +loveFFT.destroy = loveFFT.release +loveFFT.tell = loveFFT.getPlayPosition + +return loveFFT \ No newline at end of file diff --git a/src/love/lib/fft/luafft.lua b/src/love/lib/fft/luafft.lua new file mode 100644 index 00000000..3478ffa2 --- /dev/null +++ b/src/love/lib/fft/luafft.lua @@ -0,0 +1,360 @@ +--[[ +This package provides functions to carry out Fast Fourier Transformations. + +Copyright (C) 2011 by Benjamin von Ardenne + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +]] + +local complex = require "lib.fft.complex" +local scratchbuf + +--------------------------------------------------------------- +--This is a lua port of the KissFFT Library by Mark Borgerding +--It provides a simple function to carry out a fast fourier transformation (FFT). + +local luafft = {} +local cos,sin = math.cos,math.sin +local debugging = false + +local function msg(...) + if debugging == true then + print(...) + end +end + +--------------------------------------------------------------- +--Carries out a butterfly 5 run of the input sample. +--------------------------------------------------------------- +local function butterfly5(input,out_index, fstride, twiddles, m, inverse) + local i0,i1,i2,i3,i4 = out_index,out_index+m,out_index+2*m,out_index+3*m,out_index+4*m + local scratch = {} + local tw = twiddles + local ya,yb = tw[1+fstride*m],tw[1+fstride*2*m] + for u = 0,m-1 do + scratch[0] = input[i0] + + scratch[1] = input[i1] * tw[1+u*fstride] + scratch[2] = input[i2] * tw[1+2*u*fstride] + scratch[3] = input[i3] * tw[1+3*u*fstride] + scratch[4] = input[i4] * tw[1+4*u*fstride] + + scratch[7] = scratch[1] + scratch[4] + scratch[8] = scratch[2] + scratch[3] + scratch[9] = scratch[2] - scratch[3] + scratch[10] = scratch[1] - scratch[4] + + input[i0][1] = input[i0][1] + scratch[7][1] + scratch[8][1] + input[i0][2] = input[i0][2] + scratch[7][2] + scratch[8][2] + + scratch[5] = complex.new( scratch[0][1] + scratch[7][1]*ya[1] + scratch[8][1]*yb[1], + scratch[0][2] + scratch[7][2]*ya[1] + scratch[8][2]*yb[1]) + + scratch[6] = complex.new( scratch[10][2]*ya[2] + scratch[9][2]*yb[2], + -1* scratch[10][1]*ya[2] + scratch[9][1]*yb[2]) + + input[i1] = scratch[5] - scratch[6] + input[i4] = scratch[5] + scratch[6] + + scratch[11] = complex.new( scratch[0][1] + scratch[7][1]*yb[1] + scratch[8][1]*ya[1], + scratch[0][2] + scratch[7][2]*yb[1] + scratch[8][2]*ya[1]) + + scratch[12] = complex.new( -1* scratch[10][2]*yb[2] + scratch[9][2]*ya[2], + scratch[10][1]*yb[2] - scratch[9][1]*ya[2]) + + input[i2] = scratch[11] + scratch[12] + input[i3] = scratch[11] - scratch[12] + + i0=i0+1 + i1=i1+1 + i2=i2+1 + i3=i3+1 + i4=i4+1 + + end + +end + +--------------------------------------------------------------- +--Carries out a generic butterfly run of the input sample. +--------------------------------------------------------------- +local function butterfly_generic(input,out_index, fstride, twiddles, m, p, inverse ) + local norig = #input + + for u = 0,m-1 do + local k = u + for q1 = 0,p-1 do + scratchbuf[q1] = input[out_index+k] + k = k + m + end + + k = u + + for q1=0,p-1 do + local twidx = 0 + input[out_index+k] = scratchbuf[0] + for q=1,p-1 do + twidx = twidx + fstride*k + if twidx >= Norix then twidx = twidx - Norig end + local t = scratchbuf[q] * twiddles[1+twidx] + input[out_index+k] = input[out_index+k] + t + end + k = k + m + end + end +end + +--------------------------------------------------------------- +-- Returns the next possible size for data input +-- +--@param n Size +-- +--@return Next fast size. +local function next_possible_size(n) + local m = n + while (1) do + m = n + while m%2 == 0 do m = m/2 end + while m%3 == 0 do m = m/3 end + while m%5 == 0 do m = m/5 end + if m <= 1 then break end + n = n + 1 + end + return n +end + +--------------------------------------------------------------- +--Calculates the Fast Fourier Transformation of the given input +-- +--@param input A set of points that will be transformed. +-- At this point, the input has to be a list of complex numbers, +-- according to the format in complex.lua. +--@param inverse Boolean that controls whether a transformation +-- or inverse transformation will be carried out. +--@return Returns a list of complex numbers with the same size +-- as the input list. Contains the fourier transformation of the input. +--------------------------------------------------------------- +function luafft.fft(input, inverse) + --the size of input defines the number of total points + local num_points = #input + + assert(#input == next_possible_size(#input), string.format("The size of your input is not correct. For your size=%i, use a table of size=%i with zeros at the end.", #input, next_possible_size(#input))) + + local twiddles = {} + for i = 0,num_points-1 do + local phase = -2*math.pi * i / num_points + if inverse then phase = phase * -1 end + twiddles[1+i] = complex.new( cos(phase), sin(phase) ) + end + msg("Twiddles initialized...") + local factors = calculate_factors(num_points) + local output = {} + msg("FFT Initialization completed.\nFactors of size " .. #factors) + work(input, output, 1, 1, factors,1, twiddles, 1, 1, inverse) + return output + +end + +--------------------------------------------------------------- +--Calculates the real Fast Fourier Transformation of the given real input +-- + +--------------------------------------------------------------- +function luafft.fftr(input, inverse) + print("Not implemented.") +end + + + +--------------------------------------------------------------- +-- Short helper function that provides an easy way to print a list with values. +--------------------------------------------------------------- +function print_list(list) + for i,v in ipairs(list) do print(i,v) end +end + +--------------------------------------------------------------- +--The essential work function that performs the FFT +--------------------------------------------------------------- +function work(input, output, out_index, f, factors, factors_index, twiddles, fstride, in_stride, inverse) + local p = factors[factors_index] + local m = factors[factors_index+1] + factors_index = factors_index + 2 + msg(p,m) + local last = out_index + p*m + local beg = out_index + + if m == 1 then + repeat + if type(input[f]) == "number" then output[out_index] = complex.new(input[f],0) + else output[out_index] = input[f] end + f = f + fstride*in_stride + out_index = out_index +1 + until out_index == last + else + repeat + --msg("Out_index", out_index,"f", f) + work(input, output,out_index, f, factors, factors_index, twiddles, fstride*p, in_stride, inverse) + f = f + fstride*in_stride + out_index = out_index + m + until out_index == last + end + + out_index = beg + + if p == 2 then butterfly2(output,out_index, fstride, twiddles, m, inverse) + elseif p == 3 then butterfly3(output,out_index, fstride, twiddles, m, inverse) + elseif p == 4 then butterfly4(output,out_index, fstride, twiddles, m, inverse) + elseif p == 5 then butterfly5(output,out_index, fstride, twiddles, m, inverse) + else butterfly_generic(output,out_index, fstride, twiddles, m, p, inverse) end +end + + +--------------------------------------------------------------- +---devides a number into a sequence of factors +-- +--@param num_points Number of points that are used. +-- +--@return Returns a list with the factors +--------------------------------------------------------------- +function calculate_factors(num_points) + local buf = {} + local p = 4 + floor_sqrt = math.floor( math.sqrt( num_points) ) + local n = num_points + repeat + while n%p > 0 do + if p == 4 then p = 2 + elseif p == 2 then p = 3 + else p = p + 2 end + + if p > floor_sqrt then p = n end + end + n = n / p + table.insert(buf, p) + table.insert(buf, n) + until n <= 1 + return buf +end + + + +--------------------------------------------------------------- +--Carries out a butterfly 2 run of the input sample. +--------------------------------------------------------------- +function butterfly2(input,out_index,fstride, twiddles, m, inverse) + local i1 = out_index + local i2 = out_index + m + local ti = 1 + repeat + local t = input[i2]* twiddles[ti] + ti = ti + fstride + input[i2] = input[i1] - t + input[i1] = input[i1] + t + i1 = i1 + 1 + i2 = i2 + 1 + m = m - 1 + until m == 0 +end + +--------------------------------------------------------------- +--Carries out a butterfly 4 run of the input sample. +--------------------------------------------------------------- +function butterfly4(input,out_index, fstride, twiddles, m, inverse) + local ti1, ti2, ti3 = 1,1,1 + local scratch = {} + local k = m + local m2 = 2*m + local m3 = 3*m + local i = out_index + + repeat + scratch[0] = input[i+m]*twiddles[ti1] + scratch[1] = input[i+m2]*twiddles[ti2] + scratch[2] = input[i+m3]*twiddles[ti3] + + scratch[5] = input[i]-scratch[1] + input[i] = input[i] + scratch[1] + + scratch[3] = scratch[0] + scratch[2] + scratch[4] = scratch[0] - scratch[2] + + input[i+m2] = input[i] - scratch[3] + ti1 = ti1 + fstride + ti2 = ti2 + fstride*2 + ti3 = ti3 + fstride*3 + input[i] = input[i] + scratch[3] + + if inverse then + input[i+m][1] = scratch[5][1] - scratch[4][2] + input[i+m][2] = scratch[5][2] + scratch[4][1] + + input[i+m3][1] = scratch[5][1] + scratch[4][2] + input[i+m3][2] = scratch[5][2] - scratch[4][1] + else + input[i+m][1] = scratch[5][1] + scratch[4][2] + input[i+m][2] = scratch[5][2] - scratch[4][1] + + input[i+m3][1] = scratch[5][1] - scratch[4][2] + input[i+m3][2] = scratch[5][2] + scratch[4][1] + end + i = i + 1 + k = k - 1 + until k == 0 +end + +--------------------------------------------------------------- +--Carries out a butterfly 3 run of the input sample. +--------------------------------------------------------------- +function butterfly3(input,out_index, fstride, twiddles, m, inverse) + local k = m + local m2 = m*2 + local tw1, tw2 = 1,1 + local scratch = {} + local epi3 = twiddles[fstride*m] + local i = out_index + + repeat + scratch[1] = input[i+m] * twiddles[tw1] + scratch[2] = input[i+m2] * twiddles[tw2] + scratch[3] = scratch[1] + scratch[2] + scratch[0] = scratch[1] - scratch[2] + tw1 = tw1 + fstride + tw2 = tw2 + fstride*2 + + input[i+m][1] = input[i][1] - scratch[3][1]*0.5 + input[i+m][2] = input[i][2] - scratch[3][2]*0.5 + + scratch[0] = scratch[0]:mulnum(epi3[2] ) + input[i] = input[i] + scratch[3] + + input[i+m2][1] = input[i+m][1] + scratch[0][2] + input[i+m2][2] = input[i+m][2] - scratch[0][1] + + input[i+m][1] = input[i+m][1] - scratch[0][2] + input[i+m][2] = input[i+m][2] + scratch[0][1] + + i = i + 1 + k = k-1 + until k == 0 + +end + +return luafft \ No newline at end of file diff --git a/src/love/main.lua b/src/love/main.lua index 3d39bcea..3ab0d71c 100644 --- a/src/love/main.lua +++ b/src/love/main.lua @@ -129,6 +129,9 @@ function love.load() lume = require "lib.lume" Object = require "lib.classic" xml = require "lib.xml".parse + lovefftINST = require "lib.fft.lovefft" + lovefftBFVOCALS = require "lib.fft.lovefft" + lovefftENEMYVOCALS = require "lib.fft.lovefft" -- Load modules status = require "modules.status" diff --git a/src/love/modules/util.lua b/src/love/modules/util.lua index d6f5816a..ce03a095 100644 --- a/src/love/modules/util.lua +++ b/src/love/modules/util.lua @@ -90,8 +90,20 @@ function table.getKey(table, value) return nil end -function math.remapToRange(value, from1, to1, from2, to2) - return (value - from1) / (to1 - from1) * (to2 - from2) + from2 +function math.remap(value, low1, high1, low2, high2) + return low2 + (value - low1) * (high2 - low2) / (high1 - low1) +end + +function table.mergeValues(t1, t2) + -- add numbers together, concatenate strings + for k, v in pairs(t2) do + if type(v) == "number" then + t1[k] = (t1[k] or 0) + v + elseif type(v) == "string" then + t1[k] = (t1[k] or "") .. v + end + end + return t1 end -- God like coding diff --git a/src/love/sprites/weekend1/abotViz.lua b/src/love/sprites/weekend1/abotViz.lua new file mode 100644 index 00000000..e4ced9fd --- /dev/null +++ b/src/love/sprites/weekend1/abotViz.lua @@ -0,0 +1,106 @@ +return graphics.newSprite( + ABOT_IMAGE, + -- Automatically generated from aBotViz.xml + { + {x = 212, y = 0, width = 68, height = 196, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 1: viz10000 + {x = 538, y = 0, width = 68, height = 169, offsetX = 0, offsetY = -27, offsetWidth = 68, offsetHeight = 196, rotated = false}, -- 2: viz10001 + {x = 538, y = 173, width = 65, height = 135, offsetX = -3, offsetY = -61, offsetWidth = 68, offsetHeight = 196, rotated = false}, -- 3: viz10002 + {x = 806, y = 195, width = 60, height = 96, offsetX = -8, offsetY = -100, offsetWidth = 68, offsetHeight = 196, rotated = false}, -- 4: viz10003 + {x = 928, y = 299, width = 53, height = 53, offsetX = -15, offsetY = -143, offsetWidth = 68, offsetHeight = 196, rotated = false}, -- 5: viz10004 + {x = 531, y = 312, width = 46, height = 28, offsetX = -22, offsetY = -168, offsetWidth = 68, offsetHeight = 196, rotated = false}, -- 6: viz10005 + + {x = 407, y = 0, width = 58, height = 209, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 7: viz20000 + {x = 870, y = 0, width = 58, height = 183, offsetX = 0, offsetY = -26, offsetWidth = 58, offsetHeight = 209, rotated = false}, -- 8: viz20001 + {x = 607, y = 189, width = 57, height = 141, offsetX = -1, offsetY = -68, offsetWidth = 58, offsetHeight = 209, rotated = false}, -- 9: viz20002 + {x = 407, y = 213, width = 54, height = 99, offsetX = -4, offsetY = -110, offsetWidth = 58, offsetHeight = 209, rotated = false}, -- 10: viz20003 + {x = 741, y = 300, width = 48, height = 56, offsetX = -10, offsetY = -153, offsetWidth = 58, offsetHeight = 209, rotated = false}, -- 11: viz20004 + {x = 383, y = 316, width = 43, height = 27, offsetX = -15, offsetY = -182, offsetWidth = 58, offsetHeight = 209, rotated = false}, -- 12: viz20005 + + {x = 284, y = 0, width = 58, height = 215, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 13: viz30000 + {x = 747, y = 0, width = 58, height = 188, offsetX = 0, offsetY = -27, offsetWidth = 58, offsetHeight = 215, rotated = false}, -- 14: viz30001 + {x = 469, y = 182, width = 58, height = 151, offsetX = 0, offsetY = -64, offsetWidth = 58, offsetHeight = 215, rotated = false}, -- 15: viz30002 + {x = 212, y = 200, width = 55, height = 100, offsetX = -3, offsetY = -115, offsetWidth = 58, offsetHeight = 215, rotated = false}, -- 16: viz30003 + {x = 271, y = 286, width = 50, height = 57, offsetX = -8, offsetY = -158, offsetWidth = 58, offsetHeight = 215, rotated = false}, -- 17: viz30004 + {x = 668, y = 316, width = 45, height = 22, offsetX = -13, offsetY = -193, offsetWidth = 58, offsetHeight = 215, rotated = false}, -- 18: viz30005 + + {x = 346, y = 0, width = 57, height = 216, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 19: viz40000 + {x = 809, y = 0, width = 57, height = 191, offsetX = 0, offsetY = -25, offsetWidth = 57, offsetHeight = 216, rotated = false}, -- 20: viz40001 + {x = 870, y = 187, width = 54, height = 153, offsetX = 0, offsetY = -63, offsetWidth = 57, offsetHeight = 216, rotated = false}, -- 21: viz40002 + {x = 132, y = 219, width = 52, height = 101, offsetX = 0, offsetY = -115, offsetWidth = 57, offsetHeight = 216, rotated = false}, -- 22: viz40003 + {x = 806, y = 295, width = 49, height = 58, offsetX = 0, offsetY = -158, offsetWidth = 57, offsetHeight = 216, rotated = false}, -- 23: viz40004 + {x = 109, y = 324, width = 44, height = 22, offsetX = -2, offsetY = -194, offsetWidth = 57, offsetHeight = 216, rotated = false}, -- 24: viz40005 + + {x = 146, y = 0, width = 62, height = 215, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 37: viz50000 + {x = 610, y = 0, width = 61, height = 185, offsetX = 0, offsetY = -30, offsetWidth = 62, offsetHeight = 215, rotated = false}, -- 38: viz50001 + {x = 932, y = 143, width = 59, height = 152, offsetX = 0, offsetY = -63, offsetWidth = 62, offsetHeight = 215, rotated = false}, -- 39: viz50002 + {x = 0, y = 211, width = 55, height = 100, offsetX = 0, offsetY = -115, offsetWidth = 62, offsetHeight = 215, rotated = false}, -- 40: viz50003 + {x = 329, y = 285, width = 50, height = 60, offsetX = 0, offsetY = -155, offsetWidth = 62, offsetHeight = 215, rotated = false}, -- 41: viz50004 + {x = 0, y = 315, width = 46, height = 27, offsetX = 0, offsetY = -188, offsetWidth = 62, offsetHeight = 215, rotated = false}, -- 42: viz50005 + + {x = 0, y = 0, width = 67, height = 207, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 25: viz60000 + {x = 469, y = 0, width = 65, height = 178, offsetX = 0, offsetY = -29, offsetWidth = 67, offsetHeight = 207, rotated = false}, -- 26: viz60001 + {x = 675, y = 168, width = 62, height = 144, offsetX = 0, offsetY = -63, offsetWidth = 67, offsetHeight = 207, rotated = false}, -- 27: viz60002 + {x = 71, y = 197, width = 57, height = 101, offsetX = 0, offsetY = -106, offsetWidth = 67, offsetHeight = 207, rotated = false}, -- 28: viz60003 + {x = 329, y = 220, width = 51, height = 61, offsetX = 0, offsetY = -146, offsetWidth = 67, offsetHeight = 207, rotated = false}, -- 29: viz60004 + {x = 188, y = 304, width = 45, height = 30, offsetX = 0, offsetY = -177, offsetWidth = 67, offsetHeight = 207, rotated = false}, -- 30: viz60005 + + {x = 71, y = 0, width = 71, height = 193, offsetX = 0, offsetY = 0, offsetWidth = 0, offsetHeight = 0, rotated = false}, -- 31: viz70000 + {x = 675, y = 0, width = 68, height = 164, offsetX = 0, offsetY = -29, offsetWidth = 71, offsetHeight = 193, rotated = false}, -- 32: viz70001 + {x = 932, y = 0, width = 66, height = 139, offsetX = 0, offsetY = -54, offsetWidth = 71, offsetHeight = 193, rotated = false}, -- 33: viz70002 + {x = 741, y = 192, width = 61, height = 104, offsetX = 0, offsetY = -89, offsetWidth = 71, offsetHeight = 193, rotated = false}, -- 34: viz70003 + {x = 271, y = 219, width = 54, height = 63, offsetX = 0, offsetY = -130, offsetWidth = 71, offsetHeight = 193, rotated = false}, -- 35: viz70004 + {x = 59, y = 302, width = 46, height = 32, offsetX = 0, offsetY = -161, offsetWidth = 71, offsetHeight = 193, rotated = false}, -- 36: viz70005 + }, + { + ["1_6"] = {start = 1, stop = 1, speed = 24, offsetX = 0, offsetY = 0}, + ["1_5"] = {start = 2, stop = 2, speed = 24, offsetX = 0, offsetY = 0}, + ["1_4"] = {start = 3, stop = 3, speed = 24, offsetX = 0, offsetY = 0}, + ["1_3"] = {start = 4, stop = 4, speed = 24, offsetX = 0, offsetY = 0}, + ["1_2"] = {start = 5, stop = 5, speed = 24, offsetX = 0, offsetY = 0}, + ["1_1"] = {start = 6, stop = 6, speed = 24, offsetX = 0, offsetY = 0}, + + ["2_6"] = {start = 7, stop = 7, speed = 24, offsetX = 0, offsetY = 0}, + ["2_5"] = {start = 8, stop = 8, speed = 24, offsetX = 0, offsetY = 0}, + ["2_4"] = {start = 9, stop = 9, speed = 24, offsetX = 0, offsetY = 0}, + ["2_3"] = {start = 10, stop = 10, speed = 24, offsetX = 0, offsetY = 0}, + ["2_2"] = {start = 11, stop = 11, speed = 24, offsetX = 0, offsetY = 0}, + ["2_1"] = {start = 12, stop = 12, speed = 24, offsetX = 0, offsetY = 0}, + + ["3_6"] = {start = 13, stop = 13, speed = 24, offsetX = 0, offsetY = 0}, + ["3_5"] = {start = 14, stop = 14, speed = 24, offsetX = 0, offsetY = 0}, + ["3_4"] = {start = 15, stop = 15, speed = 24, offsetX = 0, offsetY = 0}, + ["3_3"] = {start = 16, stop = 16, speed = 24, offsetX = 0, offsetY = 0}, + ["3_2"] = {start = 17, stop = 17, speed = 24, offsetX = 0, offsetY = 0}, + ["3_1"] = {start = 18, stop = 18, speed = 24, offsetX = 0, offsetY = 0}, + + ["4_6"] = {start = 19, stop = 19, speed = 24, offsetX = 0, offsetY = 0}, + ["4_5"] = {start = 20, stop = 20, speed = 24, offsetX = 0, offsetY = 0}, + ["4_4"] = {start = 21, stop = 21, speed = 24, offsetX = 0, offsetY = 0}, + ["4_3"] = {start = 22, stop = 22, speed = 24, offsetX = 0, offsetY = 0}, + ["4_2"] = {start = 23, stop = 23, speed = 24, offsetX = 0, offsetY = 0}, + ["4_1"] = {start = 24, stop = 24, speed = 24, offsetX = 0, offsetY = 0}, + + ["5_6"] = {start = 25, stop = 25, speed = 24, offsetX = 0, offsetY = 0}, + ["5_5"] = {start = 26, stop = 26, speed = 24, offsetX = 0, offsetY = 0}, + ["5_4"] = {start = 27, stop = 27, speed = 24, offsetX = 0, offsetY = 0}, + ["5_3"] = {start = 28, stop = 28, speed = 24, offsetX = 0, offsetY = 0}, + ["5_2"] = {start = 29, stop = 29, speed = 24, offsetX = 0, offsetY = 0}, + ["5_1"] = {start = 30, stop = 30, speed = 24, offsetX = 0, offsetY = 0}, + + ["6_6"] = {start = 31, stop = 31, speed = 24, offsetX = 0, offsetY = 0}, + ["6_5"] = {start = 32, stop = 32, speed = 24, offsetX = 0, offsetY = 0}, + ["6_4"] = {start = 33, stop = 33, speed = 24, offsetX = 0, offsetY = 0}, + ["6_3"] = {start = 34, stop = 34, speed = 24, offsetX = 0, offsetY = 0}, + ["6_2"] = {start = 35, stop = 35, speed = 24, offsetX = 0, offsetY = 0}, + ["6_1"] = {start = 36, stop = 36, speed = 24, offsetX = 0, offsetY = 0}, + + ["7_6"] = {start = 37, stop = 37, speed = 24, offsetX = 0, offsetY = 0}, + ["7_5"] = {start = 38, stop = 38, speed = 24, offsetX = 0, offsetY = 0}, + ["7_4"] = {start = 39, stop = 39, speed = 24, offsetX = 0, offsetY = 0}, + ["7_3"] = {start = 40, stop = 40, speed = 24, offsetX = 0, offsetY = 0}, + ["7_2"] = {start = 41, stop = 41, speed = 24, offsetX = 0, offsetY = 0}, + ["7_1"] = {start = 42, stop = 42, speed = 24, offsetX = 0, offsetY = 0} + }, + "1_1", + true +) \ No newline at end of file diff --git a/src/love/stages/streets.lua b/src/love/stages/streets.lua index 960f4536..373a2686 100644 --- a/src/love/stages/streets.lua +++ b/src/love/stages/streets.lua @@ -17,6 +17,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ------------------------------------------------------------------------------]] +ABOT_IMAGE = nil +local abotVisualizers = {} +local MAX_ABOT_VIZ = 7 +local VIS_TIME_MAX = 0.033333333333333333 +local deltaCurTime = 0 + return { enter = function() stageImages = { @@ -33,6 +39,8 @@ return { ["abotBack"] = graphics.newImage(graphics.imagePath("weekend1/stereoBG")), } + ABOT_IMAGE = love.graphics.newImage(graphics.imagePath("weekend1/aBotViz")) + stageImages["skybox"].x, stageImages["skybox"].y = 351, -300 stageImages["spraycanPile"].x, stageImages["spraycanPile"].y = -314, 248 stageImages["highwayLights"].x, stageImages["highwayLights"].y = -272, -459 @@ -44,6 +52,15 @@ return { stageImages["skyline"].x, stageImages["skyline"].y = 100, -227 stageImages["foregroundCity"].x, stageImages["foregroundCity"].y = -386, 38 + for i = 1, MAX_ABOT_VIZ do + local viz = love.filesystem.load("sprites/weekend1/abotViz.lua")() + --viz:animate(tostring(i) .. "_1", false) + viz.x = -170 + (viz:getFrameWidth()/2 + 25) * i + viz.y = 0--stageImages["abot"].y + 120 + --print(viz.x) + table.insert(abotVisualizers, viz) + end + enemy = love.filesystem.load("sprites/weekend1/darnell.lua")() boyfriend = love.filesystem.load("sprites/pico-player.lua")() girlfriend = love.filesystem.load("sprites/weekend1/nene.lua")() @@ -157,6 +174,7 @@ return { end, update = function(self, dt) + deltaCurTime = deltaCurTime + dt end, draw = function() @@ -188,6 +206,30 @@ return { stageImages["foreground"]:draw() stageImages["abotBack"]:draw() + local fftArray = lovefftINST:get() + local bfFFTArray, enemyFFTArray = {}, {} + local time = inst:tell() + if deltaCurTime > VIS_TIME_MAX then + deltaCurTime = 0 + --print("Time: " .. time) + lovefftINST:updatePlayTime(time) + end + -- we only have 7 bars + local MAX_BARS = 7 + local forEach = #fftArray / MAX_BARS + local index = 1 + for i = 1, #fftArray, forEach do + local i = math.floor(i) + -- 7 bars + local barHeight = fftArray[i] * 720*100 + --print(index, i, barHeight) + -- convert bar height from a number from 1-6 + local animNum = math.floor(math.remap(barHeight, 0, 720, 1, 6)) + print(index, i, animNum) + abotVisualizers[index]:animate(tostring(index) .. "_" .. tostring(animNum), false) + abotVisualizers[index]:draw() + index = index + 1 + end stageImages["abot"]:draw() girlfriend:draw() enemy:draw() @@ -200,6 +242,10 @@ return { for _, v in pairs(stageImages) do v = nil end + for _, v in pairs(abotVisualizers) do + v = nil + end + ABOT_IMAGE = nil graphics.clearCache() end diff --git a/src/love/weeks/weekend1.lua b/src/love/weeks/weekend1.lua index 37d7813e..8e8e1c5e 100644 --- a/src/love/weeks/weekend1.lua +++ b/src/love/weeks/weekend1.lua @@ -51,19 +51,25 @@ return { stages["streets"]:load() if song == 4 then - inst = love.audio.newSource("songs/blazin/Inst" .. (erectMode and "-erect" or "") .. ".ogg", "stream") + inst = love.audio.newSource("songs/blazin/Inst" .. (erectMode and "-erect" or "") .. ".ogg", "stream") + lovefftINST:init(1024) + lovefftINST:setSoundData("songs/blazin/Inst" .. (erectMode and "-erect" or "") .. ".ogg") voicesBF = nil voicesEnemy = nil rainShaderStartIntensity = 0.2 rainShaderEndIntensity = 0.4 elseif song == 3 then inst = love.audio.newSource("songs/2hot/Inst" .. (erectMode and "-erect" or "") .. ".ogg", "stream") + lovefftINST:init(1024) + lovefftINST:setSoundData("songs/2hot/Inst" .. (erectMode and "-erect" or "") .. ".ogg") voicesBF = love.audio.newSource("songs/2hot/Voices-pico" .. (erectMode and "-erect" or "") .. ".ogg", "stream") voicesEnemy = love.audio.newSource("songs/2hot/Voices-darnell" .. (erectMode and "-erect" or "") .. ".ogg", "stream") rainShaderStartIntensity = 0.2 rainShaderEndIntensity = 0.4 elseif song == 2 then inst = love.audio.newSource("songs/lit-up/Inst" .. (erectMode and "-erect" or "") .. ".ogg", "stream") + lovefftINST:init(1024) + lovefftINST:setSoundData("songs/lit-up/Inst" .. (erectMode and "-erect" or "") .. ".ogg") voicesBF = love.audio.newSource("songs/lit-up/Voices-pico" .. (erectMode and "-erect" or "") .. ".ogg", "stream") voicesEnemy = love.audio.newSource("songs/lit-up/Voices-darnell" .. (erectMode and "-erect" or "") .. ".ogg", "stream") @@ -71,6 +77,8 @@ return { rainShaderEndIntensity = 0.2 else inst = love.audio.newSource("songs/darnell/Inst" .. (erectMode and "-erect" or "") .. ".ogg", "stream") + lovefftINST:init(1024) + lovefftINST:setSoundData("songs/darnell/Inst" .. (erectMode and "-erect" or "") .. ".ogg") voicesBF = love.audio.newSource("songs/darnell/Voices-pico" .. (erectMode and "-erect" or "") .. ".ogg", "stream") voicesEnemy = love.audio.newSource("songs/darnell/Voices-darnell" .. (erectMode and "-erect" or "") .. ".ogg", "stream") @@ -151,7 +159,7 @@ return { end end if love.system.getOS() ~= "NX" then - intensity = math.remapToRange(musicTime/1000, 0, inst:getDuration(), rainShaderStartIntensity, rainShaderEndIntensity) + intensity = math.remap(musicTime/1000, 0, inst:getDuration(), rainShaderStartIntensity, rainShaderEndIntensity) shaders["rain"]:send("uTime", love.timer.getTime()) shaders["rain"]:send("uIntensity", intensity) end