Started adding nene visualizer (currently only on dadbattle pico mix), added characterscripts (characters/character.lua)

This commit is contained in:
entar 2025-08-27 12:54:34 +07:00
parent 7dd2742093
commit b109fe2161
8 changed files with 5134 additions and 232 deletions

87
characters/nene.lua Normal file
View File

@ -0,0 +1,87 @@
---@type engine.module
local module = {}
local abot, sound, rate, channels
local spectrum = {}
local visualizers = {}
require("modules.luafft")
local function divide(list, factor)
for i, v in ipairs(list) do
list[i] = list[i] / factor
end
end
---@param character engine.character
function module.onAdded(character)
print(character.stagePosition:Add(character.sprite.position))
abot = Atlas("sprites/characters/abot/abotSystem")
abot:PlayAnimation("")
abot.layer = character.sprite.layer - 0.1
for i = 1, 7 do
print(i)
local viz = Rect("sprites/characters/abot/aBotViz.png", "sprites/characters/abot/aBotViz.xml")
viz.position = abot.position:Add(Vector2(i * 50 + 20, 50))
viz.layer = 500
viz:Frame(string.format("viz%s", i), 5)
visualizers[i] = viz
end
end
function module.onCreate(song)
local audiopath = string.format("songs/%s/Inst.ogg", song)
print(audiopath)
sound = love.sound.newSoundData(audiopath)
rate = sound:getSampleRate()
channels = sound:getChannels()
end
function module.onBeat(beat)
-- if beat % 2 == 0 then
abot:PlayAnimation()
-- end
end
function module.onUpdate(dt, el)
local curSample = inst:tell('samples')
local wave = {}
local size = next_possible_size(2048)
if channels == 2 then
for i = curSample, (curSample + (size - 1) / 2) do
local sample = (sound:getSample(i * 2) + sound:getSample(i * 2 + 1)) * 0.5
table.insert(wave, complex.new(sample, 0))
end
else
for i = curSample, curSample + (size - 1) do
local sample = (sound:getSample(i * 2) + sound:getSample(i * 2 + 1)) * 0.5
table.insert(wave, complex.new(sample, 0))
table.insert(wave, complex.new(sound:getSample(i), 0))
end
end
local spec = fft(wave, false)
--local reconstructed = fft(spec,true)
--divide(reconstructed,size)
divide(spec, size / 2)
spectrum = spec
local division = 142.857142857
local actuali = 1
for i=1, #spectrum/division do
local n = spectrum[i]:abs()
visualizers[actuali]:Frame(string.format("viz%s", actuali), math.floor(n / 0.06) > 5 and 0 or 5 - math.floor(n / 0.06))
actuali = actuali + 1
end
end
function module.onClose()
end
return module

View File

