Browse Source

lots of cleaning up, added some hard-coded drum patterns as an option for generation

master
spoonietunes 9 months ago
parent
commit
39603fc618
  1. 4
      .gitignore
  2. 382
      all.txt
  3. 130
      auto-techno.py
  4. 36
      test.tidal

4
.gitignore vendored

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
*.png
*.jpeg
*.wav
*.mp3

382
all.txt

@ -1,382 +0,0 @@ @@ -1,382 +0,0 @@
#!/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
#
# 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 = 1
# 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]
# how many percussive/rhythmic elements to generate?
percCount = 5
percMidiChanStart = 0
# perc note
# set a static note for percussion tracks
percNote = 0
# perc track names
percNames = ["kick", "hh", "sd", "cp", "?", "?", "bassline", "?", "?"]
# 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 = 4
longestMelodic = 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
# how many
# how many melodic elements to generate?
melodyCount = 1
melodyMidiChanStart = 7
## 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 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]
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
#binary = [0,0,0,1]
def genOnOff(limit,busyness):
"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)))
zeroesOnes = "$ struct \"{"+zeroesOnes+"}%16\""
print(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)]
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))+"\"")
def every():
bars = random.randint(2,16)
print("$ every "+str(bars)+" ")
def whenmod():
limit = 16
lower = random.randint(4,limit)
print("$ whenmod "+str(limit)+" "+str(lower)+" ")
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,16))
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 ,
print("bite "+number+ " \"{"+bit+"}%"+number+"\"")
def funStuff():
"""
Generate variations like `whenmod 8 7 (scramble 4)`
"""
# here are some conditions:
# https://tidalcycles.org/docs/reference/conditions
# every N - whenmod N N - sometimesBy N - someCyclesBy N
# actually assemble the stack!
print("p \""+stackName+"\" ")
# stack stuff like bite, scramble, etc. will go here
print("$ whenmod 8 7 (scramble 4)") #
# how many "fun" things to add?
def funThings():
funThings = random.randint(0,4)
for i in range(funThings):
#print(str(every) + "$ " + str(output))
every()
print(" (")
bite()
print(") ")
# uncomment this for some wildness
#funThings()
# the top of the stack
print("$ stack [")
# this is an empty track to make dealing with commas easier
# just 4 to the floor in case you want it
print("-- four to the floor")
print(" (#gain 1) $ struct \"[t*4]\" $ n \"0\" # midichan 0,")
#print(",struct \"[t*4]\" $ n 0 # midichan 0")
# generate rhythm tracks
percMidiChan = 0
for i in range(percCount):
print("-- "+percNames[percMidiChan]+" -----------------")
# this is here so there is the same thing at the start of
# each new track (so we know "whenmod" for instance always
# starts with $ and not ,)
print("degradeBy 0 ")
# insert some funStuff, maybe
if (random.choice([0,1]) > 0):
funThings()
# choose between regular or euclidean rhythms
if (random.choice([0,1]) == 0):
# 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,16))
#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)
genOnOff(percLength,busyness)
else:
# GENERATE EUCLIDEAN RHYTHMS
euclid(random.choice(dividers))
print (" $ n "+str(percNote)+" # midichan "+str(percMidiChan)+",")
percMidiChan = percMidiChan + 1
# generate melodic tracks
melodicMidiChan = melodyMidiChanStart
#melodyMidiChanStart = 7
for i in range(melodyCount):
print("-----------------------")
print("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):
genOnOff(16,(busyness))
print("$")
genNotes(1)
else:
genOnOff(32,(busyness))
print("$")
genNotes(1)
print("# midichan "+str(melodicMidiChan)+" + n (-36)")
melodicMidiChan = melodicMidiChan + 1
print("] # sunvox")
some seeds I've liked:
1493546251137461290
1781197463452869364
14959707246264745
1411204103099713935
1157315305561367902
2275918688827233254
2209526836267835322 -- electro-ish
644793890351458335
803051260356546356
1061676950143263647
-- seed: -1061676950143263647
cps = (114/60/4)
p "techno"
$ whenmod 8 7 (scramble 4)
$ stack [
-- four to the floor
(#gain 1) $ struct "[t*4]" $ n "0" # midichan 0,
-- kick -----------------
degradeBy 0
$ every 3
(
bite 8 "{6*4 0*2 5*2 5*2 }%8"
)
$ struct "[t(2,4)]"
$ n 0 # midichan 0,
-- hh -----------------
degradeBy 0
$ struct "{1001110110100101}%16"
$ n 0 # midichan 1,
-- sd -----------------
degradeBy 0
$ struct "[t(5,8)]"
$ n 0 # midichan 2,
-- cp -----------------
degradeBy 0
$ struct "[t(7,8)]"
$ n 0 # midichan 3,
-- ? -----------------
degradeBy 0
$ every 3
(
bite 4 "{0*2 0*2 0*1 1*4 0*1 0*4 0*1 2*4 0*1 3*1 1*4 0*4 4*1 }%4"
)
$ every 4
(
bite 4 "{3*2 3*4 2*4 3*1 0*4 3*1 3*1 4*1 4*2 3*4 0*1 1*4 1*4 }%4"
)
$ struct "{1111000101111000}%16"
$ n 0 # midichan 4,
-----------------------
degradeBy 0
$ struct "{1101111111110111}%16"
$
n "{22 8 22 10 2 9 11 12 8 2 0 0 10 17 3 4 }%16"
# midichan 7 + n (-36)
] # sunvox

130
auto-techno.py

@ -74,6 +74,7 @@ melodyMidiChanStart = 7 @@ -74,6 +74,7 @@ melodyMidiChanStart = 7
import sys
import random
import math
import re
##################################################
@ -97,7 +98,7 @@ bpm = "cps = ("+str(random.randrange(lowestBpm, highestBpm, 1))+"/60/4)" @@ -97,7 +98,7 @@ bpm = "cps = ("+str(random.randrange(lowestBpm, highestBpm, 1))+"/60/4)"
print(bpm+"\n")
####################### FUNCTIONS ###################
def generateBinary(busyness):
"""
busy-ness (sic)
@ -129,8 +130,6 @@ def generateBinary(busyness): @@ -129,8 +130,6 @@ def generateBinary(busyness):
binary = [0,0,1,1,1,1,1,1,1,1,1]
return binary
#binary = [0,0,0,1]
def genOnOff(limit,busyness):
"generate a series of 0's and 1's"
zeroesOnes = ""
@ -142,7 +141,19 @@ def genOnOff(limit,busyness): @@ -142,7 +141,19 @@ def genOnOff(limit,busyness):
#
for i in range(limit):
zeroesOnes = zeroesOnes + str(random.choice(generateBinary(busyness)))
zeroesOnes = "$ struct \"{"+zeroesOnes+"}%16\""
# 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)
zeroesOnes = "struct \"{"+str(zeroesOnes)+"}%16\""
return(zeroesOnes)
def euclid(divider):
@ -172,7 +183,7 @@ def euclid(divider): @@ -172,7 +183,7 @@ def euclid(divider):
secondEuclid = "<"+str(random.choice(dividers))+" "+str(random.choice(dividers))+">"
# [t(<3 8>,16)]
return ("$ struct \"[t("+str(firstEuclid)+","+str(secondEuclid)+")]\"")
return ("struct \"[t("+str(firstEuclid)+","+str(secondEuclid)+")]\"")
def genNotes(melodicOneBar):
"""
@ -192,16 +203,34 @@ def genNotes(melodicOneBar): @@ -192,16 +203,34 @@ def genNotes(melodicOneBar):
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 ("$ 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,45])
time = random.choice(["1/4","1/8","1/16","1/16","1/16"])
return("stut "+str(repeats)+" 1 \""+str(time)+"\"")
def bite():
"""
Generate something like
@ -224,16 +253,20 @@ def bite(): @@ -224,16 +253,20 @@ def bite():
return ("bite "+number+ " \"{"+bit+"}%"+number+"\"")
def funStuff():
"""
Generate variations like `whenmod 8 7 (scramble 4)`
"""
# here are some conditions:
# https://tidalcycles.org/docs/reference/conditions
# every N - whenmod N N - sometimesBy N - someCyclesBy N
########################### LISTS ##########################
# a collection of typical-ish kick drum patterns
bdPats= ["[t*4]","[t t t t*2]","[t t t t*2?]","t(3,8)","[t~~~ ~~<~t~~>~ ~~t~ ~<~t>~~]"]
hhPats= ["[t*16]","[t t*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~~~>~~~]"]
############### It's assemble time!! ###################
# actually assemble the stack!
print("p \""+stackName+"\" ")
@ -242,11 +275,24 @@ print("p \""+stackName+"\" ") @@ -242,11 +275,24 @@ print("p \""+stackName+"\" ")
print("$ whenmod 8 7 (scramble 4)") #
# 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()]
def funThings():
funThings = random.randint(1,4)
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))
return (every()+"("+bite()+")")
# for each iteration, choose an interestingThing
# indent + "every N" + ( rev )
wholeEnchilada = indent+str(every()+"("+str(random.choice(interestingThings))+")\n"+wholeEnchilada).rstrip()
# using "every"
#return (every()+"("+bite()+")")
return wholeEnchilada
# uncomment this for some wildness
#funThings()
@ -257,25 +303,55 @@ print("$ stack [") @@ -257,25 +303,55 @@ print("$ stack [")
# this is an empty track to make dealing with commas easier
# just 4 to the floor in case you want it
print(indent+"-- four to the floor")
print(indent+"(#gain 1) $ struct \"[t*4]\" $ n \"0\" # midichan 0,")
print(indent+"(#gain 0) $ struct \"[t*4]\" $ n \"0\" # midichan 0,")
#print(",struct \"[t*4]\" $ n 0 # midichan 0")
# generate rhythm tracks
percMidiChan = 0
########################################################
## this is where each "track" is generated
## percCount = how many rhythmic (non-melodic) tracks
## will be created
for i in range(percCount):
print(indent+"-- "+percNames[percMidiChan]+" -----------------")
# this is here so there is the same thing at the start of
# each new track (so we know "whenmod" for instance always
# starts with $ and not ,)
print(indent+"degradeBy 0 ")
# insert some funStuff, maybe
if (random.randint(0,10) > 8):
print(indent+funThings())
if (random.randint(0,10) > 2):
print(funThings())
# choose between random, hardcoded, or euclidean rhythms
rChoice = random.choice([0,1,2])
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:
rhythm = "t*16"
rhythm = "struct \""+rhythm+"\""
# choose between regular or euclidean rhythms
if (random.choice([0,1]) == 0):
elif (rChoice == 1):
# GENERATE A SERIES OF 0's and 1's
# choose how long the rhythm will be
if (oneBar == 1):
@ -289,16 +365,20 @@ for i in range(percCount): @@ -289,16 +365,20 @@ for i in range(percCount):
# choose a random value between 0 and 9
busyness = random.randrange(0,7)
generateBinary(busyness)
print(indent+genOnOff(percLength,busyness))
else:
rhythm = str(genOnOff(percLength,busyness))
elif (rChoice == 2):
# GENERATE EUCLIDEAN RHYTHMS
print(indent+euclid(random.choice(dividers)))
rhythm = str(euclid(random.choice(dividers)))
#print(indent+euclid(random.choice(dividers)))
#
else:
rhythm = "struct [t*4]"
print(indent+"$ "+rhythm)
print (indent+"$ n "+str(percNote)+" # midichan "+str(percMidiChan)+",")
percMidiChan = percMidiChan + 1
# generate melodic tracks
melodicMidiChan = melodyMidiChanStart
#melodyMidiChanStart = 7
@ -308,7 +388,7 @@ for i in range(melodyCount): @@ -308,7 +388,7 @@ for i in range(melodyCount):
#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+genOnOff(16,(busyness)))
print(indent+"$ "+genOnOff(16,(busyness)))
print(indent+"$ "+genNotes(1))
else:
genOnOff(32,(busyness))

36
test.tidal

@ -10,45 +10,45 @@ some seeds I've liked: @@ -10,45 +10,45 @@ some seeds I've liked:
803051260356546356
1061676950143263647
-- seed: -1061676950143263647
cps = (114/60/4)
-- seed: 1035561506162950173
cps = (115/60/4)
hush
d1 $ struct "t*4" $ n "0" # midichan 1 # sunvox
1726268759940563490
1035561506162950173 -- groovy
2138151558308434562 -- funky
-- seed: -2138151558308434562
do
let cps = (90/60/4)
p "techno"
$ whenmod 8 7 (scramble 4)
$ stack [
-- four to the floor
(#gain 1) $ struct "[t*4]" $ n "0" # midichan 0,
(#gain 0) $ struct "[t*4]" $ n "0" # midichan 0,
-- kick -----------------
degradeBy 0
$ struct "{1111001010001101}%16"
$ every 3 (("1/4" ~>))
$ every 4 (rev)
$ struct "{1011000101001100}%16"
$ n 0 # midichan 0,
-- hh -----------------
degradeBy 0
$ struct "{1010000011000010}%16"
$ every 10 (bite 8 "{4*4 7*1 2*2 4*4 0*4 7*1 4*2 8*1 3*1 3*1 1*1 8*1 1*4 4*2 }%8")
$ struct "[t(15,16)]"
$ n 0 # midichan 1,
-- sd -----------------
degradeBy 0
$ struct "[t(2,4)]"
$ struct "[~ t]*2"
$ n 0 # midichan 2,
-- cp -----------------
degradeBy 0
$ every 12 (bite 8 "{3*1 8*2 1*4 8*1 0*1 1*4 5*1 6*2 0*2 }%8")
$ struct "{0010000000000000}%16"
$ struct "[t(6,16)]"
$ n 0 # midichan 3,
-- ? -----------------
degradeBy 0
$ struct "{0110110000001111}%16"
$ every 6 (("1/4" ~>))
$ struct "{0100000000000001}%16"
$ n 0 # midichan 4,
-----------------------
degradeBy 0
$ struct "{0000000000111000}%16"
$ n "{10 10 13 35 8 14 1 9 22 8 19 11 5 16 6 7 }%16"
$ struct "{0111111110111011}%16"
$ n "{28 15 3 6 21 21 22 16 2 34 9 6 0 35 23 28 }%16"
# midichan 7 + n (-36)
] # sunvox

Loading…
Cancel
Save