Sign in to follow this  
Followers 0
D2sage

Python software to train AI model to make music

2 posts in this topic

This code works. You feed it with MIDI files or musicxml files. And then you hit generate to make the music.

Do we got any python people here?

What can we do with this code to make it optimal.

https://easyupload.io/kqac2x   <--- Project file

 

Got 50 000 midi files but not sure if the code is optimal for that large data?

 

import os

import random

import tkinter as tk

from tkinter import filedialog

from music21 import converter, instrument, note, chord, stream

import tensorflow as tf

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import LSTM, Dropout, Dense

import numpy as np

 

# Global variables

training_dir = ""

model_dir = "C:/Users/adria/OneDrive/Desktop/Model"

output_dir = "C:/Users/adria/OneDrive/Desktop"

sequences = []

model = None

 

def select_training_files():

    global training_dir

    training_dir = filedialog.askdirectory(title="Select Training MIDI Files Directory")

    print("Training files directory selected:", training_dir)

 

def select_model_directory():

    global model_dir

    model_dir = filedialog.askdirectory(title="Select Model Directory")

    print("Model directory selected:", model_dir)

 

def select_output_directory():

    global output_dir

    output_dir = filedialog.askdirectory(title="Select Output Directory")

    print("Output directory selected:", output_dir)

 

def transfer_learning():

    global model, sequences

 

    transfer_model_path = "C:/Users/adria/OneDrive/Desktop/Model"

 

    if not os.path.exists(transfer_model_path):

        print("Transfer learning model not found. Please check the path.")

        return

 

def train_model():

    global training_dir, model_dir, sequences, model

 

    if not training_dir:

        print("Please select the training files directory.")

        return

    if not model_dir:

        print("Please select the model directory.")

        return

 

    model_path = os.path.join(model_dir, "model.h5")

    # Convert MIDI files to music21 stream objects

    training_files = [os.path.join(training_dir, file) for file in os.listdir(training_dir) if file.endswith((".mid", ".musicxml"))]

    sequences = []  # Clear previous sequences

    for file in training_files:

        midi = converter.parse(file)

        notes = []

        chords = []

        for element in midi.flatten():

            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))

        sequences.append(notes)

 

    # Create input and output sequences

    sequence_length = 100

    pitch_names = sorted(set(note for sequence in sequences for note in sequence))

    note_to_int = dict((note, number) for number, note in enumerate(pitch_names))

    network_input = []

    network_output = []

    for sequence in sequences:

        for i in range(len(sequence) - sequence_length):

            sequence_in = sequence[i:i + sequence_length]

            sequence_out = sequence[i + sequence_length]

            network_input.append([note_to_int[char] for char in sequence_in])

            network_output.append(note_to_int[sequence_out])

    network_input = np.array(network_input)  # Specify dtype as object

    network_output = np.array(network_output)

    n_patterns = len(network_input)

 

    # Check if network_input is empty

    if n_patterns == 0:

        print("No training sequences found.")

        return

 

    # Reshape the input

    network_input = np.reshape(network_input, (n_patterns, sequence_length, 1))

    network_input = network_input / float(len(pitch_names))

 

    # Check if the pretrained model exists, if not create a new model

    if os.path.exists(model_path):

        model = tf.keras.models.load_model(model_path)

        print("Pretrained model loaded successfully.")

    else:

        # Create the model

        model = Sequential()

        model.add(LSTM(256, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True))

        model.add(Dropout(0.3))

        model.add(LSTM(512, return_sequences=True))

        model.add(Dropout(0.3))

        model.add(LSTM(256))

        model.add(Dense(256))

        model.add(Dropout(0.3))

        model.add(Dense(len(pitch_names), activation='softmax'))

        model.compile(loss='sparse_categorical_crossentropy', optimizer='adam')

        print("New model created.")

 

    # Train the model

    print("Training started...")

    model.fit(network_input, network_output, epochs=50, batch_size=32)

    print("Training completed.")

 

    # Save the model

    model.save(model_path)

    print("Model saved successfully.")

 

    # Save the sequences

    np.save(os.path.join(model_dir, "sequences.npy"), sequences)

    print("Sequences saved successfully.")

 

