Differences From Artifact [87c5508f415d5e6f]:
- Executable file
spiffyscore.py
- 2011-11-17 19:55:50 - part of checkin [f8034c7dfb] on branch develop - Removed leftover csound function lines that got printed. Also disabled ipdb so I get concise stacktraces. Also made program crash when your score pointed to a non-existant node. Previously that just generated an invalid MIDI file (somehow...) (user: brian) [annotate]
To Artifact [58892e1cd4aafbfb]:
- Executable file
spiffyscore.py
- 2011-11-27 02:03:54 - part of checkin [821ac3e4d6] on branch develop - Added a volume offset parameter to each instrument. Fixed a bug that kept instruments from always being rendered, and one that broke midi files. (user: brian) [annotate]
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 from __future__ import division 3 from __future__ import division
4 #import ipdb | 4 import ipdb
5 import os 5 import os
6 import random 6 import random
7 import sys 7 import sys
8 import time 8 import time
9 9
10 from midiutil.MidiFile import MIDIFile as midifile 10 from midiutil.MidiFile import MIDIFile as midifile
11 import parse 11 import parse
................................................................................................................................................................................
17 random.seed(time.time()) 17 random.seed(time.time())
18 mymidi = midifile(15) 18 mymidi = midifile(15)
19 19
20 def main(): 20 def main():
21 composition = { 21 composition = {
22 "intro": { 22 "intro": {
23 "body": { 23 "body": {
24 "lead_instr": { # Instrument 'melody' | 24 "pan_flute": { # Instrument 'melody'
25 "channel": 8, 25 "channel": 8,
26 "octave": 5, 26 "octave": 5,
27 "duration": 60, 27 "duration": 60,
28 "grammars": { # Notes for this instrument to use in this pi 28 "grammars": { # Notes for this instrument to use in this pi
29 "u": ["C2' B2 A3 D3 B C' D C2' z (u)", "C2' C2' C2' C2' | 29 "u": ["C2' B2 | A3 D3 || B | C' | D | C2' C2' | z | (u)"
30 "v": ["G2 F2 E2 F2 D5 (u)", "B/4 C/4' B/4 A/4 D2 z"], | 30 "v": ["G2 F2 | E2 F2 | D5 (u)", "B/4 C/4' B/4 A/4 | D2 D
31 "x": ["z4 (v)"], | 31 "x": ["z4 | (v)"],
32 }, 32 },
33 }, 33 },
34 "follow_instr": { # Instrument 'bass' | 34 "bass": {
35 "channel": 4, 35 "channel": 4,
36 "sync": "lead_instr", | 36 "sync": "pan_flute",
37 "octave": 2, 37 "octave": 2,
38 "duration": 60, 38 "duration": 60,
39 "grammars": { # Notes for this instrument to use in this pi 39 "grammars": { # Notes for this instrument to use in this pi
40 "u": ["C/2 C/2 C/2 z/2 (u)"], 40 "u": ["C/2 C/2 C/2 z/2 (u)"],
41 }, 41 },
42 }, 42 },
> 43 "horn_timbre1": {
> 44 "channel": 13,
> 45 "octave": 2,
> 46 "duration": 60,
> 47 "grammars": { # Notes for this instrument to use in this pi
> 48 "u": ["C4 D4 (u)"],
> 49 },
> 50 },
> 51 "horn_timbre2": {
> 52 "channel": 13,
> 53 "octave": 2,
> 54 "duration": 60,
> 55 "grammars": { # Notes for this instrument to use in this pi
> 56 "u": ["G4 A4 (u)"],
> 57 },
> 58 },
43 }, 59 },
44 }, 60 },
45 "section1": { 61 "section1": {
46 "body": { 62 "body": {
47 "lead_instr": { # Instrument 'melody' | 63 "guitar": { # Instrument 'melody'
48 "channel": 6, 64 "channel": 6,
49 "octave": 5, 65 "octave": 5,
50 "duration": 60, 66 "duration": 60,
51 "grammars": { # Notes for this instrument to use in this pi 67 "grammars": { # Notes for this instrument to use in this pi
52 "u": ["C E A F G z (u)", "C E A F G z (v)"], | 68 "u": ["C | E | A | F | G | z | (u)", "C | E | A | F | G
53 "v": ["A/2 D/2 G/2 C/2 | F/2 B/2 E/2 z/2 | (u)"], | 69 "v": ["A/2 D/2 | G/2 C/2 | F/2 B/2 | E/2 | z/2 | (u)"],
54 }, 70 },
55 }, 71 },
56 "follow_instr": { # Instrument 'bass' | 72 "bass": { # Instrument 'bass'
57 "channel": 4, 73 "channel": 4,
58 "sync": "lead_instr", | 74 "sync": "guitar",
> 75 "octave": 2,
> 76 "duration": 60,
> 77 "grammars": { # Notes for this instrument to use in this pi
> 78 "u": ["C/2 C/2 | C/2 z/2 | (u)"],
> 79 },
> 80 },
> 81 "horn_timbre1": {
> 82 "channel": 13,
> 83 "octave": 2,
> 84 "duration": 60,
> 85 "grammars": { # Notes for this instrument to use in this pi
> 86 "u": ["C4 D4 (u)"],
> 87 },
> 88 },
> 89 "horn_timbre2": {
> 90 "channel": 13,
59 "octave": 2, 91 "octave": 2,
60 "duration": 60, 92 "duration": 60,
61 "grammars": { # Notes for this instrument to use in this pi 93 "grammars": { # Notes for this instrument to use in this pi
62 "u": ["C/2 C/2 C/2 z/2 (u)"], | 94 "u": ["G4 A4 (u)"],
63 }, 95 },
64 }, 96 },
65 }, 97 },
66 }, 98 },
67 } 99 }
68 100
69 section_start = 0 101 section_start = 0
70 for section in ["intro", "section1"]: | 102 for section_name in ["intro", "section1"]:
71 print "Section " + section | 103 print "Section " + section_name
72 subsection_start = section_start 104 subsection_start = section_start
73 section = composition[section] | 105 section = composition[section_name]
74 for subsection in ["intro", "body", "outro"]: 106 for subsection in ["intro", "body", "outro"]:
75 try: | 107 if not section.has_key(subsection):
> 108 continue
76 print "Subsection " + subsection | 109 print "\tSubsection " + subsection
77 subsection = section[subsection] | 110 subsection = section[subsection]
78 111
79 unordered_instrs = [] | 112 unordered_instrs = []
80 for instr in subsection: | 113 for instr in subsection:
81 subsection[instr]["name"] = instr | 114 subsection[instr]["name"] = instr
82 if not "sync" in subsection[instr].keys(): | 115 if not "sync" in subsection[instr].keys():
83 subsection[instr]["sync"] = None | 116 subsection[instr]["sync"] = None
84 unordered_instrs.append([subsection[instr]["sync"], instr]) | 117 unordered_instrs.append([subsection[instr]["sync"], instr])
85 ordered_instrs = topsort.topsort(unordered_instrs) | 118 ordered_instrs = topsort.topsort(unordered_instrs)
86 ordered_instrs.remove(None) # None used as a placeholder for so | 119 ordered_instrs.remove(None) # None used as a placeholder for sort o
> 120 for sync_instr in ordered_instrs:
> 121 if sync_instr not in subsection.keys():
> 122 raise KeyError("The sync instrument '%s' does not exist in t
87 123
88 instrs = [] | 124 instrs = []
89 syncs = {} | 125 syncs = {}
90 track = 0 | 126 track = 0
91 for instr in ordered_instrs: | 127 for instr in ordered_instrs:
92 print "Instrument " + instr | 128 print "\t\tInstrument " + instr
> 129 # if instr == "guitar":
> 130 # ipdb.set_trace()
93 instr = subsection[instr] | 131 instr = subsection[instr]
94 max_time = instr["duration"] | 132 max_time = instr["duration"]
95 instr_score, syncs = render_instr(instr, syncs, max_time) | 133 instr_score, syncs = render_instr(instr, syncs, max_time)
96 instrs.append(instr_score) | 134 instrs.append(instr_score)
> 135
> 136 volume = 100
> 137 if instr.has_key("vol_offset"):
> 138 volume += instr["vol_offset"]
> 139 print "\t\t\tvolume offset = %d, nev volume = %d" % (instr["
97 midify_instr_score(instr_score, track, instr["channel"], sub | 140 midify_instr_score(instr_score, track, instr["channel"], subsect
98 longest_score = max(instrs, key=lambda i: score_len(i)) | 141 longest_score = max(instrs, key=lambda i: score_len(i))
99 subsection_start += score_len(longest_score) | 142 subsection_start += score_len(longest_score)
100 section_start += score_len(longest_score) | 143 section_start += score_len(longest_score)
101 track += 1 | 144 track += 1
102 except KeyError: <
103 pass <
104 with open("out.mid", "wb") as outfile: 145 with open("out.mid", "wb") as outfile:
105 mymidi.writeFile(outfile) 146 mymidi.writeFile(outfile)
106 147
107 148
108 149
109 def render_instr(instr, syncs, max_time): 150 def render_instr(instr, syncs, max_time):
110 for g in instr["grammars"]: 151 for g in instr["grammars"]:
................................................................................................................................................................................
151 grammar = random.choice(time_filtered_grammars.keys()) 192 grammar = random.choice(time_filtered_grammars.keys())
152 if score is None: 193 if score is None:
153 grammar = random.choice(time_filtered_grammars.keys()) 194 grammar = random.choice(time_filtered_grammars.keys())
154 elif instr["sync"] is None: 195 elif instr["sync"] is None:
155 grammar = get_next_node(score); 196 grammar = get_next_node(score);
156 if grammar not in instr["grammars"].keys(): 197 if grammar not in instr["grammars"].keys():
157 raise Exception("You tried to direct a grammar to a node that doesn' 198 raise Exception("You tried to direct a grammar to a node that doesn'
> 199
> 200 if grammar not in time_filtered_grammars.keys():
> 201 return [], syncs
> 202
158 phrases = time_filtered_grammars[grammar] 203 phrases = time_filtered_grammars[grammar]
159 if instr["name"] not in syncs.keys(): 204 if instr["name"] not in syncs.keys():
160 syncs[instr["name"]] = [] 205 syncs[instr["name"]] = []
161 syncs[instr["name"]].append({"node": grammar, "time": current_time}) 206 syncs[instr["name"]].append({"node": grammar, "time": current_time})
162 207
163 return random.choice(phrases), syncs 208 return random.choice(phrases), syncs
164 209
................................................................................................................................................................................
190 return total 235 return total
191 236
192 237
193 def get_midi_note(octave, note): 238 def get_midi_note(octave, note):
194 return note + 12 * (octave+1) 239 return note + 12 * (octave+1)
195 240
196 241
197 def midify_instr_score(score, track, channel, t): | 242 def midify_instr_score(score, track, channel, t, volume):
198 # Assume get_midi_note() 243 # Assume get_midi_note()
199 global mymidi 244 global mymidi
200 245
201 for token in score: 246 for token in score:
202 if isinstance(token, parse.Chord): # Chords 247 if isinstance(token, parse.Chord): # Chords
203 for note in token.chord: 248 for note in token.chord:
204 note = get_midi_note(token.octave, note) 249 note = get_midi_note(token.octave, note)
205 mymidi.addNote(track=track, channel=channel,pitch=note, time=t, | 250 mymidi.addNote(track=track, channel=channel,pitch=note, time=t,
206 elif isinstance(token, parse.Note): # Individual notes 251 elif isinstance(token, parse.Note): # Individual notes
207 note = get_midi_note(token.octave, token.value) 252 note = get_midi_note(token.octave, token.value)
208 mymidi.addNote(track=track, channel=channel,pitch=note, time=t, dura | 253 mymidi.addNote(track=track, channel=channel,pitch=note, time=t, dura
209 elif isinstance(token, tree.Tree): 254 elif isinstance(token, tree.Tree):
210 continue 255 continue
211 t += token.duration 256 t += token.duration
212 257
213 return [] 258 return []
214 259
215 260
216 if __name__ == "__main__": main() 261 if __name__ == "__main__": main()