Skip to content

Instantly share code, notes, and snippets.

@augeas
Created March 2, 2015 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save augeas/1a74e3363fd48716f9e9 to your computer and use it in GitHub Desktop.
Save augeas/1a74e3363fd48716f9e9 to your computer and use it in GitHub Desktop.
Here's Looking at Euclid...
# Licensed under the Apache License Version 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
# Here's Looking at Euclid. Giles R. Greenway, March 2015.
# Euclidian poly-rhythms...
import itertools
# http://www.pygame.org/docs/ref/midi.html
import pygame
from pygame import midi
from pygame import time
# http://cgm.cs.mcgill.ca/~godfried/publications/banff.pdf
def euclid_rhythm(n,k):
if k > n:
n,k = k,n
seq = [ [True] for i in range(k) ] + [ [False] for j in range(n-k) ]
while seq[-1] == seq[-2]: # Are there multiple copies of the same sequence at the end?
last = seq[-1]
for item in seq:
if item == last:
break # Run out of things to tack the sequence on to...
else:
if seq[-1] == last:
item += seq.pop()
else:
break # Run out of copies of the sequence.
return [ i for i in itertools.chain(*seq) ]
# Phase rhythms in and out according to a three-bit Grey code.
gray = [ [0,0,1], [0,1,1], [0,1,0], [1,1,0], [1,1,1], [1,0,1], [1,0,0] ]
# Return the ith Gray code for j beats.
def masker(i,j):
for t in range(j):
yield gray[i]
# Three rhythms, as the Korg Volca Keys has three voices. It's amusing to ring-mod them together.
# 4, 9 & 25 are the lowest triplet of relatively prime intergers, the first three primes squared.
pairs = [ (4,9), (9,25), (4,25) ]
# Lengths of each rhythm.
lengths = [ max(i) + abs(i[0]-i[1]) for i in pairs ]
# Number of beats given to each combination of rhythms given by the number of rhythms present,
# multiplied by the sum of their lengths.
dur = [ sum(gray[j]) * sum([ lengths[i] for i in gray[j] ]) for j in range(7) ]
# Iterate over the combination of rhythms at each beat.
masks = itertools.chain(*[ masker(i,dur[i]) for i in range(7) ])
# Three iterators to cycle through each rhythm.
voices = [ itertools.cycle(euclid_rhythm(*v)) for v in pairs ]
freqs = [ 30, 60, 120 ]
intervals = [ 4, 2, 1 ]
counts = [ 0, 0, 0 ]
pygame.init()
midi.init()
# Gratuitously hard-coded MIDI channel...
midi_out = midi.Output(2)
for mask in masks:
beats = [ v.next() for v in voices ]
# Each note is the base pitch for each rhythm, plus the time since the last beat multiplied by an interval.
notes = [ (freqs[i] + intervals[i] * counts[i]) & 127 for i in range(3) if beats[i] and mask[i] ]
for i in range(3):
if beats[i]:
counts[i] = 0
else:
counts[i] += 1
for i in notes:
midi_out.note_on(i,127)
time.delay(200)
for i in notes:
midi_out.note_off(i,127)
midi_out.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment