Jaman commited on
Commit
c9d790f
·
verified ·
1 Parent(s): 6b55c2e

Upload 4 files

Browse files
Files changed (4) hide show
  1. app.py +98 -0
  2. chords.lab +4 -0
  3. moonarch.py +74 -0
  4. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import base64
3
+ import os
4
+ import time
5
+ from moonarch import MusicToChordsConverter
6
+ from mido import MidiFile, MidiTrack, Message
7
+ import pretty_midi
8
+
9
+ # Set the home directory path for moonarch
10
+ home_directory = os.getcwd()
11
+
12
+ # Your app content
13
+ st.title("Moonarch Chords Analyzer: Chords")
14
+ st.write("Extract chords from any given music.")
15
+
16
+ # Set the title of the app
17
+ st.title("Your Music, Perfected by AI")
18
+
19
+ # Display the header text
20
+ st.header("Experience the Future of Sound")
21
+ st.write("""
22
+ Everything you need to create and release your music, including samples, plugins, unlimited distribution, and the world's best AI mastering engine.
23
+ """)
24
+
25
+ # Display the Start button
26
+ if st.button("Start using Monaarch"):
27
+ st.write("Welcome to Monaarch! Let's start creating amazing music.")
28
+
29
+ # Add upload option
30
+ audio_file = st.file_uploader("Upload a song", type=["mp3", "wav"])
31
+
32
+ if audio_file is not None:
33
+ st.write("File uploaded successfully.")
34
+
35
+ # Placeholder for progress bar
36
+ progress_bar = st.progress(0)
37
+
38
+ # Simulate file processing
39
+ for percent_complete in range(100):
40
+ time.sleep(0.01)
41
+ progress_bar.progress(percent_complete + 1)
42
+
43
+ st.write("File processing complete.")
44
+
45
+ if st.button('Find Chords'):
46
+ with st.spinner('Extracting chords and generating MIDI...'):
47
+ # Convert the uploaded file to a file path
48
+ file_name_without_ext = os.path.splitext(audio_file.name)[0]
49
+ audio_file_path = os.path.join('/tmp', audio_file.name)
50
+ with open(audio_file_path, 'wb') as f:
51
+ f.write(audio_file.getbuffer())
52
+
53
+ # Convert music to chords and save as MIDI
54
+ output_midi_file = f'{file_name_without_ext}.mid'
55
+ converter = MusicToChordsConverter(audio_file_path)
56
+ converter.recognize_chords()
57
+ converter.generate_midi()
58
+
59
+ # Updated save_midi method to handle PrettyMIDI object and proper message formatting
60
+ def save_midi(self, output_file):
61
+ midi = MidiFile()
62
+ track = MidiTrack()
63
+ midi.tracks.append(track)
64
+
65
+ # Ensure self.midi_chords is a PrettyMIDI object
66
+ if not isinstance(self.midi_chords, pretty_midi.PrettyMIDI):
67
+ raise TypeError(f"self.midi_chords is not a PrettyMIDI object: {type(self.midi_chords)}")
68
+
69
+ # Iterate over instruments and notes in the PrettyMIDI object
70
+ for instrument in self.midi_chords.instruments:
71
+ for note in instrument.notes:
72
+ # Ensure note, velocity, and time are within valid MIDI data byte range
73
+ midi_note = min(max(note.pitch, 0), 127)
74
+ velocity = min(max(note.velocity, 0), 127)
75
+ start_time = max(int(note.start * 1000), 0) # Convert to milliseconds
76
+ end_time = max(int(note.end * 1000), 0) # Convert to milliseconds
77
+ duration = end_time - start_time # Calculate duration
78
+
79
+ # Add note_on and note_off messages with correct formatting
80
+ track.append(Message('note_on', note=midi_note, velocity=velocity, time=start_time))
81
+ track.append(Message('note_off', note=midi_note, velocity=0, time=duration))
82
+
83
+ midi.save(output_file)
84
+
85
+ # Assign the updated method to the converter instance
86
+ converter.save_midi = save_midi.__get__(converter, MusicToChordsConverter)
87
+ converter.save_midi(output_midi_file)
88
+
89
+ st.success('Chords extraction and MIDI generation complete!')
90
+
91
+ # Provide a button to download the MIDI file
92
+ with open(output_midi_file, 'rb') as f:
93
+ st.download_button(
94
+ label="Download MIDI file",
95
+ data=f,
96
+ file_name=output_midi_file,
97
+ mime='audio/midi'
98
+ )
chords.lab ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ 0.0 1.6718367346938776 D:maj
2
+ 1.6718367346938776 3.4829931972789114 Bb:maj
3
+ 3.4829931972789114 5.340589569160998 C:maj
4
+ 5.340589569160998 8.17342403628118 D:maj
moonarch.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import autochord
2
+ import pretty_midi
3
+ import librosa
4
+ class MusicToChordsConverter:
5
+ def __init__(self, audio_file):
6
+ self.audio_file = audio_file
7
+ self.chords = None
8
+ self.midi_chords = pretty_midi.PrettyMIDI()
9
+ self.instrument_chords = pretty_midi.Instrument(program=0) # Acoustic Grand Piano
10
+
11
+ def recognize_chords(self):
12
+ """
13
+ Perform chord recognition on the audio file.
14
+ """
15
+ self.chords = autochord.recognize(self.audio_file, lab_fn='chords.lab')
16
+
17
+ def chord_to_midi_notes(self, chord_name):
18
+ """
19
+ Map chord names to MIDI notes.
20
+
21
+ Args:
22
+ chord_name (str): The chord name to be mapped.
23
+
24
+ Returns:
25
+ list: A list of MIDI notes corresponding to the chord.
26
+ """
27
+ note_mapping = {
28
+ 'C:maj': ['C4', 'E4', 'G4'],
29
+ 'C:min': ['C4', 'E-4', 'G4'],
30
+ 'D:maj': ['D4', 'F#4', 'A4'],
31
+ 'D:min': ['D4', 'F4', 'A4'],
32
+ 'E:maj': ['E4', 'G#4', 'B4'],
33
+ 'E:min': ['E4', 'G4', 'B4'],
34
+ 'F:maj': ['F4', 'A4', 'C5'],
35
+ 'F:min': ['F4', 'A-4', 'C5'],
36
+ 'G:maj': ['G4', 'B4', 'D5'],
37
+ 'G:min': ['G4', 'B-4', 'D5'],
38
+ 'A:maj': ['A4', 'C#5', 'E5'],
39
+ 'A:min': ['A4', 'C5', 'E5'],
40
+ 'B:maj': ['B4', 'D#5', 'F#5'],
41
+ 'B:min': ['B4', 'D5', 'F#5']
42
+ }
43
+ return note_mapping.get(chord_name, [])
44
+
45
+ def generate_midi(self):
46
+ """
47
+ Generate a MIDI file from the recognized chords.
48
+ """
49
+ for chord in self.chords:
50
+ start_time = chord[0]
51
+ end_time = chord[1]
52
+ chord_name = chord[2]
53
+ if chord_name != 'N': # Ignore no-chord
54
+ chord_notes = self.chord_to_midi_notes(chord_name)
55
+ for note_name in chord_notes:
56
+ midi_note = pretty_midi.Note(
57
+ velocity=100,
58
+ pitch=librosa.note_to_midi(note_name),
59
+ start=start_time,
60
+ end=end_time
61
+ )
62
+ self.instrument_chords.notes.append(midi_note)
63
+
64
+ self.midi_chords.instruments.append(self.instrument_chords)
65
+
66
+ def save_midi(self, output_file):
67
+ """
68
+ Save the generated MIDI file to disk.
69
+
70
+ Args:
71
+ output_file (str): The path where the MIDI file should be saved.
72
+ """
73
+ self.midi_chords.write(output_file)
74
+ print(f"Saved chords to {output_file}")
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ streamlit
2
+ autochord
3
+ tf_keras
4
+ keras==3
5
+ pretty_midi