spiffyscore

Check-in [8f28834102]
Login
Overview
Comment:Fixed chord support
Timelines: family | ancestors | descendants | both | develop
Files: files | file ages | folders
SHA1: 8f28834102b41a640931e718c456c3dace788a11
User & Date: brian on 2011-11-27 02:56:34
Other Links: branch diff | manifest | tags
Context
2011-12-04
20:52
Made room for arbitrary-note chording whenever I figure out the CFY to represent iTSYntax to use for it Leaf check-in: 3023a967c2 user: brian tags: develop
2011-11-27
02:56
Fixed chord support check-in: 8f28834102 user: brian tags: develop
02:26
Fixed a bug that prevented sharps and flats from working check-in: bf135b5321 user: brian tags: develop
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Modified parse.py from [4cca2f3d0c] to [0884d30f89].

1
2
3
4
5
6
7

8
9


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python

import tree

from ply import lex, yacc
class Note():
    def __init__(self, value, duration=1, octave=8):

        self.value = value
        self.duration = duration


        self.octave = octave
    def __repr__(self):
        return "Note %s %s %s" % (self.value, self.duration, self.octave)

class Chord():
    def __init__(self, value, duration=1, chord_type="major", octave=5):
        self.value = value
        self.duration = duration
        self.chord_type = chord_type
        self.octave = octave
    def __repr__(self):
        return "Chord %s %s %s" % (self.value, self.duration, self.chord_type, self.octave)

class Rest():
    def __init__(self, duration=1):
        self.duration = duration
    def __repr__(self):
        return "Rest node %s" % self.duration


def parse(score, default_octave=8):
    # Tokenize (lex)
    tokens = (
        "NOTE_LENGTH",
        "BASENOTE",
        "ACCIDENTAL",
        "REST",
        "OCTAVE",
        "CHORD_TYPE",
        "PAREN",
        "SYNCOPATE",
        "NODE",
    )

    t_ignore = " |"

    t_BASENOTE = r"[A-Ga-g]"
#    t_BASENOTE = r"I+V?|VI*|i+v?|vi*"
    t_ACCIDENTAL = r"\^{1}|_{1}|="
    t_REST = r"z"
    t_OCTAVE = r"'+|,+"
    t_CHORD_TYPE = r"m|7|m7|0|o|\+|mb5|sus|sus4|maj7|mmaj7|7sus4|dim|dim7|7b5|m7b5|6|b6|m6|mb6|46|maj9|9|add9|7b9|m9"
    t_PAREN = "\[|\]"
    t_SYNCOPATE = "\+|-"
    t_NODE = r"\([a-zA-Z0-9_-]+\)"

    def t_NOTE_LENGTH(t):
        r"/?\d+"
        multiplier = float(t.value.strip("/"))
        if t.value.startswith("/"):







>
|
|
>
>





|
|

<
<

|

















|












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20


21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#!/usr/bin/env python

import tree

from ply import lex, yacc
class Note():
    def __init__(self, value, duration=1, octave=8):
        self.duration = duration
        if value > 12:
            self.duration += 1
            value = value % 12
        self.value = value
        self.octave = octave
    def __repr__(self):
        return "Note %s %s %s" % (self.value, self.duration, self.octave)

class Chord():
    def __init__(self, notes, duration=1):
        self.notes = notes
        self.duration = duration


    def __repr__(self):
        return "Chord %s" % (self.notes)

class Rest():
    def __init__(self, duration=1):
        self.duration = duration
    def __repr__(self):
        return "Rest node %s" % self.duration


def parse(score, default_octave=8):
    # Tokenize (lex)
    tokens = (
        "NOTE_LENGTH",
        "BASENOTE",
        "ACCIDENTAL",
        "REST",
        "OCTAVE",
        "CHORD_TYPE",
        "BRACKET",
        "SYNCOPATE",
        "NODE",
    )

    t_ignore = " |"

    t_BASENOTE = r"[A-Ga-g]"
