You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
5.4 KiB
191 lines
5.4 KiB
#!/usr/bin/env python3 |
|
# a deterministic techno generator for tidalcycles |
|
# input an integer value as a seed |
|
# and it spits out some techno ready to play |
|
# |
|
################################################## |
|
########### SETTINGS ############################# |
|
# what are the lowest and highest bpm values you want? |
|
lowestBpm = 90 |
|
highestBpm = 135 |
|
|
|
# stack name |
|
stackName = "techno" |
|
|
|
# force everything to happen within 1 bar |
|
oneBar = 1 |
|
|
|
# for euclidean rhythms, define the choices for the 2nd number |
|
# eg "[t(3,NN)]" |
|
dividers = [4,8,16] |
|
# for melodic lines, what divisions do you want to choose from? |
|
# eg 4 = quarter notes, 8 = eighth notes |
|
# tip: adding more of the same number will weight the randomness toward that |
|
melodicDivisions = [8,16,16,16] |
|
# keep melodies within 1 bar |
|
#melodicOneBar = 1 |
|
|
|
# for melodic sequences, define the choices for range of the notes |
|
# eg 12 is one octave, 24 is two, etc |
|
noteRange = [12,24,36] |
|
# define the shortest and longest sequence you want |
|
# eg if shortest is 7, there will be no melodic sequences shorter than 7 |
|
shortestMelodic = 4 |
|
longestMelodic = 16 |
|
|
|
# how many |
|
# how many percussive/rhythmic elements to generate? |
|
percCount = 5 |
|
percMidiChanStart = 0 |
|
# how many melodic elements to generate? |
|
melodyCount = 1 |
|
melodyMidiChanStart = 7 |
|
|
|
|
|
# perc note |
|
# set a static note for percussion tracks |
|
percNote = 0 |
|
# perc track names |
|
percNames = ["kick", "hh", "sd", "cp", "cymbal", "?", "?", "?", "?"] |
|
# for use generating sequences of 0's and 1's |
|
binary = [0,0,0,1] |
|
|
|
## import stuff |
|
import sys |
|
import random |
|
import math |
|
|
|
|
|
################################################## |
|
# this is the 1st argument given via command line |
|
# this is used to calculate everything |
|
# seeds should be 6 digits or longer |
|
input = sys.argv[1] |
|
|
|
print("-- seed: " + str(input)) |
|
|
|
|
|
########### THIS CHANGES EVERYTHING! ############# |
|
# set the random seed based on user input |
|
random.seed(input) |
|
################################################## |
|
|
|
# generate a bpm between lowest and highest |
|
# looks like: cps = (BPM/60/4) |
|
bpm = "cps = ("+str(random.randrange(lowestBpm, highestBpm, 1))+"/60/4)" |
|
print(bpm+"\n") |
|
|
|
|
|
|
|
def genOnOff(limit): |
|
"generate a series of 0's and 1's" |
|
zeroesOnes = "" |
|
for i in range(limit): |
|
zeroesOnes = zeroesOnes + str(random.choice(binary)) |
|
zeroesOnes = ", struct \"{"+zeroesOnes+"}%16\"" |
|
print(zeroesOnes) |
|
|
|
|
|
def euclid(divider): |
|
"generate a euclidean rhythm for tidalcycles" #struct "[t(3,8)]" |
|
# 3,8 10,16 4,16 |
|
#secondEuclid = str(random.choice(dividers)) |
|
secondEuclid = divider |
|
firstEuclid = str(random.randrange(2,int(secondEuclid))) |
|
#print("firstEuclid:"+firstEuclid) |
|
#print("secondEuclid:"+str(secondEuclid)) |
|
|
|
euclidSeed = random.random() |
|
# decide whether there are going to be changes in the euclid seq |
|
if (random.random() > random.random()): |
|
# the first and the second euclid numbers will stay the same |
|
# eg no <3 6 5> |
|
#print("") |
|
firstEuclid = firstEuclid |
|
else: |
|
# the first euclid number WILL sequence (eg <4,8>) |
|
#firstEuclid = "<"+str(random.randrange(2,int(random.choice(dividers)))+" "+str(random.randrange(2,int(random.choice(dividers))))+">" |
|
firstEuclid = "<"+str(random.randrange(2,16))+" "+str(random.randrange(2,16))+">" |
|
# decide whether the second number will seq |
|
if (random.random() > random.random()): |
|
# we will do like [t(??,<16,8>)] |
|
secondEuclid = "<"+str(random.choice(dividers))+" "+str(random.choice(dividers))+">" |
|
# [t(<3 8>,16)] |
|
|
|
|
|
print(", struct \"[t("+str(firstEuclid)+","+str(secondEuclid)+")]\"") |
|
|
|
def genNotes(melodicOneBar): |
|
""" |
|
Generate a series of numbers for use as midi notes |
|
accepts 1 or 0, where 1 limits the melody to 16 16th notes |
|
and 0 sets the melody to somewhere between the values |
|
of shortestMelodic and longestMelodic |
|
""" |
|
# between let's say 4 notes and 16 notes |
|
if (melodicOneBar == 1): |
|
melodyLength = 16 |
|
else: |
|
melodyLength = random.randrange(shortestMelodic,longestMelodic) |
|
|
|
melody = "" |
|
for i in range(melodyLength): |
|
melody = str(random.randrange(0,random.choice(noteRange))) + " " + str(melody) |
|
print("n "+"\"{"+melody+"}%"+str(random.choice(melodicDivisions))+"\"") |
|
|
|
|
|
|
|
# actually assemble the stack! |
|
print("p \""+stackName+"\" ") |
|
|
|
# stack stuff like bite, scramble, etc. will go here |
|
|
|
print("$ whenmod 8 7 (scramble 4)") # |
|
|
|
|
|
# the top of the stack |
|
print("$ stack [") |
|
|
|
# this is an empty track to make dealing with commas easier |
|
print(" n \"0\"") |
|
|
|
print(",struct \"[t*4]\" $ n 0 # midichan 0") |
|
|
|
# generate percussion tracks |
|
percMidiChan = 1 |
|
for i in range(percCount): |
|
# choose how long the rhythm will be |
|
if (oneBar == 1): |
|
percLength = 16 |
|
else: |
|
percLength = int(random.randrange(4,16)) |
|
#percSequence = genOnOff(percLength) |
|
#print(","+str(genOnOff(10))) |
|
#print(str(percSequence)) |
|
print("-- "+percNames[percMidiChan]) |
|
genOnOff(percLength) |
|
print (" $ n "+str(percNote)) |
|
print(" # midichan "+str(percMidiChan)) |
|
percMidiChan = percMidiChan + 1 |
|
|
|
|
|
# generate melodic tracks |
|
melodicMidiChan = melodyMidiChanStart |
|
#melodyMidiChanStart = 7 |
|
for i in range(melodyCount): |
|
print("-- ?") |
|
#print(", ") |
|
if (oneBar == 1): |
|
genOnOff(16) |
|
print("$") |
|
genNotes(1) |
|
else: |
|
genOnOff(16) |
|
print("$") |
|
genNotes(1) |
|
print("# midichan "+str(melodicMidiChan)+" + n (-36)") |
|
melodicMidiChan = melodicMidiChan + 1 |
|
|
|
|
|
print("]") |
|
print("# sunvox")
|
|
|