|
|
|
#!/usr/bin/env python3
|
|
|
|
scriptName = "Auto-Techno Generator"
|
|
|
|
version = 0.1
|
|
|
|
author = "Chris Beckstrom"
|
|
|
|
author_email = "chris@chrisbeckstrom.com"
|
|
|
|
# a deterministic techno generator for tidalcycles
|
|
|
|
# input an integer value as a seed
|
|
|
|
# and it spits out some techno ready to play
|
|
|
|
#
|
|
|
|
# use it in emacs like this:
|
|
|
|
# it will generate a random seed
|
|
|
|
#
|
|
|
|
# (defun autotechno()
|
|
|
|
# (interactive)
|
|
|
|
# (insert (shell-command-to-string (concat "/usr/bin/python ~/tidal-auto-techno/auto-techno.py " (number-to-string(random))))))
|
|
|
|
#
|
|
|
|
##################################################
|
|
|
|
########### SETTINGS #############################
|
|
|
|
# what are the lowest and highest bpm values you want?
|
|
|
|
lowestBpm = 92
|
|
|
|
highestBpm = 135
|
|
|
|
|
|
|
|
# force everything to happen within 1 bar
|
|
|
|
oneBar = 0
|
|
|
|
|
|
|
|
# stack name
|
|
|
|
# this doesn't matter, can be any string
|
|
|
|
stackName = "techno"
|
|
|
|
|
|
|
|
|
|
|
|
####### PERCUSSION ##############################
|
|
|
|
# for euclidean rhythms, define the choices for the 2nd number
|
|
|
|
# eg "[t(3,NN)]"
|
|
|
|
#dividers = [4,8,16]
|
|
|
|
dividers = [16]
|
|
|
|
# how many percussive/rhythmic elements to generate?
|
|
|
|
percCount = 5
|
|
|
|
percMidiChanStart = 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# perc note
|
|
|
|
# set some notes for percussion tracks
|
|
|
|
percNotes = [0,1,2,3]
|
|
|
|
# perc track names
|
|
|
|
# a percussion track will be generated for each item in this list
|
|
|
|
percNames = ["kick", "hh", "sd", "cp", "ohh","ride","cymbal"]
|
|
|
|
# for use generating sequences of 0's and 1's
|
|
|
|
#
|
|
|
|
#
|
|
|
|
#
|
|
|
|
####### MELODY #################################
|
|
|
|
# NOTE about melodic sequences:
|
|
|
|
# as of October 04, 2021 all melodic sequences are all notes
|
|
|
|
# ie no rests. the rhythm/rests is determined by a "struct" value
|
|
|
|
# just like with percussion
|
|
|
|
|
|
|
|
# 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 = 3
|
|
|
|
longestMelodic = 10
|
|
|
|
|
|
|
|
# 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
|
|
|
|
# how many
|
|
|
|
# how many melodic elements to generate?
|
|
|
|
melodyCount = 1
|
|
|
|
melodyMidiChanStart = 7
|
|
|
|
|
|
|
|
|
|
|
|
## import stuff
|
|
|
|
import sys
|
|
|
|
import random
|
|
|
|
import math
|
|
|
|
import re
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
|
|
##################################################
|
|
|
|
# this is the 1st argument given via command line
|
|
|
|
# this is used to calculate everything
|
|
|
|
rawinput = sys.argv[1]
|
|
|
|
|
|
|
|
# let's assume it's a hex value
|
|
|
|
# convert to decimal
|
|
|
|
#input = int(hex,int(89))
|
|
|
|
|
|
|
|
|
|
|
|
################ SEED HEX #####################
|
|
|
|
# make sure the seed is a hex value
|
|
|
|
# why? it doesn't really matter technically
|
|
|
|
# I just think it would be cool
|
|
|
|
# plus, hex values for long numbers are shorter
|
|
|
|
# and easier to read/type
|
|
|
|
# and might be good track names
|
|
|
|
# TODO - this is in progress
|
|
|
|
# if the input is a hex value, we'll know because it starts with 0x
|
|
|
|
if (rawinput.startswith("0x")):
|
|
|
|
# the input is a hex number
|
|
|
|
#print("string starts with 0x")
|
|
|
|
seed = rawinput.upper()
|
|
|
|
else:
|
|
|
|
# the input is NOT a hex number
|
|
|
|
# convert to a hex number
|
|
|
|
seed = hex(int(rawinput)).upper()
|
|
|
|
|
|
|
|
# by now the seed should start with 0X
|
|
|
|
# let's change that X to lowercase
|
|
|
|
seed = seed.replace("X","x")
|
|
|
|
#print("seed: "+seed)
|
|
|
|
|
|
|
|
decimalSeed = int(seed,16)
|
|
|
|
|
|
|
|
### FRONTMATTER ###
|
|
|
|
print("-- raw input: " + str(rawinput))
|
|
|
|
print("-- hex seed: "+seed)
|
|
|
|
print("-- decimal seed: "+str(decimalSeed))
|
|
|
|
print("-- generated at "+str(time.time()))
|
|
|
|
print("-- "+scriptName+" v"+str(version))
|
|
|
|
print("")
|
|
|
|
|
|
|
|
|
|
|
|
########### THIS CHANGES EVERYTHING! #############
|
|
|
|
# set the random seed based on user input
|
|
|
|
random.seed(decimalSeed)
|
|
|
|
##################################################
|
|
|
|
|
|
|
|
indent = " "
|
|
|
|
# generate a bpm between lowest and highest
|
|
|
|
# looks like: cps = (BPM/60/4)
|
|
|
|
bpm = "setcps ("+str(random.randrange(lowestBpm, highestBpm, 1))+"/60/4)"
|
|
|
|
#print(bpm)
|
|
|
|
|
|
|
|
|
|
|
|
####################### FUNCTIONS ###################
|
|
|
|
|
|
|
|
def generateBinary(busyness):
|
|
|
|
"""
|
|
|
|
busy-ness (sic)
|
|
|
|
Create a list of 0's and 1's from which patterns can be
|
|
|
|
created. The higher the busyness, the more 1's in the list,
|
|
|
|
which in turn creates more events in the generated sequence
|
|
|
|
busyness range from 0 to 9, where 9 is most busy,
|
|
|
|
and 0 is no activity at all
|
|
|
|
"""
|
|
|
|
if (busyness == 0):
|
|
|
|
binary = [0,0,0,0,0,0,0,0,0,0,0,1]
|
|
|
|
elif (busyness == 1):
|
|
|
|
binary = [0,0,0,0,0,0,0,0,1]
|
|
|
|
elif (busyness == 2):
|
|
|
|
binary = [0,0,0,0,0,0,0,1,1]
|
|
|
|
elif (busyness == 3):
|
|
|
|
binary = [0,0,0,0,0,0,1,1,1]
|
|
|
|
elif (busyness == 4):
|
|
|
|
binary = [0,0,0,0,0,1,1,1,1]
|
|
|
|
elif (busyness == 5):
|
|
|
|
binary = [0,0,0,0,1,1,1,1,1]
|
|
|
|
elif (busyness == 6):
|
|
|
|
binary = [0,0,0,1,1,1,1,1,1]
|
|
|
|
elif (busyness == 7):
|
|
|
|
binary = [0,0,1,1,1,1,1,1,1]
|
|
|
|
elif (busyness == 8):
|
|
|
|
binary = [0,0,1,1,1,1,1,1,1,1]
|
|
|
|
elif (busyness == 9):
|
|
|
|
binary = [0,0,1,1,1,1,1,1,1,1,1]
|
|
|
|
return binary
|
|
|
|
|
|
|
|
def genOnOff(limit,busyness,struct):
|
|
|
|
"generate a series of 0's and 1's"
|
|
|
|
zeroesOnes = ""
|
|
|
|
|
|
|
|
# here we can change the list of 0's and 1's
|
|
|
|
# the more 1's, the busier the rhythm will be
|
|
|
|
# and we want to set this per-track
|
|
|
|
# so...
|
|
|
|
#
|
|
|
|
for i in range(limit):
|
|
|
|
zeroesOnes = zeroesOnes + str(random.choice(generateBinary(busyness)))
|
|
|
|
|
|
|
|
# TODO
|
|
|
|
# put a space between each 4 characters
|
|
|
|
# https://stackoverflow.com/questions/9475241/split-string-every-nth-character#9475354
|
|
|
|
#>>> n = 2
|
|
|
|
#>>> [line[i:i+n] for i in range(0, len(line), n)]
|
|
|
|
#['12', '34', '56', '78', '90']
|
|
|
|
#n = 4
|
|
|
|
#zeroesOnes = [zeroesOnes[i:i+n] for i in range(0, len(zeroesOnes), n)]
|
|
|
|
# >>> re.findall('.{1,2}', '123456789')
|
|
|
|
# ['12', '34', '56', '78', '9']
|
|
|
|
#zeroesOnes = re.findall('.{1,2}', zeroesOnes)
|
|
|
|
if (struct == 1):
|
|
|
|
#zeroesOnes = "struct \"{"+str(zeroesOnes)+"}%16\""
|
|
|
|
zeroesOnes = "[{"+str(zeroesOnes)+"}%16]"
|
|
|
|
return(zeroesOnes)
|
|
|
|
else:
|
|
|
|
return(zeroesOnes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def euclid(divider):
|
|
|
|
"generate a euclidean rhythm for tidalcycles"
|
|
|
|
# like struct "[t(3,8)]"
|
|
|
|
# 3,8 10,16 4,16
|
|
|
|
#secondEuclid = str(random.choice(dividers))
|
|
|
|
secondEuclid = divider
|
|
|
|
firstEuclid = str(random.randrange(2,divider))
|
|
|
|
#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()):
|
|
|
|
if (1 > 0):
|
|
|
|
# the first and the second euclid numbers will stay the same
|
|
|
|
# eg no <3 6 5>
|
|
|
|
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,divider))+" "+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)]
|
|
|
|
|
|
|
|
#return ("struct \"[t("+str(firstEuclid)+","+str(secondEuclid)+")]\"")
|
|
|
|
return ("[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)
|
|
|
|
return ("n "+"\"[{"+melody+"}%"+str(random.choice(melodicDivisions))+"]\"")
|
|
|
|
|
|
|
|
def offset():
|
|
|
|
amounts = ["1/4","1/8","1/16","1/16","1/16"]
|
|
|
|
return ("(\""+str(random.choice(amounts))+"\" ~>)")
|
|
|
|
|
|
|
|
def every():
|
|
|
|
# TODO add a switch to choose divisible by 2/4/8 or not
|
|
|
|
bars = random.randint(2,16)
|
|
|
|
return (indent+indent+"$ every "+str(bars)+" ")
|
|
|
|
|
|
|
|
def scramble():
|
|
|
|
divisions = [4,8,16]
|
|
|
|
return ("scramble "+str(random.choice(divisions)))
|
|
|
|
|
|
|
|
def whenmod():
|
|
|
|
limit = 16
|
|
|
|
lower = random.randint(4,limit)
|
|
|
|
return ("$ whenmod "+str(limit)+" "+str(lower)+" ")
|
|
|
|
|
|
|
|
def stut():
|
|
|
|
"""
|
|
|
|
Stutter
|
|
|
|
stut REPEATS VOLUME TIME
|
|
|
|
"""
|
|
|
|
# choose how many repeats
|
|
|
|
repeats = random.choice([1,1,1,1,1,1,2,2,2,3,3,3,4,4,4,4,4,5])
|
|
|
|
time = random.choice([0.125,0.125,0.125,0.0625,0.0625])
|
|
|
|
return("stut "+str(repeats)+" 1 \""+str(time)+"\"")
|
|
|
|
|
|
|
|
def bite():
|
|
|
|
"""
|
|
|
|
Generate something like
|
|
|
|
bite 16 "{2*4 1*2 10*4 8*8}%16
|
|
|
|
"""
|
|
|
|
divisions = [4,8]
|
|
|
|
number = str(random.choice(divisions))
|
|
|
|
|
|
|
|
# generate like 1*4 8*4 2*2 1*2 9*1
|
|
|
|
repeatChoices = [1,2,4]
|
|
|
|
# how long should it be?
|
|
|
|
length = int(random.randint(4,8))
|
|
|
|
bit = ""
|
|
|
|
for i in range(length):
|
|
|
|
bit = str(random.randint(0,int(number)))+"*"+str(random.choice(repeatChoices))+" "+bit
|
|
|
|
|
|
|
|
# since bite will always be encapsulated by ( )
|
|
|
|
# eg whenmod 8 7 (bite 4 "2*4")
|
|
|
|
# we don't need to prepend with $ or ,
|
|
|
|
return ("bite "+number+ " \"{"+bit+"}%"+number+"\"")
|
|
|
|
|
|
|
|
def offset():
|
|
|
|
offsetChoices = [0.125,0.125,0.125,0.125,0.1875,0.1875,0.1875]
|
|
|
|
return ("("+str(random.choice(offsetChoices))+" ~>)")
|
|
|
|
|
|
|
|
|
|
|
|
def fills():
|
|
|
|
"""
|
|
|
|
Generate some things that would be cool at the end of phrases,
|
|
|
|
eg whenmod 8 7 (do something)
|
|
|
|
But nothing too intense
|
|
|
|
"""
|
|
|
|
# like whenmod 8 7
|
|
|
|
fillChoices = [stut(),"rev",scramble()]
|
|
|
|
# how many filles do we want?
|
|
|
|
fills = ""
|
|
|
|
for i in range(1,10):
|
|
|
|
# roll the dice
|
|
|
|
whenmods = ["8 7","16 15","16 14","32 31","64 62","64 63","32 30"]
|
|
|
|
fills = str(random.choice(fillChoices))+" "+fills
|
|
|
|
return "whenmod "+str(random.choice(whenmods))+" ("+fills.rstrip()+")"
|
|
|
|
|
|
|
|
def sometimesBeQuiet():
|
|
|
|
"""
|
|
|
|
Generate a gain pattern so that sometimes a track
|
|
|
|
is silent, and other times it isn't
|
|
|
|
"""
|
|
|
|
#def genOnOff(limit,busyness,struct):
|
|
|
|
# decide whether to do this at all
|
|
|
|
if (random.randint(0,10) > 5):
|
|
|
|
# for now, 8 bar phrases
|
|
|
|
# (# gain "[0 1 0 0 1]/8")
|
|
|
|
# how many cycles to make?
|
|
|
|
quietCycles = random.choice([2,3,4])
|
|
|
|
quietBinary = genOnOff(quietCycles,2,0)
|
|
|
|
# split 001001 into 0 0 1 0 0 1
|
|
|
|
quietBinary = list(quietBinary)
|
|
|
|
finalQuietBinary = ""
|
|
|
|
for i in quietBinary:
|
|
|
|
finalQuietBinary = i + " " + finalQuietBinary
|
|
|
|
print(indent+indent+"$ degradeBy \"<"+str(finalQuietBinary).rstrip()+">/8\"")
|
|
|
|
|
|
|
|
########################### LISTS ##########################
|
|
|
|
|
|
|
|
# a collection of typical-ish kick drum patterns
|
|
|
|
bdPats=["[t*4]","[tttt*2]","[tttt*2?]","t(3,8)","[t~~~~~<~t~~>~~~t~~<~t>~~]"]
|
|
|
|
hhPats=["[t*16]","[tt*2]*4","[~t]*4","[t*16]"]
|
|
|
|
sdPats=["[~t]*2","[t(3,8)]","[[~~~t][~t]]*2"]
|
|
|
|
cpPats=["[~t]*2","[t(3,8)]","[[~~~t][~t]]*2"]
|
|
|
|
cyPats=["[t*4]","[t*8]","[t~~~]","[t~~[~~~t]]","[<t~~~>~~~]"]
|
|
|
|
|
|
|
|
# a collection of misc rhythms
|
|
|
|
rhythmLibrary = ["[1*4]","[1*8]","[1*9]","[01]*2","[0101]","[1*16]","[1*16?]","[111111[1001][01]]/2","[{100}%16]","[{101011010101}%16]","[{10100}%16]","[{10001}%16]","[{10101}%16]","[{1001010}%16]","[{1011010}%16]","[{10101000100}%16]","[{10101001010}%16]","[{10010010010}%16]","[{1010101001010}%16]","[{1001001001010}%16]","[11*2]*4","[100000<0100>000100<01>00]","[1[10000001]]","[1111*2]","[[0001][01]]*2","[0010000100000001]","[[0001][01]]*2","[[01]1[1001][01]]","[[01]1[1001][0001]]","[11000010]*2","[[0001]000]","[[0001]]*4"]
|
|
|
|
|
|
|
|
############### It's assemble time!! ###################
|
|
|
|
|
|
|
|
print("do")
|
|
|
|
#print("")
|
|
|
|
|
|
|
|
# create "let" statements
|
|
|
|
print(indent+"let fourToTheFloor = 0")
|
|
|
|
print(indent+" -- control density per track")
|
|
|
|
for i in percNames:
|
|
|
|
#print("let "+i+"M = \"["+genOnOff(4,5,0)+"]\"")
|
|
|
|
print(indent+" "+i+"M = \"[1111]\"")
|
|
|
|
|
|
|
|
#print("")
|
|
|
|
|
|
|
|
|
|
|
|
# actually assemble the stack!
|
|
|
|
print(indent+"p \""+stackName+"\" ")
|
|
|
|
|
|
|
|
# stack stuff like bite, scramble, etc. will go here
|
|
|
|
print(indent+indent+"-- fills")
|
|
|
|
# roll the dice up to N times
|
|
|
|
for i in range(1,8):
|
|
|
|
if (random.randint(0,10) > 4):
|
|
|
|
print(indent+indent+"$ "+fills())
|
|
|
|
|
|
|
|
# how many "fun" things to add?
|
|
|
|
# a list of things to do to patterns to make them more interesting
|
|
|
|
# these happen BEFORE struct, note, etc.
|
|
|
|
#interestingThings = [stut(),bite(),"rev",scramble(),offset()]
|
|
|
|
interestingThings = [stut(),"rev",scramble(),offset()]
|
|
|
|
def funThings():
|
|
|
|
wholeEnchilada = ""
|
|
|
|
# add between 1 and 4 "fun" things
|
|
|
|
# (things like `every 3 (scramble 4)`)
|
|
|
|
funThings = random.randint(1,3)
|
|
|
|
for i in range(funThings):
|
|
|
|
#print(str(every) + "$ " + str(output))
|
|
|
|
|
|
|
|
# for each iteration, choose an interestingThing
|
|
|
|
# indent + "every N" + ( rev )
|
|
|
|
wholeEnchilada = str(every()+"("+str(random.choice(interestingThings))+")\n"+wholeEnchilada).rstrip()
|
|
|
|
return wholeEnchilada
|
|
|
|
|
|
|
|
# the top of the stack
|
|
|
|
print(indent+indent+"$ stack [")
|
|
|
|
|
|
|
|
# this is an empty track to make dealing with commas easier
|
|
|
|
# just 4 to the floor in case you want it
|
|
|
|
print(indent+indent+"-- four to the floor")
|
|
|
|
print(indent+indent+"degradeBy fourToTheFloor $ struct \"[t*4]\" $ n \"0\" # midichan 0,")
|
|
|
|
|
|
|
|
# generate rhythm tracks
|
|
|
|
# set the starting midi channel
|
|
|
|
percMidiChan = 0
|
|
|
|
|
|
|
|
########################################################
|
|
|
|
## this is where each "track" is generated
|
|
|
|
## percCount = how many rhythmic (non-melodic) tracks
|
|
|
|
## will be created
|
|
|
|
for i in percNames:
|
|
|
|
|
|
|
|
# print the name of the track (from the percNames list)
|
|
|
|
print(indent+indent+"-------------- "+i+" ---------------")
|
|
|
|
|
|
|
|
# MASK: make this so once the entire thing is generated, it's easy to
|
|
|
|
# alter how dense the pattern is, by altering "let nnM = "[1111]
|
|
|
|
print(indent+indent+"mask "+i+"M")
|
|
|
|
|
|
|
|
# sometimes be quiet
|
|
|
|
if (i != "kick"):
|
|
|
|
sometimesBeQuiet()
|
|
|
|
|
|
|
|
#### VARIATIONS #####
|
|
|
|
# insert some funStuff, maybe
|
|
|
|
if (random.randint(0,10) > 3):
|
|
|
|
print(funThings())
|
|
|
|
|
|
|
|
#### OFFSET ###
|
|
|
|
# offset the pattern by a certain amount
|
|
|
|
# this can make things much funkier
|
|
|
|
if (random.randint(0,10) > 6):
|
|
|
|
print(indent+indent+"$ "+offset())
|
|
|
|
|
|
|
|
|
|
|
|
##### THE RHYTHMS #####
|
|
|
|
# how many bars to create?
|
|
|
|
rhythmLengthChoices = [1,1,1,1,1,1,2,2]
|
|
|
|
rhythmLength = random.choice(rhythmLengthChoices)
|
|
|
|
|
|
|
|
# for the number of bars, do this:
|
|
|
|
fullRhythm = ""
|
|
|
|
for i in range(rhythmLength):
|
|
|
|
|
|
|
|
# choose between random, type-specific (bd,hh,etc),
|
|
|
|
# rhythm library, or euclidean rhythms
|
|
|
|
rChoice = random.choice([0,1,1,1,2,3])
|
|
|
|
rhythm = "" # placeholder for the rhythm
|
|
|
|
if (rChoice == 0):
|
|
|
|
# if choice = 0, choose hardcoded rhythms
|
|
|
|
# if this is the first iteration, ie "kick"
|
|
|
|
# choose from some hard-coded kick rhythms
|
|
|
|
# 2nd? same for hh
|
|
|
|
# 3rd? same for sd
|
|
|
|
if (i == 0):
|
|
|
|
rhythm = str(random.choice(bdPats))
|
|
|
|
elif (i == 1):
|
|
|
|
rhythm = str(random.choice(hhPats))
|
|
|
|
elif (i == 2):
|
|
|
|
rhythm = str(random.choice(sdPats))
|
|
|
|
elif (i == 3):
|
|
|
|
rhythm = str(random.choice(cpPats))
|
|
|
|
elif (i == 4):
|
|
|
|
rhythm = str(random.choice(cyPats))
|
|
|
|
else:
|
|
|
|
# print("LIBRARY")
|
|
|
|
rhythm = str(random.choice(rhythmLibrary))
|
|
|
|
#rhythm = "struct \""+rhythm+"\""
|
|
|
|
|
|
|
|
elif (rChoice == 1):
|
|
|
|
# GENERATE A SERIES OF 0's and 1's
|
|
|
|
# choose how long the rhythm will be
|
|
|
|
# if (oneBar == 1):
|
|
|
|
# percLength = 16
|
|
|
|
# else:
|
|
|
|
# percLength = int(random.randrange(4,8))
|
|
|
|
percLength = int(random.randrange(4,10))
|
|
|
|
#percSequence = genOnOff(percLength)
|
|
|
|
#print(","+str(genOnOff(10)))
|
|
|
|
#print(str(percSequence))
|
|
|
|
# how busy will it be?a
|
|
|
|
# choose a random value between 0 and 9
|
|
|
|
busyness = random.randrange(0,7)
|
|
|
|
generateBinary(busyness)
|
|
|
|
rhythm = str(genOnOff(percLength,busyness,1))
|
|
|
|
|
|
|
|
elif (rChoice == 2):
|
|
|
|
# GENERATE EUCLIDEAN RHYTHMS
|
|
|
|
rhythm = str(euclid(random.choice(dividers)))
|
|
|
|
#print(indent+indent+euclid(random.choice(dividers)))
|
|
|
|
#
|
|
|
|
else:
|
|
|
|
# print("LIBRARY")
|
|
|
|
rhythm = str(random.choice(rhythmLibrary))
|
|
|
|
#rhythm = "struct \""+rhythm+"\""
|
|
|
|
|
|
|
|
fullRhythm = str(rhythm) + " " + fullRhythm
|
|
|
|
# remove the trailing space
|
|
|
|
fullRhythm = fullRhythm.rstrip()
|
|
|
|
|
|
|
|
# add "struct" to the beginning
|
|
|
|
# and enclose in < >
|
|
|
|
print(indent+indent+"$ struct \"<"+fullRhythm+">\"")
|
|
|
|
print (indent+indent+"$ n "+str(random.choice(percNotes))+" # midichan "+str(percMidiChan)+",")
|
|
|
|
percMidiChan = percMidiChan + 1
|
|
|
|
|
|
|
|
# generate melodic tracks
|
|
|
|
melodicMidiChan = melodyMidiChanStart
|
|
|
|
#melodyMidiChanStart = 7
|
|
|
|
for i in range(melodyCount):
|
|
|
|
print(indent+indent+"-----------------------")
|
|
|
|
print(indent+indent+"degradeBy 0 ")
|
|
|
|
#print(", ")
|
|
|
|
busyness = random.choice([0,1,2,3,4,5,6,6,6,6,7,7,7,7,8,8,8,9,9])
|
|
|
|
if (oneBar == 1):
|
|
|
|
print(indent+indent+"$ struct \""+genOnOff(16,(busyness),1)+"\"")
|
|
|
|
print(indent+indent+"$ "+genNotes(1))
|
|
|
|
else:
|
|
|
|
# how many 16th notes?
|
|
|
|
thisLength = random.randint(3,16)
|
|
|
|
#genOnOff(8,(busyness))
|
|
|
|
print(indent+indent+"$ struct \""+genOnOff(thisLength,(busyness),1)+"\"")
|
|
|
|
print(indent+indent+"$ "+genNotes(0))
|
|
|
|
print(indent+indent+"# midichan "+str(melodicMidiChan)+" + n (-42)")
|
|
|
|
melodicMidiChan = melodicMidiChan + 1
|
|
|
|
|
|
|
|
print(indent+indent+"] # sunvox")
|