def __init__(self): QMainWindow.__init__(self) self.resize(1300, 700) self.setFixedSize(self.size()) self.setWindowTitle('PyChord') self.add_combo_boxes() self.add_buttons() self.sl = QSlider(Qt.Horizontal, self) self.volume = QLCDNumber(self) self.add_slider() self.actual_key = None self.actual_meter = 4 self.actual_instrument = instrument.Piano() self.melody_stream = stream.Stream() self.harmonized_melody_stream = stream.Stream() self.reset_stream(self.melody_stream) self.reset_stream(self.harmonized_melody_stream) mixer.init(44100, -16, 2, 1024) self.tmpStream = stream.Stream() self.tmpStream.insert(instrument.Piano()) self.lpc = lily.translate.LilypondConverter() self.lpc.context = lily.lilyObjects.LyMusicList() self.keyboard = Keyboard(self) self.melody = Melody(self, self.actual_key)
def autocomplete( self, prefix: List[int], limit: Optional[int] = None) -> List[Tuple[Melody, float]]: """Return up to <limit> matches for the given interval sequence. The return value is a list of tuples (melody, weight), and must be ordered in non-increasing weight. (You can decide how to break ties.) If limit is None, return *every* match for the given interval sequence. Precondition: limit is None or limit > 0 """ a = self.autocompleter.autocomplete(prefix, limit) new = [] name = '' for item in a: for mel in self._melody_name: if mel[0] == item[0]: name = mel[1] new.append(( Melody(name, item[0]), item[1], )) return new
def index(): file = request.files.get('file') name, extension = os.path.splitext(file.filename) filename = os.path.join(os.path.dirname(__file__), 'tmp/' + time.strftime("%Y%m%d%H%M%S") + '_' + str(randint(1000000,9999999)) + '_' + name + extension) file.save(filename) downsample = int(os.environ.get('DOWNSAMPLE', 1)) samplerate = int(os.environ.get('SAMPLERATE', 44100)) // downsample fft_size = int(os.environ.get('FTT_SIZE', 512)) // downsample hop_size = int(os.environ.get('HOP_SIZE', 256)) // downsample source_file = source(filename, samplerate, hop_size) samplerate = source_file.samplerate tolerance = 0.8 pitch_o = pitch("yin", fft_size, hop_size, samplerate) pitch_o.set_unit("Hz") pitch_o.set_tolerance(tolerance) pitches = [] total_frames = 0 while True: samples, read = source_file() frequency = pitch_o(samples)[0] start = total_frames / float(samplerate) pitches += [Note(start=start, frequency=frequency)] total_frames += read if read < hop_size: break ending_time = total_frames / float(samplerate) melody = Melody(pitches=pitches, ending_time=ending_time) response.content_type = 'application/json' return dict(melody=melody)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) else: self.autocompleter = CompressedPrefixTree(config['weight_type']) with open(config['file']) as csvfile: csvfile = csvfile.readlines() temp = [] name_list = [] for i in csvfile: i = i.strip('\n').split(',') name_list.append(i[0]) k = [] for letter in i: if letter != '': k.append(letter) temp.append(k) nested = [] for item in temp: new_temp = [] num = 0 while num < len(item) - 1: new_temp.append((int(item[1:][num]), int(item[1:][num + 1]))) num += 2 nested.append(new_temp) new_temp = [] for node in nested: prefix = [] num = 0 while num < len(node) - 1: prefix.append((int(node[num + 1][0]) - int(node[num][0]))) num += 1 new_temp.append(prefix) for i in range(len(nested)): self.autocompleter.insert(Melody(name_list[i], nested[i]), 1, new_temp[i])
def generate_melody(self, intro=True): melody = Melody() if intro: print("I will now write a melody according to your constraints.") print( "By default, I simplify the process with generic questions and implied constraints." ) print( "If you would like more control, call this function with smart=False" ) print("After any prompt, type \"exit\" to cancel this melody.") print("To supress this intro, set intro=False") exit = False if self.smart: # determine melody or bassline # exit, bassline = self.question("Is this a bassline? (y/n)", ["y","n"]) # if exit: # return # if bassline == "y": # melody.octave_range = (1,5) # if bassline == "n": # melody.octave_range = (4,8) melody.octave_range = (3, 5) # determine key exit, key = self.question( "What key is this in? (ex: A, Am, D#, Ebm etc.)", key_list) if exit: return melody.key = key # determine scale scale_options = self.get_scale_options(key) print("Choose a scale by typing the number:") for i, scale in enumerate(scale_options): print("{0}. {1}".format(i + 1, scale)) exit, scale = self.question( "Scale Choice: ", list(map(str, range(1, len(scale_options) + 1, 1)))) if exit: return melody.scale = scale_options[int(scale) - 1] melody = self.select_notes(melody) self.compositions.append(melody) return melody
def parse_melody(line: List) -> Tuple[List, Melody]: """Parse list of notes and return a tuple pairing a list of intervals and a Melody object """ line = list(filter(None, line)) intervals = [] notes = [] for i in range(3, len(line), 2): intervals.append(int(line[i]) - int(line[i - 2])) notes.append((int(line[i - 2]), int(line[i - 1]))) return intervals, Melody(line[0], notes)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. self.autocompleter = None # determine tree type if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) elif config['autocompleter'] == 'compressed': self.autocompleter = CompressedPrefixTree(config['weight_type']) with open(config['file']) as file: reader = csv.reader(file) for item in reader: name = item[0] # get song name index = 1 notes = [] interval = [] prev_pit = None # loop to record notes and pitches while index < len(item) and len(item[index]) != 0: pitch = int(item[index]) if prev_pit is not None: interval.append(pitch - prev_pit) prev_pit = pitch notes.append((pitch, int(item[index + 1]))) index += 2 self.autocompleter.insert(Melody(name, notes), 1, interval)
def auto_compose(progs, time_sig, path): progs = progressions.slice_bar(progs) st1 = stream.Stream() # Get Parts m_part = Melody(progs=progs, time_sig=time_sig).part b_part = Bass(progs=progs, time_sig=time_sig).part d_part = Drum(progs=progs, time_sig=time_sig).score # Append Parts st1.insert(0, m_part) st1.insert(0, b_part) st1.insert(0, d_part) commons.save(input_score=st1, path=filepath)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) elif config['autocompleter'] == 'compressed': self.autocompleter = CompressedPrefixTree(config['weight_type']) with open(config['file']) as csvfile: reader = csv.reader(csvfile) for line in reader: prefix = [] song = [] i = 1 song.append((int(line[i]), int(line[i + 1]))) i += 2 while line[i] != '': song.append((int(line[i]), int(line[i + 1]))) prefix.append(int(line[i]) - int(line[i - 2])) i += 2 try: isinstance(line[i], str) except IndexError: break melody = Melody(line[0], song) self.autocompleter.insert(melody, 1.0, prefix)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) else: self.autocompleter = CompressedPrefixTree(config['weight_type']) with open(config['file']) as csvfile: reader = csv.reader(csvfile) for line in reader: if any([s == "" for s in line]): continue notes = [] interval = [] name = line[0] linelist = [x for x in line] linelist = linelist[1:] pitch = linelist[::2] duration = linelist[1::2] i = 0 while i < len(pitch): notes.append((int(pitch[i]), int(duration[i]))) i += 1 for i in range(1, len(notes)): interval.append(notes[i][0] - notes[i - 1][0]) self.autocompleter.insert(Melody(name, notes), 1.0, interval)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) else: self.autocompleter = CompressedPrefixTree(config['weight_type']) # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. with open(config['file']) as csvfile: reader = csv.reader(csvfile) for line in reader: name = line[0] tuple_list = [] prefix = [] for i in range(1, len(line) // 2 + 1): if line[2 * i] == '': break else: tuple_list.append( (int(line[2 * i - 1]), int(line[2 * i]))) melody = Melody(name, tuple_list) for i in range(1, len(tuple_list)): prefix.append(tuple_list[i][0] - tuple_list[i - 1][0]) self.autocompleter.insert(melody, 1, prefix)
def __init__(self, data: Dict[str, Dict[str, List[int]]], build_matrix_representation=False) -> 'Dataset': self.melodies = [Melody(melody_name, representation) for melody_name, representation in list(data.items())] self.id_to_pitches, pitches_to_id = Dataset.build_mappings(self.extract_pitches()) self.id_to_durations, durations_to_id = Dataset.build_mappings(self.extract_durations()) for melody in self.melodies: melody.build_integer_representation(self.id_to_pitches, pitches_to_id, self.id_to_durations, durations_to_id) if build_matrix_representation: max_length = 0 for melody in self.melodies: melody.build_matrix_representation(len(self.id_to_pitches), len(self.id_to_durations)) max_length = max(max_length, len(melody)) for melody in self.melodies: melody.build_standardized_matrix_representation(max_length)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. if config['autocompleter'] == 'simple': self.autocompleter = SimplePrefixTree(config['weight_type']) else: self.autocompleter = CompressedPrefixTree(config['weight_type']) with open(config['file'], encoding='utf8') as csvfile: f = csv.reader(csvfile) for line in f: helper = line[1::2] while helper[len(helper) - 1] == '': helper.pop() prefix = [] notes = [] for i in range(1, len(helper) - 1): prefix.append(int(helper[i]) - int(helper[i - 1])) for element in helper: index = line.index(element) note = (int(line[index]), int(line[index + 1])) notes.append(note) melody = Melody(line[0], notes) self.autocompleter.insert(melody, 1.0, prefix)
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the following format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. self.autocompleter = SimplePrefixTree(config['weight_type']) \ if config['autocompleter'] == 'simple' \ else CompressedPrefixTree(config['weight_type']) with open(config['file']) as f: lines = csv.reader(f) for line in lines: if line: pairs = [] for i in range(1, len(line) - 1, 2): pairs.append((int(line[i]), int(line[i + 1]))) interval = [] for i in range(len(pairs) - 1): interval.append( int(pairs[i + 1][0]) - int(pairs[i][0])) value = Melody(line[0], pairs) self.autocompleter.insert(value, 1, interval)
plt.xlim(0, len(mask)) plt.ylim(0, 2) plt.xlabel(r'position $i$') plt.ylabel(r'$\alpha$') # ------------------------------------------------------------------------------ # notes = bwv816 # notes = bwv1009 notes = gossec_gavotte # notes = ['c8']*600 # notes = ['c8'] + \ # ['d', 'e', 'f', 'g', 'a', 'b', 'c'] * 20 # notes = [ "c'4", "g", "e8", "c" ] M = Melody(notes) N = len(M.notes) # for n in M.notes: # print(n) I = pitch_intervals(M) R = rhythmic_intervals(M) plt.figure() plt.scatter(I, np.ones(len(I)), s=2**2) plt.savefig('figures/results01.png', dpi=450) # plt.scatter(R, np.ones(len(I)), s=2**2) I_mask = mask(I) # R_mask = mask(R)
class MyWindow(QMainWindow): def __init__(self): QMainWindow.__init__(self) self.resize(1300, 700) self.setFixedSize(self.size()) self.setWindowTitle('PyChord') self.add_combo_boxes() self.add_buttons() self.sl = QSlider(Qt.Horizontal, self) self.volume = QLCDNumber(self) self.add_slider() self.actual_key = None self.actual_meter = 4 self.actual_instrument = instrument.Piano() self.melody_stream = stream.Stream() self.harmonized_melody_stream = stream.Stream() self.reset_stream(self.melody_stream) self.reset_stream(self.harmonized_melody_stream) mixer.init(44100, -16, 2, 1024) self.tmpStream = stream.Stream() self.tmpStream.insert(instrument.Piano()) self.lpc = lily.translate.LilypondConverter() self.lpc.context = lily.lilyObjects.LyMusicList() self.keyboard = Keyboard(self) self.melody = Melody(self, self.actual_key) def change_volume(self, vl): mixer.music.set_volume(vl / 100.0) self.volume.display(vl) def add_buttons(self): play_button = QPushButton('Play', self) play_button.move(1100, 300) play_button.clicked.connect(self.play_notes) reset_button = QPushButton('Reset', self) reset_button.move(1100, 350) reset_button.clicked.connect(self.reset) notes_button = QPushButton('Show Notes', self) notes_button.clicked.connect(self.show_notes) notes_button.move(1100, 400) save_button = QPushButton('Save', self) save_button.clicked.connect(self.save) save_button.move(1100, 450) def add_combo_boxes(self): key_info = QLabel('Choose a key:', self) key_info.move(600, 50) key_choice = QComboBox(self) key_choice.move(600, 100) key_choice.addItems(['None', 'C', 'D', 'E', 'F', 'G', 'A', 'B']) key_choice.currentIndexChanged.connect(self.change_key) meter_info = QLabel('Choose a meter:', self) meter_info.move(400, 50) meter_choice = QComboBox(self) meter_choice.move(400, 100) meter_choice.addItems(['4/4', '3/4', '2/4']) meter_choice.currentIndexChanged.connect(self.change_meter) instrument_choice = QComboBox(self) instrument_choice.move(1100, 250) instrument_choice.addItems( ['Piano(default)', 'Guitar', 'Violin', 'Flute', 'Mandolin']) instrument_choice.currentIndexChanged.connect(self.change_instrument) def add_slider(self): self.sl.setMinimum(0) self.sl.setMaximum(100) self.sl.setValue(80) self.sl.setTickInterval(1) self.sl.move(1100, 220) self.sl.valueChanged.connect( lambda: self.change_volume(self.sl.value())) self.volume.move(1100, 180) self.volume.display(80) def play_notes(self): try: if not self.melody.is_well_rhythmic: confirm = QMessageBox() confirm.setWindowTitle('Error') confirm.setText('The rhythm is not correct.') confirm.setIcon(QMessageBox.Information) confirm.exec() else: if self.actual_key is not None: self.melody.harmonize() mixer.music.load( self.harmonized_melody_stream.write('midi')) mixer.music.play() else: mixer.music.load(self.melody_stream.write('midi')) mixer.music.play() except exceptions21.StreamException: pass def show_notes(self): if not self.melody.is_well_rhythmic: confirm = QMessageBox() confirm.setWindowTitle('Error') confirm.setText('The rhythm is not correct.') confirm.setIcon(QMessageBox.Information) confirm.exec() else: self.lpc.context.contents = [] self.lpc.appendObjectsToContextFromStream(self.melody_stream) with open('notes.ly', 'w+') as f: f.write('\\version "2.20.0"\n') if self.actual_key is None: f.write("{\n") f.write('\\key c \\major \n') f.write(str(self.lpc.context)) f.write("}\n") else: f.write('{<<\n') f.write('\\chords {') for i in self.melody.list_of_chords: f.write(i.lower() + " ") f.write('}\n') f.write('{\\key ' + self.actual_key.tonic.name.lower() + ' \\' + self.actual_key.mode) f.write('\n') f.write(str(self.lpc.context)) f.write('}>>}\n') if platform.system() == 'Linux': process = subprocess.Popen(['lilypond notes.ly'], shell=True) process.wait(100) subprocess.Popen(['chmod 755 notes.pdf'], shell=True) subprocess.Popen(['xdg-open notes.pdf'], shell=True) elif platform.system() == 'Windows': process = subprocess.Popen(['powershell', 'lilypond notes.ly']) process.wait(100) subprocess.Popen(['powershell', '.\\notes.pdf']) def save(self): if not self.melody.is_well_rhythmic: confirm = QMessageBox() confirm.setWindowTitle('Error') confirm.setText('The rhythm is not correct.') confirm.setIcon(QMessageBox.Information) confirm.exec() else: if not os.path.exists('music'): os.makedirs('music') today = date.today() flag = True count = 1 path = '' while flag is True: path = os.path.join('music', '{}.{}.mid'.format(str(count), str(today))) flag = os.path.isfile(path) count += 1 self.harmonized_melody_stream.write('midi', fp=path) confirm = QMessageBox() confirm.setWindowTitle('Confirmation') confirm.setText('File saved') confirm.setIcon(QMessageBox.Information) confirm.exec() def add_note(self, my_note): self.melody.rhythmic_values_sum = sum( self.melody.note_buttons[i].rhythmic_value for i in range(len(self.melody.note_buttons))) if self.melody.rhythmic_values_sum < self.melody.max_notes: self.melody_stream.insert(self.melody.rhythmic_values_sum + 2, note.Note(my_note.nameWithOctave)) for i in range(8): if mixer.Channel(i).get_busy(): pass else: if platform.system() == 'Linux': mixer.Channel(i).play( mixer.Sound('notes/{}.wav'.format(my_note))) elif platform.system() == 'Windows': mixer.Channel(i).play( mixer.Sound('notes\\{}.wav'.format(my_note))) break self.melody.add_note_to_melody(my_note) self.melody.show_melody() def reset_stream(self, stream_to_reset): stream_to_reset.clear() stream_to_reset.insert(0, self.actual_instrument) stream_to_reset.insert( 1, meter.TimeSignature('{}/4'.format(self.actual_meter))) def change_instrument(self, choice): instruments = [ instrument.Piano(), instrument.AcousticGuitar(), instrument.Violin(), instrument.Flute(), instrument.Mandolin() ] self.actual_instrument = instruments[choice] self.melody_stream[0] = self.actual_instrument def reset(self): for button in self.melody.note_buttons: button.hide() self.melody.note_buttons.clear() self.melody.notes_counter = 0 self.melody.rhythmic_values_sum = 0 self.reset_stream(self.melody_stream) self.reset_stream(self.harmonized_melody_stream) def change_key(self, choice): self.reset() self.keyboard.reset() if choice == 0: self.actual_key = None else: keys = ['None', 'C', 'D', 'E', 'F', 'G', 'A', 'B'] self.actual_key = key.Key(keys[choice]) self.keyboard.on_key_change(self.actual_key) self.melody.actual_key = self.actual_key def change_meter(self, choice): self.reset() meters = [4, 3, 2] self.actual_meter = meters[choice] self.melody.on_meter_change(self.actual_meter) self.update(0, 0, 1000, 1000) def paintEvent(self, e): lines = QPainter(self) lines.setPen(QPen(QColor(240, 240, 240), 10, Qt.SolidLine)) for i in range(17): lines.drawLine(250 + i * 45, 290, 250 + i * 45, 350) lines.setPen(QPen(Qt.black, 10, Qt.SolidLine)) for i in range(5): lines.drawLine(250 + i * self.actual_meter * 45, 290, 250 + i * self.actual_meter * 45, 350) lines.end()
def __init__(self, config: Dict[str, Any]) -> None: """Initialize this engine with the given configuration. <config> is a dictionary consisting of the following keys: - 'file': the path to a CSV file - 'autocompleter': either the string 'simple' or 'compressed', specifying which subclass of Autocompleter to use. - 'weight_type': either 'sum' or 'average', which specifies the weight type for the prefix tree. Precondition: The given file is a *CSV file* where each line has the format: - The first entry is the name of a melody (a string). - The remaining entries are grouped into pairs (as in Assignment 1) where the first number in each pair is a note pitch, and the second number is the corresponding duration. HOWEVER, there may be blank entries (stored as an empty string ''); as soon as you encounter a blank entry, stop processing this line and move onto the next line the CSV file. Each melody is be inserted into the Autocompleter with a weight of 1. """ # We haven't given you any starter code here! You should review how # you processed CSV files on Assignment 1. self._weight_type = config['weight_type'] self._autocompleter_type = config['autocompleter'] if self._autocompleter_type == 'simple': self.autocompleter = SimplePrefixTree(self._weight_type) else: self.autocompleter = CompressedPrefixTree(self._weight_type) with open(config['file']) as csvfile: reader = csv.reader(csvfile) for line in reader: name = line[0] #name of the melody notes = [] #list of notes in the melody interval_sequence = [] found_empty = False for x in range(1, len(line) - 1, 2): pitch = int(line[x]) duration = int(line[x + 1]) if pitch == '' or duration == '': found_empty = True else: #add the note to the list of notes as a tuple notes.append((pitch, duration)) if not found_empty: for i in range(3, len(line) - 1, 2): #interval = int(line[i]) - int(line[i-2]) interval_sequence.append( int(line[i]) - int(line[i - 2])) melody = Melody(name, notes) self.autocompleter.insert(melody, 1, interval_sequence)
random_walk_edge_weight(g) # create roll object roll = Roll(length = 1, repeat = 1, transitions = 4, shade = 1) print roll.groove # bring it all together m = Melody(scale=scale, graph=g, length=1, repeat=1, roll=roll) m.plot_graph() print m.loop[0] # loop = Melody.loop output = mido.open_output( u'ZynAddSubFX') s = Sequencer( output, bpm=120, roll=m.loop, loop=False) s.play() s.play()
"""CSC148 Assignment 2: Autocomplete engines