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 Side-by-Side Diffs Ignore Whitespace 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
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
        self.value = value
        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, value, duration=1, chord_type="major", octave=5):
        self.value = value
    def __init__(self, notes, duration=1):
        self.notes = notes
        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)
        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",
        "PAREN",
        "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_PAREN = "\[|\]"
    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
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 : PAREN note PAREN
                 | PAREN note CHORD_TYPE PAREN
        '''chord : BRACKET note BRACKET
                 | BRACKET note CHORD_TYPE BRACKET
        '''
        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]
        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
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,
                    "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)"],
#                        "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,
                    "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
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"]
                    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)
248
249
250
251
252
253
254
255
256
257



258
259
260
261
262
263
264
265
266
267
268
269
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):  # Chords
            for note in token.chord: 
                note = get_midi_note(token.octave, note)
        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()