MusikalischeWurfelspiele.py

#

You can see the actual code file here. The .xml for Musikalische Wurfelspiele is here. A PDF of an annotated score sorted by output measures is here.

from music21 import converter, stream, clef, meter, bar
import random
#

init function to parse MusikalischeWurfelspiele.xml and split the single stream of 176 measures into 176 streams each of one measure.

def init():
#

Parse the "Musikalische Wurfelspiele" instruction score.

    s = converter.parse('MusikalischeWurfelspiele.xml')
#

Split score into measures.

    measures = [stream.Stream() for i in range(176)]
    for part in s.parts:
        for i, this_measure in enumerate(part.getElementsByClass('Measure')):
            measures[i].insert(0, this_measure.notesAndRests.stream())
#

chance table--each row corresponds to the option for a single measure in the output

    table = [[96, 32, 69, 40, 148, 104, 152, 119, 98, 3, 54],
             [22, 6, 95, 17, 74, 157, 60, 84, 142, 87, 130],
             [141, 128, 158, 113, 163, 27, 171, 114, 42, 165, 10],
             [41, 63, 13, 85, 45, 167, 53, 50, 156, 61, 103],
             [105, 146, 153, 161, 80, 154, 99, 140, 75, 135, 28],
             [122, 46, 55, 2, 97, 68, 133, 86, 129, 47, 37],
             [11, 134, 110, 159, 36, 118, 21, 169, 62, 147, 106],
             [30, 81, 24, 100, 107, 91, 127, 94, 123, 33, 5],
             [70, 117, 66, 90, 25, 138, 16, 120, 65, 102, 35],
             [121, 39, 139, 176, 143, 71, 155, 88, 77, 4, 20],
             [26, 126, 15, 7, 64, 150, 57, 48, 19, 31, 108],
             [9, 56, 132, 34, 125, 29, 175, 166, 82, 164, 92],
             [112, 174, 73, 67, 76, 101, 43, 51, 137, 144, 12],
             [49, 18, 58, 160, 136, 162, 168, 115, 38, 59, 124],
             [109, 116, 145, 52, 1, 23, 89, 72, 149, 173, 44],
             [14, 83, 79, 170, 93, 151, 172, 111, 8, 78, 131]]
    
    return (measures, table)
#

Make a random choice from each of the 16 rows of the chance table.

def generate_selections(table):
#
    selections = []
    for row in table:
        index = random.randint(0, 5) + random.randint(0, 5)
        selections.append(row[index])
    return selections
#

measures is a list of 176 streams of a single measure each. selections is a list corresponding to 16 of the 176 measure streams.

Returns out, which is a stream consisting of the 16 selected measures.

def create_waltz(measures, selections):
#

Use selections to create output.

    out = stream.Stream()
    for i in range(2):
        p = stream.Part()
        for selection in selections:
            p.append(measures[selection - 1][i])
        out.insert(0, p)
    return out
#

Add clefs and time signatures to the waltz (s).

def add_clefs_and_timesignatures(s):
#
    s[0][0].insert(0, clef.TrebleClef())
    s[1][0].insert(0, clef.BassClef())
    for i in range(2):
        s[i][0].insert(0, meter.TimeSignature('3/8'))
#

Add repeat signs to the waltz (s).

def add_repeats(s):
#
    for i in range(2):
        for m in [0, 8]:
            s[i][m].leftBarline = bar.Repeat(direction='start')
        for m in [7, 15]:
            s[i][m].rightBarline = bar.Repeat(direction='end')
#

Generate a new Waltz based on Mozart's "Musikalische Wurfelspiele". measures is a list of 176 streams of a single measure each. table is a matrix for the possible selection for each measure of the resulting 16-bar waltz.

def play_the_game(measures, table, show=True):
#
    selections = generate_selections(table)
    waltz = create_waltz(measures, selections)
    add_clefs_and_timesignatures(waltz)
    add_repeats(waltz)
    if show == True:
        waltz.show()
    return waltz
#

Sorts the possible measures by their location in the resulting waltz into a single music21 stream; e.g. the eleven possible first bars are bars 1 - 11 in the output stream, the eleven possible second bars are bars 12 - 22 in the output stream, and so forth.

def options_by_measures(measures, table, show=True):
#
    collated_measures = [cell for row in table for cell in row]
    measures_options = create_waltz(measures, collated_measures)
    add_clefs_and_timesignatures(measures_options)
    if show == True:
        measures_options.show()
    return measures_options
#

Split the instructions into individual measures and grab the chance table.

measures, table = init()
#

Play the game!

play_the_game(measures, table)
#

Create score sorted by output measures.

options_by_measures(measures, table)