File size: 5,126 Bytes
9857383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import moviepy.editor as mp
import numpy as np
import librosa
import librosa.display
import matplotlib.pyplot as plt
import io
import os

# Funci贸n principal para generar el video
def audio_to_video(audio_file, image_file, effect_type="waveform"):
    """
    Genera un video a partir de un archivo de audio y una imagen, con un efecto visual sincronizado.

    Args:
        audio_file: Ruta al archivo de audio (wav o mp3).
        image_file: Ruta al archivo de imagen (debe ser un formato soportado por MoviePy).
        effect_type: Tipo de efecto visual a utilizar ("waveform" por defecto, otros tipos se pueden agregar).

    Returns:
        Ruta al archivo de video generado (mp4).  Si falla, retorna un mensaje de error.
    """
    try:
        # 1. Cargar el audio usando Librosa
        y, sr = librosa.load(audio_file)
        duration = librosa.get_duration(y=y, sr=sr)

        # 2. Cargar la imagen
        img_clip = mp.ImageClip(image_file)
        img_clip = img_clip.set_duration(duration)  # Asignar la duraci贸n del audio a la imagen

        # 3. Generar el efecto visual
        if effect_type == "waveform":
            audio_envelope = np.abs(y)  # Calculate the audio envelope

            # Normalize audio envelope to image dimensions
            audio_envelope = audio_envelope / np.max(audio_envelope)
            audio_envelope = audio_envelope * img_clip.size[1] / 2  # Scale to half the image height


            def make_frame(t):
                # Create a new figure for each frame
                fig, ax = plt.subplots(figsize=(img_clip.size[0]/100, img_clip.size[1]/100), dpi=100) # Adjust figsize for image dimensions
                ax.set_xlim(0, duration)
                ax.set_ylim(-img_clip.size[1] / 2, img_clip.size[1] / 2)
                ax.axis('off')  # Hide axis

                # Plot waveform
                time_index = int(t * sr)
                wave_slice = audio_envelope[max(0,time_index - sr//10):min(len(audio_envelope), time_index + sr//10)]
                time_slice = np.linspace(0,0.2,len(wave_slice))
                ax.plot(np.linspace(t-0.1,t+0.1,len(wave_slice)), wave_slice-img_clip.size[1]/4, color='red')
                ax.plot(np.linspace(t-0.1,t+0.1,len(wave_slice)), -wave_slice+img_clip.size[1]/4, color='red')


                # Convert the Matplotlib figure to an image
                buf = io.BytesIO()
                fig.canvas.print_png(buf)
                data = np.frombuffer(buf.getvalue(), dtype=np.uint8)
                img = plt.imread(io.BytesIO(data)) #read as image
                plt.close(fig) # Close the figure to prevent memory leaks
                return img


            audio_effect_clip = mp.VideoClip(make_frame, duration=duration)
            audio_effect_clip = audio_effect_clip.set_fps(24)  # Set a reasonable frame rate

        else:
            return "Error: Efecto visual no soportado."

        # 4.  Overlay effect onto image
        final_clip = mp.CompositeVideoClip([img_clip, audio_effect_clip.set_pos("center")])


        # 5. Agregar el audio al video
        audio_clip = mp.AudioFileClip(audio_file)
        final_clip = final_clip.set_audio(audio_clip)


        # 6. Guardar el video
        output_video_path = "output.mp4"
        final_clip.write_videofile(output_video_path, fps=24, codec="libx264", audio_codec="aac")  # Ajustar los par谩metros de codificaci贸n seg煤n sea necesario
        return output_video_path

    except Exception as e:
        return f"Error: {str(e)}"


# ----------------------------------
# Gradio Interface
# ----------------------------------

iface = gr.Interface(
    fn=audio_to_video,
    inputs=[
        gr.Audio(source="upload", type="filepath", label="Subir Archivo de Audio (WAV o MP3)"),
        gr.Image(source="upload", type="filepath", label="Subir Imagen"),
        gr.Radio(["waveform"], value="waveform", label="Tipo de Efecto Visual (Waveform es el 煤nico soportado por ahora)")
    ],
    outputs="video",
    title="Audio to Video Generator",
    description="Sube un archivo de audio y una imagen para crear un video con un efecto visual sincronizado con la m煤sica.  Por ahora solo funciona el efecto 'waveform'.",
    examples=[["audio_example.wav", "image_example.jpg", "waveform"]] # Add example files if you want.
)


# ----------------------------------
#  Example files (optional).  Create these files
#  or remove the 'examples' line above.
# ----------------------------------
# Create dummy audio and image for example purposes if they don't exist
if not os.path.exists("audio_example.wav"):
    sr = 22050
    T = 5
    t = np.linspace(0, T, int(T*sr), endpoint=False)
    x = 0.5*np.sin(2*np.pi*440*t)  # A4 frequency
    librosa.output.write_wav("audio_example.wav", x, sr)

if not os.path.exists("image_example.jpg"):
    # Create a simple placeholder image
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(figsize=(6,4))
    ax.text(0.5, 0.5, "Placeholder Image", ha="center", va="center")
    ax.axis("off")
    fig.savefig("image_example.jpg")
    plt.close(fig)



iface.launch()