def load_model():

    global model_dir, model, sequences

 

    if not model_dir:

        print("Please select the model directory.")

        return

 

    model_path = os.path.join(model_dir, "model.h5")

 

    # Check if the model file exists

    if not os.path.exists(model_path):

        print("Trained model not found. Please train the model first.")

        return

 

    # Load the trained model

    model = tf.keras.models.load_model(model_path)

    print("Model loaded successfully.")

 

    # Load the sequences

    if os.path.exists(os.path.join(model_dir, "sequences.npy")):

        sequences = np.load(os.path.join(model_dir, "sequences.npy"), allow_pickle=True).tolist()

        print("Sequences loaded successfully.")

    else:

        print("Sequences not found. Please train the model first.")

        return

 

def generate_music():

    global model, sequences, output_dir

 

    if not model:

        print("Please load or train the model.")

        return

    if not output_dir:

        print("Please select the output directory.")

        return

 

    # Rest of the code for generating music...

 

    # Create input sequences

    sequence_length = 100

    pitch_names = sorted(set(note for sequence in sequences for note in sequence))

    note_to_int = dict((note, number) for number, note in enumerate(pitch_names))

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

    network_input = []

    for sequence in sequences:

        for i in range(len(sequence) - sequence_length):

            sequence_in = sequence[i:i + sequence_length]

            network_input.append([note_to_int[char] for char in sequence_in])

 

    # Check if network_input is empty

    if not network_input:

        print("Please train the model first.")

        return

 

    # Generate music

    for file_number in range(10):  # For creating multiple files

        start = np.random.randint(0, len(network_input) - 1)

        pattern = network_input[start]

        prediction_output = []

        for _ in range(8 * 4):  # Generate 8 bars (4/4 time signature)

            prediction_input = np.reshape(pattern, (1, len(pattern), 1))

            prediction_input = prediction_input / float(len(pitch_names))

            predicted_probs = model.predict(prediction_input, verbose=0)

            predicted_index = np.argmax(predicted_probs)

            predicted_note = int_to_note[predicted_index]

            prediction_output.append(predicted_note)

            pattern = np.append(pattern, predicted_index)

            pattern = pattern[1:len(pattern)]

 

        # Rest of the code...

 

        # Create music21 objects from the generated output

        offset = 0

        output_notes = []

        for pattern in prediction_output:

            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.offset = offset

                    new_note.storedInstrument = instrument.Piano()

                    output_notes.append(new_note)

            else:

                new_note = note.Note(pattern)

                new_note.offset = offset

                new_note.storedInstrument = instrument.Piano()

                output_notes.append(new_note)

            offset += 0.5

 

        # Create a music21 stream object and add the generated notes

        midi_stream = stream.Stream(output_notes)

 

        # Save generated sequence to a MIDI file

        file_number = random.randint(1000, 9999)

        output_path = os.path.join(output_dir, f"output_{file_number}.mid")

        midi_stream.write('midi', fp=output_path)

        print(f"Music generated successfully: {output_path}")


 

def main():

    # Create a Tkinter window

    window = tk.Tk()

    window.title("MIDI Music Generation")

 

    # Create buttons for each action

    btn_select_training_files = tk.Button(window, text="Select Training Files", command=select_training_files)

    btn_select_model_directory = tk.Button(window, text="Select Model Directory", command=select_model_directory)

    btn_select_output_directory = tk.Button(window, text="Select Output Directory", command=select_output_directory)

    btn_train_model = tk.Button(window, text="Train Model", command=train_model)

    btn_load_model = tk.Button(window, text="Load Model", command=load_model)

    btn_generate_music = tk.Button(window, text="Generate Music", command=generate_music)

 

    # Place the buttons on the window

    btn_select_training_files.pack()

    btn_select_model_directory.pack()

    btn_select_output_directory.pack()

    btn_train_model.pack()

    btn_load_model.pack()

    btn_generate_music.pack()

 

    # Start the Tkinter event loop

    window.mainloop()

 

if __name__ == "__main__":

    main()

 

Edited by D2sage

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0