6bfc2449ff 2010-11-04 spiffytech@gm: #!/usr/bin/env python 6bfc2449ff 2010-11-04 spiffytech@gm: 5a35ffdd27 2010-11-17 spiffytech@gm: from __future__ import division 42c3ba150c 2011-10-18 brian: import ipdb 4f5bc3936f 2011-10-20 brian: import os 6bfc2449ff 2010-11-04 spiffytech@gm: import random 6bfc2449ff 2010-11-04 spiffytech@gm: import sys 6bfc2449ff 2010-11-04 spiffytech@gm: import time 689adc054e 2011-02-10 brian@linux-8: 9bd31df856 2010-11-16 spiffytech@gm: import parse 689adc054e 2011-02-10 brian@linux-8: import topsort 689adc054e 2011-02-10 brian@linux-8: import yaml 689adc054e 2011-02-10 brian@linux-8: 192b8b1639 2011-10-11 brian: import tree 192b8b1639 2011-10-11 brian: 192b8b1639 2011-10-11 brian: random.seed(time.time()) 192b8b1639 2011-10-11 brian: 6a17d4d36a 2010-11-12 spiffytech@gm: def main(): 192b8b1639 2011-10-11 brian: composition = { 192b8b1639 2011-10-11 brian: "fm_test": { 192b8b1639 2011-10-11 brian: "intro": { 192b8b1639 2011-10-11 brian: "melody": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(note)s 2 6 5 1", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 10, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["G/2 G/2 | G/4 G/4 A/4 A/4 | A/2 A/2 | G | G | A | A | A3 (w)"], 192b8b1639 2011-10-11 brian: "w": ["E | E | F | F | G/2 G/2 | G3 (u)"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "verse1": { 192b8b1639 2011-10-11 brian: "intro": { 192b8b1639 2011-10-11 brian: "melody": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(note)s 1", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 10, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["G/2 G/2 | G/4 G/4 A/4 A/4 | A/2 A/2 | G | G | A | A | A3 (w)"], 192b8b1639 2011-10-11 brian: "w": ["E | E | F | F | G/2 G/2 | G3 (u)"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "body": { 192b8b1639 2011-10-11 brian: "melody": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(note)s 1", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 10, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C | G/2 G/2 | G/2 G/2 | C | B, | F' | C | F | C | B | F | (w)"], 192b8b1639 2011-10-11 brian: "w": ["E/4 A/4 D/4 G/4 | F/4 F/4 B2 | (u)"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "outro": { 192b8b1639 2011-10-11 brian: "melody": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(note)s 1", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 10, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C/4 C/4 C/4 C/4 | z2"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "verse2": { 192b8b1639 2011-10-11 brian: "body": { 192b8b1639 2011-10-11 brian: "melody": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i2 %(time)f %(duration)f 7000 %(octave)d.%(note)s 1", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 30, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C | C | C | C | F/2 F/2 | F/2 F/2 | (u)", "D | D | G/2 A/2 | D | D | (u)"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "harmony": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i3 %(time)f %(duration)f 4000 %(octave)d.%(note)s 2 3 5 3", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 30, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C | C | z | C | C | z/2 F/4 F/2 F/2 | F/2 F/2 | z (u)", "D | D | G/2 A/2 | D | D | z (u)"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "percussion": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(note)s %(octave)d.%(note)s 0 6", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 30, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C/4 C/4 C/4 C/4 | F/2 F/2 | F/2 F/2 | (u)", "D/4 D/4 G/4 A/4 | D | D | (v)"], 192b8b1639 2011-10-11 brian: "v": ["C | D | E | F | E | D | C | (u)",], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: "outro": { 192b8b1639 2011-10-11 brian: "percussion": { # Instrument 'melody' 192b8b1639 2011-10-11 brian: "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(note)s %(octave)d.%(note)s 0 6", 192b8b1639 2011-10-11 brian: "octave": 8, 192b8b1639 2011-10-11 brian: "duration": 30, 192b8b1639 2011-10-11 brian: "grammars": { # Notes for this instrument to use in this piece 192b8b1639 2011-10-11 brian: "u": ["C/4 C/4 C/4 C/4"], 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 192b8b1639 2011-10-11 brian: }, 42c3ba150c 2011-10-18 brian: "sync_test": { 42c3ba150c 2011-10-18 brian: "body": { c9abf46a9f 2011-11-01 brian: # "lead_instr": { # Instrument 'melody' c9abf46a9f 2011-11-01 brian: # "score_line": "i1 %(time)f %(duration)f 7000 %(octave)d.%(note)s %(octave)d.%(note)s 0 6", c9abf46a9f 2011-11-01 brian: # "octave": 8, c9abf46a9f 2011-11-01 brian: # "duration": 30, c9abf46a9f 2011-11-01 brian: # "grammars": { # Notes for this instrument to use in this piece c9abf46a9f 2011-11-01 brian: # "u": ["A/4, B/4, C/4 D/4 (u)", "D/4' D/4' D/4' D/4' (v)"], c9abf46a9f 2011-11-01 brian: # "v": ["C/4 C/4 C/4 C/4 (w)"], c9abf46a9f 2011-11-01 brian: # "w": ["E/4 F/4 E/4 F/4 (u)"], c9abf46a9f 2011-11-01 brian: # }, c9abf46a9f 2011-11-01 brian: # }, 42c3ba150c 2011-10-18 brian: "follow_instr": { # Instrument 'melody' eb81d5f9fd 2011-11-01 brian: "score_line": "i3 %(time)f %(duration)f 7000 %(octave)d.%(note)s", eb81d5f9fd 2011-11-01 brian: # "sync": "lead_instr", eb81d5f9fd 2011-11-01 brian: "octave": 2, 42c3ba150c 2011-10-18 brian: "duration": 30, 42c3ba150c 2011-10-18 brian: "grammars": { # Notes for this instrument to use in this piece b5a8b20242 2011-11-03 brian: "u": ["A ^A B C ^C D ^D E F ^F G ^G"], b5a8b20242 2011-11-03 brian: # "u": ["E F G E (v)"], b5a8b20242 2011-11-03 brian: # "v": ["G A A A (e)", "G A A A (v)"], b5a8b20242 2011-11-03 brian: # "e": ["B A G A (v)"], 42c3ba150c 2011-10-18 brian: }, 42c3ba150c 2011-10-18 brian: }, 42c3ba150c 2011-10-18 brian: }, 42c3ba150c 2011-10-18 brian: }, 702d933446 2011-02-10 brian@linux-8: } 192b8b1639 2011-10-11 brian: print '''f1 0 512 10 1 192b8b1639 2011-10-11 brian: f2 0 8192 10 .24 .64 .88 .76 .06 .5 .34 .08 192b8b1639 2011-10-11 brian: f3 0 1025 10 1 192b8b1639 2011-10-11 brian: t 0 100 192b8b1639 2011-10-11 brian: ''' 192b8b1639 2011-10-11 brian: 192b8b1639 2011-10-11 brian: section_start = 0 192b8b1639 2011-10-11 brian: # for section in ["verse1", "verse2"]: 42c3ba150c 2011-10-18 brian: for section in ["sync_test"]: 192b8b1639 2011-10-11 brian: print "; Section " + section 192b8b1639 2011-10-11 brian: subsection_start = section_start 192b8b1639 2011-10-11 brian: section = composition[section] 192b8b1639 2011-10-11 brian: for subsection in ["intro", "body", "outro"]: 192b8b1639 2011-10-11 brian: try: 192b8b1639 2011-10-11 brian: print "; Subsection " + subsection 192b8b1639 2011-10-11 brian: subsection = section[subsection] 42c3ba150c 2011-10-18 brian: fde4a012ea 2011-10-13 brian: unordered_instrs = [] 192b8b1639 2011-10-11 brian: for instr in subsection: 4f5bc3936f 2011-10-20 brian: subsection[instr]["name"] = instr 42c3ba150c 2011-10-18 brian: if not "sync" in subsection[instr].keys(): fde4a012ea 2011-10-13 brian: subsection[instr]["sync"] = None fde4a012ea 2011-10-13 brian: unordered_instrs.append([subsection[instr]["sync"], instr]) fde4a012ea 2011-10-13 brian: ordered_instrs = topsort.topsort(unordered_instrs) 42c3ba150c 2011-10-18 brian: ordered_instrs.remove(None) # None used as a placeholder for sort order for instruments with no sync setting 42c3ba150c 2011-10-18 brian: fde4a012ea 2011-10-13 brian: instrs = [] 42c3ba150c 2011-10-18 brian: syncs = {} fde4a012ea 2011-10-13 brian: for instr in ordered_instrs: 192b8b1639 2011-10-11 brian: print ";Instrument " + instr 192b8b1639 2011-10-11 brian: instr = subsection[instr] 192b8b1639 2011-10-11 brian: max_time = instr["duration"] 42c3ba150c 2011-10-18 brian: instr_score, syncs = render_instr(instr, syncs, max_time) 192b8b1639 2011-10-11 brian: instrs.append(instr_score) 192b8b1639 2011-10-11 brian: for line in generate_csound_score(instr_score, instr["score_line"], subsection_start): 192b8b1639 2011-10-11 brian: print line 192b8b1639 2011-10-11 brian: longest_score = max(instrs, key=lambda i: score_len(i)) 192b8b1639 2011-10-11 brian: subsection_start += score_len(longest_score) 192b8b1639 2011-10-11 brian: section_start += score_len(longest_score) 192b8b1639 2011-10-11 brian: except KeyError: 192b8b1639 2011-10-11 brian: pass 192b8b1639 2011-10-11 brian: 192b8b1639 2011-10-11 brian: 42c3ba150c 2011-10-18 brian: def render_instr(instr, syncs, max_time): 192b8b1639 2011-10-11 brian: for g in instr["grammars"]: 42c3ba150c 2011-10-18 brian: for i in range(len(instr["grammars"][g])): eb81d5f9fd 2011-11-01 brian: instr["grammars"][g][i] = parse.parse(instr["grammars"][g][i], default_octave=instr["octave"]) 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: score= [] 4f5bc3936f 2011-10-20 brian: try: a9e60898b7 2011-10-20 brian: score, syncs = choose_phrase(instr, syncs, 0, max_time, None) 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: while True: 4f5bc3936f 2011-10-20 brian: score_index_to_replace = None 4f5bc3936f 2011-10-20 brian: for item in range(len(score)): # Optimize this by caching the index of the last node I replaced and startng there a9e60898b7 2011-10-20 brian: if isinstance(score[item], tree.Tree): # Also, make this use the find_next_node() function (or whatever I called it) 4f5bc3936f 2011-10-20 brian: score_index_to_replace = item 4f5bc3936f 2011-10-20 brian: if score_index_to_replace is None: 4f5bc3936f 2011-10-20 brian: raise ValueError("No more nodes to fill in") 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: time_remaining = max_time - score_len(score) a9e60898b7 2011-10-20 brian: new_phrase, syncs = choose_phrase(instr, syncs, score_len(score), time_remaining, score) 2ae36c6e68 2011-10-20 brian: score = score[:score_index_to_replace] + new_phrase + score[score_index_to_replace+1:] 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: except ValueError: 4f5bc3936f 2011-10-20 brian: return (score, syncs) 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: a9e60898b7 2011-10-20 brian: def choose_phrase(instr, syncs, current_time, time_remaining, score): 4f5bc3936f 2011-10-20 brian: '''Filters grammars for ones that match the sync option, and phrases that fit the time remaining in the score''' 4f5bc3936f 2011-10-20 brian: time_filtered_grammars = {} 4f5bc3936f 2011-10-20 brian: for grammar in instr["grammars"]: 601339a475 2011-10-20 brian: fitting_phrases = get_phrases_that_fit(instr["grammars"][grammar], time_remaining) 601339a475 2011-10-20 brian: if len(fitting_phrases) > 0: 601339a475 2011-10-20 brian: time_filtered_grammars[grammar] = fitting_phrases 4f5bc3936f 2011-10-20 brian: if len(time_filtered_grammars.keys()) == 0: 4f5bc3936f 2011-10-20 brian: raise ValueError("No available grammars that will fit in the score") 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: grammar = None 42c3ba150c 2011-10-18 brian: if instr["sync"] is not None: 42c3ba150c 2011-10-18 brian: guiding_instr = instr["sync"] 42c3ba150c 2011-10-18 brian: sync_node = get_sync_node_at_time(syncs[guiding_instr], current_time) 4f5bc3936f 2011-10-20 brian: if sync_node in time_filtered_grammars.keys(): 4f5bc3936f 2011-10-20 brian: grammar = sync_node a9e60898b7 2011-10-20 brian: else: a9e60898b7 2011-10-20 brian: grammar = random.choice(time_filtered_grammars.keys()) a9e60898b7 2011-10-20 brian: if score is None: 4f5bc3936f 2011-10-20 brian: grammar = random.choice(time_filtered_grammars.keys()) a9e60898b7 2011-10-20 brian: elif instr["sync"] is None: a9e60898b7 2011-10-20 brian: grammar = get_next_node(score); 4f5bc3936f 2011-10-20 brian: phrases = time_filtered_grammars[grammar] 4f5bc3936f 2011-10-20 brian: if instr["name"] not in syncs.keys(): 4f5bc3936f 2011-10-20 brian: syncs[instr["name"]] = [] 4f5bc3936f 2011-10-20 brian: syncs[instr["name"]].append({"node": grammar, "time": current_time}) 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: return random.choice(phrases), syncs 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: 4f5bc3936f 2011-10-20 brian: def get_phrases_that_fit(grammar, time_remaining): 4f5bc3936f 2011-10-20 brian: valid_phrases = [] 4f5bc3936f 2011-10-20 brian: for phrase in grammar: 4f5bc3936f 2011-10-20 brian: if score_len(phrase) <= time_remaining: 4f5bc3936f 2011-10-20 brian: valid_phrases.append(phrase) 4f5bc3936f 2011-10-20 brian: return valid_phrases 42c3ba150c 2011-10-18 brian: 42c3ba150c 2011-10-18 brian: 42c3ba150c 2011-10-18 brian: def get_sync_node_at_time(syncs, t): 4f5bc3936f 2011-10-20 brian: for s in range(len(syncs)): 4f5bc3936f 2011-10-20 brian: if syncs[s]["time"] >= t: 42c3ba150c 2011-10-18 brian: return syncs[s]["node"] 4f5bc3936f 2011-10-20 brian: a9e60898b7 2011-10-20 brian: def get_next_node(score): a9e60898b7 2011-10-20 brian: for token in score: a9e60898b7 2011-10-20 brian: if isinstance(token, tree.Tree): a9e60898b7 2011-10-20 brian: return token.name a9e60898b7 2011-10-20 brian: 192b8b1639 2011-10-11 brian: 192b8b1639 2011-10-11 brian: def score_len(score): 192b8b1639 2011-10-11 brian: total = 0 192b8b1639 2011-10-11 brian: for n in score: 192b8b1639 2011-10-11 brian: if not isinstance(n, tree.Tree): 192b8b1639 2011-10-11 brian: total += n.duration 192b8b1639 2011-10-11 brian: return total 702d933446 2011-02-10 brian@linux-8: 702d933446 2011-02-10 brian@linux-8: 192b8b1639 2011-10-11 brian: def generate_csound_score(score, score_line, t): 702d933446 2011-02-10 brian@linux-8: csound_note_values = { 702d933446 2011-02-10 brian@linux-8: "C": "00", b5a8b20242 2011-11-03 brian: "C#": "01", "Db": "01", 702d933446 2011-02-10 brian@linux-8: "D": "02", b5a8b20242 2011-11-03 brian: "D#": "03", "Eb": "03", 702d933446 2011-02-10 brian@linux-8: "E": "04", 702d933446 2011-02-10 brian@linux-8: "F": "05", b5a8b20242 2011-11-03 brian: "F#": "06", "Gb": "06", 702d933446 2011-02-10 brian@linux-8: "G": "07", b5a8b20242 2011-11-03 brian: "G#": "08", "Ab": "08", 702d933446 2011-02-10 brian@linux-8: "A": "09", b5a8b20242 2011-11-03 brian: "A#": "10", "Bb": "10", 702d933446 2011-02-10 brian@linux-8: "B": "11", 6a17d4d36a 2010-11-12 spiffytech@gm: } 6a17d4d36a 2010-11-12 spiffytech@gm: csound_score = [] 6a17d4d36a 2010-11-12 spiffytech@gm: for token in score: 9bd31df856 2010-11-16 spiffytech@gm: if isinstance(token, parse.Chord): # Chords 9bd31df856 2010-11-16 spiffytech@gm: for note in token.chord: 5aa14570f1 2010-11-13 spiffytech@gm: note = csound_note_values[note] b5a8b20242 2011-11-03 brian: csound_score.append(score_line % {"time": t, "octave": token.octave, "note": note, "duration": token.duration}) 192b8b1639 2011-10-11 brian: csound_score.append(score_line % {"time": t, "octave": token.octave, "note": note, "duration": token.duration}) aa88358397 2010-11-17 spiffytech@gm: elif isinstance(token, parse.Note): # Individual notes 9bd31df856 2010-11-16 spiffytech@gm: note = csound_note_values[token.value] 192b8b1639 2011-10-11 brian: csound_score.append(score_line % {"time": t, "octave": token.octave, "note": note, "duration": token.duration}) 192b8b1639 2011-10-11 brian: elif isinstance(token, tree.Tree): 192b8b1639 2011-10-11 brian: continue 192b8b1639 2011-10-11 brian: t += token.duration 6a17d4d36a 2010-11-12 spiffytech@gm: return csound_score 338933c1a8 2010-11-12 spiffytech@gm: 6bfc2449ff 2010-11-04 spiffytech@gm: 6a17d4d36a 2010-11-12 spiffytech@gm: if __name__ == "__main__": main()