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
lilypond-user@gnu.org
http://lists.gnu.org/mailman/listinfo/lilypond-user

Reply via email to