import pickle
import numpy
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"

from music21 import instrument, note, stream, chord
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.layers import BatchNormalization as BatchNorm
from keras.layers import Activation
from dataSequencing import DataStructuring
from lstmModel import LSTMModel
class prediction:
    def __init__(self):
        datastructuring = DataStructuring(100)
        self.lengthOfNotes = datastructuring.LengthOfNotes()
        inputs, normInputs = datastructuring.prepareSequencesTrain()
        lstmModel = LSTMModel()
        lstmModel.layersInstantiate()
        self.model = lstmModel.model
        self.inputs = inputs
        self.pitchnames = datastructuring.pitchnames
        with open('data/notes', 'rb') as filepath:
            self.notes = pickle.load(filepath)
    def predictOutput(self):
        start = numpy.random.randint(0, len(self.inputs) - 1)

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

        pattern = self.inputs[start]
        predictionOutput = []

        # generate 500 notes
        for note_index in range(500):
            predictionInput = numpy.reshape(pattern, (1, len(pattern), 1))
            predictionInput = predictionInput / float(len(set(self.notes)))

            prediction = self.model.predict(predictionInput, verbose=0)

            index = numpy.argmax(prediction)
            result = int_to_note[index]
            predictionOutput.append(result)

            pattern.append(index)
            pattern = pattern[1:len(pattern)]
            self.pred = predictionOutput
        return predictionOutput
    def returnOutputAsMidi(self):
        offset = 0
        output_notes = []

        # create note and chord objects based on the values generated by the model
        for pattern in self.pred:
            # 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='test_output.mid')


