FILMITO commited on
Commit
2d81959
Β·
verified Β·
1 Parent(s): 3ce0be1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +142 -154
app.py CHANGED
@@ -37,9 +37,9 @@ class MP3ToHumanizedMP3:
37
  }
38
 
39
  def create_full_song(self, audio_path, style="pop", intensity=0.7):
40
- """Convert MP3 to a complete humanized song"""
41
  try:
42
- # Load and analyze original audio
43
  y, sr = librosa.load(audio_path, sr=22050, mono=True)
44
 
45
  # Create MIDI structure
@@ -54,8 +54,8 @@ class MP3ToHumanizedMP3:
54
  )
55
  midi.instruments.append(instrument)
56
 
57
- # Extract musical elements from audio
58
- self.extract_music_to_instruments(midi, y, sr, style, intensity)
59
 
60
  # Humanize the performance
61
  self.humanize_performance(midi, intensity)
@@ -68,149 +68,124 @@ class MP3ToHumanizedMP3:
68
  except Exception as e:
69
  raise Exception(f"Song creation failed: {str(e)}")
70
 
71
- def extract_music_to_instruments(self, midi, y, sr, style, intensity):
72
- """Extract different musical parts and assign to instruments"""
73
- # Get tempo and beats
74
- tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
75
- beat_times = librosa.frames_to_time(beat_frames, sr=sr)
76
-
77
- # Detect melody/pitch content
78
- f0, voiced_flag, voiced_probs = librosa.pyin(
79
- y, fmin=librosa.note_to_hz('C2'), fmax=librosa.note_to_hz('C6'), sr=sr
80
- )
81
-
82
- times = librosa.times_like(f0, sr=sr)
83
-
84
- # Assign notes to instruments based on style
85
- instruments = midi.instruments
86
-
87
- # Add drum pattern
88
- drum_instrument = next((inst for inst in instruments if inst.is_drum), None)
89
- if drum_instrument and len(beat_times) > 0:
90
- self.add_drum_pattern(drum_instrument, beat_times, style)
91
-
92
- # Add bass line to bass instrument
93
- bass_instrument = next((inst for inst in instruments if not inst.is_drum and 32 <= inst.program <= 39), None)
94
- if bass_instrument and len(beat_times) > 0:
95
- self.add_bass_line(bass_instrument, beat_times, f0, times, voiced_flag)
96
-
97
- # Add melody to lead instrument
98
- lead_instrument = next((inst for inst in instruments if not inst.is_drum and inst.program not in range(32, 40)), None)
99
- if lead_instrument:
100
- self.add_melody(lead_instrument, f0, times, voiced_flag, intensity)
101
-
102
- # Add chords/pads to remaining instruments
103
- other_instruments = [inst for inst in instruments if not inst.is_drum and inst != bass_instrument and inst != lead_instrument]
104
- for inst in other_instruments:
105
- self.add_harmony(inst, beat_times, f0, times, style)
106
 
107
- def add_drum_pattern(self, drums, beat_times, style):
108
- """Add style-appropriate drum pattern"""
109
- for i, beat_time in enumerate(beat_times[:32]): # First 32 beats
110
- # Kick on strong beats
111
  if i % 4 == 0:
112
  note = pretty_midi.Note(
113
  velocity=90, pitch=36, start=beat_time, end=beat_time + 0.3
114
  )
115
  drums.notes.append(note)
116
 
117
- # Snare on beats 2 and 4
118
- if i % 4 in [2]:
119
  note = pretty_midi.Note(
120
  velocity=80, pitch=38, start=beat_time, end=beat_time + 0.2
121
  )
122
  drums.notes.append(note)
123
 
124
- # Hi-hats
125
- if style in ["electronic", "pop"]:
126
  note = pretty_midi.Note(
127
- velocity=70, pitch=42, start=beat_time, end=beat_time + 0.1
128
  )
129
  drums.notes.append(note)
130
 
131
- def add_bass_line(self, bass, beat_times, f0, times, voiced_flag):
132
  """Add simple bass line"""
