diff --git a/auto-techno.py b/auto-techno.py index 6267775..f0aa185 100644 --- a/auto-techno.py +++ b/auto-techno.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 scriptName = "Auto-Techno Generator" -version = 0.1 +version = "0.1.1" author = "Chris Beckstrom" author_email = "chris@chrisbeckstrom.com" # a deterministic techno generator for tidalcycles @@ -20,6 +20,12 @@ author_email = "chris@chrisbeckstrom.com" lowestBpm = 92 highestBpm = 135 + +# swing +# see https://tidalcycles.org/docs/patternlib/tour/time/#swing +minSwing = 0 +maxSwing = 0.2 + # force everything to happen within 1 bar oneBar = 1 @@ -29,27 +35,27 @@ stackName = "techno" ####### PERCUSSION ############################## +# some settings for rhythm generation # 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 notes -# set some notes for percussion tracks -# these notes correspond to notes (C3, C#3, etc) -percNotes = [0,1,2,3,4,5,6,7] +percCount = 5 # this setting doesn't do anything right now, use "percNames" instead +percMidiChanStart = 0 # the starting MIDI channel for perc tracks # perc track names # a percussion track will be generated for each item in this list percNames = ["kick", "hh","sd","ohh","rim","cp","tom","ride","cymbal"] # for use generating sequences of 0's and 1's # -# +# perc notes +# set some notes for percussion tracks +# these notes correspond to notes (C3, C#3, etc) +# each percussion track will pick one of these notes +# and send note on/off messages to that note +percNotes = [0,1,2,3,4,5,6,7] + # ####### MELODY ################################# # NOTE about melodic sequences: @@ -78,14 +84,32 @@ melodyCount = 1 melodyMidiChanStart = 10 - ############### PADS ########################### +# how many pad tracks to generate padCount = 1 + +# how long should the pad pattern be? +# tip: add more of the same number to weight that choice +padBars = [1,1,1,2,4] +# at what speed should the pad chord change? +# every bar = 1, every 2 bars = 2, etc +padSpeed = [1,2,2,2,4] + +# what MIDI channel should it start on? +# padMidiChanStart = melodyMidiChanStart + 1 will start it right after the last melody track padMidiChanStart = melodyMidiChanStart + 1 +################ MIDI ##################### +# on what channel should we send MIDI CC messages? +midiCCChannel = 15 +# list of MIDI CC's: +midiCCs = [0,1,2,3,4,5,6]] + + +################# SETUP ################# ## import stuff import sys import random @@ -96,7 +120,7 @@ import decimal from decimal import Decimal -################################################## +############## PARSE ARGUMENT(S) ############### # this is the 1st argument given via command line # this is used to calculate everything rawinput = sys.argv[1] @@ -105,7 +129,6 @@ rawinput = sys.argv[1] # 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 @@ -132,7 +155,7 @@ seed = seed.replace("X","x") # here is the seed in decimal format (eg 3892423) decimalSeed = int(seed,16) -### FRONTMATTER ### +#################### FRONTMATTER ### # put some stuff at the top of the tidal code print("-- raw input: " + str(rawinput)) print("-- hex seed: "+seed) @@ -148,6 +171,7 @@ 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)" @@ -156,6 +180,20 @@ bpm = "setcps ("+str(random.randrange(lowestBpm, highestBpm, 1))+"/60/4)" ####################### FUNCTIONS ################### +def swing(minSwing,maxSwing): + """ + Generate a swing value for the entire stack + """ + # the goal is something like this: + # swingBy 0.2 8 + #print("We will swing!!") + # choose the first value + #firstSwing = (decimal.Decimal(random.range())).quantize(Decimal('.001')) + firstSwing = str(decimal.Decimal(random.randrange(0, 20))/100) + secondSwing = 8 # if 8: swing 16th notes, if 4: swing 8th notes + return "swingBy "+str(firstSwing)+" "+str(secondSwing) + + def generateBinary(busyness): """ busy-ness (sic) @@ -220,6 +258,8 @@ def genOnOff(limit,busyness,struct): def genVelocity(limit): """ Generate a series of decimals < 1 to control velocity + This adds a more organic feel to the rhythms, and makes + them about 20% funkier """ velocities = "" for i in range(limit): @@ -441,6 +481,11 @@ for i in percNames: # actually assemble the stack! print(indent+"p \""+stackName+"\" ") +# swing? +# roll the dice to see if there will be any swing at all +if (random.randint(0,10) > 7): + print(indent+indent+"$ "+str(swing(minSwing,maxSwing))) + # stack stuff like bite, scramble, etc. will go here print(indent+indent+"-- fills") # roll the dice up to N times @@ -494,8 +539,8 @@ for i in percNames: print(indent+indent+"mask "+i+"M") # sometimes be quiet - if (i != "kick"): - sometimesBeQuiet() + #if (i != "kick"): + # sometimesBeQuiet() #### VARIATIONS ##### # insert some funStuff, maybe @@ -680,13 +725,44 @@ for i in range(padCount): #print(str(padNotesList)) # make a chord - chord = "\"["+random.choice(padNotesList)+","+random.choice(padNotesList)+","+random.choice(padNotesList)+","+random.choice(padNotesList)+"]\"" + padsStart = "\"<" + padsEnd = ">" + # generate a sequence of chords + + pads = "" + for i in range(random.choice(padBars)): + pads = "["+ random.choice(padNotesList)+","+random.choice(padNotesList)+","+random.choice(padNotesList)+","+random.choice(padNotesList)+"]"+str(pads) # build the track print(indent+indent+"degradeBy 0 ") - print(indent+indent+"$ n "+chord) - print(indent+indent+"# midichan "+str(padMidiChan)+" + n (0)") + sometimesBeQuiet() + + # roll the dice, choose between a long steady pad + # or more rhythmic hits + #if (random.choice([1,1]) == 1): + if (random.choice([0,1]) == 1): + print(indent+indent+"$ struct \""+genOnOff(16,(busyness),1)+"\"") + + print(indent+indent+"$ n "+padsStart+pads+padsEnd+"/"+str(random.choice(padSpeed))+"\"") + print(indent+indent+"# midichan "+str(padMidiChan)+" + n (0),") + +############## MIDI CCS ############# +# the goal: +# do reverb/delay throws + + +for i in range(midiCCs): + print("midicc: "+i) + + + + + + + + + -## put the finishing touches on the beautiful stack +## put the finishing touches on the beautiful stack! :-) :-) print(indent+indent+"] # sunvox") diff --git a/deleteme.tidal b/deleteme.tidal index d4890e9..7796492 100644 --- a/deleteme.tidal +++ b/deleteme.tidal @@ -1,8 +1,8 @@ --- raw input: -1654319963628270068 --- hex seed: -0x16F5533DF0E671F4 --- decimal seed: -1654319963628270068 --- generated at 1633644744.38 --- Auto-Techno Generator v0.1 +-- raw input: 1280237863746818918 +-- hex seed: 0x11C4518DD8A25366 +-- decimal seed: 1280237863746818918 +-- generated at 1633699097.67 +-- Auto-Techno Generator v0.1.1 do let fourToTheFloor = 0 @@ -18,99 +18,96 @@ do cymbalM = "[1111]" p "techno" -- fills - $ whenmod 32 31 (rev) - $ whenmod 16 15 (scramble 8) + $ whenmod 32 31 (bite 2 "{12}%2") + $ whenmod 16 14 (bite 2 "{0}%2") + $ whenmod 32 30 (rev) $ whenmod 16 15 (bite 4 "{4}%4") - $ whenmod 8 7 (bite 2 "{8}%2") - $ whenmod 32 31 (rev) - $ whenmod 32 30 (bite 2 "{8}%2") - $ whenmod 32 31 (rev) + $ whenmod 32 31 (scramble 4) $ stack [ -- four to the floor degradeBy fourToTheFloor $ struct "[t*4]" $ n "0" # midichan 0, -------------- kick --------------- mask kickM - $ every 9 ((0.125 ~>)) - $ every 9 ((0.125 ~>)) - $ struct "<[{101000010}%16]>" - $ n 5 - # gain "{0.85 1 0.85}%16" + $ struct "<[t*4]>" + $ n 0 + # gain "{1 1}%16" # midichan 0, -------------- hh --------------- mask hhM - $ degradeBy "<0 1 0 0 0 0 0 0>/8" - $ struct "<[t*4]>" - $ n 3 - # gain "{0.9 0.85 0.9}%16" + $ degradeBy "<0 0 0 0 0 1 1 0>/8" + $ every 4 (degradeBy 0.93) + $ every 14 (scramble 16) + $ every 14 (stut 1 1 "0.0625") + $ (0.125 ~>) + $ struct "" + $ n 2 + # gain "{1 1 0.85 0.85 0.9 0.85 0.9 0.85}%16" # midichan 1, -------------- sd --------------- mask sdM - $ degradeBy "<0 0 0 0 0 1 1 0>/8" - $ every 11 ((0.125 ~>)) - $ every 12 ((0.125 ~>)) - $ every 8 (scramble 8) - $ struct "<[t(7,16)]>" - $ n 6 - # gain "{0.85 0.9 1}%16" + $ degradeBy "<1 1 0 0 1 1 1 0>/8" + $ struct "<[{0000}%16]>" + $ n 2 + # gain "{0.9 1 1 0.85 1}%16" # midichan 2, -------------- ohh --------------- mask ohhM - $ degradeBy "<0 0 0 0 0 1 0 0>/8" - $ every 6 ((0.125 ~>)) - $ struct "<[{0000}%16] [{00001}%16]>" + $ degradeBy "<1 0 0 0 1 0 1 1>/8" + $ (0.1875 ~>) + $ struct "<[tt*2]*4 [[0001]000]>" $ n 4 - # gain "{0.85 0.85 0.85 0.9 0.85 1 1 0.9 1 1 1}%16" + # gain "{0.85 0.9 0.9 1 0.85 0.85 0.9 0.9 0.85 1 0.85}%16" # midichan 3, -------------- rim --------------- mask rimM - $ degradeBy "<0 1 0 1 0 1 0 0>/8" - $ every 14 ((0.125 ~>)) - $ every 5 (scramble 8) - $ (0.125 ~>) - $ struct "<[{111010}%16]>" - $ n 1 - # gain "{0.9 1 0.85}%16" + $ degradeBy "<0 1 0 0 0 0 1 1>/8" + $ struct "<[t(6,16)]>" + $ n 2 + # gain "{0.85 1 1 0.85 1}%16" # midichan 4, -------------- cp --------------- mask cpM - $ every 3 ((0.125 ~>)) - $ every 11 (scramble 8) - $ every 10 (stut 1 1 "0.0625") + $ degradeBy "<0 1 1 0 0 0 0 0>/8" + $ every 12 (degradeBy 0.93) + $ every 6 (rev) $ (0.125 ~>) - $ struct "<[{0000}%16] [{10010010010}%16]>" - $ n 2 - # gain "{0.9 0.9 0.9 1 0.9 0.9 1}%16" + $ struct "<[{0000001}%16]>" + $ n 7 + # gain "{1 1 0.9 0.9 0.85 0.9 0.85 1 1}%16" # midichan 5, -------------- tom --------------- mask tomM - $ every 12 (stut 1 1 "0.0625") + $ degradeBy "<1 0 1 0 0 1 0 0>/8" $ (0.1875 ~>) - $ struct "<[{10011100}%16] [t(11,16)]>" - $ n 0 - # gain "{0.9 0.85 0.85 0.9 0.9 1 1 0.85 0.9 1 1 0.85 0.9 0.85}%16" + $ struct "<[t(7,16)]>" + $ n 6 + # gain "{0.9 0.9 0.9 0.9 0.9 0.9 1 0.9 1 0.85}%16" # midichan 6, -------------- ride --------------- mask rideM - $ degradeBy "<0 0 0 0 0 0 0 0>/8" - $ every 15 (stut 1 1 "0.0625") - $ struct "<[t(10,16)]>" - $ n 7 - # gain "{0.9 1 0.9 0.85 0.85 0.9 0.85 1 0.9 0.9 1 0.9 0.9}%16" + $ degradeBy "<1 1 0 1 1 0 1 1>/8" + $ every 14 ((0.125 ~>)) + $ (0.125 ~>) + $ struct "<[1*16]>" + $ n 1 + # gain "{1 1 0.85 0.9 1 0.9 0.9 0.9 0.9 1}%16" # midichan 7, -------------- cymbal --------------- mask cymbalM - $ degradeBy "<1 0 0 0 0 0 0 1>/8" - $ struct "<[{1011010}%16]>" - $ n 5 - # gain "{0.85 1 0.9 0.85 0.9 0.85 1 0.9}%16" + $ every 14 (degradeBy 0.93) + $ struct "<[t*4]>" + $ n 4 + # gain "{1 0.85 0.85 1 0.85 0.85 0.9 1 0.85 1}%16" # midichan 8, ------------ bassline ------- degradeBy 0 - $ struct "[{00111110101011110000}%16]" - $ n "[{4 11 0 22 3 10 10 3 11 1 5 10 5 10 4 4 }%16]" + $ struct "[{1111011111110111}%16]" + $ n "[{7 18 6 20 3 7 15 0 2 10 23 5 10 16 20 22 }%16]" # midichan 10 + n (-24), ------------ pad ------- degradeBy 0 - $ n "[1,4,3,3]" + -- $ degradeBy "<1 1 0 1 1 0 0 0>/8" + $ struct "[t ~ ~ ~]" + $ n "<[10,7,20,15]>/2" # midichan 11 + n (0) ] # sunvox diff --git a/test.tidal b/test.tidal index 5658a36..1e8952d 100644 --- a/test.tidal +++ b/test.tidal @@ -20,6 +20,7 @@ some seeds I've liked: 2195224328517994763 -- funnnnkkky 0x508DFAD3954D1C9 -- cooool seed: -2138151558308434562 +82408580741001929 -- cool bassline setcps = (18/60/4)