@ -7,7 +7,7 @@
"difficulties": ["easy", "normal", "hard"],
"characters": {
"player": "pico-playable",
"girlfriend": "gf",
"girlfriend": "nene",
"opponent": "dad",
"instrumental": "pico",
"altInstrumentals": []

View File

@ -1,141 +1,109 @@
--[[
LUA MODULE
complex v$(_VERSION) - complex numbers implemented as Lua tables
SYNOPSIS
-- complex 0.3.0
-- Lua 5.1
local complex = require 'complex'
local cx1 = complex "2+3i" -- or complex.new(2, 3)
local cx2 = complex "3+2i"
assert( complex.add(cx1,cx2) == complex "5+5i" )
assert( tostring(cx1) == "2+3i" )
DESCRIPTION
'complex' provides common tasks with complex numbers
-- '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 ( "(-)<number>" and/or "(+/-)<number>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
-- function complex.to( arg ); complex( arg )
-- returns a complex number on success, nil on failure
-- arg := number or { number,number } or ( "(-)<number>" and/or "(+/-)<number>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 Cartesian 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 an add on. When it comes to speed, one is faster using a direct function call.
-- 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
API
-- http://luaforge.net/projects/LuaMatrix
-- http://lua-users.org/wiki/ComplexNumbers
See code and test_complex.lua.
DEPENDENCIES
None (other than Lua 5.1 or 5.2).
HOME PAGE
http://luamatrix.luaforge.net
http://lua-users.org/wiki/LuaMatrix
DOWNLOAD/INSTALL
./util.mk
cd tmp/*
luarocks make
Licensed under the same terms as Lua itself.
Developers:
Michael Lutz (chillcode)
David Manura http://lua-users.org/wiki/DavidManura (maintainer)
--]]
-- Licensed under the same terms as Lua itself.
--/////////////--
--// complex //--
--/////////////--
-- link to complex table
local complex = {_TYPE='module', _NAME='complex', _VERSION='0.3.3.20111212'}
local complex = {}
-- link to complex metatable
local complex_meta = {}
-- helper functions for parsing complex number strings.
local function parse_scalar(s, pos0)
local x, n, pos = s:match('^([+-]?[%d%.]+)(.?)()', pos0)
if not x then return end
if n == 'e' or n == 'E' then
local x2, n2, pos2 = s:match('^([+-]?%d+)(.?)()', pos)
if not x2 then error 'number format error' end
x = tonumber(x..n..x2)
if not x then error 'number format error' end
return x, n2, pos2
else
x = tonumber(x)
if not x then error 'number format error' end
return x, n, pos
end
end
local function parse_component(s, pos0)
local x, n, pos = parse_scalar(s, pos0)
if not x then
local x2, n2, pos2 = s:match('^([+-]?)(i)()$', pos0)
if not x2 then error 'number format error' end
return (x2=='-' and -1 or 1), n2, pos2
end
if n == '/' then
local x2, n2, pos2 = parse_scalar(s, pos)
x = x / x2
return x, n2, pos2
end
return x, n, pos
end
local function parse_complex(s)
local x, n, pos = parse_component(s, 1)
if n == '+' or n == '-' then
local x2, n2, pos2 = parse_component(s, pos)
if n2 ~= 'i' or pos2 ~= #s+1 then error 'number format error' end
if n == '-' then x2 = - x2 end
return x, x2
elseif n == '' then
return x, 0
elseif n == 'i' then
if pos ~= #s+1 then error 'number format error' end
return 0, x
else
error 'number format error'
end
end
-- 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
local real, imag = parse_complex(num)
return setmetatable( { real, imag }, complex_meta )
end
-- 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 )
@ -146,15 +114,15 @@ 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 )
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
if getmetatable( arg ) == complex_meta then
return "complex"
end
end
-- complex.convpolar( r, phi )
@ -162,16 +130,16 @@ end
-- 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 )
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 deg]
-- 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 )
phi = phi/180 * math.pi
return setmetatable( { radius * math.cos( phi ), radius * math.sin( phi ) }, complex_meta )
end
--// complex number functions only
@ -180,31 +148,31 @@ end
-- 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"
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( ... ) )
print( complex.tostring( ... ) )
end
-- complex.polar( cx )
@ -212,50 +180,49 @@ end
-- 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] )
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 deg]
-- 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
return math.sqrt( cx[1]^2 + cx[2]^2 ), math.atan2( cx[2], cx[1] ) / math.pi * 180
end
-- complex.norm2( cx )
-- multiply with conjugate, function returning a scalar number
-- norm2(x + i*y) returns x^2 + y^2
function complex.norm2( cx )
return cx[1]^2 + cx[2]^2
-- 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 )
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]
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
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
if cx[1] == real and cx[2] == imag then
return true
end
return false
end
--// functions returning a new complex number
@ -263,156 +230,152 @@ end
-- complex.copy( cx )
-- copy complex number
function complex.copy( cx )
return setmetatable( { cx[1],cx[2] }, complex_meta )
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 )
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 )
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 )
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 )
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 )
-- 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 )
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 )
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 )
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 )
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 )
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 )
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 )
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
--// variables
complex.zero = complex.new(0, 0)
complex.one = complex.new(1, 0)
--// metatable functions
complex_meta.__add = function( cx1,cx2 )
local cx1,cx2 = complex.to( cx1 ),complex.to( cx2 )
return complex.add( 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 )
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 )
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 )
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 )
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 )
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
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 ) )
return tostring( complex.tostring( cx ) )
end
complex_meta.__concat = function( cx,cx2 )
return tostring(cx)..tostring(cx2)
return tostring(cx)..tostring(cx2)
end
-- cx( cx, formatstr )
complex_meta.__call = function( ... )
print( complex.tostring( ... ) )
print( complex.tostring( ... ) )
end
complex_meta.__index = {}
for k,v in pairs( complex ) do
complex_meta.__index[k] = v
complex_meta.__index[k] = v
end
return complex

360
modules/luafft.lua Normal file
View File

@ -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.
]]
complex = require "modules.complex"
---------------------------------------------------------------
--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).
--
--module("LuaFFT", package.seeall)
local cos,sin = math.cos,math.sin
debugging = false
function msg(...)
if debugging == true then
print(...)
end
end
---------------------------------------------------------------
-- Returns the next possible size for data input
--
--@param n Size
--
--@return Next fast size.
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 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 fftr(input, inverse)
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
---------------------------------------------------------------
--Carries out a butterfly 5 run of the input sample.
---------------------------------------------------------------
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.
---------------------------------------------------------------
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

View File

@ -6,6 +6,20 @@ local json = require("modules.json")
---Character class, child of Sprite class. Makes work with characters easier by calling some sprite functions with preset character file arguments.
---@class engine.character
---@field scale number
---@field animations table
---@field animInfo table
---@field sprite engine.sprite
---@field singing boolean
---@field stagePosition engine.vector2
---@field stageCamera engine.vector2
---@field flipX boolean
---@field beats number
---@field animation string
---@field icon string
---@field starterFrame number
---@field colors table
---@field module engine.module?
local CharacterClass = {}
CharacterClass.__index = CharacterClass
@ -40,6 +54,7 @@ function CharacterClass:PlayAnimation(name)
end
function CharacterClass:Destroy()
self.module.onClose()
self.sprite:Destroy()
self = nil
end
@ -105,6 +120,16 @@ function _G.Character(name)
newCharacter:PlayAnimation("danceLeft")
end
local charModule = files.read_file(string.format("characters/%s.lua", name))
if charModule then
local loadedModule = require(string.format("characters.%s", name))
modules[#modules+1] = loadedModule
if loadedModule.onAdded then
loadedModule.onAdded(newCharacter)
end
newCharacter.module = loadedModule
end
return newCharacter
end

View File

@ -133,7 +133,7 @@ function _G.Sprite(image, sheet)
name = sprite["_name"]
rotated = sprite["_rotated"]
end
print(name)
-- print(name)
local num = tonumber(string.sub(name, name:len() - 3, name:len()))
@ -186,7 +186,7 @@ end
--- Plays a animation on the sprite.
--- @param name string
--- @param fps number
--- @param loop boolean
--- @param loop boolean?
--- @param allowed table?
function Sprite:PlayAnimation(name, fps, loop, allowed)
self.animation = name

File diff suppressed because one or more lines are too long

View File

@ -98,8 +98,8 @@ local function state(songName, songDifficulty, show)
local chart = json.parse(chartString)
local inst = love.audio.newSource(string.format("songs/%s/Inst.ogg", metadata.songName), "stream")
local voices = love.filesystem.getInfo(string.format("songs/%s/Voices.ogg", metadata.songName))
_G.inst = love.audio.newSource(string.format("songs/%s/Inst.ogg", metadata.songName), "stream")
_G.voices = love.filesystem.getInfo(string.format("songs/%s/Voices.ogg", metadata.songName))
if voices then
voices = love.audio.newSource(string.format("songs/%s/Voices.ogg", metadata.songName), "stream")
end
@ -125,7 +125,7 @@ local function state(songName, songDifficulty, show)
local combo = 0
local highestCombo = 0
local modules = {}
_G.modules = {}
local playing = false