View on GitHub

total-serialism

Toolbox full of Algorithmic Composition methods

Stochastic

Methods for procedurally generating number sequences based on various types of randomness, such as white noise (evenly distributed), rolling dice, flipping a coin and more. Also includes Markov Chain.

Include

const Rand = require('total-serialism').Stochastic;

Methods

seed

Set the seed for the Random Number Genrators. A value of 0 sets to unpredictable seeding. The seed can only be set once for every import of the library. However, seed can be reset between function calls.

// set the random number generator seed
Rand.seed(19374);

getSeed

Get the seed from the Random Number Generator. Returns the value that was latest set with seed().

// get the random number generator seed
Rand.getSeed();
// => 19374

random randomFloat

Generate a list of random integers or floating points between a specified range (excluding high value).

Alias: randomF

arguments

// generate an array of random integers in range
Rand.random(5, 0, 12); 
//=> [ 3, 3, 7, 1, 0 ]

// generate an array of random floats in range -1 to 1
Rand.randomFloat(3, -1, 1); 
//=> [ 0.6291111850577886, 0.15153786227276944, 0.32814801081039646 ]

drunk drunkFloat

Generate a list of random values (int/float) but the next random value is within a limited step-range of the previous value generating a random “drunk” walk, also referred to as brownian motion. Inspired by the [drunk]-object in MaxMSP

Alias: drunkF

arguments

Rand.drunkFloat(5);
//=> [ 0.493, 0.459, 0.846, 0.963, 0.400 ] 

//  0.88 ┼╮╭╮  
//  0.76 ┤╰╯│  
//  0.63 ┤  │  
//  0.51 ┤  ╰╮ 
//  0.39 ┤   │ 
//  0.26 ┤   ╰ 

Rand.drunk(10, 5, 0, 24);
//=> [ 13, 10, 14, 13, 14, 13, 15, 10, 8, 4 ] 

// 22.00 ┼       ╭╮ 
// 17.80 ┼─╮╭─╮  ││ 
// 13.60 ┤ ││ ╰╮╭╯│ 
//  9.40 ┤ ││  ╰╯ │ 
//  5.20 ┤ ╰╯     │ 
//  1.00 ┤        ╰ 

Rand.drunk(10, 4, 0, 12, 6, false);
//=> [ 2, -2, 2, 1, -3, -1, -2, -1, 3, 6 ] 

//  2.00 ┤╭╮        
// -0.20 ┤│╰╮     ╭ 
// -2.40 ┼╯ ╰╮    │ 
// -4.60 ┤   │╭╮ ╭╯ 
// -6.80 ┼   ╰╯│╭╯  
// -9.00 ┤     ╰╯  

coin

Generate a list of random integer values 0 or 1 like a coin toss, heads/tails. Or

arguments

// generate an array of coin tosses
Rand.coin(10); 
//=> [ 0, 1, 0, 1, 0, 1, 0, 0, 1, 0 ]

dice

Generate a list of dice rolls, resulting in random integer values from 1 to 6. Optionally use a second argument to set the amount of sides for the die.

arguments

// generate an array of dice rolls
Rand.dice(4); 
//=> [ 4, 4, 2, 3 ] 

// optionally set the amount of sides for the die
Rand.dice(4, 8); 
//=> [ 8, 3, 7, 1 ]

urn

Generate a list of unique random integer values between a certain specified range (excluding high val). An ‘urn’ is filled with values and when one is picked it is removed from the urn. If the outputlist is longer then the range, the urn refills when empty. On refill it is made sure no repeating value can be picked. Inspired by the [urn]-object in MaxMSP.

arguments

// generate an array with random values picked from an urn
// with default range 0 to 12 (exclusive)
Rand.urn(5);
//=> [ 3, 6, 2, 8, 7 ] 

// set the range with a second argument to 0-7 (exclusive)
// when more values then range are requested the urn 
// refills and reshuffles
Rand.urn(10, 7);
//=> [ 6, 4, 3, 2, 0, 5, 1, 4, 2, 1 ] 

// A third argument sets a lower range replacing the default 0
Rand.urn(12, -3, 3);
//=> [ -3, 1, -1, 2, 0, -2, 2, -2, 0, -1, -3, 1 ]

