-
Notifications
You must be signed in to change notification settings - Fork 5
Generative
Generative syntax is a way of defining aleatory melodies (which is a fancy word for random or semirandom melodies). ? is a random note, (x,y) is a random note between x and y, [a,b c,d]* will randomnly pick one from the list, for example:
z1 "[: q ? ? ? 0 ? ? ? (1,2) [6,7] (1,2) [6,7] (1,2) [6,7] (1,2) [6,[7 2,8,9 3,11]] :]"
Random syntax can also be nested which will eventually melt your brain:
z1 "([1,4,5,3],[(6,7),(6,[8,10,11]),(6,[9,10,39])])" # This is a loop of a single note
As you might have noticed, everything can be nested, meaning that you can put random numbers inside your random numbers (yo dawg) and create pretty crazy (and mostly completely useless) combinations:
zplay "(1,(2,[4,5,(6,9),10]))" # Plays a random note 1 between 2 between 4 or 5 or 6 between 9 ... and so on.
To repeat the process again (like the teletubbies would want) you can use repeated sets like so:
zplay "(: (1,(2,[4,5,(6,9),10])) :4)"
Lists are also pretty nifty for doing all sorts of things, for example:
z1 "q (0 1 2 3)+(1,3)" # Adding random stuff to set
zplay "q (0 1 2 3)+(-1 1 -1 1)" # Cartesian sum
zplay "q (1 2 3 4)*(-1 1 -1 1)" # Cartesian product
z1 "q (1 2 3 4)+[1 3, 2 2, 3 1]" # Cartesian sum with a random set
zplay "(1 2 3)<>(4 5 3)" # Zip two lists
Use ? for random number between 0-11
z1 "q 0 ? 1 ? 2 ? 3 ?"
z1 "% ? % ?" # Can be used as random duration
z1 "{%>0.5?0:4} 3" # or in conditional statements
Totally random note lengths would sound well ... totally random, but since we often long for some sort of continuity, the random durations generated with the % are random within the measure length, which can be altered using measure_length parameter. By default measure length is 1.0.
Example of two loops using random durations and different measure length:
z0 "h 2 % [1 4 3, 2 4, 3 2 4 6, 1]| q 2 3 % 9 3", synth: :dtri, release: 0.1, attack: 0.1, sustain: 0.1, cutoff: 20
z1 "h 3 2 % 3 [? 3, 3] | h 4 % ? ? 3", synth: :bass_foundation, octave: -2, measure_length: 2.0
It is completely optional to use the measure length. If the measures are full, all random relative durations will be 0.
Random syntax (x,y) creates random integers between x and y.
zplay "(1,5)" # Random number between 1 and 5
zplay "(: (1,4) :4)" # Random number between 1 and 4 - 4 times
zplay "([2,4,6],[7,8,12])" # Generates random number between numbers picked from a spesific set of numbers
Random decimals can be used to define random note lengths or parameter values:
# Random note length between 0.1 and 0.25
z1 "(0.1,0.25) 1"
# Set release to random between 0.1-2.0 and note length between 0.1-1.0
z2 "R<(0.1,2.0)> (0.1,1.0) 0..3"
# Random slide length
z3 "q ~<(0.01,1.0)>0123"
Ziffers lists are ordered sequences of pitch classes denoted using ( ) characters. Lists can be created, modified and combined with other lists using operators.
Set operations include all basic computational operators including *, +, -, **, /, ^, %, |, &, <<, >>. See [ruby's operators](https://www.tutorialspoint.com/ruby/ruby_operators.htm for more details.
Examples:
zplay "(0 1 2 3)+3" # Add 3 to each in a set
zplay "(0 1 2 3)+(1,6)" # Add a random number to each in a set
zplay "(0 1 2 3)<<(0,3)" # Add a random number to each in a set
zplay "(0 1 2 3)<<(1,3)" # Do a binary left switch using random number
zplay "(1 2 3)+(2 4 6)" # Do cartesian sum with two sets
zplay "((1 2 3)*(2 4 6))%7" # Do cartesian product with two sets and use mod 7
Additionally there are support for different array operations, such as: <> zip(ish) <*> pitch multiplication <+> product <&> intersection <|> union <-> difference <1-n> interpolation
Examples:
zplay "(1 2 3)<>(3 6 3 2)" # Zip to sets, behaves like a ring if there are odd number of elements
zplay "(q e)<>(3 6 3 2)" # Also works for note lengths or octaves etc.
zplay "(1 2 3)<+>(3 6 3)" # Product of two sets
zplay "(1 2 3)<*>(3 6 3)" # Two sets interval multiplication
zplay "(1 2 3)<&>(3 6 3)" # Intersection of two sets
zplay "(1 2 3)<|>(3 6 3)" # Union of two sets
zplay "(1 2 3)<->(3 6 3)" # Difference of two sets
zplay "(1 3 2 4)<4>(1 -2 3)" # Shorthand for scale interpolation
! Unique: Create unique set
& Combine: Interpret integers as chords
$ Separate: Interpret integers as sequences
zplay "(0 1 1 2)!" # ! Unique set: 0 1 2
z1 "q ((-3..4){(3x+2)(3x^3)})$" # $ Splits generated integers 1432 -> 1 4 3 2
z1 "q ((-3..4){(3x+2)(3x^3)})&" # $ Splits generated integers 1432 -> 1 4 3 2
z1 "q ((-3..4){(3x+2)(3x^3)})$!" # Unique set and reflect can be combined
zplay "((1000,5000))&" # Generates a chord: 1243
zplay "(1,30) ((1,30))$ ((1,30))&" # Generates: {23} 2 3 14"
zplay "(((10,50),(100,1000)))&" # Generates random chord between random numbers
zplay "(((10,50),(100,1000)))$" # Generates random list from random numbers
zplay "10..12" # Sequence: {10} {11} {12}
zplay "(10..12)&" # Sequence: 10 11 12
zplay "(10..12)$" # Sequence: 1 0 1 1 1 2
zplay "q (100..200+8)&" # Sequence of chords: 100 108 116 124 132 140 148 156 164 172 180 188 196
In addition to list methods some transformations can also be called inside Ziffers syntax (For full list of transformations see Transformations-page).
Shorthands defined for some transformations:
Reflect set (aka reflect)
Mirror set (aka mirror)
Inverse pcs (aka inverse)
Rotate set (aka rotate)
Stretch (aka stretch)
Swap (aka swap)
Deal (aka deal)
(index,items)
Get permutation with index, second parameter optionalz1 "q (1 2 3 4)<r>" # Reflect set. Nice for loops
z1 "q (1 2 3 4)<m>" # Similar to reflect, but mirrors completely
z1 "q (1 2 3 4)<i>" # Inverses pcs
z1 "q (1 2 3 4)<i>(3)" # Inverse transpose by 3
z1 "(q 0 1 2 3)<i>(0 -2 5 6)" # Cycle inversions
z1 "q (1 2 3 4)<rot>" # Rotates set by 1
z1 "q (1 2 3 4)<rot>((1,4))" # Rotates set randomly
z1 "q (1 2 3 4)<d>((1,4))" # Deal randomly
z1 "q (1 2 3 4)<p>(3,5)" # 3 note permutation index 5
z1 "q (1 2 3 4)<p>(3,(0,5))" # 3 note permutation from random index
z1 "(q 0 1 2 3)<p>(0 2 5 6)" # Cycle different permutations
z1 "(i iva)@(q 0 1 2)<p>((0,7),2)" # Create arpeggios with random permutations size 2
Create sequences of pitches using s..e notation. Alternatively sequences can also be parsed as splitted integers s;;e or chords s::e.
zplay "1..7" # Sequence: 1 2 3 4 5 6 7
zplay "q 0..(1,7)" # Random sequence from 0 to random
Arithmetic sequences
zplay "0..6+2" # Sequence: 0 2 4 6
zplay "0..6+4" # Sequence: 0 4
zplay "0..6*4" # Sequence: 0 4 8 12 16 20
zplay "0..4**2" # Geometric sequence: 1 2 4 8
zplay "-3..4*3" # Sequence: -3 0 3 6
# Random arithmetic sequences
z1 "a (0..3*(1,7)) h ((0,2)..2*(1,9)) a (0..3*(-7,-5))", synth: :piano, key: :c4, scale: :minor
# Real fun starts when the generated sequences are summed together as sets (sometimes called Slonimsky sets).
zplay "q (0..4*3)+(2..-5*2)"
Sequences, random numbers and random picks can be modified as lists using ( ) syntax:
zplay "(0..7)" # Populate list
zplay "(1..7)~" # Sequence in random order: "2135764"
zplay "(1..7)~3" # Sequence from 1 to 7 take random 3: "152"
zplay "(1..9+2)?3" # Can be combined with take random
zplay "(1 3 4 6 7)~2" # Take different random 2: "3 6"
zplay "(1 3 4 6 7)?2" # Take random 2: "3 3"
z1 "(q. e e q)<>(: (1,4)..[5,6,7] :3)~" # Create random range between randomized values and add note lengths by zipping
Values can be assigned to control characters. This is a way of creating repeating randomized patterns and shortening the notation. Assigned values can also be reused within new lists.
zplay "A=(1..3 {(1,3)+2}) q A A A" # Repeats the assigned list
zplay "A=(3 2 (1,5) 3) B=(? (1,3) 3) q A B A B" # Repeat two separate lists
z1 "A=(1,4) B=? C=[4,5,6] A B A C B A B C B A" # Assign different random values and play as pattern
z1 "q A=(0 2 1 4) B=(5 4 3 2) (A B)+[1,2,3,4]" # Assign lists and reuse in lists for arithmetic operations
List values can be accessed using index values or ranges:
zplay "q (1..3)[2]" # Play value from index 2
zplay "q (1..3)[1001]" # Wait what? Lists act like rings!
zplay "q (1..3)~[2,6]" # Randomize and take 6 starting from index 2
zplay "q (1..6)[(1,4)]" # Play value from random index
zplay "q (0..7)[0..4]" # Populate list from 0 to 7 but only take first 4
zplay "q (0..7)[3..]" # Take from index 3 to the end
zplay "q (0..7)[..3]" # Take from end to the index 3
zplay "q (0..7)[-2..3]" # Take from -2 to 3
zplay "q A=(0..4) A (A)[0..3] (A)[..0]" # Assing list to value and modify it multiple times
z1 "q (0..7)[(-2,3)..5]" # Or use any other random syntax inside accessors which makes things more interesting
Same works for ziffers "native" arrays also:
a = zparse "q 0..6"
zplay a+a[0..4]+a[0..3]+a[..1]
As you might have already noticed Ziffer's lists are not sets in a a set theory sense. If you really want to create a set (meaning no same pitch classes), you can use different set operators.
Note lengths can be used with the traditional set operations, but two pitch classes with different length are considered as equal, for example:
zplay "(1 2 q3)<|>(2 6 e3)" # Union of two sets with note lengths
To change the behaviour use Ziffers.set_eql_keys method to define which keys are compared, for example:
Ziffers.set_eql_keys([:pc,:duration]) # Currently only global definition possible
zplay "(1 2 q3)<|>(2 6 e3)" # Union of two sets with different result
Alternative you can use to_pc_set method to get rid of extra notes from the set:
not_a_set = zparse "q (0 1 2 3 0 1 2 3)*(1 3 2)", scale: :chromatic
pc_set = not_a_set.to_pc_set # Transform to pitch class set
zplay pc_set
Use zip to set note lengths for the list:
zplay "(q e)<>(1..4)" # With note lengths: "q 2 e 2 q 3 e 4"
zplay "(q e)<>(1 2 3 4 5)" # With note lengths: "q 1 e 2 q 3 e 4 q 5"
zplay "(q e q)<>(1..9+2)+1*2" # Note lengths can be combined with any operations in a set
Scales can be changed within the lists
zplay "<minor>(q 0 2 3 4 5 1) <major>(q 0 2 3 4 5 1)" # Set scales for different lists
zplay "<a>(q 0 4 3 2) <c>(q 0 4 3 2) <f>(q 0 4 3 2)" # Use shorthands for modes
zplay "L<mixolydian> 0 2 3 4 <minor>3 4 2 <major>(2 3 4 9)" # Too many ways to do the same thing ...
(: :) = do n-times
zplay "(: 1..3 :)" # Create sequence 2 times
zplay "(: 1..3 (4,6) :3)~ # Create sequence add random number and randomize order 3 times
Lists can be transformed using syntax inspired by polynomial functions. Each term of the polynomial function is added at the end of the set, for example: (n..n){(2x^2)(x+2)}. The x in the function (0 1 2){2x} is evaluated using numbers in the list (0 1 2). The n in the function (3 2 1){n*x} is the index in the list and would be evaluated as (0*3 1*2 2*1).
Examples:
zplay "q (0 1 2){2x-1}" # Polynomial with one term
zplay "q (0 1 2){(2x-1)(2x^2-4)}" # Polynomial with two terms
zplay "q (0 1 2){(2x)-(3x)}" # Polynomial sets substracted
z1 "q (0 1 2){((1,2)x-1)(x-[4,1,-1])}" # Random polynomial functions
z1 "q ( (1,4) ){(2x-1)+(2x-(4,6))+(x-(1,4))}" # Multiple additive polynomial functions
zplay "(0..10){x-(1,7)}" # Random polynomial function applied to range
z1 "(3..0){(n*x)+n}" # Function using the list index
Set's can also be transformed conditionally using alternating functions
Examples:
zplay "((1,5)){x<2?4}" # Simple function returning value based on condition
zplay "(: (1,6) :5){x>3?x+10}" # Simple function doing addition based on condition
zplay "(0..20){x>7?x-(1,7):x+2}" # Minus random values based on condition
zplay "(0..10){x>3?x-(1,4):x+(1,4)}" # Minus or add ...
z1 "q(1..10){x%10==0?(0,3):{x%5==0?(2,4):{x%3==0?(6,7):(3,5)}}}" # Multiple recursive conditional statements in function
Conditional statements can be used to create random melodies. Conditions can use %, (1,5) or [1,3,4] syntax to compare the result to some value.
Examples:
z1 "1 {%>0.5? e 3 1}" # Simple conditional statement returning one value or nothing
z1 "{(1,4)>3?0:3}" # If random number is > 3 then 0 else 3
z1 "2 {[1,3,2]==1?4:5}" # Random values based on comparison on random array
z1 "{%<0.25? q 0 2 4 3 : q 2 4 e 3 5 3 1}" # Alternate patterns
z1 "(: {%>0.5?0:2} :10)" # Repeat statements -> "0 2 0 0 0 2 0 2"
z1 "{%>0.5 ? q 3 0 : {%<0.25 ? e 6 1 : e 0 5}}" # Loop recursive conditional statements
z1 "{%<0.25? q 0 2 4 3 : q (0 1 2 3){x%2==0?x+1:x-2} }" # Conditional function inside conditional
Ok ... thats it. Now go crazy with the combinations ...
Maybe something minorly disturbing:
z1 "q ((1..4*(2,5))%6*(1 -2 -1 (-1,2) -2 3))<qee>", scale: :minor
z2 "(036 468)*[1,-2,3,4]", scale: :minor
Or some atonal mayhem:
z1 "(q e e)<>((((1,10)..(15,25))~*([2 3 1, -1 2 3, 5 3 2]))%24)", scale: :chromatic
z2 "q (0 31 2 46)*(2 [-1,-2,3] (3,4) (1,4))", scale: :chromatic
This generative syntax / live code golfing thing is still evolving so leave feedback or post issues if you run into some problems.
------------------------------------ See more stuff from the menu --------------------------------------->