SimpleBlog

Index of all articles

How it came to the scores (hummingbird mind thinking and one day of fun)

I’ve read Martin Gardener’s ’’The Colossal Book of Mathematics’’. In chapter 27 ’’Fractal Music’’ he discusses 1/f (pink noise) music generartion. So I was allways interested in algorithmic music and decided to try it with pink noise. Gardener describes Voss’s dice algorithm. It sounded easy, so a straight forward implementation in Ruby (which is the language of choice doing rapid prototyping) was even easier:

The Pink Noise Generator

#!/bin/ruby
# save this as "pinknoise.rb" 

# helpers:
# Voss uses binary representations of numbers to decide,
# which dice has to be to diced. Here is the function that checks the represtentations:

def getpdif(a,b)
  r=Array.new
  a.size.times do |i|
    r << i if a[i]!=b[i]
  end
  r
end

# classes:
# Dice Class, but every number of sides is possible:
class Dice
  def initialize(sides=6)
    @sides=sides
    @shows=rand(@sides)
  end
  def die
    @shows=rand(@sides)
  end
  def shows
    @shows
  end
end

# Pink Noise Class that computes first what dices
# (number of sides) will be needed, to generate pink noise in the range of r:
class PinkNoise
  def initialize(r=12)
    @sides=(Math.sqrt(r).to_i)+1
    @size=(Math.sqrt(r).to_i)+1
    @p0=2**@size
    @start=(@p0-1)
    @dices=Hash.new
    @size.times do |i|
      @dices[i+1]=Dice.new(@sides)
    end
  end
  def to_s
    [@size,@start,@dices]
  end
  def adddices
    r=0
    @dices.values.each do |y|
      r+=y.shows
    end
    r
  end
  def next
    n=@start+1
    n=(n%(2**@size)+@p0)
    r=getpdif(n.to_s(2),@start.to_s(2))
    @start=n
    r.each do |i|
      @dices[i].die
    end
    adddices
  end
end

# Example:
# pinknoisegenerator = PinkNoise.new(20)
# 10.times do
#   nextevent = pinknoisegenerator.next
# end

Fine this works!

If you want to do this and all that follows I reconmend:

  1. Use Linux, cause every thing is available (Ruby, Lilypond etc.) and this is an example of thinking unix.
  2. Or if you have a MS Laptop like me, use Cygwin where also every thing, you’ll need is available in a unix like enviroment.

Generating Music and Score (first try)

So what is the easiest way to generate score and midi?

Lilypond

I added this piece of code to pinknoise.rb (remember this is really rapid prototyping):

# header and footer of a lilypond source file:
$H=<<EOH
\\version "2.10.33" 
\\header { }
\\score {

EOH
$F=<<EOF

  \\layout { }
  \\midi { }
}
EOF

class Lily
  def initialize(n,tones)
    @n=n
    @tones=tones
    @m=@tones.size
    @png=PinkNoise.new(@m)
  end
  def write
    erg=$H+"{\n" 
    @n.times do |i|
      erg << "\n" if (i+1)%16==0
      erg << @tones[@png.next % @m] << "16 " 
    end
    erg << "\n}" << $F
    erg
  end
end

c_dur_pent=["c'","e'","f'","g'","a'","c''","e''","f''","g''","a''"]
c_dur=["c'","d'","e'","f'","g'","a'","b'","c''","d''","e''","f''","g''","a''","b''"]
l=Lily.new(64,c_dur)
print l.write

Now you do:
  1. ruby pinknoise.rb >test.ly
  2. lilypond test.ly

and you get ’’test.mid’’ and ’’test.pdf’’, so you can look at the score and hear the midi file.

The Hummingbird Situation

Until now everything was fine and quite easy. So I began to think about musical form, rythmn, harmonies and so on. Quite complex things. And I really got in panic about all this work with the moods and scales. (Ok, this is not the hard thing in algorithmic music, but it’s still a lot of typing) I thought, there must be someone, who has done all this work and there should be a repository of scales in a common format. So I googeled. And yapadapadoo I found lucytune where Charles Lucy (By the way: Sorry Charles, that until now I have not read all the other material on the luzytune side, but I’m really a hummingbird mind, but I’m sure it’s worth reading) has done a great thing, that caught me at once, cause of his mathematical approach (every possible scale in enharmonic space from unison to twelfetone with base tone c) and on the other side cause he did such a lot of work in finding the namings of the scales.

I downloaded his Excelfile of all Scales base tone c and wow there are so many that make sense.

Visualisation

Hey Mr. Hummingbird, you wanted to make pink noise music? Ok, this could be done later. Let’s first see what we have got here. There are so many Ragas and I love classical indian music. So let’s visualize first the scales.

Again this could be done with lilypond. But first we need a parser for the xls file.

So let’s save it as csv first. (I used OpenOffice to do this) We now have a 2339.csv file.

Here the ruby programm that reads the csv and makes the lilypond sourcefiles for generating the scores:

#!/bin/ruby

# the schema of the csv:
$Pattern=["Name Of Scale", "ScaleCoding", "Pitch Set binary",
"Binary 12notes 1&0", "PitchSet Notation 12 edo", "Note Names from C",
"NotesInStepsOfFifiths", "L and s Interval Sequence", "Major Triads", 
"Minor Triads", "Aug. Triads", "Dim. Triads", "Number Of Notes In Scale", 
"Ascending Note Positions in Scale", "LengthOfChain", "Flatmost Note",
"Sharpmost Note", "Contiguous Notes", "PositionOfTonic"]

# should be called makedutch!
def makeenglish(s)
  s=s.gsub("#","is")
  s=s.gsub("b","es")
  s=s.gsub("Ces","Ces'")
  l=s.split(" ").map { |x| x+"'" }
  s=l.join(" ")
  s.downcase
end

# The parser class (not much parsing more mapping)
class AbstractScale
  def initialize(s)
    @a=s.chop.split(";")
    @attr=Hash.new
    @a.each_with_index do |e,i|
      @attr[$Pattern[i]]=e
    end
  end
  def show
    p @attr
  end
  def nameandtones
    [makeenglish(@attr["Note Names from C"]),@attr["Name Of Scale"]]
  end
  def tonesnames
    [@attr["Name Of Scale"], makeenglish(@attr["Note Names from C"])]
  end
  def allattrwithname
    erg=[]
    $Pattern.each do |k|
      erg << k
      erg << @attr[k]
    end
    erg
  end
  def astxt
    muster="|%s:|%s|\n" 
    ergh="" 
    erg="" 
    li=0
    $Pattern.each do |k|
      if li==0
        ergh << "h3. %s\n\n" % @attr[k]
      else
        erg << muster % [k, @attr[k]]
      end
      li+=1
    end
    [ergh,erg]
  end
  def tnumber
    @attr["Number Of Notes In Scale"].to_i
  end
  def nameofscale
    @attr["Name Of Scale"]
  end
  def notenamesbasec
    @attr["Note Names from C"]
  end

end

# a little helper to make filenames that sort right:
def mn(n)
  s=n.to_s
  while s.size<4
    s="0"+s
  end
  s
end

# Reading the scales into the list erg.
# 2339-gut because, I had to remove some unicodes to be able to process with lilypond.
erg=[]
open("2339-gut.csv") do |f|
  f.readlines.each do |l|
    l=l.delete('"')
    erg << AbstractScale.new(l)
  end
end

# removing the header of the table
erg.delete_at(0)

# test functions: It reads all 2338 scales.
def donan(erg)
  erg.each do |as|
    p as.nameandtones
  end
end

#erg[0].show

#print erg[100].astxt[0]

#donan(erg)

# The lilypond sorcefile template:
$Score=<<EOSS
\\version "2.10.33" 

\\markup { \"%s:\" }

\\score {
\\new GregorianTranscriptionStaff { 
    %s
  }
}

EOSS

# This is the processing. You'll need a pngs dir
li=0
erg.each do |as|
  open("pngs/scale%s.ly" % mn(li),"w") do |f|
    f.write($Score % as.tonesnames)
  end
  li+=1
end

After running this we will have 2338 ’’.ly’’ files named scale0000.ly up to scale2337.ly in the pngs directory.

So now:
  1. cd pngs
  2. lilypond -dbackend=eps -dno-gs-load-fonts -dinclude-eps-fonts—png *.ly (we want png files not pdf)

and you’ll get 2338 png files, one for every scale. So they will be a4 format, cause my version of lilypond can not produce smaller pngs, but I think version 2.12 can do it. But this version is not available on Cygwin yet.

But this is not a problem, cause we can convert the pngs with the convert tool of ImageMagick which is also available on Linux and Cygwin:

#!/bin/ruby
# save this as convert.rb
# to become sortable filenames:
def mn(n)
  s=n.to_s
  while s.size<4
    s="0"+s
  end
  s
end

# I decided to make the small pngs 415x165:
li=0
Dir["pngs/scale*.png"].each do |path|
  p path
  np="pngs4/s%s.jpg" % mn (li)
  `convert #{path} -crop 415x165+210+65 #{np}`
  li+=1
end

In the pngs dir call ’’ruby convert.rb’’ and you will get s0000.png upto s2337.png which are the small versions of the score pics, which you can download here http://www.muzuu.org/new_life/pics/simpleblog/scales/scalespngs.zip (10 MB)

Just for fun: A movie with all the scales

This was made with Mencoder of the Mplayer suite.

Ah, I wanted to make pink noise music …