Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import pretty_midi | |
| import numpy as np | |
| import tempfile | |
| import librosa | |
| import soundfile as sf | |
| import os | |
| class SimpleMP3Humanizer: | |
| def __init__(self): | |
| self.style_presets = { | |
| "pop": [0, 33, 25, 1], # Drums, Bass, Guitar, Piano | |
| "electronic": [0, 39, 81, 89], # Drums, Synth Bass, Lead, Pad | |
| "rock": [0, 33, 30, 27], # Drums, Bass, Distortion Guitar, Clean Guitar | |
| "cinematic": [0, 48, 61, 5] # Drums, Strings, Horn, Piano | |
| } | |
| def mp3_to_humanized_mp3(self, mp3_path, style="pop", intensity=0.7): | |
| """Convert MP3 to humanized MP3 in one step""" | |
| try: | |
| # Load the MP3 | |
| y, sr = librosa.load(mp3_path, sr=22050, mono=True) | |
| duration = len(y) / sr | |
| # Create MIDI | |
| midi = pretty_midi.PrettyMIDI() | |
| # Add instruments | |
| for program in self.style_presets[style]: | |
| is_drum = (program == 0) | |
| instrument = pretty_midi.Instrument(program=program, is_drum=is_drum) | |
| midi.instruments.append(instrument) | |
| # Create simple music based on audio | |
| self.create_simple_music(midi, y, sr, duration, style, intensity) | |
| # Add human feel | |
| self.add_human_touch(midi, intensity) | |
| # Convert to audio | |
| audio_data = midi.synthesize() | |
| return audio_data, sr | |
| except Exception as e: | |
| raise Exception(f"Conversion failed: {str(e)}") | |
| def create_simple_music(self, midi, y, sr, duration, style, intensity): | |
| """Create basic musical structure""" | |
| # Create beats | |
| num_beats = max(8, min(32, int(duration * 2))) # 2 beats per second | |
| beat_times = np.linspace(0, duration, num_beats) | |
| instruments = midi.instruments | |
| # Add drums | |
| drums = next((inst for inst in instruments if inst.is_drum), None) | |
| if drums: | |
| for i, time in enumerate(beat_times): | |
| # Kick on strong beats | |
| if i % 4 == 0: | |
| drums.notes.append(self.create_note(36, 90, time, 0.3)) | |
| # Snare on off-beats | |
| if i % 4 == 2: | |
| drums.notes.append(self.create_note(38, 80, time, 0.2)) | |
| # Hi-hats for electronic/pop | |
| if style in ["electronic", "pop"]: | |
| drums.notes.append(self.create_note(42, 70, time, 0.1)) | |
| # Add bass | |
| bass = next((inst for inst in instruments if not inst.is_drum and 32 <= inst.program <= 39), None) | |
| if bass: | |
| bass_notes = [36, 38, 41, 43, 45, 48] # Simple bass line | |
| for i, time in enumerate(beat_times[::2]): # Every other beat | |
| if i < len(bass_notes): | |
| bass.notes.append(self.create_note(bass_notes[i], 85, time, 0.8)) | |
| # Add melody | |
| melody_instruments = [inst for inst in instruments if not inst.is_drum and inst.program not in range(32, 40)] | |
| if melody_instruments: | |
| melody = melody_instruments[0] | |
| melody_notes = [60, 62, 64, 65, 67, 69, 71, 72] # C major scale | |
| for i, time in enumerate(beat_times[::4]): # Every 4 beats | |
| if i < len(melody_notes): | |
| melody.notes.append(self.create_note(melody_notes[i], 80, time, 1.0)) | |
| def create_note(self, pitch, velocity, start, duration): | |
| """Helper to create a note""" | |
| return pretty_midi.Note( | |
| velocity=velocity, | |
| pitch=pitch, | |
| start=start, | |
| end=start + duration | |
| ) | |
| def add_human_touch(self, midi, intensity): | |
| """Add humanization to the music""" | |
| for instrument in midi.instruments: | |
| for note in instrument.notes: | |
| # Random timing | |
| note.start += np.random.normal(0, 0.02 * intensity) | |
| note.start = max(0, note.start) | |
| # Random velocity | |
| note.velocity += int(np.random.normal(0, 10 * intensity)) | |
| note.velocity = max(40, min(127, note.velocity)) | |
| # Random duration for non-drums | |
| if not instrument.is_drum: | |
| note.end += np.random.normal(0, 0.05 * intensity) | |
| note.end = max(note.start + 0.1, note.end) | |
| def convert_mp3(input_mp3, style, intensity): | |
| """Main conversion function""" | |
| if input_mp3 is None: | |
| return None, "Please upload an MP3 file" | |
| converter = SimpleMP3Humanizer() | |
| try: | |
| # Convert to humanized MP3 | |
| audio_data, sr = converter.mp3_to_humanized_mp3(input_mp3, style, intensity) | |
| # Save as temporary MP3 file | |
| output_path = tempfile.mktemp(suffix='_humanized.mp3') | |
| sf.write(output_path, audio_data, sr) | |
| return output_path, "β Conversion successful! Your humanized song is ready below." | |
| except Exception as e: | |
| return None, f"β Error: {str(e)}" | |
| # Simple and compatible interface | |
| with gr.Blocks(theme=gr.themes.Soft(), title="MP3 Humanizer") as demo: | |
| gr.Markdown(""" | |
| # π΅ MP3 Humanizer | |
| **Upload AI Music β Get Human Version β Download MP3** | |
| """) | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 1. Upload Your AI Song") | |
| input_audio = gr.Audio( | |
| sources=["upload"], | |
| type="filepath", | |
| label="Upload MP3 File" | |
| ) | |
| gr.Markdown("### 2. Choose Settings") | |
| style = gr.Radio( | |
| ["pop", "electronic", "rock", "cinematic"], | |
| value="pop", | |
| label="Music Style" | |
| ) | |
| intensity = gr.Slider( | |
| 0.1, 1.0, value=0.7, | |
| label="Human Feel Intensity" | |
| ) | |
| convert_btn = gr.Button( | |
| "β¨ Convert to Human Version", | |
| variant="primary", | |
| size="lg" | |
| ) | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 3. Download Result") | |
| output_audio = gr.Audio( | |
| label="Your Humanized Song", | |
| type="filepath", | |
| interactive=False | |
| ) | |
| status = gr.Textbox( | |
| label="Status", | |
| interactive=False | |
| ) | |
| # Simple instructions | |
| with gr.Accordion("π How to Use", open=True): | |
| gr.Markdown(""" | |
| 1. **Upload** your AI-generated MP3 file | |
| 2. **Choose** your preferred music style | |
| 3. **Adjust** the human feel slider | |
| 4. **Click Convert** and wait a few seconds | |
| 5. **Play the preview** to hear your humanized song | |
| 6. **Click the download icon** in the audio player to save your MP3 | |
| That's it! You'll get a complete MP3 file with drums, bass, melody, and human-sounding timing. | |
| """) | |
| # Conversion process | |
| def process_conversion(input_mp3, style, intensity): | |
| output_path, message = convert_mp3(input_mp3, style, intensity) | |
| return output_path, message | |
| convert_btn.click( | |
| fn=process_conversion, | |
| inputs=[input_audio, style, intensity], | |
| outputs=[output_audio, status] | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() |