Skip to content

Instantly share code, notes, and snippets.

@schollz
Created January 23, 2023 16:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save schollz/e2cc49425d54336b422e144e7eeb34cc to your computer and use it in GitHub Desktop.
Save schollz/e2cc49425d54336b422e144e7eeb34cc to your computer and use it in GitHub Desktop.
-- melody generator
engine.name="PolyPerc"
musicutil=require("musicutil")
function init()
engine.release(2)
engine.amp(0.3)
local chords={"I","vi","IV","iii"} -- change to any chords
local movement_left=6 -- change to 0-12
local movement_right=6 -- change to 0-12
local stay_on_chord=0.95 -- change to 0-1
play(chords,1,movement_left,movement_right,stay_on_chord)
end
function play(chord_structure,factor,move_left,move_right,stay_scale)
stay_scale=util.clamp(stay_scale,0,1)
-- notes to play
local notes_to_play={}
-- generate chords
local chords={}
for i,v in ipairs(chord_structure) do
local scale=musicutil.generate_scale(12,1,8)
local chord_notes=musicutil.generate_chord_roman(12,1,v)
local notes_in_chord={}
for _,u in ipairs(chord_notes) do
notes_in_chord[u]=true
for j=1,8 do
notes_in_chord[u+(12*j)]=true
end
end
local note_start=72
for jj=1,4*factor do
-- find note_start in scale
local notes_to_choose={}
for _,note in ipairs(scale) do
if note>note_start-move_left and note<note_start+move_right then
table.insert(notes_to_choose,note)
end
end
local weights={}
local scale_size=#notes_to_choose
for i,note in ipairs(notes_to_choose) do
weights[i]=notes_in_chord[note]~=nil and scale_size or scale_size*(1-stay_scale)
-- weights[i]=weights[i]+(scale_size-i)
end
local note_next=choose_with_weights(notes_to_choose,weights)
table.insert(notes_to_play,note_next)
note_start=note_next
end
end
local notei=0
local note_last=0
clock.run(function()
while true do
clock.sync(1/factor)
notei=(notei)%#notes_to_play+1
local note_next=notes_to_play[notei]
if note_next~=note_last then
engine.hz(musicutil.note_num_to_freq(note_next))
end
note_last=note_next
end
end)
end
function choose_with_weights(choices,weights)
local totalWeight=0
for _,weight in pairs(weights) do
totalWeight=totalWeight+weight
end
local rand=math.random()*totalWeight
local choice=nil
for i,weight in pairs(weights) do
if rand<weight then
choice=choices[i]
break
else
rand=rand-weight
end
end
return choice
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment