I've been working on an algorithmic music-generating program written in
Python. It uses the function below to convert its numerical output (the same
output that is converted to sound) into Lilypond text output, thus
automatically producing scores (or midi files).
I thought it might be of interest to those working in similar areas. Any
feedback appreciated.
Regards,
John
Python code:
def auto_lily(arg, tempo=120, percussion=False, bass=False, midi=False,
filename="auto_lily"):
"""Translate arg into a Lilypond score or midi file.
Arg must be a list of bars. A bar is a list of 2-tuples,
of which the first element is a list of integers representing pitches,
and the second is an integer representing duration.
For example:
[ [([0, 4, 7], 4), ([0, 4, 7], 4)], [([0, 4, 7], 8)] ]
will be converted to a bar of two C-major chords
each four quavers in length, followed by
a bar of one C-major chord eight quavers in length."""
pitch_dict = { 0:" c", 1:" cis", 2:" d", 3:" dis", 4:" e", 5:" f",
6:" fis", 7:" g", 8:" gis", 9:" a", 10:" ais", 11:" b", "rest":"r" }
duration_dict = {1:str(8), 2:str(4), 3:str(4)+"." , 4:str(2) ,
6:str(2)+".", 7:str(2) + "." + ".", 8:str(1) }
if percussion:
clef = "percussion"
elif bass:
clef = "bass"
else:
clef = "treble"
clef = "\n \\clef " + clef
tempo = " \n \\tempo 4 = " + str(tempo)
score = [" \\score { \n\n \\version \"2.10.33\" { ", clef, tempo]
last_octave = ""
last_time_sig = ""
for bar in arg:
highest = max([max(event[0]) for event in bar])
lowest = min([min(event[0]) for event in bar])
middle = (highest + lowest) / 2
if middle >= 30 :
octave = 2
elif middle in range(18, 30):
octave = 1
elif middle in range(-18, 18):
octave = 0
elif middle in range(-30, -18):
octave = -1
elif middle < -30 :
octave = -2
octave =" #(set-octavation " + str(octave) +")"
if octave == last_octave:
octave = ""
else:
last_octave = octave
numerator = sum([event[1] for event in bar])
if (numerator != 6) and (numerator != 12) and not numerator % 2:
numerator /= 2
time_sig = " \n \\time " + str(numerator) + "/4"
else:
time_sig = " \n \\time " + str(numerator) + "/8"
if time_sig == last_time_sig:
time_sig = ""
else:
last_time_sig = time_sig
newbar = ["\n", time_sig, octave, "\n"]
for event in bar:
duration = event[1]
if duration == 0:
continue
else:
if len(event) > 1:
openchord , closechord = " < ", " > "
else:
openchord , closechord = "", ""
pitches = [openchord]
for i in event[0] :
tag = [""]
if i >= 0:
for _ in range(((i)/12 + 1)) :
tag.append("'")
else:
for _ in range(abs(((i)/12 + 1))) :
tag.append(",")
pitches += [pitch_dict[(i) % 12]] + tag
pitches.append(closechord)
pitches = ''.join(pitches)
if duration == 5:
newbar += [pitches, " 2", " ~", pitches, "8"]
elif duration <= 8:
newbar += [pitches, duration_dict[duration]]
else:
semibreves = duration/8
newbar += [pitches, " 1"]
for _ in range(1, semibreves):
newbar += ["~", pitches, " 1"]
if duration % 8 == 5:
newbar += [" ~", pitches, " 2" , "~", pitches, "8"]
elif duration % 8:
newbar += ["~", pitches, duration_dict[ duration % 8]]
score += newbar
if midi:
score.append("\n }\n \\midi \n{ }\n } ")
else:
score.append("\n }\n }")
score = ''.join(score)
return score
_______________________________________________
lilypond-user mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/lilypond-user