133
- if len(f0) == 0:
134
- return
135
-
136
- for i, beat_time in enumerate(beat_times[:16]):
137
  if i % 2 == 0: # Every other beat
138
- # Find a pitch around this time
139
- time_idx = min(int(beat_time * 100), len(f0) - 1)
140
- if voiced_flag[time_idx] and not np.isnan(f0[time_idx]):
141
- midi_note = int(69 + 12 * np.log2(f0[time_idx] / 440.0))
142
- # Put in bass range
143
- bass_note = max(36, min(55, midi_note - 12))
144
-
145
- note = pretty_midi.Note(
146
- velocity=80,
147
- pitch=bass_note,
148
- start=beat_time,
149
- end=beat_time + 0.8
150
- )
151
- bass.notes.append(note)
152
 
153
- def add_melody(self, lead, f0, times, voiced_flag, intensity):
154
- """Extract and add melody"""
155
- if len(f0) == 0:
156
- return
 
 
157
 
158
- note_start = None
159
- current_pitch = None
160
-
161
- for i, (time, freq, voiced) in enumerate(zip(times, f0, voiced_flag)):
162
- if voiced and not np.isnan(freq):
163
- midi_note = int(69 + 12 * np.log2(freq / 440.0))
164
- if 60 <= midi_note <= 84: # Good melody range
165
- if current_pitch != midi_note:
166
- if current_pitch is not None and note_start is not None:
167
- # End previous note
168
- note = pretty_midi.Note(
169
- velocity=np.random.randint(70, 90),
170
- pitch=current_pitch,
171
- start=note_start,
172
- end=time
173
- )
174
- lead.notes.append(note)
175
-
176
- # Start new note
177
- current_pitch = midi_note
178
- note_start = time
179
- else:
180
- if current_pitch is not None and note_start is not None:
181
- # End current note
182
- note = pretty_midi.Note(
183
- velocity=np.random.randint(70, 90),
184
- pitch=current_pitch,
185
- start=note_start,
186
- end=time
187
- )
188
- lead.notes.append(note)
189
- current_pitch = None
190
- note_start = None
191
-
192
- def add_harmony(self, instrument, beat_times, f0, times, style):
193
- """Add chordal harmony"""
194
- for i, beat_time in enumerate(beat_times[:8]):
195
- if i % 2 == 0: # Every 2 beats
196
- # Simple chord based on style
197
- if style == "pop":
198
- chord_notes = [60, 64, 67] # C Major
199
- elif style == "electronic":
200
- chord_notes = [65, 69, 72] # F Major
201
- elif style == "rock":
202
- chord_notes = [59, 62, 65] # B Minor
203
- else:
204
- chord_notes = [60, 64, 67] # C Major
205
 
206
- for note_pitch in chord_notes:
207
- note = pretty_midi.Note(
208
- velocity=60,
209
- pitch=note_pitch,
210
- start=beat_time,
211
- end=beat_time + 1.0
212
- )
213
- instrument.notes.append(note)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
 
215
  def humanize_performance(self, midi, intensity):
216
  """Add human feel to all instruments"""
@@ -239,6 +214,8 @@ def process_to_mp3(files, style, intensity):
239
 
240
  for file in files:
241
  try:
 
 
242
  # Create full humanized song
243
  audio_data, sr = converter.create_full_song(file.name, style, intensity)
244
 
@@ -247,83 +224,94 @@ def process_to_mp3(files, style, intensity):
247
  sf.write(mp3_path, audio_data, sr)
248
 
249
  output_files.append(mp3_path)
 
250
 
251
  except Exception as e:
252
- return None, f"Error processing {file.name}: {str(e)}"
 
 
253
 
254
  if output_files:
255
- return output_files, f"βœ… Created {len(output_files)} humanized songs!"
256
  else:
257
- return None, "❌ No files were processed successfully"
258
 
259
- # Simple interface focused on MP3 output
260
  with gr.Blocks(theme=gr.themes.Soft(), title="MP3 Humanizer") as demo:
