lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

A python function to covert lists of numbers to Lilypond files


From: John O'Hagan
Subject: A python function to covert lists of numbers to Lilypond files
Date: Thu, 11 Jun 2009 16:03:35 +0000
User-agent: KMail/1.11.2 (Linux/2.6.26-2009-05-03-05.07; KDE/4.2.2; i686; ; )

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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]