twelveTone

Generate a list of 12 semitones then shuffle the list based on the random seed.

arguments

// generate a twelve-tone series, influenced by the random seed
// basically the same as: Mod.shuffle(Gen.spread(12));
Rand.twelveTone(); 
//=> [ 11, 0, 8, 2, 4, 9, 1, 6, 3, 5, 7, 10 ]

shuffle

Shuffle an array, influenced by the random seed. Based on the Fisher-Yates shuffle algorithm by Ronald Fisher and Frank Yates in 1938. The algorithm has run time complexity of O(n)

Alias: scramble()

arguments

// shuffle the items in an array, influenced by the random seed
Rand.shuffle([0, 5, 7, 12]); 
//=> [ 7, 5, 0, 12 ]

choose

Choose random items from an array provided with uniform probability distribution. The default array is an array of 0 and 1.

arguments

// Choose random items from an array provided, uniform distribution
Rand.choose(5, [0, 1, 2, 3, 5, 8, 13]);
//=> [ 3, 0, 13, 3, 2 ] 

// Array can have any datatype
Rand.choose(5, ['c', 'e', 'g']);
//=> [ 'c', 'c', 'g', 'e', 'g' ] 

pick

Pick random items from an array provided. An “urn” is filled with values and when one is picked it is removed from the urn. If the outputlist is longer then the range, the urn refills when empty. On refill it is made sure no repeating value can be picked.

arguments

// Pick random items from an array similar to urn
// no repeating values untill urn is empty
Rand.pick(5, [0, 1, 2, 3, 5, 8, 13]);
//=> [ 2, 5, 8, 1, 3 ] 

// Array can have any datatype
Rand.pick(5, ['c', 'e', ['g', 'd']]);
//=> [ 'e', [ 'g', 'd' ], 'c', [ 'g', 'd' ], 'e' ] 

clave

Generate random clave patterns. The output is a binary list that represents a rhythm, where 1’s represent onsets and 0’s rests. First argument sets the list length output, second argument sets the maximum gap between onsets, third argument the minimum gap.

arguments

Rand.clave();
//=> [ 1, 0, 1, 0, 0, 1, 0, 1 ] 
//=> █ █  █ █

Rand.clave(8);
//=> [ 1, 0, 0, 1, 0, 1, 0, 1 ] 
//=> █  █ █ █

Rand.clave(16, 4);
//=> [ 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1 ] 
//=> █   █ █   █  █ █

Rand.clave(16, 3, 1);
//=> [ 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1 ] 
//=> █  █  ██  █ █  █  

expand

Expand an array based upon the pattern within an array. The pattern is derived from the rate in change between values by calculating the differences between every consecutive value. The newly generated values are selected randomly from the list of possible changes, but in such a way that every change occurs once in the sequence of total changes before reshuffling and selecting the next one (see the pick method for explanation). The resulting output starts with the input array.

arguments

Rand.seed(3141);
Rand.expand([0, 9, 7, 3, 5, 0, -1], 30);

//=>  9.00 ┤╭╮      ╭╮                    
//    6.80 ┤│╰╮     ││                    
//    4.60 ┤│ │╭╮   ││                    
//    2.40 ┤│ ╰╯│   │╰─╮             ╭─╮  
//    0.20 ┼╯   ╰─╮╭╯  │             │ │╭ 
//   -2.00 ┤      ╰╯   ╰╮   ╭─╮      │ ╰╯ 
//   -4.20 ┼            │   │ │    ╭╮│    
//   -6.40 ┤            ╰╮  │ │    │╰╯    
//   -8.60 ┤             │╭╮│ ╰─╮  │      
//  -10.80 ┤             ╰╯╰╯   │╭╮│      
//  -13.00 ┤                    ╰╯╰╯       

Rand.seed(6181);
Rand.expand([0, 9, 7, 3, 5, 0, -1], 30);

