spiffyscore
Diff
Not logged in

Differences From Artifact [8ccb7c15cbf62012]:

To Artifact [6468589fdee69e24]:


1 #!/usr/bin/env python 1 #!/usr/bin/env python 2 2 > 3 from __future__ import division > 4 import ipdb 3 import os 5 import os 4 import random 6 import random 5 import sys 7 import sys 6 import time 8 import time > 9 > 10 import parse > 11 import topsort > 12 import yaml > 13 > 14 import tree > 15 7 random.seed(time.time()) 16 random.seed(time.time()) 8 17 9 grammars = { < 10 "u": ["I V I IV u", "e"], < > 18 def main(): > 19 composition = { > 20 "fm_test": { > 21 "intro": { > 22 "melody": { # Instrument 'melody' > 23 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no 11 "e": [""], | 24 "octave": 8, > 25 "duration": 10, > 26 "grammars": { # Notes for this instrument to use in this pi > 27 "u": ["G/2 G/2 | G/4 G/4 A/4 A/4 | A/2 A/2 | G | G | A | > 28 "w": ["E | E | F | F | G/2 G/2 | G3 (u)"], 12 } | 29 }, > 30 }, > 31 }, > 32 }, > 33 "verse1": { > 34 "intro": { > 35 "melody": { # Instrument 'melody' > 36 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no > 37 "octave": 8, > 38 "duration": 10, > 39 "grammars": { # Notes for this instrument to use in this pi > 40 "u": ["G/2 G/2 | G/4 G/4 A/4 A/4 | A/2 A/2 | G | G | A | > 41 "w": ["E | E | F | F | G/2 G/2 | G3 (u)"], > 42 }, > 43 }, > 44 }, > 45 "body": { > 46 "melody": { # Instrument 'melody' > 47 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no > 48 "octave": 8, > 49 "duration": 10, > 50 "grammars": { # Notes for this instrument to use in this pi > 51 "u": ["C | G/2 G/2 | G/2 G/2 | C | B, | F' | C | F | C | > 52 "w": ["E/4 A/4 D/4 G/4 | F/4 F/4 B2 | (u)"], > 53 }, > 54 }, > 55 }, > 56 "outro": { > 57 "melody": { # Instrument 'melody' > 58 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no > 59 "octave": 8, > 60 "duration": 10, > 61 "grammars": { # Notes for this instrument to use in this pi > 62 "u": ["C/4 C/4 C/4 C/4 | z2"], > 63 }, > 64 }, > 65 }, > 66 }, > 67 "verse2": { > 68 "body": { > 69 "melody": { # Instrument 'melody' > 70 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no > 71 "octave": 8, > 72 "duration": 30, > 73 "grammars": { # Notes for this instrument to use in this pi > 74 "u": ["C | C | C | C | F/2 F/2 | F/2 F/2 | (u)", "D | D > 75 }, > 76 }, > 77 "harmony": { # Instrument 'melody' > 78 "score_line": "i3 %(time)f %(duration)f 4000 %(octave)d.%(no > 79 "octave": 8, > 80 "duration": 30, > 81 "grammars": { # Notes for this instrument to use in this pi > 82 "u": ["C | C | z | C | C | z/2 F/4 F/2 F/2 | F/2 F/2 | z > 83 }, > 84 }, > 85 "percussion": { # Instrument 'melody' > 86 "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(no > 87 "octave": 8, > 88 "duration": 30, > 89 "grammars": { # Notes for this instrument to use in this pi > 90 "u": ["C/4 C/4 C/4 C/4 | F/2 F/2 | F/2 F/2 | (u)", "D/4 > 91 "v": ["C | D | E | F | E | D | C | (u)",], > 92 }, > 93 }, > 94 }, > 95 "outro": { > 96 "percussion": { # Instrument 'melody' > 97 "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(no > 98 "octave": 8, > 99 "duration": 30, > 100 "grammars": { # Notes for this instrument to use in this pi > 101 "u": ["C/4 C/4 C/4 C/4"], > 102 }, > 103 }, > 104 }, > 105 }, > 106 "sync_test": { > 107 "body": { > 108 "lead_instr": { # Instrument 'melody' > 109 "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(no > 110 "octave": 8, > 111 "duration": 30, > 112 "grammars": { # Notes for this instrument to use in this pi > 113 "u": ["D/4 D/4 D/4 D/4"], > 114 "v": ["C/4 C/4 C/4 C/4"], > 115 }, > 116 }, > 117 "follow_instr": { # Instrument 'melody' > 118 "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(no > 119 "sync": "lead_instr", > 120 "octave": 8, > 121 "duration": 30, > 122 "grammars": { # Notes for this instrument to use in this pi > 123 "u": ["D/4 D/4 D/4 D/4"], > 124 "v": ["C/4 C/4 C/4 C/4"], > 125 }, > 126 }, > 127 }, > 128 }, 13 | 129 } 14 score = "u" < > 130 print '''f1 0 512 10 1 > 131 f2 0 8192 10 .24 .64 .88 .76 .06 .5 .34 .08 > 132 f3 0 1025 10 1 > 133 t 0 100 > 134 ''' 15 135 > 136 section_start = 0 > 137 # for section in ["verse1", "verse2"]: > 138 for section in ["sync_test"]: > 139 print "; Section " + section > 140 subsection_start = section_start > 141 section = composition[section] > 142 for subsection in ["intro", "body", "outro"]: > 143 try: > 144 print "; Subsection " + subsection > 145 subsection = section[subsection] > 146 > 147 unordered_instrs = [] > 148 for instr in subsection: > 149 subsection[instr]["name"] = instr > 150 if not "sync" in subsection[instr].keys(): > 151 subsection[instr]["sync"] = None > 152 unordered_instrs.append([subsection[instr]["sync"], instr]) > 153 ordered_instrs = topsort.topsort(unordered_instrs) > 154 ordered_instrs.remove(None) # None used as a placeholder for so > 155 > 156 instrs = [] > 157 syncs = {} > 158 for instr in ordered_instrs: > 159 print ";Instrument " + instr > 160 instr = subsection[instr] > 161 max_time = instr["duration"] > 162 instr_score, syncs = render_instr(instr, syncs, max_time) > 163 instrs.append(instr_score) > 164 for line in generate_csound_score(instr_score, instr["score_ 16 print score | 165 print line > 166 longest_score = max(instrs, key=lambda i: score_len(i)) > 167 subsection_start += score_len(longest_score) > 168 section_start += score_len(longest_score) > 169 except KeyError: > 170 pass > 171 > 172 > 173 def render_instr(instr, syncs, max_time): > 174 for g in instr["grammars"]: > 175 for i in range(len(instr["grammars"][g])): > 176 instr["grammars"][g][i] = parse.parse(instr["grammars"][g][i]) > 177 > 178 score= [] > 179 try: > 180 score, syncs = choose_phrase(instr, syncs, 0, max_time) > 181 17 while 1: | 182 while True: 18 found_substitution = False < > 183 score_index_to_replace = None > 184 for item in range(len(score)): # Optimize this by caching the index > 185 if isinstance(score[item], tree.Tree): > 186 score_index_to_replace = item > 187 if score_index_to_replace is None: > 188 raise ValueError("No more nodes to fill in") > 189 > 190 time_remaining = max_time - score_len(score) > 191 new_phrase, syncs = choose_phrase(instr, syncs, score_len(score), ti > 192 score = score[:node_index-1] + new_phrase + score[node_index+1:] > 193 > 194 except ValueError: > 195 return (score, syncs) > 196 > 197 > 198 def choose_phrase(instr, syncs, current_time, time_remaining): > 199 '''Filters grammars for ones that match the sync option, and phrases that fi > 200 time_filtered_grammars = {} > 201 for grammar in instr["grammars"]: > 202 time_filtered_grammars[grammar] = get_phrases_that_fit(instr["grammars"] > 203 if len(time_filtered_grammars.keys()) == 0: > 204 raise ValueError("No available grammars that will fit in the score") > 205 > 206 grammar = None > 207 # if instr["name"] == "follow_instr": > 208 # ipdb.set_trace() > 209 if instr["sync"] is not None: > 210 guiding_instr = instr["sync"] > 211 sync_node = get_sync_node_at_time(syncs[guiding_instr], current_time) > 212 if sync_node in time_filtered_grammars.keys(): > 213 grammar = sync_node > 214 if grammar is None: > 215 grammar = random.choice(time_filtered_grammars.keys()) > 216 phrases = time_filtered_grammars[grammar] > 217 if instr["name"] not in syncs.keys(): > 218 syncs[instr["name"]] = [] > 219 syncs[instr["name"]].append({"node": grammar, "time": current_time}) > 220 > 221 return random.choice(phrases), syncs > 222 > 223 > 224 def get_phrases_that_fit(grammar, time_remaining): > 225 valid_phrases = [] 19 for key,value in grammars.iteritems(): | 226 for phrase in grammar: 20 print "key, value =", key, value < 21 if score.find(key) != -1: < 22 print "here" < 23 found_substitution = True < 24 while score.find(key) != -1: < 25 score = score.replace(key, random.choice(grammars[key]), 1) < > 227 if score_len(phrase) <= time_remaining: > 228 valid_phrases.append(phrase) > 229 return valid_phrases > 230 > 231 > 232 def get_sync_node_at_time(syncs, t): > 233 for s in range(len(syncs)): > 234 if syncs[s]["time"] >= t: > 235 return syncs[s]["node"] > 236 > 237 > 238 def score_len(score): > 239 total = 0 26 print score | 240 for n in score: 27 time.sleep(.25) < 28 if found_substitution is False: < 29 break < > 241 if not isinstance(n, tree.Tree): > 242 total += n.duration > 243 return total > 244 > 245 > 246 def generate_csound_score(score, score_line, t): > 247 csound_note_values = { > 248 "C": "00", > 249 "C#": "01", > 250 "D": "02", > 251 "D#": "03", > 252 "E": "04", > 253 "F": "05", > 254 "F#": "06", > 255 "G": "07", > 256 "G#": "08", > 257 "A": "09", > 258 "A#": "10", > 259 "B": "11", > 260 } > 261 csound_score = [] 30 print score | 262 for token in score: > 263 if isinstance(token, parse.Chord): # Chords > 264 for note in token.chord: > 265 note = csound_note_values[note] > 266 csound_score.append(score_line % {"time": t, "octave": token.oct > 267 elif isinstance(token, parse.Note): # Individual notes > 268 note = csound_note_values[token.value] > 269 csound_score.append(score_line % {"time": t, "octave": token.octave, > 270 elif isinstance(token, tree.Tree): > 271 continue > 272 t += token.duration > 273 return csound_score > 274 > 275 > 276 if __name__ == "__main__": main()