示例#1
0
    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)
示例#2
0
    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
示例#3
0
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])
示例#5
0
 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)
示例#8
0
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)
示例#10
0
    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)
示例#12
0
    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)
示例#14
0
    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)
示例#15
0
    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)
示例#16
0
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