Coder Social home page Coder Social logo

amiika / ziffers Goto Github PK

View Code? Open in Web Editor NEW
77.0 9.0 4.0 1.22 MB

Numbered musical notation for composing algorithmic and generative melodies

License: MIT License

Ruby 100.00%
sonic-pi numbered-musical-notation numeric-notation numbered-notation music-theory music-notation algorithmic-composition generative-music music music-composition

ziffers's Introduction

Ziffers: Numeric notation for composing algorithmic and generative music using Sonic Pi

Ziffers is a generative numbered musical notation (aka. Ziffersystem) and a live code golfing framework that makes composing melodies and rhythms easier and faster in Sonic Pi.

Writing and playing melodies in any key or scale will be as simple as:

zplay "q 4 e 1 1 q 2 1 r #3 4 ", key: "f", scale: "major", synth: :piano

or playing loops:

zloop :ride, "e 3 3 2 2 1 1 2 2", key: :c, scale: :chromatic, synth: :piano

or loops with generative live rules:

z1 "e1",
rules: {
  "1"=>"3",
  "3"=>"2",
  "2"=>"4",
  "4"=>"(1,6)",
  "5"=>"1",
  "6"=>"2"
}, synth: :pretty_bell

or play infinite sequences. Easy as:

zplay pi, rhythm: "q q h q q h h q ee h q ee"

or simple aleatoric melodies:

z1 "[0,3,5] 4 (1,3) (4,6) 2 e <3 0 (2,4)> (5,7)", scale: :ahirbhairav, key: :e, synth: :piano, attack: 0.25

or go crazy and create lists and do list operations using transformations and nested notation:

z1 "q (0 1 (3,7) 3)~<*>(4 [6,4,[5,4,2,7]] (0,(5,8)) (1,6))", synth: :kalimba

and much more ... See Ziffers wiki or download A4 cheatsheet to learn more.

Here is a cheatsheet you can copy to Sonic Pi editor:

# Pitches: -2 -1 0 1 2
# Chords: 0 024 2 246
# Note lengths: w 0 h 1 q 2 e 3 s 4
# Subdivision: [1 2 [3 4]]
# Decimal durations: 0.25 0 1 <0.333>2 3
# Octaves: ^ 0 ^ 1 _ 2 _ 3
# Escaped octave: <2> 1 <1>1<-2>3
# Roman chords: i ii iii+4 iv+5 v+8 vi+10 vii+20
# Named chords: i^7 i^min i^dim i^maj7
# Modal interchange (a-g): iiia ig ivf^7
# Escape/eval: {10 11} {1.2 2.43} {3+1*2}
# Randoms: % ? % ? % ?
# Random between: (-3,6)
# Random selections: [q 1 2, q 3 e 4 6]
# Repeat: [: 1 (2,6) 3 :4]
# Repeat cycles: [: <q e> (1,4)  <(2 3) (3 (1,7))> :]
# Lists: h 1 q(0 1 2 3) 2
# List cycles: (: <q e> (1,4) <(2 3) (3 (1,7))> :)
# Loop cycles (for zloop or z0-z9): <0 <1 <2 <3 <4 5>>>>>
# Basic operations: (1 2 (3 4)+2)*2 ((1 2 3)+(0 9 13))-2 ((3 4 {10})*(2 9 3))%7
# Product operations: (0 1 2 3)+(1 4 2 3) (0 1 2)-(0 2 1)+2
# Euclid cycles: (q1)<6,7>(q4 (e3 e4) q2) or (q1)<6,7<(q4 q3 q2)
# Transformations: (0 1 2)<r> (0 1 2)<i>(-2 1) etc.
# List assignation: A=(0 (1,6) 3) B=(3 ? 2) B A B B A
# Random repeat: (: 1 (2,6) 3 :4)
# Conditionals: 1 {%<0.5?3} 3 4 (: 1 2 {%<0.2?3:2} :3)
# Functions: (0 1 2 3){x%3==0?x-2:x+2}
# Polynomials: (-10..10){(x**3)*(x+1)%12}

Quick start

Requirements

Install ziffers

Install Ziffers to your Sonic Pi by cloning this project into your home directory (this makes referencing easier as most of the examples use ~ shorthand to require stuff). Ziffers can then be required to your Sonic Pi project using:

require "~/ziffers/ziffers.rb" # ~ references ziffers under users home folder, works also in Windows

Stay up to date as the Ziffers is an ongoing project. Post Issues to report bugs or to ask questions.

Examples

There are some pretty random examples in the Examples-folder. You can also try out one line examples from tests or browse trough wiki. If you make some nice tunes do a pull request to Examples folder to share! Thanks!

Documentation

Syntax and methods are documented in Ziffers wiki.

Help & Contributions

For bugs post an issue or a fix using merge request. Use discussions for general questions and feature requests.

ziffers's People

Contributors

amiika avatar sohalt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ziffers's Issues

Add when option for loops cycles

Add when option for loops. Something that could be run for every 6 cycle or last 2 cycles etc.

For example:

z1 "1234", seed: 2, when: {
cycles: 4,
last: 2
do: { offset: 2 }
}