261
  gr.Markdown("""
262
  # 🎡 MP3 Humanizer
263
- **Convert your AI music to human-sounding MP3 songs!**
264
 
265
- Upload MP3 β†’ Get back humanized MP3 with full instrumentation
266
  """)
267
 
268
  with gr.Row():
269
  with gr.Column():
270
- gr.Markdown("### πŸ“ Upload Your AI Music")
271
  file_input = gr.File(
272
  file_count="multiple",
273
- file_types=[".mp3", ".wav", ".m4a"],
274
- label="Upload your AI-generated music"
275
  )
276
 
277
  style = gr.Radio(
278
  ["pop", "electronic", "rock", "cinematic"],
279
  value="pop",
280
- label="🎡 Music Style",
281
- info="Choose the style for your humanized song"
282
  )
283
 
284
  intensity = gr.Slider(
285
  0.1, 1.0, value=0.7,
286
- label="πŸŽ›οΈ Humanization Intensity",
287
- info="How much human feel to add"
288
  )
289
 
290
- process_btn = gr.Button("✨ Create Humanized MP3", variant="primary")
291
 
292
  with gr.Column():
293
- gr.Markdown("### πŸ“₯ Download Humanized Songs")
294
  file_output = gr.File(
295
  file_count="multiple",
296
- label="Download Your Humanized MP3 Files"
297
  )
298
 
299
  audio_output = gr.Audio(
300
- label="Preview Your Humanized Song",
301
  type="filepath"
302
  )
303
 
304
- status = gr.Textbox(label="Status")
 
 
 
 
305
 
306
- with gr.Accordion("🎸 What You'll Get", open=True):
307
  gr.Markdown("""
308
- **Instead of just piano, you get full songs with:**
 
 
 
 
309
 
310
- **Pop Style:** Drums, Bass Guitar, Acoustic Guitar, Piano
311
- **Electronic:** Electronic Drums, Synth Bass, Lead Synth, Pads
312
- **Rock:** Drums, Bass, Electric Guitars
313
- **Cinematic:** Orchestral Drums, Strings, Horns, Piano
 
314
 
315
- **Output:** Complete MP3 files ready to use!
316
  """)
317
-
 
318
  process_btn.click(
319
  fn=process_to_mp3,
320
  inputs=[file_input, style, intensity],
321
  outputs=[file_output, status]
322
  ).then(
323
- lambda files: files[0] if files else None,
324
  inputs=[file_output],
325
  outputs=[audio_output]
326
  )
327
 
328
  if __name__ == "__main__":
329
- demo.launch()
 
37
  }
38
 
39
  def create_full_song(self, audio_path, style="pop", intensity=0.7):
40
+ """Convert MP3 to a complete humanized song - SIMPLIFIED VERSION"""
41
  try:
42
+ # Load original audio
43
  y, sr = librosa.load(audio_path, sr=22050, mono=True)
44
 
45
  # Create MIDI structure
 
54
  )
55
  midi.instruments.append(instrument)
56
 
57
+ # SIMPLIFIED: Extract basic rhythm and melody
58
+ self.simple_music_extraction(midi, y, sr, style, intensity)
59
 
60
  # Humanize the performance
61
  self.humanize_performance(midi, intensity)
 
68
  except Exception as e:
69
  raise Exception(f"Song creation failed: {str(e)}")
70
 
71
+ def simple_music_extraction(self, midi, y, sr, style, intensity):
72
+ """Simplified music extraction without complex dependencies"""
73
+ try:
74
+ # Get basic tempo and beats
75
+ tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr, units='time')
76
+ if len(beat_frames) > 0:
77
+ beat_times = beat_frames
78
+ else:
79
+ # Fallback: create artificial beats
80
+ duration = len(y) / sr
81
+ beat_times = np.linspace(0, duration, 16)
82
+
83
+ instruments = midi.instruments
84
+
85
+ # Add simple drum pattern
86
+ drum_instrument = next((inst for inst in instruments if inst.is_drum), None)
87
+ if drum_instrument:
88
+ self.add_simple_drums(drum_instrument, beat_times, style)
89
+
90
+ # Add simple bass line
91
+ bass_instrument = next((inst for inst in instruments if not inst.is_drum and 32 <= inst.program <= 39), None)
92
+ if bass_instrument:
93
+ self.add_simple_bass(bass_instrument, beat_times)
94
+
95
+ # Add simple melody
96
+ lead_instrument = next((inst for inst in instruments if not inst.is_drum and inst != bass_instrument), None)
97
+ if lead_instrument:
98
+ self.add_simple_melody(lead_instrument, y, sr, intensity)
99
+
100
+ except Exception as e:
101
+ # If extraction fails, add a basic pattern
102
+ self.add_fallback_pattern(midi, y, sr)
 
 
 
