Markov Chain Beatbox Generator
I made these tracks:
http://soundcloud.com/belisarius/sets/golf-music
Using the following transition matrix:
{{10, 1, 3/2, 2},
{1/2, 10, 3/2, 2},
{1/2, 1, 10, 2},
{1/2, 1, 3/2, 10}}
And the following program in Mathematica:
musicGen[n_, notes_, transMatrix_] :=
Module[{
im := IdentityMatrix[Length@notes],
a := Array[2^(# - 1) &, Length@notes],
soundLength = .1 n,
which
},
which[x_] := Position[x, 1][[1, 1]];
Sound[Join[
(SoundNote /@ notes[[
which[#] & /@
NestList[
RandomChoice[transMatrix[[which@#]] -> im] &,
RandomChoice@im,
n - 1]
]]
)
],
soundLength]
]
tm = {{10, 1, 3/2, 2}, {1/2, 10, 3/2, 2}, {1/2, 1, 10, 2}, {1/2, 1, 3/2, 10}}
notesSet = {"Snare", {"Slap", "Shaker"}, {"OpenTriangle", "Maracas"}, "RideBell"};
m = Array[If[#2 == 5 || #2 == #1, 10, #2/2] &, {Length@notesSet,Length@notesSet}];
mg = musicGen[100, notesSet, tm]
Being German, I was almost falling off my chair laughing at this creative abuse of our language. :-)
Here is some Scala. I am encoding the probabilities in a map that maps the beat to a list of successor beats in which the beats occure with a frequency proportional to their probability. An infinite lazy evaluated stream of beats is created, whose first 10 beats are skipped to get the appropriate randomness of the first output beat. We return the appropriate number of beats from the beginning of that stream. I use the type parameter T to be shorter and generic.
def markovChain[T](length : Int, nodes : Seq[T], probabilities : Map[T, Seq[T]]) : Seq[T] = {
def randomElement(seq : Seq[T]) = seq(Random.nextInt(seq.length))
def chain(node: T): Stream[T] =
Stream.cons(node, chain(randomElement(probabilities(node))))
return chain(randomElement(nodes)) drop(10) take(length)
}
which can be called like this:
val nodes = List("pv", "zk", "bschk", "kkkk")
val probabilities = Map(
"pv" -> List("pv", "zk", "zk", "zk", "zk", "bschk", "bschk", "bschk", "bschk", "bschk"),
"zk" -> List("pv", "pv", "pv", "zk", "zk", "bschk", "bschk", "bschk", "kkkk", "kkkk") ,
"bschk" -> List("zk", "zk", "zk", "bschk", "bschk", "kkkk", "kkkk", "kkkk", "kkkk", "kkkk"),
"kkkk" -> List("pv", "zk", "zk", "zk", "zk", "zk", "zk", "zk", "zk", "bschk"))
markovChain(20, nodes, probabilities) foreach (s => print (s + " "))