- tools/musicator:\n - markov model generator and pattern generator operational\n- DDR sound generation in-progress
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
46
tools/musicator/midi_converter.py
Normal file
46
tools/musicator/midi_converter.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from mido import MidiFile
|
||||
|
||||
MIDI_FILE = "/tmp/teletype_impostor_musicator/maestro-v3.0.0/2018/MIDI-Unprocessed_Schubert7-9_MID--AUDIO_16_R2_2018_wav.midi"
|
||||
|
||||
# resolution: rows per beat (e.g. 4 = 16th notes)
|
||||
ROWS_PER_BEAT = 4
|
||||
|
||||
names = ["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"]
|
||||
|
||||
def note_name(n):
|
||||
octave = n // 12 - 1
|
||||
return f"{names[n % 12]}-{octave}"
|
||||
|
||||
mid = MidiFile(MIDI_FILE)
|
||||
tpb = mid.ticks_per_beat
|
||||
|
||||
row_ticks = tpb // ROWS_PER_BEAT
|
||||
|
||||
time = 0
|
||||
rows = {}
|
||||
|
||||
for msg in mid:
|
||||
time += msg.time
|
||||
if msg.type == "note_on" and msg.velocity > 0:
|
||||
row = int(time // row_ticks)
|
||||
rows.setdefault(row, []).append(msg.note)
|
||||
|
||||
# build monophonic sequence (highest note wins)
|
||||
max_row = max(rows.keys())
|
||||
sequence = []
|
||||
|
||||
for r in range(max_row + 1):
|
||||
if r in rows:
|
||||
n = max(rows[r])
|
||||
sequence.append(note_name(n))
|
||||
else:
|
||||
sequence.append("...")
|
||||
|
||||
# trim (optional)
|
||||
sequence = sequence[:512]
|
||||
|
||||
# output as Lua
|
||||
print("sequence = {")
|
||||
for n in sequence:
|
||||
print(f' "{n}",')
|
||||
print("}")
|
||||
@@ -1,130 +1,127 @@
|
||||
unpack = unpack or table.unpack
|
||||
-- key separator: |
|
||||
-- empty note: "..."
|
||||
|
||||
function build_markov_model(sequence, order)
|
||||
local function make_key(tbl)
|
||||
return table.concat(tbl, "|")
|
||||
math.randomseed(os.time())
|
||||
|
||||
local unpack = unpack or table.unpack
|
||||
|
||||
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
|
||||
|
||||
local function unmake_key(k)
|
||||
local result = {}
|
||||
for t in string.gmatch(k, "[^|]+") do
|
||||
result[#result + 1] = t
|
||||
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 function has_value (tab, val)
|
||||
for index, value in ipairs(tab) do
|
||||
if value == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function add_key(str, value)
|
||||
return str .. "|" .. value
|
||||
-- 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
|
||||
|
||||
local function split_last(full)
|
||||
local i = full:match(".*()|")
|
||||
return full:sub(1, i-1), full:sub(i+1)
|
||||
end
|
||||
function build_markov_model(sequence, order)
|
||||
-- TODO: add {"..." x order} to beginning?
|
||||
|
||||
local counts = {}
|
||||
local totals = {}
|
||||
local model = { }
|
||||
|
||||
-- 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 key = make_key({unpack(sequence, i, i + order - 1)})
|
||||
local next_note = sequence[i + order]
|
||||
|
||||
local notes_full = add_key(notes, sequence[i + order])
|
||||
counts[notes_full] = (counts[notes_full] or 0) + 1
|
||||
local data = model[key] or { next={}, total=0 }
|
||||
|
||||
data.next[next_note] = (data.next[next_note] or 0) + 1
|
||||
data.total = data.total + 1
|
||||
|
||||
model[key] = data
|
||||
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]
|
||||
-- normalize
|
||||
for temp_key,temp_data in pairs(model) do
|
||||
for temp_note, temp_count in pairs(temp_data.next) do
|
||||
model[temp_key].next[temp_note] = temp_count / temp_data.total
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
for k,v in pairs(model) do
|
||||
print("-----" .. k)
|
||||
for k2,v2 in pairs(v.next) do
|
||||
print(k2, v2)
|
||||
end
|
||||
end
|
||||
--]]
|
||||
|
||||
return {
|
||||
order = order,
|
||||
model = model,
|
||||
counts = counts -- keep raw counts (useful!)
|
||||
model = model
|
||||
}
|
||||
end
|
||||
|
||||
function generate_sequence(model_data, length)
|
||||
local model = model_data.model
|
||||
local order = model_data.order
|
||||
local order = model.order
|
||||
local model_data = model_data.model
|
||||
|
||||
-- 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
|
||||
-- random start key
|
||||
local model_keys = {}
|
||||
for k,_ in pairs(model) do
|
||||
start_key = k
|
||||
break
|
||||
model_keys[#model_keys + 1] = k
|
||||
end
|
||||
local start_key = model_keys[math.ceil(math.random() * #model_keys)]
|
||||
|
||||
-- (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
|
||||
-- sequence starts with the start key
|
||||
local seq = unmake_key(start_key)
|
||||
|
||||
-- generation loop
|
||||
while #seq < length do
|
||||
-- build current state key
|
||||
local state = table.concat({unpack(seq, #seq - order + 1, #seq)}, "|")
|
||||
local current_key = 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}
|
||||
local chosen = "..."
|
||||
|
||||
local key_data = model[current_key]
|
||||
if key_data then
|
||||
local r = math.random()
|
||||
local prob_sum = 0.0
|
||||
for new_note, new_prob in pairs(key_data.next) do
|
||||
prob_sum = prob_sum + new_prob
|
||||
if prob_sum < r then
|
||||
chosen = new_note
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #matches == 0 then break end
|
||||
-- print(current_key .. " --> " .. chosen)
|
||||
|
||||
-- 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
|
||||
seq[#seq+1] = chosen
|
||||
end
|
||||
|
||||
return seq
|
||||
end
|
||||
|
||||
-- todo: feed samples
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
-- todo
|
||||
42
tools/musicator/sequence_to_strudel.py
Normal file
42
tools/musicator/sequence_to_strudel.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import sys
|
||||
import re
|
||||
|
||||
ROWS_PER_BEAT = 4 # keep consistent with your MIDI extraction
|
||||
SOUND = "piano"
|
||||
|
||||
def parse_sequence(text):
|
||||
return re.findall(r'"([^"]+)"', text)
|
||||
|
||||
def to_strudel_notes(seq):
|
||||
out = []
|
||||
for n in seq:
|
||||
if n == "..." or n == "---":
|
||||
out.append("~")
|
||||
else:
|
||||
# C-5 → c5, C#5 → c#5
|
||||
note = n.replace("-", "")
|
||||
out.append(note.lower())
|
||||
return out
|
||||
|
||||
def chunk(seq, size):
|
||||
for i in range(0, len(seq), size):
|
||||
yield seq[i:i+size]
|
||||
|
||||
# read from stdin
|
||||
text = sys.stdin.read()
|
||||
|
||||
sequence = parse_sequence(text)
|
||||
notes = to_strudel_notes(sequence)
|
||||
|
||||
# group into musical lines (4 beats)
|
||||
lines = []
|
||||
for group in chunk(notes, ROWS_PER_BEAT * 4):
|
||||
lines.append(" ".join(group))
|
||||
|
||||
pattern = "\n".join(lines)
|
||||
|
||||
print("note(`")
|
||||
print(pattern)
|
||||
print(f"`).sound(\"{SOUND}\")")
|
||||
|
||||
# npm install -g strudel-cli
|
||||
414
tools/musicator/teach.lua
Normal file
414
tools/musicator/teach.lua
Normal file
@@ -0,0 +1,414 @@
|
||||
-- teach the musicator
|
||||
-- uses samples from: https://magenta.tensorflow.org/datasets/maestro#v300
|
||||
|
||||
--require("luarocks.loader")
|
||||
--require("luamidi")
|
||||
|
||||
require("./musicator")
|
||||
local inspect = require("inspect")
|
||||
|
||||
math.randomseed(os.time())
|
||||
|
||||
function flatten(v)
|
||||
local res = {}
|
||||
local function flatten(v)
|
||||
if type(v) ~= "table" then
|
||||
table.insert(res, v)
|
||||
return
|
||||
end
|
||||
for _, v in ipairs(v) do
|
||||
flatten(v)
|
||||
end
|
||||
end
|
||||
flatten(v)
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local training_data = {
|
||||
|
||||
-- simple ascending phrase
|
||||
{
|
||||
"C-4","...","D-4","...","E-4","...","G-4","...",
|
||||
"E-4","...","D-4","...","C-4","...","...","..."
|
||||
},
|
||||
|
||||
-- descending answer
|
||||
{
|
||||
"G-4","...","F-4","...","E-4","...","D-4","...",
|
||||
"C-4","...","D-4","...","E-4","...","...","..."
|
||||
},
|
||||
|
||||
-- arpeggio major
|
||||
{
|
||||
"C-4","...","E-4","...","G-4","...","C-5","...",
|
||||
"G-4","...","E-4","...","C-4","...","...","..."
|
||||
},
|
||||
|
||||
-- arpeggio minor
|
||||
{
|
||||
"A-4","...","C-5","...","E-5","...","A-5","...",
|
||||
"E-5","...","C-5","...","A-4","...","...","..."
|
||||
},
|
||||
|
||||
-- stepwise melody (folk-like)
|
||||
{
|
||||
"D-4","...","E-4","...","F-4","...","G-4","...",
|
||||
"F-4","...","E-4","...","D-4","...","...","..."
|
||||
},
|
||||
|
||||
-- repeated note rhythm
|
||||
{
|
||||
"C-5","C-5","...","C-5","...","C-5","C-5","...",
|
||||
"D-5","...","E-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- bounce pattern
|
||||
{
|
||||
"C-5","...","G-4","...","C-5","...","G-4","...",
|
||||
"D-5","...","A-4","...","D-5","...","...","..."
|
||||
},
|
||||
|
||||
-- scale run up
|
||||
{
|
||||
"C-4","D-4","E-4","F-4","G-4","A-4","B-4","C-5",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- scale run down
|
||||
{
|
||||
"C-5","B-4","A-4","G-4","F-4","E-4","D-4","C-4",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- syncopated feel
|
||||
{
|
||||
"C-5","...","...","D-5","...","...","E-5","...",
|
||||
"C-5","...","...","G-4","...","...","...","..."
|
||||
},
|
||||
|
||||
-- triplet-ish feel (simulated)
|
||||
{
|
||||
"E-5","D-5","C-5","...","E-5","D-5","C-5","...",
|
||||
"G-4","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- small jumps
|
||||
{
|
||||
"C-5","...","E-5","...","D-5","...","F-5","...",
|
||||
"E-5","...","C-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- call
|
||||
{
|
||||
"G-4","...","A-4","...","C-5","...","A-4","...",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- response
|
||||
{
|
||||
"E-4","...","F-4","...","G-4","...","F-4","...",
|
||||
"D-4","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- denser pattern (DDR-like)
|
||||
{
|
||||
"C-5","D-5","E-5","...","D-5","E-5","F-5","...",
|
||||
"E-5","D-5","C-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- alternating pattern (good for gameplay)
|
||||
{
|
||||
"C-5","...","E-5","...","C-5","...","E-5","...",
|
||||
"D-5","...","F-5","...","D-5","...","...","..."
|
||||
},
|
||||
|
||||
-- higher register variant
|
||||
{
|
||||
"G-5","...","A-5","...","B-5","...","D-6","...",
|
||||
"B-5","...","A-5","...","G-5","...","...","..."
|
||||
},
|
||||
|
||||
-- low register grounding
|
||||
{
|
||||
"C-4","...","G-3","...","C-4","...","G-3","...",
|
||||
"F-3","...","C-4","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- variant of ascending with offset
|
||||
{
|
||||
"...","C-4","...","D-4","...","E-4","...","G-4",
|
||||
"...","E-4","...","D-4","...","C-4","...","..."
|
||||
},
|
||||
|
||||
-- staggered rhythm
|
||||
{
|
||||
"C-4","...","...","D-4","...","E-4","...","...",
|
||||
"G-4","...","E-4","...","D-4","...","...","..."
|
||||
},
|
||||
|
||||
-- broken arpeggio (different spacing)
|
||||
{
|
||||
"C-4","E-4","...","G-4","...","C-5","...",
|
||||
"G-4","E-4","...","C-4","...","...","...","..."
|
||||
},
|
||||
|
||||
-- minor variation (shifted)
|
||||
{
|
||||
"...","A-4","C-5","...","E-5","...","A-5","...",
|
||||
"E-5","...","C-5","...","A-4","...","...","..."
|
||||
},
|
||||
|
||||
-- repeated + variation
|
||||
{
|
||||
"D-4","D-4","...","E-4","...","F-4","F-4","...",
|
||||
"G-4","...","F-4","...","E-4","...","...","..."
|
||||
},
|
||||
|
||||
-- zig-zag motion
|
||||
{
|
||||
"C-5","...","E-5","...","D-5","...","F-5","...",
|
||||
"E-5","...","G-5","...","F-5","...","...","..."
|
||||
},
|
||||
|
||||
-- alternating step/jump
|
||||
{
|
||||
"C-5","...","D-5","...","G-5","...","F-5","...",
|
||||
"E-5","...","C-5","...","D-5","...","...","..."
|
||||
},
|
||||
|
||||
-- denser burst pattern
|
||||
{
|
||||
"C-5","D-5","E-5","F-5","...","E-5","D-5","C-5",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- rolling pattern
|
||||
{
|
||||
"E-5","...","D-5","...","C-5","...","D-5","...",
|
||||
"E-5","...","G-5","...","E-5","...","...","..."
|
||||
},
|
||||
|
||||
-- syncopation variant
|
||||
{
|
||||
"...","C-5","...","...","E-5","...","...","G-5",
|
||||
"...","E-5","...","C-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- low-high interplay
|
||||
{
|
||||
"C-4","...","G-4","...","C-5","...","G-4","...",
|
||||
"E-4","...","C-4","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- descending but staggered
|
||||
{
|
||||
"C-5","...","...","B-4","...","A-4","...","...",
|
||||
"G-4","...","F-4","...","E-4","...","...","..."
|
||||
},
|
||||
|
||||
-- small trill-like feel
|
||||
{
|
||||
"E-5","F-5","E-5","...","E-5","F-5","E-5","...",
|
||||
"D-5","...","C-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- call variant (shifted timing)
|
||||
{
|
||||
"...","G-4","...","A-4","...","C-5","...","A-4",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- response variant
|
||||
{
|
||||
"...","E-4","...","F-4","...","G-4","...","F-4",
|
||||
"D-4","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- dense DDR-ish alternating
|
||||
{
|
||||
"C-5","...","D-5","...","C-5","...","D-5","...",
|
||||
"E-5","...","F-5","...","E-5","...","...","..."
|
||||
},
|
||||
|
||||
-- higher variation arpeggio
|
||||
{
|
||||
"G-5","...","B-5","...","D-6","...","G-6","...",
|
||||
"D-6","...","B-5","...","G-5","...","...","..."
|
||||
},
|
||||
|
||||
-- low groove pattern
|
||||
{
|
||||
"C-3","...","C-4","...","G-3","...","C-4","...",
|
||||
"F-3","...","C-4","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- slightly chaotic (good for branching)
|
||||
{
|
||||
"C-5","...","E-5","D-5","...","G-5","...","F-5",
|
||||
"...","D-5","...","C-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- mixed density
|
||||
{
|
||||
"C-5","D-5","...","E-5","...","F-5","G-5","...",
|
||||
"E-5","...","D-5","C-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- offset staircase up
|
||||
{
|
||||
"...","C-4","D-4","E-4","F-4","G-4","A-4","B-4",
|
||||
"C-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- offset staircase down
|
||||
{
|
||||
"...","C-5","B-4","A-4","G-4","F-4","E-4","D-4",
|
||||
"C-4","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- dense zigzag
|
||||
{
|
||||
"C-5","E-5","D-5","F-5","E-5","G-5","F-5","A-5",
|
||||
"G-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- jack pattern (DDR classic)
|
||||
{
|
||||
"C-5","C-5","C-5","...","C-5","C-5","...","...",
|
||||
"D-5","D-5","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- alternating two-note burst
|
||||
{
|
||||
"C-5","D-5","C-5","D-5","C-5","D-5","...","...",
|
||||
"E-5","F-5","E-5","F-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- wide jumps
|
||||
{
|
||||
"C-4","...","G-5","...","D-4","...","A-5","...",
|
||||
"E-4","...","B-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- rolling triplet-ish
|
||||
{
|
||||
"C-5","E-5","G-5","...","E-5","C-5","E-5","...",
|
||||
"G-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- syncopated dense
|
||||
{
|
||||
"...","C-5","D-5","...","E-5","...","F-5","G-5",
|
||||
"...","E-5","...","C-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- mirrored pattern
|
||||
{
|
||||
"C-5","D-5","E-5","F-5","E-5","D-5","C-5","...",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- chord-outline arpeggio feel
|
||||
{
|
||||
"C-4","...","G-4","...","E-5","...","G-4","...",
|
||||
"C-4","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- broken rhythm variant
|
||||
{
|
||||
"C-5","...","D-5","E-5","...","F-5","...","G-5",
|
||||
"E-5","...","D-5","...","C-5","...","...","..."
|
||||
},
|
||||
|
||||
-- fast burst then rest
|
||||
{
|
||||
"C-5","D-5","E-5","F-5","G-5","A-5","...","...",
|
||||
"...","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- low-high bounce fast
|
||||
{
|
||||
"C-3","C-5","C-3","C-5","C-3","C-5","...","...",
|
||||
"G-3","G-5","G-3","G-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- repeated with shift
|
||||
{
|
||||
"...","E-5","...","E-5","...","E-5","...","...",
|
||||
"D-5","...","C-5","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- clustered mid
|
||||
{
|
||||
"D-5","E-5","F-5","...","E-5","D-5","C-5","...",
|
||||
"D-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- broken descending
|
||||
{
|
||||
"C-6","...","A-5","...","F-5","...","D-5","...",
|
||||
"C-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- chaotic jumpy (important for branching)
|
||||
{
|
||||
"C-5","...","F-5","D-5","...","A-5","...","E-5",
|
||||
"...","G-5","...","C-5","...","...","...","..."
|
||||
},
|
||||
|
||||
-- double-step pattern
|
||||
{
|
||||
"C-5","D-5","D-5","E-5","E-5","F-5","...","...",
|
||||
"G-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- uneven spacing
|
||||
{
|
||||
"C-5","...","...","D-5","E-5","...","...","F-5",
|
||||
"G-5","...","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- fast alternating high
|
||||
{
|
||||
"G-5","A-5","G-5","A-5","G-5","A-5","...","...",
|
||||
"F-5","E-5","...","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- low groove with variation
|
||||
{
|
||||
"C-3","...","C-4","...","G-3","...","D-4","...",
|
||||
"F-3","...","C-4","...","...","...","...","..."
|
||||
},
|
||||
|
||||
-- semi-random filler (very useful)
|
||||
{
|
||||
"C-5","...","E-5","...","D-5","...","G-5","...",
|
||||
"F-5","...","A-5","...","E-5","...","...","..."
|
||||
},
|
||||
|
||||
-- near-repetition (state collision booster)
|
||||
{
|
||||
"C-5","...","D-5","...","E-5","...","C-5","...",
|
||||
"D-5","...","E-5","...","C-5","...","...","..."
|
||||
},
|
||||
|
||||
-- same but shifted (VERY important)
|
||||
{
|
||||
"...","C-5","...","D-5","...","E-5","...","C-5",
|
||||
"...","D-5","...","E-5","...","C-5","...","..."
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
local model = build_markov_model(flatten(training_data), 2)
|
||||
|
||||
print(inspect(model))
|
||||
|
||||
--[[
|
||||
local generated = generate_sequence(model, 100)
|
||||
|
||||
for i,v in ipairs(generated) do
|
||||
print(v)
|
||||
end
|
||||
--]]
|
||||
Reference in New Issue
Block a user