2018-06-24 22:23:39 +02:00
|
|
|
COOLDOWN_FACTOR = 0.9998
|
2018-06-19 22:13:22 +02:00
|
|
|
OVERDRIVE = 1.70
|
|
|
|
EXPONENT = 1.5
|
2018-06-24 22:23:39 +02:00
|
|
|
W_EXPONENT = 2.2
|
2018-06-19 22:13:22 +02:00
|
|
|
|
2019-12-17 22:09:53 +01:00
|
|
|
M = 10.0 -- mass
|
2018-06-19 22:13:22 +02:00
|
|
|
D = 1 -- spring strength
|
|
|
|
DAMPING = {} -- filled in init()
|
|
|
|
|
2019-12-17 22:09:53 +01:00
|
|
|
num_modules = 16
|
|
|
|
center_module = 16
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
num_masses = math.floor(num_modules/2)
|
|
|
|
excitement_pos = 1
|
|
|
|
|
|
|
|
-- maximum energy values for each band
|
|
|
|
maxRedEnergy = 1
|
|
|
|
maxGreenEnergy = 1
|
|
|
|
maxBlueEnergy = 1
|
2018-06-24 22:23:39 +02:00
|
|
|
maxWhiteEnergy = 1
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
-- spring-mass-grid values
|
|
|
|
pos_r = {}
|
|
|
|
pos_g = {}
|
|
|
|
pos_b = {}
|
2018-06-24 22:23:39 +02:00
|
|
|
pos_w = {}
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
vel_r = {}
|
|
|
|
vel_g = {}
|
|
|
|
vel_b = {}
|
2018-06-24 22:23:39 +02:00
|
|
|
vel_w = {}
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
acc_r = {}
|
|
|
|
acc_g = {}
|
|
|
|
acc_b = {}
|
2018-06-24 22:23:39 +02:00
|
|
|
acc_w = {}
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
-- output color buffers
|
|
|
|
red = {}
|
|
|
|
green = {}
|
|
|
|
blue = {}
|
2018-06-24 22:23:39 +02:00
|
|
|
white = {}
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
r_tmp = {}
|
|
|
|
g_tmp = {}
|
|
|
|
b_tmp = {}
|
2018-06-24 22:23:39 +02:00
|
|
|
w_tmp = {}
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
function limit(val)
|
|
|
|
if val > 1 then
|
|
|
|
return 1
|
|
|
|
elseif val < 0 then
|
|
|
|
return 0
|
|
|
|
else
|
|
|
|
return val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function periodic()
|
|
|
|
local redEnergy = get_energy_in_band(0, 400);
|
|
|
|
local greenEnergy = get_energy_in_band(400, 4000);
|
2018-06-24 22:23:39 +02:00
|
|
|
local blueEnergy = get_energy_in_band(4000, 12000);
|
|
|
|
local whiteEnergy = get_energy_in_band(12000, 22000);
|
2018-06-19 22:13:22 +02:00
|
|
|
local centerIndex = 2 * center_module + 1;
|
|
|
|
|
2018-08-14 21:52:33 +02:00
|
|
|
--print(maxRedEnergy .. "\t" .. maxGreenEnergy .. "\t" .. maxBlueEnergy .. "\t" .. maxWhiteEnergy)
|
2018-06-24 22:23:39 +02:00
|
|
|
|
2018-06-19 22:13:22 +02:00
|
|
|
maxRedEnergy = maxRedEnergy * COOLDOWN_FACTOR
|
|
|
|
if redEnergy > maxRedEnergy then
|
|
|
|
maxRedEnergy = redEnergy
|
|
|
|
end
|
|
|
|
|
|
|
|
maxGreenEnergy = maxGreenEnergy * COOLDOWN_FACTOR
|
|
|
|
if greenEnergy > maxGreenEnergy then
|
|
|
|
maxGreenEnergy = greenEnergy
|
|
|
|
end
|
|
|
|
|
|
|
|
maxBlueEnergy = maxBlueEnergy * COOLDOWN_FACTOR
|
|
|
|
if blueEnergy > maxBlueEnergy then
|
|
|
|
maxBlueEnergy = blueEnergy
|
|
|
|
end
|
|
|
|
|
2018-06-24 22:23:39 +02:00
|
|
|
maxWhiteEnergy = maxWhiteEnergy * COOLDOWN_FACTOR
|
|
|
|
if whiteEnergy > maxWhiteEnergy then
|
|
|
|
maxWhiteEnergy = whiteEnergy
|
|
|
|
end
|
|
|
|
|
2018-06-19 22:13:22 +02:00
|
|
|
-- update the spring-mass string
|
|
|
|
|
|
|
|
-- the outside masses are special, as they are auto-returned to 0 position
|
|
|
|
-- { spring-mass pendulum } { friction }
|
|
|
|
--acc_r[1] = (-pos_r[1] + (pos_r[2] - pos_r[1])) * D / M
|
|
|
|
--acc_g[1] = (-pos_g[1] + (pos_g[2] - pos_g[1])) * D / M
|
|
|
|
--acc_b[1] = (-pos_b[1] + (pos_b[2] - pos_b[1])) * D / M
|
2018-06-24 22:23:39 +02:00
|
|
|
--acc_w[1] = (-pos_w[1] + (pos_w[2] - pos_w[1])) * D / M
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
acc_r[num_masses] = (-pos_r[num_masses] + (pos_r[num_masses-1] - pos_r[num_masses])) * D / M
|
|
|
|
acc_g[num_masses] = (-pos_g[num_masses] + (pos_g[num_masses-1] - pos_g[num_masses])) * D / M
|
|
|
|
acc_b[num_masses] = (-pos_b[num_masses] + (pos_b[num_masses-1] - pos_b[num_masses])) * D / M
|
2018-06-24 22:23:39 +02:00
|
|
|
acc_w[num_masses] = (-pos_w[num_masses] + (pos_w[num_masses-1] - pos_w[num_masses])) * D / M
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
-- inside masses are only influenced by their neighbors
|
|
|
|
for i = 2,num_masses-1 do
|
|
|
|
acc_r[i] = (pos_r[i-1] + pos_r[i+1] - 2 * pos_r[i]) * D / M
|
|
|
|
acc_g[i] = (pos_g[i-1] + pos_g[i+1] - 2 * pos_g[i]) * D / M
|
|
|
|
acc_b[i] = (pos_b[i-1] + pos_b[i+1] - 2 * pos_b[i]) * D / M
|
2018-06-24 22:23:39 +02:00
|
|
|
acc_w[i] = (pos_w[i-1] + pos_w[i+1] - 2 * pos_w[i]) * D / M
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- update velocity and position
|
|
|
|
for i = 1,num_masses do
|
|
|
|
vel_r[i] = DAMPING[i] * (vel_r[i] + acc_r[i])
|
|
|
|
vel_g[i] = DAMPING[i] * (vel_g[i] + acc_g[i])
|
|
|
|
vel_b[i] = DAMPING[i] * (vel_b[i] + acc_b[i])
|
2018-06-24 22:23:39 +02:00
|
|
|
vel_w[i] = DAMPING[i] * (vel_w[i] + acc_w[i])
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
pos_r[i] = pos_r[i] + vel_r[i]
|
|
|
|
pos_g[i] = pos_g[i] + vel_g[i]
|
|
|
|
pos_b[i] = pos_b[i] + vel_b[i]
|
2018-06-24 22:23:39 +02:00
|
|
|
pos_w[i] = pos_w[i] + vel_w[i]
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- set the new position for the center module
|
|
|
|
newRed = redEnergy / maxRedEnergy
|
|
|
|
pos_r[excitement_pos] = newRed
|
|
|
|
vel_r[excitement_pos] = 0
|
|
|
|
acc_r[excitement_pos] = 0
|
|
|
|
|
|
|
|
newGreen = greenEnergy / maxGreenEnergy
|
|
|
|
pos_g[excitement_pos] = newGreen
|
2018-06-24 22:23:39 +02:00
|
|
|
vel_g[excitement_pos] = 0
|
|
|
|
acc_g[excitement_pos] = 0
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
newBlue = blueEnergy / maxBlueEnergy
|
|
|
|
pos_b[excitement_pos] = newBlue
|
|
|
|
vel_b[excitement_pos] = 0
|
|
|
|
acc_b[excitement_pos] = 0
|
|
|
|
|
2018-06-24 22:23:39 +02:00
|
|
|
newWhite = whiteEnergy / maxWhiteEnergy
|
|
|
|
pos_w[excitement_pos] = newWhite
|
|
|
|
vel_w[excitement_pos] = 0
|
|
|
|
acc_w[excitement_pos] = 0
|
|
|
|
|
2018-06-19 22:13:22 +02:00
|
|
|
-- map to LED modules
|
|
|
|
for i = 1,num_masses do
|
|
|
|
r_tmp[i] = pos_r[i]
|
|
|
|
g_tmp[i] = pos_g[i]
|
|
|
|
b_tmp[i] = pos_b[i]
|
2018-06-24 22:23:39 +02:00
|
|
|
w_tmp[i] = pos_w[i]
|
2018-06-19 22:13:22 +02:00
|
|
|
|
2018-06-30 01:42:34 +02:00
|
|
|
--r_tmp[num_modules-i+1] = pos_r[i]
|
|
|
|
--g_tmp[num_modules-i+1] = pos_g[i]
|
|
|
|
--b_tmp[num_modules-i+1] = pos_b[i]
|
|
|
|
--w_tmp[num_modules-i+1] = pos_w[i]
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
--print(i, pos_r[i])
|
|
|
|
end
|
|
|
|
|
|
|
|
-- make colors more exciting
|
|
|
|
for i = 1,num_modules do
|
|
|
|
red[i] = limit(OVERDRIVE * math.pow(r_tmp[i], EXPONENT))
|
|
|
|
green[i] = limit(OVERDRIVE * math.pow(g_tmp[i], EXPONENT))
|
|
|
|
blue[i] = limit(OVERDRIVE * math.pow(b_tmp[i], EXPONENT))
|
2018-06-24 22:23:39 +02:00
|
|
|
white[i] = limit(OVERDRIVE * math.pow(w_tmp[i], W_EXPONENT))
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
2019-12-17 22:09:53 +01:00
|
|
|
-- return the 4 color arrays
|
2018-06-24 22:23:39 +02:00
|
|
|
return red, green, blue, white
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
function init(nmod, cmod)
|
|
|
|
num_modules = nmod
|
2018-08-14 21:52:33 +02:00
|
|
|
center_module = nmod --cmod
|
2018-06-19 22:13:22 +02:00
|
|
|
|
2018-06-30 01:42:34 +02:00
|
|
|
num_masses = nmod --math.floor(nmod/2)
|
2018-06-19 22:13:22 +02:00
|
|
|
excitement_pos = 1
|
|
|
|
|
|
|
|
for i = 1,nmod do
|
|
|
|
red[i] = 0
|
|
|
|
green[i] = 0
|
|
|
|
blue[i] = 0
|
2018-06-24 22:23:39 +02:00
|
|
|
white[i] = 0
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
for i = 1,num_masses do
|
|
|
|
pos_r[i] = 0
|
|
|
|
pos_g[i] = 0
|
|
|
|
pos_b[i] = 0
|
2018-06-24 22:23:39 +02:00
|
|
|
pos_w[i] = 0
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
vel_r[i] = 0
|
|
|
|
vel_g[i] = 0
|
|
|
|
vel_b[i] = 0
|
2018-06-24 22:23:39 +02:00
|
|
|
vel_w[i] = 0
|
2018-06-19 22:13:22 +02:00
|
|
|
|
|
|
|
acc_r[i] = 0
|
|
|
|
acc_g[i] = 0
|
|
|
|
acc_b[i] = 0
|
2018-06-24 22:23:39 +02:00
|
|
|
acc_w[i] = 0
|
2018-06-19 22:13:22 +02:00
|
|
|
|
2019-12-17 22:09:53 +01:00
|
|
|
DAMPING[i] = 1 - 0.15 * math.abs((i - excitement_pos) / num_masses)^2
|
2018-06-19 22:13:22 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
-- don't use fading
|
|
|
|
return 0
|
|
|
|
end
|