Rewrite zparse

Current string parsing function zparse is an accumulated piece of steaming spaghetti and meatballs. Refactor parsing function to produce plain parsed hash array and create separate functions for sliding, chord parsing etc etc.

Plain hash arrays (without parsed notes and chords) would work better with loops as they could be resolved on the fly.

Midi sustain vs. Sonic Pi envelopes

Figure out best way to transform Sonic Pi envelopes to midi sustain.

Currently if sustain is used in ziffers, eg. "S1 1234" it is also used as midi sustain. If not used default release becomes midi sustain. Should it be something like: attack+decay+sustain+release or not?

Used midi synth might also support attack & decay trough midi_cc ?

Negative degrees

Planning breaking change in syntax. Current octave change characters: -+ will change to _^

This change allows use of -+ characters with negative degrees. Two octaves using negative and positive degrees: "-7654321+1234567". This can also be more intuitive in some cases, for example "1-123" is more intuitive than current "1-765", which would be "1_765" after the change.

Negative degrees also come in handy when creating harmonies and inverse melodies. Inverse melody can be created by inversing the degree and adding offset. Simple way to add this:

degrees.each do |degree|
    -(degree)+inverse+offset if degree!=inverse && degree!=0
end

zplay "1231", inverse: 0 # Complete inversion. Plays "-1231"
zplay "1231", inverse: 1 # Inversion with same starting point. Plays "1-12+1"
zplay "1231", inverse: 1, offset: 3 # --..-- and offset. Plays "4254"

These two parameters would then make easy way to invert melodies and create harmonies when playing same original melody in multiple threads.

Change rest character from 0 to r and degrees from 0..9

Use of 0 causes problems with generative sequences and lsystems. Mathematical operations causes unwanted rests in the generated music. Changing 0 to r (as in lilypond syntax) would fix that, but in the same time degrees would change from 1..9 to 0..9.

1..9 is traditionally used as degree numbers in numbered notations but 0..9 is also used in musical set theory. All an all 0..9 notation for degrees (0=1, 1=2, 2=... ) can be confusing but in the same time it's more usable as computable notation.

Custom character mapping

It could be possible to rewrite the ziffers parser to support custom character mapping to control symbols, like:

setMapping({"S": :sustain, "A": :attack})

and

setNoteLengths({"p": 0.25236, "l": 0.3242})

Add variable assingment for random syntax

It would be nice to be able to assign variable once and use it multiple times.

For example:
"<?=(1,7)> ? 12 ? 23 ? 34"

This would allow to generate lsystem rules to generate brownian motion with random cuts. Like:
" 1 1 1 1 1 1 1 1 1 ", {/([1-9]) ([1-9]) ([1-9])/=>"0.3%=<?=(-7,7)>'$1+?' '$2+?' '$3+?'"}, 40

Add chord key

Add new key for chords only. Useful when you want to play chord for example octavle lower or in different key

Issues with the inverse

Inverse is still preparsed. Maybe it should be transformation?

I should also check if the inverse: 2 etc. notation is working as expected, current formula:

dgr = -((dgr-ziff[:inverse])-ziff[:inverse])

Add harmony to existing melody

Simple melodies could be turned to harmonized melodies with simple harmony parameter providing number of steps between the notes and number of notes, for example:

zplay "123", harmony: [2,3]

would be same as:

zplay "{1,3,5}0{2,4,6}0{3,5,7}0"

Change custom chord notation

Custom chord syntax is too complex for string manipulation and lsystem,

Currently for example: {1,2,3}

Should be something like: 1,2,3

Add sequence notation

Random syntax can now generate random numbers for example:

(2000,3000,2) -> 2345 2984
(20,30,2;qe) -> q2e7 q2e5
(1..4) -> 3214
(1..3;hqe) -> h1q3e2

It would be nice to also have some sequence notation that could produce sequences with explicit or random steps. Simple syntax for following examples:

(1..10).step(2).to_a
(1..10).step(rrand_i(1,4)).to_a

Add multiplying syntax

Change current "jump repeat"=* to something else. Add multiplying syntax for degrees and assigned characters.

zplay "14"->"1 1 1 1"
zplay "K
4"->" K K K K"
etc.

but maybe as a separate opt under current hash, like ... times: 4

Syntax for harmony notes

Create syntax for creating harmonies. Harmonies can be done by creating two simultanious lines, but it could be useful to create speficic syntax that plays difference from current degree.

1_3 = 1 and down by 3
1^3 =1 and up by 3
0_3 = rest and down from 1 by 3

For example in Adeste fideles like:

q 1_3 | h 1_3 q 0_2 1_3 | h 2_3 0_3 | ...

Fix sample effects ... again

Not working:

Effects can also be applied to samples using run:

z1 "B K (B B) K", run: [{with_bpm: 120}],
use: {B: :bd_fat, K: { sample: :drum_snare_soft, run: [{with_fx: :echo}] }}

Or all of the samples:

z1 "B K (B B) K", run: [{with_bpm: 120}],
use: {B: :bd_fat, K: { sample: :drum_snare_soft },
run: [{with_fx: :echo}]}

