File size: 5,786 Bytes
337e17d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import streamlit as st
import numpy as np
import requests
import time
import pickle
import tensorflow as tf
from music21 import *
from midi2audio import FluidSynth
from streamlit_lottie import st_lottie
import hydralit_components as hc

# Set page config
st.set_page_config(page_title="Music Generation", page_icon=":tada:", layout="wide")

def load_lottieurl(url):
    r = requests.get(url)
    if r.status_code != 200:
        return None
    return r.json()

# Load Lottie animation
lottie_coding = load_lottieurl("https://assets5.lottiefiles.com/private_files/lf30_fjln45y5.json")

# Header section
with st.container():
    left_column, right_column = st.columns(2)
    with left_column:
        st.subheader("Music Generation :musical_keyboard:")
        st.write(
            "Our website is an application of piano music generation, you can listen to new musical notes generated by LSTM artificial neural network, which is used in fields of AI and deep learning. Let's get it started :notes:"
        )
    with right_column:
        st_lottie(lottie_coding, height=300, key="coding")

# Sidebar for user input
with st.sidebar:
    len_notes = st.slider('Please Choose The Notes Length', 20, 750, 20, 4)
    st.write("Notes Length = ", len_notes)

# Music generation functionality
if st.sidebar.button('Generate My Music'):
    if len_notes:
        with st.container():
            st.write("---")
            with hc.HyLoader('✨ Your music is now under processing ✨', hc.Loaders.standard_loaders, index=[3, 0, 5]):
                time.sleep(10)
                generate(10, len_notes)

                fs = FluidSynth('font.sf2', sample_rate=44100)
                fs.midi_to_audio('test_output2.mid', 'output.wav')

                st.audio('output.wav')
                st.markdown("Here you are! You can download your music by right-clicking on the media player.")

####################### Music Generation Functions #######################
def generate(seq_len, x):
    """ Generate a piano midi file """
    with open('final_notes', 'rb') as filepath:
        notes = pickle.load(filepath)

    pitchnames = sorted(set(item for item in notes))
    n_vocab = len(set(notes))

    network_input, normalized_input = prepare_sequences(notes, pitchnames, n_vocab, seq_length=seq_len)
    model = create_network(normalized_input, n_vocab)
    prediction_output = generate_notes(model, network_input, pitchnames, n_vocab, x)
    create_midi(prediction_output)

def prepare_sequences(notes, pitchnames, n_vocab, seq_length):
    note_to_int = dict((note, number) for number, note in enumerate(pitchnames))
    network_input = []
    normalized_input = []
    output = []
    for i in range(0, len(notes) - seq_length, 1):
        sequence_in = notes[i:i + seq_length]
        sequence_out = notes[i + sequence_length]
        network_input.append([note_to_int[char] for char in sequence_in])
        output.append(note_to_int[sequence_out])

    n_patterns = len(network_input)
    normalized_input = np.reshape(network_input, (n_patterns, seq_length, 1))
    normalized_input = normalized_input / float(n_vocab)

    return (network_input, normalized_input)

def create_network(network_input, n_vocab):
    model = tf.keras.Sequential()
    model.add(tf.keras.layers.LSTM(512, input_shape=(network_input.shape[1], network_input.shape[2]), return_sequences=True, recurrent_dropout=0.3))
    model.add(tf.keras.layers.LSTM(512, return_sequences=True, recurrent_dropout=0.3))
    model.add(tf.keras.layers.LSTM(256))
    model.add(tf.keras.layers.BatchNormalization())
    model.add(tf.keras.layers.Dropout(0.2))
    model.add(tf.keras.layers.Dense(256, activation='relu'))
    model.add(tf.keras.layers.BatchNormalization())
    model.add(tf.keras.layers.Dropout(0.2))
    model.add(tf.keras.layers.Dense(n_vocab, activation='softmax'))
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
    model.load_weights('best2.h5')
    return model

def generate_notes(model, network_input, pitchnames, n_vocab, x):
    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 = []

    for note_index in range(x):
        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.append(index)
        pattern = pattern[1:len(pattern)]

    return prediction_output

def create_midi(prediction_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.storedInstrument = instrument.Piano()
                notes.append(new_note)
            new_chord = chord.Chord(notes)
            new_chord.offset = offset
            output_notes.append(new_chord)
        elif pattern == 'r':
            new_note = note.Rest(pattern)
            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

    midi_stream = stream.Stream(output_notes)
    midi_stream.write('midi', fp='test_output2.mid')