- added ddr test to main menu\n- tweaked sounds\n- musicator tool base code, needs samples

This commit is contained in:
2026-03-19 00:21:48 +01:00
parent 0d7dcad54a
commit 47e41f4054
5 changed files with 156 additions and 16 deletions

View File

@@ -0,0 +1,130 @@
unpack = unpack or table.unpack
function build_markov_model(sequence, order)
local function make_key(tbl)
return table.concat(tbl, "|")
end
local function unmake_key(k)
local result = {}
for t in string.gmatch(k, "[^|]+") do
result[#result + 1] = t
end
return result
end
local function add_key(str, value)
return str .. "|" .. value
end
local function split_last(full)
local i = full:match(".*()|")
return full:sub(1, i-1), full:sub(i+1)
end
local counts = {}
local totals = {}
-- count
for i = 1, #sequence - order do
local notes = make_key({unpack(sequence, i, i + order - 1)})
totals[notes] = (totals[notes] or 0) + 1
local notes_full = add_key(notes, sequence[i + order])
counts[notes_full] = (counts[notes_full] or 0) + 1
end
-- build model
local model = {}
for notes_full,count in pairs(counts) do
local notes, _ = split_last(notes_full)
model[notes_full] = count[notes_full] / total[notes]
end
return {
order = order,
model = model,
counts = counts -- keep raw counts (useful!)
}
end
function generate_sequence(model_data, length)
local model = model_data.model
local order = model_data.order
-- helper: split key into parts
local function split(k)
local t = {}
for part in string.gmatch(k, "[^|]+") do
t[#t+1] = part
end
return t
end
-- pick random starting state
local start_key
for k,_ in pairs(model) do
start_key = k
break
end
-- (optional: better random start)
for k,_ in pairs(model) do
if math.random() < 0.1 then
start_key = k
end
end
local parts = split(start_key)
-- initial sequence = first `order` items
local seq = {}
for i = 1, order do
seq[i] = parts[i]
end
-- generation loop
while #seq < length do
-- build current state key
local state = table.concat({unpack(seq, #seq - order + 1, #seq)}, "|")
-- collect matching transitions
local matches = {}
for full,prob in pairs(model) do
if full:sub(1, #state) == state and full:sub(#state+1, #state+1) == "|" then
matches[#matches+1] = {key=full, prob=prob}
end
end
if #matches == 0 then break end
-- weighted pick
local r = math.random()
local sum = 0
local chosen
for _,m in ipairs(matches) do
sum = sum + m.prob
if r <= sum then
chosen = m.key
break
end
end
if not chosen then
chosen = matches[#matches].key
end
-- extract next symbol (after last '|')
local next_symbol = chosen:match("|([^|]+)$")
seq[#seq+1] = next_symbol
end
return seq
end
-- todo: feed samples