#    t_BASENOTE = r"I+V?|VI*|i+v?|vi*"
    t_ACCIDENTAL = r"\^{1}|_{1}|="
    t_REST = r"z"
    t_OCTAVE = r"'+|,+"
    t_CHORD_TYPE = r"m|7|m7|0|o|\+|mb5|sus|sus4|maj7|mmaj7|7sus4|dim|dim7|7b5|m7b5|6|b6|m6|mb6|46|maj9|9|add9|7b9|m9"
    t_BRACKET = r"\[|\]"
    t_SYNCOPATE = "\+|-"
    t_NODE = r"\([a-zA-Z0-9_-]+\)"

    def t_NOTE_LENGTH(t):
        r"/?\d+"
        multiplier = float(t.value.strip("/"))
        if t.value.startswith("/"):
100
101
102
103
104
105
106
107
108
109
110

111

112
113
114
115
116
117
118
119
120
121
        '''
        new_note = p[1]
        new_note.duration = p[2]
        p[0] = new_note


    def p_chord(p):
        '''chord : PAREN note PAREN
                 | PAREN note CHORD_TYPE PAREN
        '''
        pitch = p[2].value

        pitch = pitch.upper()

        p[0] = Chord(value=pitch, octave=default_octave)
        if len(p) > 3:
            p[0].chord_type = p[3]


    def p_note_syncopate(p):
        ''' note : note SYNCOPATE
        '''
        note.syncopate = p[2]








|
|

|
>
|
>
|
|
|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
        '''
        new_note = p[1]
        new_note.duration = p[2]
        p[0] = new_note


    def p_chord(p):
        '''chord : BRACKET note BRACKET
                 | BRACKET note CHORD_TYPE BRACKET
        '''
        root_note = p[2].value
        chorded_notes = []

        for offset in [0, 4, 7]:
            chorded_notes.append(Note(root_note+offset, octave=p[2].octave))

        p[0] = Chord(notes=chorded_notes)


    def p_note_syncopate(p):
        ''' note : note SYNCOPATE
        '''
        note.syncopate = p[2]

Modified spiffyscore.py from [8b19298d3a] to [11e8d97d43].

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

36

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
mymidi = midifile(15)

