import glob
from music21 import converter, instrument, note, chord, stream
import numpy as np
import cv2
import pretty_midi
import random

def get_notes(target):
    """ Get all the notes and chords from the midi files """
    notes = []
    for file in glob.glob("midi/{}/*.mid".format(target)):
        midi = converter.parse(file)

        print("Parsing %s" % file)

        notes_to_parse = None

        try: # file has instrument parts
            s2 = instrument.partitionByInstrument(midi)
            notes_to_parse = s2.parts[0].recurse() 
        except: # file has notes in a flat structure
            notes_to_parse = midi.flat.notes
            
        for element in notes_to_parse:
            if isinstance(element, note.Note):
                notes.append(str(element.pitch))
            elif isinstance(element, chord.Chord):
                notes.append('.'.join(str(n) for n in element.normalOrder))

    return notes

def generate_notes(model, notes, network_input, n_vocab):
    """ Generate notes from the neural network based on a sequence of notes """
    # pick a random sequence from the input as a starting point for the prediction
    pitchnames = sorted(set(item for item in notes))
    
    start = np.random.randint(0, len(network_input)-1)

    int_to_note = dict((number, note) for number, note in enumerate(pitchnames))

    pattern = network_input[start]
    prediction_output = []
    # generate 500 notes
    for note_index in range(500):
        prediction_input = np.reshape(pattern, (1, len(pattern), 1))
        prediction_input = prediction_input / float(n_vocab)

        prediction = model.predict(prediction_input, verbose=0)
        index = np.argmax(prediction)
        result = int_to_note[index]
        prediction_output.append(result)
        
        pattern = np.append(pattern,index)
        pattern = pattern[1:len(pattern)]

    return prediction_output

def create_midi(prediction_output, filename):
    """ convert the output from the prediction to notes and create a midi file
        from the notes """
    offset = 0
    output_notes = []

    # create note and chord objects based on the values generated by the model
    for pattern in prediction_output:
        # pattern is a chord
        if ('.' in pattern) or pattern.isdigit():
            notes_in_chord = pattern.split('.')
            notes = []
            for current_note in notes_in_chord:
                new_note = note.Note(int(current_note))
                new_note.storedInstrument = instrument.Piano()
                notes.append(new_note)
            new_chord = chord.Chord(notes)
            new_chord.offset = offset
            output_notes.append(new_chord)
        # pattern is a note
        else:
            new_note = note.Note(pattern)
            new_note.offset = offset
            new_note.storedInstrument = instrument.Piano()
            output_notes.append(new_note)
        # increase offset each iteration so that notes do not stack
        offset += 0.5

    midi_stream = stream.Stream(output_notes)
    midi_stream.write('midi', fp='{}.mid'.format(filename))

def generate_png_midi(png, midi_class):
    img = cv2.imread(png)
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    imgYUV = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
    imgY = imgYUV[:,:,0]
    result = cv2.Canny(imgY, 100, 200)
    chord = pretty_midi.PrettyMIDI()
    cello_program = pretty_midi.instrument_name_to_program('Cello')
    cello = pretty_midi.Instrument(program=cello_program)
    code_seed = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
    #code_seed = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
    code_counter = 0
    count = 0
    code_counter = 0
    melody_count = 0
    melody_pitch = .5
    debug_count = 0
    random_seed = [0.2, 0.4, 0.6, 0.8, 1.0]
    for r in result:
        code = []
        if code_counter == 9:
            code_counter = 0
        for seed in code_seed:
            code.append(seed+str(code_counter))
        if count == len(code_seed):
            count = 0
        if max(r) == 0:
            continue
        else:
            melody_count = 0
            melody_pitch = .5
            for pic in r:
                #melody_pitch = random.choice(random_seed)
                melody_count+=melody_pitch
                if pic == 255:
                    note_number = pretty_midi.note_name_to_number(random.choice(code))
                    note = pretty_midi.Note(velocity=random.randrange(10, 100, 10), pitch=note_number, start=melody_count, end=melody_count+melody_pitch)
                    cello.notes.append(note)
        count+=1
        code_counter+=1
    chord.instruments.append(cello)
    chord.write('midi/{}/cello-C-chord.mid'.format(midi_class))