Blog

Edit to the beat (standalone app)

User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

Photographers often ask me to edit a short film with their photos on weddings.

It´s a little bit stressful once i usualy have to edit a SDE aswell so i decided to make a small app in Python that does it automatically. 

 

                                                               

The code:

import contextlib
import csv
import os
import tkinter
import tkinter as tk
import wave
from tkinter import *
from tkinter import filedialog
import ffmpeg
import librosa
import matplotlib.pyplot as plt
import numpy as np
from PIL import ImageTk, Image
#from moviepy.editor import VideoFileClip, concatenate_videoclips
import cv2
#import moviepy.editor
import cv
from tkinter.filedialog import asksaveasfile
from tqdm import tqdm
import time
from tkinter.ttk import *
import webbrowser
from mhmovie.code import *




root = Tk()
root.title('Edit to the beat')
root.geometry("809x470")
pane = Frame(root)
pane.grid(row=0,column=0)
pane_2=Frame(root)
pane_2.grid(row=1,column=0)
pane_3=Frame(root)
pane_3.grid(row=20,column=0)

file_path_2 = ""


def beat_estimate():

    root = tk.Tk()

    root.withdraw()

    global file_path_2
    file_path_2 = ""
    file_path_2 = filedialog.askopenfilename(filetypes=(("Audio Files", ".wav "),))
    y, sr = librosa.load(file_path_2)

    #y, sr = librosa.load('/Users/User/Desktop/Patrick_M/Casamentos_musica/heading-home---short-version_by_zac-nelson_Artlist.wav')
    #y, sr = librosa.load(librosa.util.example_audio_file())
    tempo, beats = librosa.beat.beat_track(y, sr=sr, units='frames')
    librosa.output.times_csv('beat_times_11.csv', beats)


    onset_env = librosa.onset.onset_strength(y, sr=sr,aggregate=np.median)
    tempo, beats = librosa.beat.beat_track(onset_envelope=onset_env,sr=sr)
    global tempo_2
    tempo_2 = (librosa.beat.tempo(onset_envelope=onset_env, sr=sr))
    print(tempo_2)

    tempo
    64.599609375

    beats[:20]
    ([ 320,  357,  397,  436,  480,  525,  569,  609,  658,
            698,  737,  777,  817,  857,  896,  936,  976, 1016,
           1055, 1095])
    hop_length = 512
    plt.figure(figsize=(8, 4))
    times = librosa.times_like(onset_env, sr=sr, hop_length=hop_length)
    plt.plot(times, librosa.util.normalize(onset_env),label='Onset strength')
    plt.vlines(times[beats], 0, 1, alpha=0.5, color='r',linestyle='--', label='Beats')
    plt.legend(frameon=True, framealpha=0.75)

    #plt.xlim(0,60)
    plt.tight_layout()
    #plt.savefig('/Users/User/PycharmProjects/SDE_maker/beats.png')
    plt.savefig('beats.png')
    #plt.show()

    global beat_img
    beat_img = ImageTk.PhotoImage(Image.open("beats.png"))
    my_label = Label(pane_2,image=beat_img)
    #my_label.pack(side = LEFT, expand = True, fill = BOTH)
    my_label.grid(row=2,column=0,sticky=W)


    input_file = open("beat_times_11.csv", "r+")
    global reader_file
    reader_file = (csv.reader(input_file,quoting=csv.QUOTE_NONNUMERIC))


    #for row in reader_file:
        #if (row):
            #z = float(row[0])
            #print(z)




    global value
    value = round(len(list(reader_file)) / 2, 2)
    print(value)





    fname = file_path_2
    with contextlib.closing(wave.open(fname, 'r')) as f:
        frames = f.getnframes()
        rate = f.getframerate()
        global duration
        duration = round(frames / float(rate),2)
        print(duration)
        print(frames)
        print(rate)



    my_label_2 = Label(pane_2,text="Beat events --> " + str(value) + " beats" + "\n"+
                             "  " +"Duration -->" + str(duration) + " seconds" + "\n"+
          "        "           +"Tempo -->" + str(tempo_2) + " BPM" + "             ")
    my_label_2.grid(row=2,column=0,sticky=W)
    #my_label_2.pack(side = LEFT, expand = True, fill = BOTH)




my_Button = Button(pane, text="Estimate beats",command=beat_estimate,width=32,state=DISABLED)
my_Button.grid(row=0,column=0)
#my_Button.pack(side = LEFT, expand = True, fill = BOTH)


#fourcc = cv2.VideoWriter_fourcc(*'MJPG')