def main():
    composition = {
        "intro": {
            "body": {
                "percusion": {
                    "channel": 14,
                    "octave": 4,
                    "duration": 60,
                    "grammars": {
                        "u": ["A ^A (u)"]
                    }
                },
                "pan_flute": {
                    "channel": 8,
                    "octave": 5,
                    "duration": 60,

                    "grammars": {  # Notes for this instrument to use in this piece

                        "u": ["C2' B2 | A3 D3 || B | C' | D | C2' C2' | z | (u)", "C2' C2' | C2' C2' | (x)"],
                        "v": ["G2 F2 | E2 F2 | D5 (u)", "B/4 C/4' B/4 A/4 | D2 D2 | z | (u)"],
                        "x": ["z4 | (v)"],
                    },
                },
                "bass": {
                    "channel": 4,
                    "sync": "pan_flute",
                    "octave": 2,
                    "duration": 60,
                    "grammars": {  # Notes for this instrument to use in this piece
                        "u": ["C/2 C/2 C/2 z/2 (u)"],
                    },
                },
                "horn_timbre1": { 
                    "channel": 13,
                    "octave": 2,
                    "duration": 60,
                    "grammars": {  # Notes for this instrument to use in this piece
                        "u": ["C4 D4 (u)"],
                    },
                },
                "horn_timbre2": {  







|










>

>
|
|
|












|







18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
mymidi = midifile(15)

def main():
    composition = {
        "intro": {
            "body": {
                "percusion": {
                    "channel": 14,  # Orchestra kit
                    "octave": 4,
                    "duration": 60,
                    "grammars": {
                        "u": ["A ^A (u)"]
                    }
                },
                "pan_flute": {
                    "channel": 8,
                    "octave": 5,
                    "duration": 60,
                    "vol_offset": -15,
                    "grammars": {  # Notes for this instrument to use in this piece
                        "u": ["[C2'] C2' | [A3] A3 (u)"],
#                        "u": ["[C2'] [B2] | [A3] D3 || B | C' | D | C2' C2' | z | (u)", "C2' C2' | C2' C2' | (x)"],
#                        "v": ["G2 F2 | E2 F2 | D5 (u)", "B/4 C/4' B/4 A/4 | D2 D2 | z | (u)"],
#                        "x": ["z4 | (v)"],
                    },
                },
                "bass": {
                    "channel": 4,
                    "sync": "pan_flute",
                    "octave": 2,
                    "duration": 60,
                    "grammars": {  # Notes for this instrument to use in this piece
                        "u": ["C/2 C/2 C/2 z/2 (u)"],
                    },
                },
                "horn_timbre1": { 
                    "channel": 13,  # 'Atmosphere'
                    "octave": 2,
                    "duration": 60,
                    "grammars": {  # Notes for this instrument to use in this piece
                        "u": ["C4 D4 (u)"],
                    },
                },
                "horn_timbre2": {  
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
                max_time = instr["duration"]
                instr_score, syncs = render_instr(instr, syncs, max_time)
                instrs.append(instr_score)

                volume = 100
                if instr.has_key("vol_offset"):
                    volume += instr["vol_offset"]
                    print "\t\t\tvolume offset = %d, nev volume = %d" % (instr["vol_offset"], volume)
                midify_instr_score(instr_score, track, instr["channel"], subsection_start, volume=volume)
            longest_score = max(instrs, key=lambda i: score_len(i))
            subsection_start += score_len(longest_score)
            section_start += score_len(longest_score)
            track += 1
    with open("out.mid", "wb") as outfile:
        mymidi.writeFile(outfile)







<







142
143
144
145
146
147
148

149
150
151
152
153
154
155
                max_time = instr["duration"]
                instr_score, syncs = render_instr(instr, syncs, max_time)
                instrs.append(instr_score)

                volume = 100
                if instr.has_key("vol_offset"):
                    volume += instr["vol_offset"]

                midify_instr_score(instr_score, track, instr["channel"], subsection_start, volume=volume)
            longest_score = max(instrs, key=lambda i: score_len(i))
            subsection_start += score_len(longest_score)
            section_start += score_len(longest_score)
            track += 1
    with open("out.mid", "wb") as outfile:
        mymidi.writeFile(outfile)
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269


def midify_instr_score(score, track, channel, t, volume):
    # Assume get_midi_note()
    global mymidi

    for token in score:
        if isinstance(token, parse.Chord):  # Chords
            for note in token.chord: 
                note = get_midi_note(token.octave, note)
                mymidi.addNote(track=track, channel=channel,pitch=note, time=t, duration=token.duration, volume=volume)
        elif isinstance(token, parse.Note):  # Individual notes
            note = get_midi_note(token.octave, token.value)
            mymidi.addNote(track=track, channel=channel,pitch=note, time=t, duration=token.duration, volume=volume)
        elif isinstance(token, tree.Tree):
            continue
        t += token.duration

    return []


if __name__ == "__main__": main() 







|
|
|












249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270


def midify_instr_score(score, track, channel, t, volume):
    # Assume get_midi_note()
    global mymidi

    for token in score:
        if isinstance(token, parse.Chord):
            for note in token.notes: 
                note = get_midi_note(note.octave, note.value)
                mymidi.addNote(track=track, channel=channel,pitch=note, time=t, duration=token.duration, volume=volume)
        elif isinstance(token, parse.Note):  # Individual notes
            note = get_midi_note(token.octave, token.value)
            mymidi.addNote(track=track, channel=channel,pitch=note, time=t, duration=token.duration, volume=volume)
        elif isinstance(token, tree.Tree):
            continue
        t += token.duration

    return []


if __name__ == "__main__": main()