• Jona

    i use [l2s] and [s2l] a lot recently. @whale-av i did not know that there is a vanilla version of [l2s]. thanks for that.
    is there perhaps a vanilla [s2l] too (i am fine with using the external, but still)?

    posted in technical issues read more
  • Jona

    Here is an update of the patch.
    It is now possible to choose the GM midi instruments that are stored in the midifile, but mostly it sounds more interesting to choose different sounds.
    And it is possible to store collections of midi data to a file.
    For now I could not store the length of the notes, because between note on and note off events of one note are often other notes in the midifile and because of the markov characteristic the note off can happen in a markov chain a long time after the note on, or even before.
    Because of that the sound would hang a lot of times.
    The only way to have the note length information from a midifile that I can think of would be to calculate the milliseconds of a note with counting the ticks from one note on event to the corresponding note off event and to save this millisecond value together with the other midi values like pitch, velocity, program change etc..
    But that seems to be quite complicated.
    I hope the patch is more or less self explainig but I will try to answer any questions if that is not the case (and perhaps write a little documentation).
    I am also happy to hear about errors.
    Here is an interesting read about markov chains and jazz improvisation:

    https://vtechworks.lib.vt.edu/bitstream/handle/10919/36831/dmfetd.pdf?sequence=1

    LuaMidiMarkovX.pd

    posted in patch~ read more
  • Jona

    Based on the midi generator https://forum.pdpatchrepo.info/topic/10791/markovgenerator-a-music-generator-based-on-markov-chains-with-variable-length that i made with @ingox some time ago I made a Lua markov chain generator that generates endless markov chains from midi files.
    The patch needs the Ofelia, Cyclone and Zexy libraries.

    I have one question: Is there a way to keep the "original" sounds from the midi file? Perhaps if i store the midi control data together with the other values (pitch, velocity, program change, midi channel)? Somehow the midi program change values do not have the "right" sound information. If I play midi files with the [seq] object it sounds like it should. So for now i choose the sound manually but it would be nice if it sounds like it is meant to.
    LuaMidiMarkov.pd
    LuaMidiMarkov.PNG

    A silly example:

    posted in patch~ read more
  • Jona

    @Cuinjune thanks for pointing that out. I overlooked the first error message. I will replace it with the faster list drip with list store from @ingox as a subpatch. https://forum.pdpatchrepo.info/topic/11122/faster-list-drip-with-list-store-pd-0-48

    posted in patch~ read more
  • Jona

    @Cuinjune Hi. Thanks for trying. The error tells that there is no list in the generator yet. It should be already fixed, it was because of the order creation of Pure Data "Inits". Tell me if not.

    posted in patch~ read more
  • Jona

    I finished the Ofelia / Lua Markov Generator abstraction / patch.
    The markov generator is part of two patches but can easily be used as an abstraction.
    I want to use it for pattern variations of a sequencer for example.
    It just needs a Pure Data list as input and outputs a markov chain of variable order and length.
    Or draw into the array and submit it to the markov generator.
    The first patch is an experiment trying to create interesting sounds with the markov algorithm.
    In addition I used the variable Delay from the Pure Data help files:
    LuaMarkovGeneratorSynthesizer.pd
    LuaMarkovGeneratorSynthesizer.PNG
    The second patch creates markov chains at audio rate, it is quite cpu heavy but works until the 10th markov order.
    It is quite noisy but I was courius how it will sound:
    LuaMarkovGeneratorAudioRate.pd
    LuaMarkovGeneratorAudioRate.PNG

    And here is the Lua code.
    The core of the code is adapted from this python code: https://eli.thegreenplace.net/2018/elegant-python-code-for-a-markov-chain-text-generator/
    A few things that I do not really understand yet, but finally it works without errors (it was not easy sometimes ;) ):

    -- LUA MARKOV GENERATOR;
    function ofelia.list(fv);
    ;
    math.randomseed(os.time()- os.clock() * 1000);
    ;
    print("LUA MARKOV GENERATOR");
    local markovOrder = fv[1];
    print("Markov Order: ", math.floor(markovOrder));
    ;
    -- make dictionary;
    ;
    local function defaultdict(default_value_factory);
    ;
    local t = {};
    local metatable = {};
    metatable.__index = function(t, key);
    if not rawget(t, key) then;
    rawset(t, key, default_value_factory(key));
    end;
    return rawget(t, key);
    end;
    return setmetatable(t, metatable);
    end;
    ;
    -- make markov matrix;
    ;
    local model = defaultdict(function() return {} end);
    local data = {};
    for i = 1, #ofelia.markovInputList do;
    data[i] = ofelia.markovInputList[i];
    end;
    print("Data Size: ", #ofelia.markovInputList);
    for i = 1, markovOrder do;
    table.insert(data, data[i]);
    end;
    for i = 1, #data - markovOrder do;
    local state = table.concat({table.unpack(data, i, i + markovOrder - 1)}, "-");
    local next = table.unpack(data, i + markovOrder, i + markovOrder);
    model[state][next] = (model[state][next] or 0)+1;
    end;
    ;
    -- make tables from dict;
    ;
    local keyTbl = {};
    local nexTbl = {};
    local prbTbl = {};
    for key, value in pairs(model) do;
    for k, v in pairs(value) do;
    table.insert(keyTbl, key);
    table.insert(nexTbl, k);
    table.insert(prbTbl, v);
    end;
    end;
    ;
    print("Key: ", table.unpack(keyTbl));
    print("Nex: ", table.unpack(nexTbl));
    print("Prb: ", table.unpack(prbTbl));
    ;
    print("Make a Markov Chain...");
    ;
    function ofelia.markovChain();
    ;
    -- make start key;
    ;
    local startKey = {};
    if ofelia.randomStart == 1 then;
    local randomKey = math.random(#keyTbl);
    startKey = randomKey;
    else;
    startKey = 1;
    end;
    ;
    local markovString = keyTbl[startKey];
    local out = {};
    for match in string.gmatch(keyTbl[startKey], "[^-]+") do;
    table.insert(out, match);
    end;
    ;
    -- make markov chain;
    ;
    for i = 1, ofelia.markovChainLength do;
    ;
    -- weighted random choices;
    ;
    local choices = {};
    local weights = {};
    for j = 1, #keyTbl do;
    if markovString == keyTbl[j] then;
    table.insert(choices, nexTbl[j]);
    table.insert(weights, prbTbl[j]);
    end;
    end;
    ;
    -- print ("choices:", table.unpack(choices));
    -- print ("weights:", table.unpack(weights));
    ;
    local totalWeight = 0;
    for _, weight in pairs(weights) do;
    totalWeight = totalWeight + weight;
    end;
    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;
    ;
    if math.type(choice) == "integer" then;
    choice = choice * (1.0);
    end;
    ;
    table.insert(out, choice);
    local lastStep = {table.unpack(out, #out - (markovOrder-1), #out)};
    markovString = table.concat(lastStep, "-");
    end;
    ;
    return {table.unpack(out, markovOrder + 1, #out)};
    end;
    end;
    ;
    

    posted in patch~ read more
  • Jona

    The markov generator works now. It was just a small formatting error.
    Here is a small experiment with the markov generator, but basically i want to use it for sequencing and it can be used for anything else, just needs string formatted data as input. i think it is quite a bit faster than the generator that i build together with @ingox some time ago. https://forum.pdpatchrepo.info/topic/10791/markovgenerator-a-music-generator-based-on-markov-chains-with-variable-length/1
    lua_markov_generator3b.pd

    posted in technical issues read more
  • Jona

    i build a lua markov generator inspired from this python code with the idea to use it with pure data / ofelia: https://eli.thegreenplace.net/2018/elegant-python-code-for-a-markov-chain-text-generator/
    finally the code works fine with the eclipse lua ide or with this ide https://studio.zerobrane.com/, but somehow not yet with pure data / ofelia.
    here is the (not yet working) patch: ofelia_markov.pd
    and here the lua code: markov_pd.lua

    math.randomseed(os.time()- os.clock() * 1000);
    -- make dictionary;
    function defaultdict(default_value_factory);
    local t = {};
    local metatable = {};
    metatable.__index = function(t, key);
    if not rawget(t, key) then;
    rawset(t, key, default_value_factory(key));
    end;
    return rawget(t, key);
    end;
    return setmetatable(t, metatable);
    end;
    ;
    ;
    -- make markov matrix;
    print('Learning model...')
    ;
    STATE_LEN = 3;
    print ("markov order: " , STATE_LEN) 
    model = defaultdict(function() return {} end)
    data = "00001111010100700111101010000005000700111111177111111";
    datasize = #data;
    print("data: ", data);
    print("datasize: ", #data);
    data = data .. data:sub(1, STATE_LEN);
    print("altered data: ", data);
    print("altered datasize: ", #data);
    for i = 1, (#data - STATE_LEN) do;
    state = data:sub(i, i + STATE_LEN-1);
    -- print("state: ", state)    
    local next = data:sub(i + STATE_LEN, i + STATE_LEN);
    -- print("next: ", next);
    model[state][next] = (model[state][next] or 0)+1;
    end;
    ;
    ;
    -- make markov chain;
    print('Sampling...');
    ;
    local keyTbl = {};
    local nexTbl = {};
    local prbTbl = {};
    for key, value in pairs(model) do;
    for k, v in pairs(value) do;
    table.insert(keyTbl, key);
    table.insert(nexTbl, k);
    table.insert(prbTbl, v);
    end;
    end;
    print ("keyTbl: ", table.unpack(keyTbl));
    print ("nexTbl: ", table.unpack(nexTbl));
    print ("prbTbl: ", table.unpack(prbTbl));
    ;
    ;
    -- make random key;
    local randomKey = keyTbl[math.random(#keyTbl)];
    state = randomKey;
    print("RandomKey: ", randomKey);
    ;
    -- make table from random key;
    local str = state;
    local stateTable = {};
    for i = 1, #str do;
    stateTable[i] = str:sub(i, i);
    end;
    ;
    out = stateTable;
    print ("random key as table: ", table.unpack(out));
    ;
    -- make markov chain;
    for i = 1, datasize do;
    ;
    -- weighted random choices;
    local choices = {};
    local weights = {};
    for j = 1, #keyTbl do;
    if state == keyTbl[j] then;
    table.insert(choices, nexTbl[j]);
    table.insert(weights, prbTbl[j]);        
    end;  
    end;
    -- print ("choices:",table.unpack(choices));
    -- print ("weights:",table.unpack(weights));
    ;
    local totalWeight = 0;
    for _, weight in pairs(weights) do;
    totalWeight = totalWeight + weight;
    end;
    rand = math.random() * totalWeight;     
    local choice = nil;
    for i, weight in pairs(weights) do;
    if rand < weight then;       
    choice = choices[i];
    choice = choice:sub(1,1);
    break;
    else;
    rand = rand - weight;
    end;
    end;  
    ;
    table.insert(out, choice); 
    state = string.sub(state, 2, #state) .. out[#out];
    -- print("choice", choice);
    -- print ("state", state);
    end;    
    ;
    print("markov chain: ", table.concat(out));
    

    somehow pure data / ofelia interprets the nexTbl values as a functions while they are strings?
    this is part of what the pure data console prints: nexTbl: function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30 function: 0000000003B9BF30
    ofelia: [string "package.preload['#d41b70'] = nil package.load..."]:93: attempt to index a function value (local 'choice')

    and this ist the output from the lua ide:

    Program 'lua.exe' started in 'C:\Users\Jonat\Downloads\ZeroBraneStudio\myprograms' (pid: 220).
    Learning model...
    markov order:   1
    data:   00001111010100700111101010000005000700111111177111111
    datasize:   53
    altered data:   000011110101007001111010100000050007001111111771111110
    altered datasize:   54
    Sampling...
    keyTbl:     5   7   7   7   1   1   1   0   0   0   0
    nexTbl:     0   0   1   7   7   1   0   5   7   1   0
    prbTbl:     1   2   1   1   1   17  7   1   2   7   13
    RandomKey:  1
    random key as table:    1
    markov chain:   111111000077701111100070001100000001100017011171111117
    Program completed in 0.06 seconds (pid: 220).
    

    posted in technical issues read more
  • Jona

    i implemented the generations family which remembers, in addition to the cellular automata rules, the generation of the cell and changes the color accordingly.
    here is some information about the generations: http://www.mirekw.com/ca/rullex_gene.html
    Ofelia2_GridXConwayGenerations.pd

    posted in patch~ read more
  • Jona

    Hi @Cuinjune, thank you for the feedback.

    1. Happily "Shift" works again. I meant the functions that shift the grid one step into one direction. It did not work anymore because i needed to adjust the functions to the 2 dimensional table.
    2. You are right, I do not need to return the table, i think your suggestion to do that internally with pd.Array() is the solution. Will try that tonight.
    3. It is fine for me to write a 2-dimensional lua table to a 1 dimensional [array]. With "flatten" I meant to make a 1 dimensional table out of a 2 dimensional table. With "deflatten" I meant to make a 2 dimensional table out of a 1 dimensional table. I think I did not found the right terms for that.
    4. Thanks. That was my mistake, it works again. I still think there is some strange behaviour under certain conditions with sending bangs into ofelia objects, but I am not sure anymore. I will check that and post a minimal patch if I still find that behaviour.

    posted in patch~ read more
  • Jona

    I implemented Conways Game of Life and variations into the Grid patch.
    The original game of life rules are applied if the second and third green and the third red toggle are selected (rule 23/3).
    Click some "cells" in the grid for the start position.
    The green toggles set the condition for the living cells.
    The red toggles set the condition for the dead cells.
    It is possible to change the rules while the game of life is running.
    Ofelia2_GridXConway.pd
    gridXConway.PNG

    posted in patch~ read more
  • Jona

    @Cuinjune the conway implementation does work now (with and without borders). to achieve that i changed the 1-dimensional table into a 2-dimensional table. because of that i could not figure out yet how to make "shift" work again (except "shift up", which already works), but i will find a solution. the second issue is (again) saving the grid, because pd seems to crash when i return a 2-dimensional table (even without setting the pd [array]).
    here is a minimal example of my issue: return_2dim_table.pd
    i also wonder if it makes more sense to save a 2-dimensional lua table into a [text] object (which seems kind of an equivalent) or an [array] object. if i save into [array] i have to flatten the lua table before saving and "de"flatten before i load it back into the lua table. or get and set the array/table line by line. basically my main question is: what is the best way to save and recall a 2-dimensional lua table in pure data? everything else does work (and i think better than before).
    i also put the matrix transformation functions (shift, invert and so on...) into single ofelia define objects (again), because i think it is better for keeping track of the code.
    Ofelia2_GridXMatrix.pd
    another issue that i found is that sending a bang into ofelia.bang does not work sometimes while a directly connected bang does work (the "Invert" bang in ofelia2_gridxmatrix.pd for example). which is not really a problem because there are easy workarounds, just wanted to mention it.
    i really appreciate all the possibilities of the ofelia library, and i think i just scratched the surface....
    edit: everything besides saving works again.

    posted in patch~ read more
  • Jona

    @Cuinjune no problem and thanks, i think i can figure that out by myself. i will try.

    These are the conway (game of life) rules:
    For a space that is 'populated': Each cell with one or no neighbors dies, as if by solitude. Each cell with four or more neighbors dies, as if by overpopulation. Each cell with two or three neighbors survives.
    For a space that is 'empty' or 'unpopulated' Each cell with three neighbors becomes populated.

    and here i found a very basic example that is easy for me to understand, so i do not need the grid abstraction that i posted above (although it could be useful for further experiments):

    function Evolve( cell )
        local m = #cell
        local cell2 = {}
        for i = 1, m do
            cell2[i] = {}
            for j = 1, m do
                cell2[i][j] = cell[i][j]
            end
        end
     
        for i = 1, m do
            for j = 1, m do
                local count
                if cell2[i][j] == 0 then count = 0 else count = -1 end
                for x = -1, 1 do
                    for y = -1, 1 do
                        if i+x >= 1 and i+x <= m and j+y >= 1 and j+y <= m and cell2[i+x][j+y] == 1 then count = count + 1 end
                    end
                end
                if count < 2 or count > 3 then cell[i][j] = 0 end
                if count == 3 then cell[i][j] = 1 end
            end
        end
     
        return cell
    end    
    

    https://rosettacode.org/wiki/Conway's_Game_of_Life#Lua

    i still think that i need to use a 2 dimensional table like this for conway (like they did in the conway examples that i found too):

    mt = {}          -- create the matrix
        for i=1,N do
          mt[i] = {}     -- create a new row
          for j=1,M do
            mt[i][j] = 0
          end
        end
    

    posted in patch~ read more
  • Jona

    @Cuinjune thanks a lot for the update :)
    inspired by the conway implementation from @weightless https://forum.pdpatchrepo.info/topic/10916/conway-s-game-of-life-implementation-with-data-structures i tried to implement the conway algorhithm. if you select the first preset and click the conway toggle you can see an example.
    Ofelia2_GridXConway.pd
    it works inside the grid, but i cant figure out the upper and lower border logic yet. i think it is a disadvantage of the one dimensional table for this case, perhaps a 2 dimensional table would make things easier? or i just dont get the logic ;) it could be more difficult to implement the existing functions (like shift or shuffle) into the 2 dimensional table, that was quite easy with the one dimensional table. @weightless also used "2 dimensional arrays" (the [text] object) in his conway patch. something like this: https://github.com/syntruth/Lua-Grid sounds great for the grid logic, but still to complex for me to understand...

    posted in patch~ read more
  • Jona

    @Cuinjune thanks for checking the patch. it crashes on my computer if the grid has more than ~1100 cells, except it is 1 * y or x * 1. i also tried to reinstall ofelia and pure data, but still. i wonder if anyone else can reproduce the crash? good idea with the abstractions, i updated it in the post above, its now vanilla (except ofelia).

    posted in patch~ read more
  • Jona

    @cuinjune hi. of course, here is the patch: Ofelia2_GridX.pd
    i meant save or copy the grid (with the toggles at the bottom of the interface), not the patch. that happens in the [pd pattern] subpatch, perhaps it has to do with pd class?

    posted in patch~ read more
  • Jona

    i updated the patch and put all of the grid transform functions into one define object. i think its more structured, on the other side it makes perhaps sense to have smaller objects to find errors more easily and organize the patch visually? i also got rid of the red rectangles so i dont need the step position fbo anymore which makes a big difference in performance. @cuinjune my problem now is that pure data crashes when i save or copy a grid that is bigger than 32x32. do you know the reason for that?

    posted in patch~ read more
  • Jona

    or something like that?
    no51no0.pd
    no51no0.PNG

    posted in technical issues read more
  • Jona

    i added some new features and optimized the patch as far as i am able for now.
    mainly matrix transformations but also a pattern save mechanism which makes use of pd class.
    i think it would make sense to combine some of the functions into one define object, i am sure there is still some redundant code.
    and perhaps it can be more efficient, but i tried my best and its fast enough for my needs.
    be careful with invertMatrix if you have sound, it can get loud (its only midi out).
    @cuinjune I found one thing: I can toggle the define objects that are toggled from the pure data interface(except delete_matrix) only if they are connected with a cord, and not with send and receive. And thanks angain for the help with the patch :)
    Ofelia2_GridX.pd
    Ofelia2_GridX.PNG

    posted in patch~ read more
  • Jona

    i tried to optimize the patch. i dont think its perfect, but much more efficient than before.
    somehow it seems to slow down a little bit with a lot of cells although the cpu load is still below 50 percent.
    every drawing except the background is done with fbo now, i tried just to update the fbos when its necessary. so there is one fbo for the lines, one for the "raster", one for the toggled cells and one for the yellow/red play position.
    Ofelia2_GridX.pd
    gridX.PNG

    posted in patch~ read more
Internal error.

Oops! Looks like something went wrong!