Last active
August 7, 2018 14:17
-
-
Save martinmestres/9db4270028a6d5e1d0b1b42a23c2537e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Markov's Playground | |
-- -------------------------------- | |
-- Page 1: | |
-- Key 1 change PAGE | |
-- Key 2 randomize SCALE | |
-- Key 3 randomize PROBABILITIES | |
-- | |
-- Page 2: | |
-- Key 1 change PAGE | |
-- Key 2 PLAY recorded LOOP | |
-- Key 3 record LOOP | |
-- Enc 1 LOOP LENGTH | |
-- Enc 2 NOTE ON probability | |
engine.name = "PolyPerc" | |
local loopLength = 8 -- Loops Length {8,8} ??? | |
local Scale = {0,2,4,5,7,9,11} | |
local Prob = {{},{},{},{},{},{},{}} | |
local Loop1 = {{".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","."}, | |
{".",".",".",".",".",".",".",".",".",".",".",".",".",".",".","."}} | |
local loopPos = 0 | |
local writeLoop = 0 | |
local playLoop = 0 | |
local newNote = 1 | |
local noteSel = 1 | |
local loopSel = 1 | |
local loopRecSel = 1 | |
local pageNumber = 1 | |
local noteOnProb = 90 | |
local alternate = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} | |
local restCounter = 0 | |
local anchor = 1 | |
local blink = 1 | |
local rollResult | |
local loopStateMemory = 0 | |
local altControls = 0 | |
params:add_number("bpm",40,200,100) | |
params:add_number("root note",30,90,60) | |
params:add_number("rest counter limit",1,16,2) | |
function init() | |
math.randomseed( os.time() ) | |
engine.cutoff(4000) | |
params:add_control("cutoff",controlspec.new(60,10000,'exp',2,4000,'hz')) | |
params:set_action("cutoff", function(x) engine.cutoff(x) end) | |
engine.amp(1) | |
engine.pw(0.5) | |
rndProb() | |
counter = metro.alloc(count, 0.15, -1) | |
counter:start() | |
end | |
-- Counter | |
function count() | |
blinker() | |
counter.time = (60 / (params:get("bpm"))) / 4 --Change Tempo | |
if playLoop == 0 then --Check LOOPER OFF state | |
rollResult = noteOnRoll() | |
if rollResult == 1 then | |
noteSel = probRoll() | |
engine.hz(midi_to_hz(params:get("root note") + noteSel)) --Play note | |
restCounter = 0 --Rester Counter | |
else actRestCounter() | |
end | |
looper() --If | |
else | |
rollResult = noteOnRoll() | |
looper() | |
if tonumber(Loop1[loopSel][loopPos]) ~= nil then -- Check LOOPER ON state | |
engine.hz(midi_to_hz(params:get("root note") + Loop1[loopSel][loopPos])) | |
if loopSel == loopRecSel then | |
for i=1, 7 do -- LOOP path update | |
if Loop1[loopSel][loopPos] == Scale[i] then | |
newNote = i | |
break | |
end | |
end | |
else noteSel = probRoll() -- Keep on markoving if LOOP ~ REC | |
end | |
end | |
end | |
redraw() | |
end | |
-- LOOPER | |
function looper() | |
loopPos = util.clamp(((loopPos + 1) % (loopLength+1)), 1, loopLength) | |
if writeLoop == 1 then | |
if rollResult == 0 then | |
Loop1[loopRecSel][loopPos] = "." | |
else | |
Loop1[loopRecSel][loopPos] = noteSel | |
end | |
end | |
end | |
-- Random Scale Generator | |
function rndScale() | |
for i=2, 7 do | |
Scale[i] = Scale[i-1] + math.random(1,3) -- Creates Scale{} | |
end | |
end | |
-- Random Prob Gen per note --REVOIR SYSTEME D'ALEATOIRE | |
function rndProb() --FAIRE DE LA FONCTION LE MELANGE DUNE TABLE | |
for i=1, 7 do --METTRE CA EN CAS DE LONG PRESS DANS KEY3 | |
remain = 100 | |
deck = shuffleTable{1,2,3,4,5,6,7} -- random distribution order | |
for i=1, math.random(0, 10) do deck = shuffleTable(deck) end -- even more deck shuffle | |
for j=1, 7 do | |
Prob[i][deck[j]] = util.clamp((math.random(0, remain)), 0, 90) -- Mixup tables + prevent 100% | |
remain = (remain - Prob[i][deck[j]]) | |
end | |
end | |
end | |
-- Note On roll | |
function noteOnRoll() | |
local Test = math.random(100) | |
if Test >= noteOnProb then return 0 | |
else return 1 | |
end | |
end | |
-- Midi to Hz | |
function midi_to_hz(note) | |
local hz = (440 / 32) * (2 ^ ((note - 9) / 12)) | |
return hz | |
end | |
-- Prob roll | |
function probRoll() | |
currentNote = 1 | |
repeat | |
local Test = math.random(100) | |
if Test >= Prob[newNote][currentNote] then | |
currentNote = currentNote+1 | |
if currentNote > 7 then currentNote = 1 end | |
x = false | |
else x = true end | |
until x == true | |
newNote = currentNote | |
if restCounter >= params:get("rest counter limit") then --check Restcounter and reset | |
newNote = anchor end --Anchor HERE | |
return Scale[newNote] | |
end | |
-- shuffle table content | |
function shuffleTable(t) | |
for i = #t, 2, -1 do | |
local swap = math.random(1, i) | |
t[i], t[swap] = t[swap], t[i] | |
return t | |
end | |
end | |
-- Rest Counter | |
function actRestCounter() | |
restCounter = restCounter + 1 | |
end | |
--Blinker | |
function blinker() | |
blink = (blink + 7) % 14 | |
end | |
-- FPS | |
function fps() | |
end | |
-- BUTTONS | |
function key(n, z) | |
-- KEY1 activate alternative controls | |
if n == 1 and z == 1 then altControls = 1 | |
elseif n == 1 and z == 0 then altControls = 0 | |
end | |
-------------KEYPAGE1---------------------------------------------------- | |
if pageNumber == 1 then | |
if altControls == 1 then -- ALT CONTROLS | |
-- PAGE 1 Key2 change Scale | |
if n == 2 and z == 1 then | |
rndScale() end | |
-- PAGE 1 Key 3 chang Probs | |
if n == 3 and z == 1 then | |
rndProb() | |
end | |
end | |
-------------KEYPAGE2---------------------------------------------------- | |
else | |
if altControls == 1 then -- ALT CONTROLS | |
-- Loop REC Selector | |
if n == 2 and z == 1 then loopRecSel = 1 | |
elseif n == 3 and z == 1 then loopRecSel = 2 | |
end | |
else -- BASE CONTROLS | |
if n == 2 and z == 1 then -- LOOP SWITCH ON/OF | |
playLoop = (playLoop + 1) % 2 | |
loopStateMemory = 1 | |
writeLoop = 0 | |
if playLoop == 0 then loopStateMemory = 0 end | |
end | |
if n == 3 and z == 1 then | |
writeLoop = 1 | |
else | |
writeLoop = 0 | |
if loopStateMemory == 1 then playLoop = 1 end | |
end | |
end | |
end | |
-------------END---------------------------------------------------- | |
redraw() | |
end | |
--ENCODERS | |
function enc(n, d) | |
--Page change | |
if altControls == 0 and n == 1 then | |
pageNumber = util.clamp((pageNumber + d),1,2) | |
end | |
-------------ENCPAGE1---------------------------------------------------- | |
if pageNumber == 1 then | |
if altControls == 1 then -- ALT CONTROLS | |
-- Anchor SELECTOR | |
if n == 3 then | |
anchor = util.clamp((anchor + d),1,7) | |
redraw() | |
end | |
-- Note selected note MANUAL change | |
if n == 2 then | |
Scale[anchor] = util.clamp(Scale[anchor] + d, 0, 24) | |
end | |
end | |
if altControls == 0 then -- BASIC CONTROLS | |
-- Note On Prob | |
if n == 3 then | |
noteOnProb = util.clamp((noteOnProb + d), 1, 100) | |
redraw() | |
end | |
end | |
end | |
-------------ENCPAGE2---------------------------------------------------- | |
if pageNumber == 2 then | |
-- Loop Selection | |
if n == 3 then | |
loopSel = util.clamp((loopSel + d), 1, 2) | |
end | |
-- Loop Length | |
if n == 1 and altControls == 1 then | |
loopLength = util.clamp((loopLength + d), 1, 16) | |
redraw() | |
end | |
--Table SHIFT | |
if n == 2 then | |
--RIGHT | |
if d-1 == 0 then | |
local memory = Loop1[loopSel][loopLength] | |
table.remove(Loop1[loopSel], loopLength) | |
table.insert(Loop1[loopSel],1,memory) | |
--LEFT | |
else | |
local memory = Loop1[loopSel][1] | |
table.remove(Loop1[loopSel], 1) | |
table.insert(Loop1[loopSel],loopLength,memory) | |
end | |
end | |
end | |
end | |
function redraw() | |
screen.clear() | |
--------------------------------------------------------PAGE1---------------------------------------------------- | |
if pageNumber == 1 then | |
screen.aa(0) | |
screen.font_size(8) | |
-- Draws Notes | |
for i=1, 7 do | |
screen.move((15*i)+1, 6) | |
if i == anchor then --Anchor blink Feedback | |
screen.level(blink) | |
else screen.level(10) | |
end | |
screen.font_face(1) | |
screen.text_center(Scale[i]) | |
-- Draws probability for each note | |
for j=1, 7 do | |
screen.move((15*i)+1, 10 + (j*7)) | |
screen.level(1) | |
screen.text_center(Prob[i][j]) | |
end | |
end | |
-- Line | |
screen.move(11, 9) | |
screen.line(112, 9) | |
screen.stroke() | |
-- Curent note Feedback | |
screen.rect((newNote*15-1)+1,8,4,1) | |
screen.level(5) | |
screen.stroke() | |
-- NoteOne Probability | |
screen.move(120, 64) | |
screen.level(5) | |
screen.text_center(noteOnProb .. "%") | |
--------------------------------------------------------PAGE2---------------------------------------------------- | |
else | |
-- Line | |
screen.level(2 - loopSel) -- Loop 1 selection FeedBack | |
screen.rect(0, 30, 128, 4) | |
screen.fill() | |
screen.level(-1 + loopSel) -- Loop 2 selection FeedBack | |
screen.rect(0, 45, 128, 4) | |
screen.fill() | |
-- Looper Memory feedback | |
for ii=1, 2 do | |
for i=1, loopLength do | |
screen.move(((127/loopLength)*i)-4, ((15+(ii*15)) - alternate[ii][i])) | |
-- Jumping numbers feedback | |
if loopSel == ii then | |
if playLoop == 1 then | |
if tonumber(Loop1[ii][i]) ~= nil then -- Marche mais entraine ligne du dessous | |
alternate[ii][i] = (alternate[ii][i] + 1) % math.random(2, 4) | |
end | |
else alternate[ii] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
end | |
else alternate[ii] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | |
end | |
-- Looper current position feedback | |
if i == loopPos then screen.level(15) | |
else screen.level(4) | |
end | |
screen.font_face(1) | |
screen.text_center(Loop1[ii][i]) | |
end | |
end | |
-- Looper On/oFF Feedback rect | |
screen.move(11, 9) | |
if playLoop == 1 then --Loop On Blink | |
screen.rect(115, 58, 6, 6) | |
screen.level(blink) | |
screen.fill() | |
elseif loopStateMemory == 1 then --Loop On, Write On Steady State | |
screen.rect(115, 58, 6, 6) | |
screen.level(15) | |
screen.fill() | |
end | |
if playLoop == 0 and loopStateMemory == 0 then --Loop Off, Write Off | |
screen.rect(116, 59, 5, 5) | |
screen.level(1) | |
screen.stroke() | |
end | |
-- Write On/oFF Feedback | |
screen.move(80, 64) | |
if writeLoop == 1 then screen.level(blink) | |
else screen.level(1) | |
end | |
screen.text("REC".. loopRecSel) | |
end | |
-----------------------------------------------------ALL----------------------------------------- | |
--Curent page | |
screen.move(0, 64) | |
screen.level(4) | |
screen.text("P" .. pageNumber) | |
screen.update() | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you, your advices will certainly help me a lot. I will try to apply them one by one without breaking everything.