//=>  9.00 ┤╭╮                            
//    6.80 ┤│╰╮                           
//    4.60 ┤│ │╭╮                         
//    2.40 ┤│ ╰╯│        ╭╮╭╮             
//    0.20 ┼╯   ╰─╮╭╮    │╰╯╰╮        ╭── 
//   -2.00 ┤      ╰╯│  ╭╮│   ╰╮       │   
//   -4.20 ┼        ╰╮ │││    ╰╮   ╭╮ │   
//   -6.40 ┤         │ │╰╯     │╭╮ ││ │   
//   -8.60 ┤         ╰╮│       ╰╯╰╮│╰╮│   
//  -10.80 ┤          ╰╯          ││ ╰╯   
//  -13.00 ┤                      ╰╯      

MarkovChain

Build a Markov Chain from a set of datapoints and use it to generate new values or an array of values based on the probabilities of the transitions in the provided training dataset. A Markov Chain is a model that describes possible next events based on a current state (first order) and sometimes previous states (2nd, 3rd, … n-order). The Markov Chain is a broadly used method in algorithmic music to generate new material (melodies, rhythms, but even words) based on a set of provided material, but can also be used in linguistics to analyze word or sentence structures.

const Rand = require('total-serialism').Stochastic;

var melody = ['c', 'e', 'f', 'e', 'g', 'f', 'a', 'c'];
// make a MarkovChain instance and optionally train with array
let markov = new Rand.MarkovChain(melody);

// add more to the training
var melody2 = ['g', 'a', 'b', 'g', 'a', 'f', 'd', 'e'];
markov.train(melody2);

// view the transition table (stored as dictionary)
// can also be used to export the table to a file
console.log(markov.table);
// { c: [ 'e' ],
//   e: [ 'f', 'g' ],
//   f: [ 'e', 'a', 'd' ],
//   g: [ 'f', 'a', 'a' ],
//   a: [ 'c', 'b', 'f' ],
//   b: [ 'g' ],
//   d: [ 'e' ] }

// set the state of the model used as initial value
markov.state('c');

// set the seed for the global random number generator
markov.seed(31415); 
// same as works with Rand.seed()

// go to the next state based on the models probabilities
markov.next();
// => 'e'

// generate an array of 10 values 
markov.chain(10);
// => [ 'f', 'd', 'e', 'g', 'a', 'b', 'g', 'a', 'c', 'e' ]

// clear the model
markov.clear();

// read a model from a json/object structure
markov.read({ c: ['e'], e: ['f', 'g' ]});

DeepMarkovChain

This is an identical approach to the Markov Chain while also offering the possibility of training to create n-order chains. In theory, longer chains preserve the original structure of the model, but won’t generate as diverse outputs.

Alias: DeepMarkov()

const Rand = require('total-serialism').Stochastic;

var pattern = [1, 2, 3, 1, 2, 4, 1, 2, 5, 2, 3, 4];
// make a MarkovChain instance and optionally train with array
// an optional second argument sets the order of the markov (default=2)
let markov = new Rand.DeepMarkov(pattern, 2);

// view the transition table (stored as Map())
// Keys are stored as stringis derived via JSON.stringify()
console.log(markov.table);
// Map(7) {
//   '[1,2]' => [ 3, 4, 5 ],
//   '[2,3]' => [ 1, 4 ],
//   '[3,1]' => [ 2 ],
//   '[2,4]' => [ 1 ],
//   '[4,1]' => [ 2 ],
//   '[2,5]' => [ 2 ],
//   '[5,2]' => [ 3 ]
// }

// set the state of the model used as initial value
markov.state([1, 2]);

// set the seed for the global random number generator
markov.seed(31415); 
// same as works with Rand.seed()

// go to the next state based on the model probabilities
markov.next();
// => 5

// generate an array of 10 values 
markov.chain(10);
// => [ 2, 3, 1, 2, 5, 2, 3, 4, 1, 2 ]

// clear the model
markov.clear();

// TO DO:
// read/write a model from a Map structure
let model = markov.table;
let otherMarkov = new DeepMarkov();
otherMarkov.read(model);

// for storage to file or transfer between DeepMarkov instances
// you can use the build in stringify and parse methods
// these methods utilize JSON.stringify() and .parse()
// with specific replacer and reviver methods
let modelString = markov.stringify();
let fromStringMarkov = new DeepMarkov();
fromStringMarkov.parse(modelString);