|
|
|
@ -1,6 +1,6 @@
@@ -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"
@@ -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"
@@ -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
@@ -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
@@ -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]
@@ -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")
@@ -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)
@@ -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)"
@@ -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):
@@ -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:
@@ -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:
@@ -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):
@@ -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") |
|
|
|
|