notes-gabrielsoule

Euclidean Polyrhythm Generation

The main idea here is that n onsets spread as evenly as possible over k slots generates very nice rhythms that can be found in music from all over the world. The original paper noted that these rhythms are generated by invocations of the Euclidean algorithm, however I think that observation unnecessarily complicates the technique. The original paper can be found here: https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.1340&rep=rep1&type=pdf)

Obviously, this procedure is simple when gcd(n, k) != 1. When the two parameters are coprime, however, things get interesting (and slightly more difficult to calculate).

Let E(n, k) define such a rhythm for positive integers n, k. In a rhythmic sequence, let . denote a rest and x denote an onset. Here are some examples of Euclidean rhythms:

Some observations are as follows:

Code

import math
import random
import sys

rotate = True ## TODO add rotation
bpm = 100

def gen(n, k, bars):
    step = k / n
    out_bin = [0] * (k * bars)
    out = []
    for i in range(n * bars):
        out_bin[round(step * i)] = 1
        out.append((round(step * i)) * ((bpm / 60.0) / k)) 

    print(out_bin)
    print(out)
    return out

def random_pair(k):
    return random.randint(1, k), k

def main():
    in_data = []
    sequences = []
    print(len(sys.argv))
    flag = random.randint(0, 1)
    r1 = [3, 4]
    r2 = [6, 8]
    r3 = [12, 16]
    r4 = [6, 8]

    if len(sys.argv) == 1:
        in_data.append("")
        sequence = random_pair(r1[flag])
        print(sequence)
        in_data.append(sequence[0])
        in_data.append(sequence[1])
        sequence = random_pair(r2[flag])
        print(sequence)
        in_data.append(sequence[0])
        in_data.append(sequence[1])
        sequence = random_pair(r3[flag])
        print(sequence)
        in_data.append(sequence[0])
        in_data.append(sequence[1])
        sequence = random_pair(r4[flag])
        sequence = ((int) (sequence[0] / 3) + 1, sequence[1])
        print(sequence)
        in_data.append(sequence[0])
        in_data.append(sequence[1])
        # sequence = random_pair(24)
        # print(sequence)
        # in_data.append(sequence[0])
        # in_data.append(sequence[1])
    else:
        in_data = sys.argv

    for i in range(1, len(in_data), 2):
        sequences.append(gen(int(in_data[i]), int(in_data[i + 1]), 8))



    f = open("polyrhythm.synthSequence", "w")
    freq_options = [58, 62, 65, 67, 73, 78, 82, 87]
    freq = random.choice(freq_options)
    amplitude = 0.7
    for sequence in sequences:
        for i in sequence:
            f.write("@  {} 0.05 SineEnv {} {} 0.01 0.1 0.0\n".format(i, amplitude, freq))
            print("@  {} 0.05 SineEnv {} {} 0.01 0.1 0.0".format(i, amplitude, freq))
        f.write("\n")
        print()
        freq = freq * 2
        amplitude = amplitude * 0.7
    f.close()

main()