Thanks Sam!
Short history of Ziffers is going from “I have no idea what i am doing” to “I sort know what i would like and having fun while experimenting” during ~5 years.
One of the first goals (meaning i sort of knew what i would like) was to make minimalistic numerical notation that enables live coder to improvise meaningful melodic sequences on the fly. I think this is accomplished but it requires some practice for sure. If you can hum a melody and imagine those as integers you are good to go. Then you just have to pick key and a scale and maybe find one you like. For rhythm you have to know bit more syntax to get what you want, for example:
0 4 2 6 4 1 # Imagined melody
0 4 [2 6] [4 1] # Rhythm as subdivision
0 4 h 2 6 4 1 # Rhyhm as "standard" note durations
zplay "h 0 4 q 2 6 4 1", key: :d, scale: :minor # Ziffers realization with a key and scale
z1 "h 0 4 q 2 6 4 1", key: :d, scale: :minor, add: [0,-2,-1,3] # Realization as a loop & transformations
I did not mean to create my own “sublanguage” for Sonic Pi, but minimalist in me forced me to do it … but you can always use Ziffers as a way to parse melodies to data and code everything else yourself if you want:
melody = zparse "h 0 4 q 2 6 4 1", key: :d, scale: :minor
print melody # Nice data format for the melody
I wanted an easy way to evolve the melodies and that was the main reason creating my own methods for looping, transforming and adding effects. The end result is that you can create complete live compositions using Ziffers.
There is also a long history in using numerical notation, musical set theory, musical analysis, mathematical transformations and use of number sequences to compose music. Some things i have reinvented and some picked up somewhere along the way.
The most recent goal i’v been working on for the last year has been to implement notation for generative music. So instead of coding all generative things, you would have a simple notation for some of it. Simple here is also bit relative as it goes from simple to complex as soon as you start doing list operations and recursion.
z1 "h 0 2 [q 3 2, h5] 4 [h2, q 3 1]", synth: :piano # Simple semirandom melody
z1 "q 0 (5,7) 2 (4,6)", synth: :piano # Another simple semirandom melody
z1 "h 0 2 (1,(3,6)) [2 3,[1 2,3 (2,4)]]" # Gaining complexity with recursion
z1 "h (0..3*[1,2,4])~+(0 2 6 1)" # Using lists to make things complex
z1 "h ((1..7)*(2 4 1))%7+(: (1,6) :4)" # Making totally random yet interesting things
z1 "h {%>0.5?(1..4*[2,4,6]):(1..4*3)}" # Conditional statements are also fun
z1 "q (1..7){x%2==0?x-(1,3):x+(2,4)}" # Or conditional functions doing random things
… and that rabbithole goes deep
Use of enumerators is bit of a sidetrack but related to my passion for math and integer sequences. One of my hobbies is to get lost in online encyclopedia of integer sequences to find musically interesting sequences. Those sequences (like pi, recaman, noergaard …) are usually easiest to implement as enumerators that can be used to compose infinite music by combining the melody (integers as pitch classes in a certain scale) with some rhythmic elements.
Enumerators seemed like a good way to organize other types of recurring sequences as well, like integers generated with markov chains or cellular automatons. Ziffers can play any integer or a sequence in a given scale, so given an enumerator ziffers just keeps asking for more until the end of time or computer crashes
While experimenting with things i’v come across many interesting topics and examples here in these forums and github, so thanks you all sharing ideas, especially @Bubo, @enkerli, @Nechoj, @blipson, @mlange, @emlyn, @perpetual_monday, @robin.newman, @d0lfyn for many interesting conversations and feedback.