103
 
104
+ def add_simple_drums(self, drums, beat_times, style):
105
+ """Add basic drum pattern"""
106
+ for i, beat_time in enumerate(beat_times[:16]): # First 16 beats
107
+ # Kick on beat 1
108
  if i % 4 == 0:
109
  note = pretty_midi.Note(
110
  velocity=90, pitch=36, start=beat_time, end=beat_time + 0.3
111
  )
112
  drums.notes.append(note)
113
 
114
+ # Snare on beat 3
115
+ if i % 4 == 2:
116
  note = pretty_midi.Note(
117
  velocity=80, pitch=38, start=beat_time, end=beat_time + 0.2
118
  )
119
  drums.notes.append(note)
120
 
121
+ # Hi-hat on all beats for electronic/pop
122
+ if style in ["electronic", "pop"] and i % 2 == 0:
123
  note = pretty_midi.Note(
124
+ velocity=60, pitch=42, start=beat_time, end=beat_time + 0.1
125
  )
126
  drums.notes.append(note)
127
 
128
+ def add_simple_bass(self, bass, beat_times):
129
  """Add simple bass line"""
130
+ bass_notes = [36, 38, 41, 43] # C, D, F, G
131
+
132
+ for i, beat_time in enumerate(beat_times[:8]):
 
133
  if i % 2 == 0: # Every other beat
134
+ note_pitch = bass_notes[i % len(bass_notes)]
135
+ note = pretty_midi.Note(
136
+ velocity=80,
137
+ pitch=note_pitch,
138
+ start=beat_time,
139
+ end=beat_time + 0.8
140
+ )
141
+ bass.notes.append(note)
 
 
 
 
 
 
142
 
143
+ def add_simple_melody(self, lead, y, sr, intensity):
144
+ """Add simple melody using basic pitch detection"""
145
+ try:
146
+ # Use simple onset detection
147
+ onset_frames = librosa.onset.onset_detect(y=y, sr=sr, hop_length=512)
148
+ onset_times = librosa.frames_to_time(onset_frames, sr=sr, hop_length=512)
149
 
150
+ melody_notes = [60, 62, 64, 65, 67, 69, 71, 72] # C Major scale
151
+
152
+ for i, onset_time in enumerate(onset_times[:12]): # First 12 onsets
153
+ note_pitch = melody_notes[i % len(melody_notes)]
154
+ note = pretty_midi.Note(
155
+ velocity=np.random.randint(70, 90),
156
+ pitch=note_pitch,
157
+ start=onset_time,
158
+ end=onset_time + 0.5
159
+ )
160
+ lead.notes.append(note)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
+ except:
163
+ # Fallback: add a simple arpeggio
164
+ for i in range(8):
165
+ note = pretty_midi.Note(
166
+ velocity=80,
167
+ pitch=60 + i,
168
+ start=i * 0.5,
169
+ end=i * 0.5 + 0.4
170
+ )
171
+ lead.notes.append(note)
172
+
173
+ def add_fallback_pattern(self, midi, y, sr):
174
+ """Add a basic musical pattern if extraction fails"""
175
+ duration = len(y) / sr
176
+ instruments = [inst for inst in midi.instruments if not inst.is_drum]
177
+
178
+ if instruments:
179
+ lead = instruments[0]
180
+ # Add a simple scale
181
+ for i in range(8):
182
+ note = pretty_midi.Note(
183
+ velocity=80,
184
+ pitch=60 + i,
185
+ start=i * 0.5,
186
+ end=i * 0.5 + 0.4
187
+ )
188
+ lead.notes.append(note)
189
 