#file_6 = ""
def concatenate():
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    fps = 43.1034482759
    out = cv2.VideoWriter('output.AVI', fourcc, fps, (1920, 1080))


    input_file = open("beat_times_11.csv", "r+")
    global reader_file
    reader_file = ""
    reader_file = (csv.reader(input_file, quoting=csv.QUOTE_NONNUMERIC))


    image_formats = [("JPEG", "*.jpg","*.png")]
    file_path_list = tkinter.filedialog.askopenfilenames( initialdir="/",
                                      title='Please select pictures to make vídeo',filetypes = (("jpeg files","*.jpg"),))
    #l = len(file_path_list)
    pbar = tqdm(total=value)
    progress = Progressbar(root, orient=HORIZONTAL,
                           length=750, mode='determinate')

    #print(file_path_list)
    #ImageTk.PhotoImage(Image.open(file_path_list))
    i = 1
    global soma
    soma = 0
    for file_path in file_path_list:
        pbar.update(1)
        soma = (soma + (100/value))
        progress['value'] = soma
        progress.grid(row=3, column=0)
        #progress.pack(side = LEFT)
        root.update_idletasks()
        for row in reader_file:
            if (row):
                z = float(row[0])
                #print(z)
                #i+=1

                break

        while i<=z:
            #print(i)
            #frame = cv2.VideoCapture(file_path)
            frame = cv2.imread(file_path)
            #out.VideoWriter(frame)
            out.write(frame)
            #cv2.imshow('video', frame)
            if (cv2.waitKey(1) & 0xFF) == ord('q'):  # Hit `q` to exit
                break
            i+=1
    final = out.release()
    cv2.destroyAllWindows()
    print(file_path_2)
    video = ffmpeg.input('output.AVI')
    audio = ffmpeg.input(file_path_2)

    #m = movie("output.AVI")
    #mu = music(file_path_2)
    #mu.Aconvert()  # convert wav to mp3


    #out_2 = ffmpeg.output(video, audio, 'final', vcodec='copy', acodec='aac', strict='experimental')
    #files = [('All Files', '*.*')]
    pbar.update(1)
    soma = 0
    progress['value'] = soma
    progress.grid(row=3, column=0)

    file_5 = asksaveasfile()
    pbar.update(1)
    soma = 60
    progress['value'] = soma
    progress.grid(row=3, column=0)
    root.update_idletasks()
    global file_6
    file_6=""
    file_6 = file_5.name + ".mp4"
    print(file_6)



    #out_2 = ffmpeg.output(video, audio,'final_2.mp4')

    out_2 = ffmpeg.output(video, audio,file_6)
    out_2.run()

    #final = m + mu
    #final.save(file_6)

    pbar.update(1)
    soma = 100
    progress['value'] = soma
    progress.grid(row=3, column=0)
    #final.write_videofile("output.AVI", audio=file_path_2)
    pbar = ""
def play_video():
    print(file_6)
    os.startfile(file_6)



def activate():
    my_Button_2 = Button(pane, text="Make mp.4", command=concatenate, width=32,state=NORMAL)
    my_Button_2.grid(row=0, column=1)
    my_Button = Button(pane, text="Estimate beats", command=beat_estimate, width=32, state=NORMAL)
    my_Button.grid(row=0, column=0)
    my_Button_3 = Button(pane, text="Play video", command=play_video, width=32, state=NORMAL)
    my_Button_3.grid(row=0, column=2)
    webbrowser.open("http://patrickmvideographer.com/en/blog-en/94-sde-maker")



my_Button_2 = Button(pane, text="Make mp.4",command=concatenate,width=32,state=DISABLED)
#my_Button_2.config(width=20)
my_Button_2.grid(row=0,column=1)
#my_Button_2.pack(side = LEFT, expand = True, fill = BOTH)

my_Button_3 = Button(pane, text="Play video",command=play_video,width=32,state=DISABLED)
my_Button_3.grid(row=0,column=2)
#my_Button_3.pack(side = LEFT, expand = True, fill = BOTH)

my_Button_4 = Button(pane, text="Activate",command=activate,width=32)
my_Button_4.grid(row=0,column=3)



root.mainloop()

 

How it works:

 Click Estimate Beats button and choose song (wav files only).

 

 

Wait for the info. It will output the song duration, tempo and beats. 

 

 

Click Make MP4 button and choose pics (the number of files should be at least equal to the number of beats of the choosen song).

IMPORTANT: The files must have jpeg extension and size 1920x1080 in order to work.

 

 

Choose the desired path and click save.

 

 

Click Play video button to watch the final result.

 

 Download:

You can safely download this small app bi clicking HERE

 

 

 

Comments powered by CComment