Notation assignation for custom samples

Playing degrees with samples works now with sample parameter.

Add syntax for and character assingment for multiple samples:

zplay "O X O X", samples: {"O"=>:drum_heavy_kick, "X"=>:drum_snare_hard}
zplay "q B 1 2 3 h C 3 2 1", samples: {"B"=>:ambi_glass_rub, "C"=>:ambi_drone}

Add fading to zplay and zloop

Add option to fade notes in or adjust parameters as a ring.

zplay "123456", adjust: {amp: [0.0,0.1,0.2,0.3,1,2] }
zloop "12345", adjust: {amp: [0.5,1,2].ring}

Add function to create common easing functions:

zplay "123456", adjust: {amp: (zrange :expo, 0, 2, 10) }

Add retrograde

Add retrograde function that would inverse the notes but not the chords

Syntax for ties (sort of)

Add support for adding note lengths together:

"q a 3" -> q+a

This is basically a "tie" with q3 and a3.

Tests Not Working in Ziffers2

In Sonic Pi 3.3.1 using Ziffers2 branch from this morning, stopping at the first test:

testzplay

Getting the following error:

Runtime Error: [buffer 3, line 194] - NoMethodError
Thread death!
 undefined method `value' for nil:NilClass
~/ziffers/parser/zgrammar.rb:40:in `parse_ziffers'
~/ziffers/ziffers.rb:230:in `zparse'
~/ziffers/ziffers.rb:562:in `normalize_melody'
~/ziffers/ziffers.rb:435:in `zplay'
workspace_three:50:in `testinverseoffset'
workspace_three:194:in `block (2 levels) in __spider_eval'
/Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/lib/sonicpi/runtime.rb:830:in `eval'
/Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/lib/sonicpi/runtime.rb:830:in `block (2 levels) in __spider_eval'
/Applications/Sonic Pi.app/Contents/Resources/app/server/ruby/lib/sonicpi/runtime.rb:1093:in `block (2 levels) in __in_thread'

Add syntax for cyclic groups

Cyclic groups are generally marked as <1> or <6> etc. in music theory.

Current sequence generation for ziffers is (1..5)?3 etc.

Combine these somehow, maybe change the syntax of mirroring since % is usually used as mod. Cyclic groups could then be created using % as mod:

(3)%12 -> 3690
(2)%6 -> 240

Add automatic sync to z1 if it exists

Add default sync from z2-20 to :z1 if it exists.

Maybe some other control to override the default like:
Ziffers.set_default_loop_sync :foo

or

zloop :main, "1 2 3", default: true

And overriding should be possible as usually:
z2 "1 2 3", sync: :z3

Changes in random sequence format

Sequence notation has gone trough many changes. Something else than current regexp solution should be explored.

Some new syntax for adding degree escapes could also be useful, for example:
(0..11)= -> "0123456789=10=11"

Set zero based notation as default

Set the zero based notation as default. It allows some fancy inversion stuff that is otherwise too hard to implement.

This requires tons of documentation change ...

Preparser for alternate syntax with notenames

Preparser that produces degree notation from alternate syntax: "4cccdddee2c" -> "q11122233h1"

For example in key of C:
znotes "4cccdddee2c", key: :c

Note characters:
c,d,e,f,g,a,b

Note lengths:
1 = whole
2 = half
4 = quarter
8 = eight
6 = sixteenth
3 = thirty-second
5 = sixty-fourth
7 = double whole
8 = long
9 = max
0 = zero

Add new transposition function for parsed melodies

Currently there is undocumented :add parameter that increases or decreases the degree values, that works like:

zplay "0 1 2 3", add: 1 -> "1 2 3 4"

Problem with that is that it is done before/during parsing. Add new transposition function:

m = zparse "0 1 2 3 4"
transposition m, 3 -> "3 4 5 6"

L-system like syntax and parameters for melody generation

Generative fractal melodies using regexp is super simple in ruby, for example:

t = {"0"=> "10010", "1"=>"1?" }
n = "0"
3.times { n = n.gsub(Regexp.union(t.keys),t) }
print n

Add parameter for number of "generations" and "axioms" that supports ziffers syntax.

midi support

Hi and thank you, ziffers looks like an amazing additon to Sonic-Pi !
Is it already possible to use ziffers with midi, in order to play external instruments ?
If not, would you try to implement midi support later on ?
All the best !

Add escape characters for channel and port

Adding escape character for channels and ports. Usually using same port but channel could be useful to play chords in different sound / non blocking way.

"O1 i O2 1234" = Plays i chord in channel 1 and melody in channel 2
"Uport_1 123432 Uport_2 3242" = Plays melody in port_1 and then in port_2

List of current escape characters:

    'A': :amp,
    'E': :env_curve,
    'C': :attack, # Charge?
    'P': :pan,
    'D': :decay,
    'S': :sustain,
    'R': :release,
    'Z': :sleep, #Zzz
    'X': :chordSleep,
    'T': :pitch, # Tuning
    'K': :key,
    '~': :note_slide,
    '^': :chord_name,
    'i': :chord,
    'v': :chord,
    '%': :chordInvert

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.