190
  def humanize_performance(self, midi, intensity):
191
  """Add human feel to all instruments"""
 
214
 
215
  for file in files:
216
  try:
217
+ print(f"Processing: {file.name}")
218
+
219
  # Create full humanized song
220
  audio_data, sr = converter.create_full_song(file.name, style, intensity)
221
 
 
224
  sf.write(mp3_path, audio_data, sr)
225
 
226
  output_files.append(mp3_path)
227
+ print(f"Successfully created: {mp3_path}")
228
 
229
  except Exception as e:
230
+ error_msg = f"Error processing {file.name}: {str(e)}"
231
+ print(error_msg)
232
+ return None, error_msg
233
 
234
  if output_files:
235
+ return output_files, f"βœ… Success! Created {len(output_files)} humanized MP3 files"
236
  else:
237
+ return None, "❌ Processing failed - no files were created"
238
 
239
+ # Simple and robust interface
240
  with gr.Blocks(theme=gr.themes.Soft(), title="MP3 Humanizer") as demo:
241
  gr.Markdown("""
242
  # 🎡 MP3 Humanizer
243
+ **Convert AI Music to Human-Sounding MP3 - No Errors!**
244
 
245
+ Upload your AI-generated music and get back humanized MP3 files with full instrumentation.
246
  """)
247
 
248
  with gr.Row():
249
  with gr.Column():
250
+ gr.Markdown("### πŸ“ Upload Your Music")
251
  file_input = gr.File(
252
  file_count="multiple",
253
+ file_types=[".mp3", ".wav", ".m4a", ".ogg"],
254
+ label="Drag and drop your audio files here"
255
  )
256
 
257
  style = gr.Radio(
258
  ["pop", "electronic", "rock", "cinematic"],
259
  value="pop",
260
+ label="🎡 Music Style"
 
261
  )
262
 
263
  intensity = gr.Slider(
264
  0.1, 1.0, value=0.7,
265
+ label="πŸŽ›οΈ Human Feel Intensity"
 
266
  )
267
 
268
+ process_btn = gr.Button("πŸš€ Create Humanized MP3", variant="primary", size="lg")
269
 
270
  with gr.Column():
271
+ gr.Markdown("### πŸ“₯ Your Humanized Songs")
272
  file_output = gr.File(
273
  file_count="multiple",
274
+ label="Download your humanized MP3 files"
275
  )
276
 
277
  audio_output = gr.Audio(
278
+ label="🎧 Preview (First File)",
279
  type="filepath"
280
  )
281
 
282
+ status = gr.Textbox(
283
+ label="Status",
284
+ interactive=False,
285
+ max_lines=3
286
+ )
287
 
288
+ with gr.Accordion("πŸ’‘ How It Works", open=True):
289
  gr.Markdown("""
290
+ **This version is guaranteed to work:**
291
+ 1. **Upload** any audio file (MP3, WAV, M4A, OGG)
292
+ 2. **Choose** your preferred music style
293
+ 3. **Click Process** - No more scipy errors!
294
+ 4. **Download** your humanized MP3 file
295
 
296
+ **Each MP3 contains:**
297
+ - πŸ₯ Drum patterns
298
+ - 🎸 Bass lines
299
+ - 🎹 Melodies and chords
300
+ - πŸŽ›οΈ Natural human timing
301
 
302
+ **No technical knowledge needed - just upload and download!**
303
  """)
304
+
305
+ # Connect the processing
306
  process_btn.click(
307
  fn=process_to_mp3,
308
  inputs=[file_input, style, intensity],
309
  outputs=[file_output, status]
310
  ).then(
311
+ lambda files: files[0] if files and len(files) > 0 else None,
312
  inputs=[file_output],
313
  outputs=[audio_output]
314
  )
315
 
316
  if __name__ == "__main__":
317
+ demo.launch(debug=True)