File size: 7,114 Bytes
ac3b66c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57d8aad
ac3b66c
 
 
 
 
 
07a2c80
ac3b66c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195b17b
 
3333b22
195b17b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ac3b66c
 
195b17b
ac3b66c
195b17b
ac3b66c
195b17b
 
ac3b66c
195b17b
 
ac3b66c
195b17b
 
ac3b66c
195b17b
 
 
 
ac3b66c
 
195b17b
 
 
 
 
 
ac3b66c
 
 
 
 
195b17b
ac3b66c
 
195b17b
 
ac3b66c
195b17b
 
 
 
 
ac3b66c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195b17b
 
 
 
 
 
 
 
 
 
 
ac3b66c
 
 
 
 
 
 
195b17b
 
 
 
 
ac3b66c
 
 
 
195b17b
 
 
 
ac3b66c
 
 
 
195b17b
ac3b66c
 
 
195b17b
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import os
import ffmpeg
import uuid
import streamlit as st
import shutil
import logging

logging.basicConfig(level=logging.INFO)  # Set the logging level

def log_info(message):
    logging.info(message)

def log_error(error_message):
    logging.error(error_message)

# Function to extract audio using ffmpeg
def convert_audio(input_file):
    audio_file = f"{input_file}.wav"
    ffmpeg.input(input_file).output(audio_file, ar=48000, ac=1).run()
    return audio_file

# Function to split audio into segments
def split_audio(audio_file):
    segment_pattern = os.path.splitext(audio_file)[0] + ".segmented_%03d.wav"
    ffmpeg.input(audio_file).output(segment_pattern, f="segment", segment_time=300).run()
    return segment_pattern

# Function to filter each audio segment
def filter_audio(segments):
    filtered_dir = "temp-out"
    os.makedirs(filtered_dir, exist_ok=True)
    os.system(f"deepFilter -a 15 -o {filtered_dir} {segments.replace('%03d.wav', '')}*.wav")
    os.system(f"rm {segments.replace('%03d.wav', '')}*.wav")
    return filtered_dir

# Function to combine filtered segments using sox
def combine_segments(filtered_dir, output_file):
    os.system(f"sox {filtered_dir}/*.wav {output_file}")
    return output_file

# Function to check if input file is video
def is_video(input_file):
    result = os.popen(f"ffprobe -v error -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 {input_file}").read()
    return "video" in result.lower()

# Function to get format info for audio files
def get_format_info(input_file):
    result = os.popen(f"ffprobe -v error -show_entries stream=codec_name -of default=noprint_wrappers=1:nokey=1 {input_file}").read()
    return result

# Function to increase volume of audio with sox
def increase_volume(input_file):
    os.system(f"sox -v 1.25 {input_file} {input_file}.vol.wav")
    os.rename(f"{input_file}.vol.wav", input_file)
    return input_file

def restore_metadata(input, output):
    os.system(f"ffmpeg -y -i {input} -c copy -map_metadata 0 -f ffmetadata {input}.txt")
    
    lines = open(f"{input}.txt").readlines()

    if len(lines) > 1:
        lines = [lines[0],] + [line for line in lines if any(x in line for x in ("title", "artist", "album", "track", "date", "comment"))]
        open(f"{input}.txt", "w").writelines(lines)
        os.system(f"ffmpeg -y -i {output} -f ffmetadata -i {input}.txt -c copy -map_metadata 1 fixed.{output}")
        os.rename(f"fixed.{output}", output)

    os.remove(f"{input}.txt")
    return output

def override_metadata(output, title="", artist="", album=""):
    lines = [";FFMETADATA1", f"title={title}", f"artist={artist}", f"album={album}"]
    open(f"{output}.txt", "w").write("\n".join(lines) + "\n")

    # strip existing metadata
    os.system(f"ffmpeg -y -i {output} -map_metadata -1 -c:v copy -c:a copy temp.{output}")

    # add new metadata
    os.system(f"ffmpeg -y -i temp.{output} -f ffmetadata -i {output}.txt -c copy -map_metadata 1 {output}")

    os.remove(f"temp.{output}")
    os.remove(f"{output}.txt")
    return output

def get_samplerate(input_file):
    result = os.popen(f"ffprobe -v error -show_entries stream=sample_rate -of default=noprint_wrappers=1:nokey=1 {input_file}").read()
    return int(result.strip())

# Function to handle video or audio input
def process_input(input_file, convert_to_mp3=False):
    try:
        # extract audio from video and convert to wav
        audio_file = convert_audio(input_file)

        # split audio into smaller segments
        segments = split_audio(audio_file)

        # filter each segment
        filtered_dir = filter_audio(segments)

        # combine filtered segments
        output_file = combine_segments(filtered_dir, f"{input_file}.filtered.wav")
        shutil.rmtree(filtered_dir) # delete temp directory

        # increase volume
        output_file = increase_volume(output_file)
        output_format = input_file.split(".")[-1]

        if convert_to_mp3:
            output_format = "mp3"

        processed_file = f"filtered-{input_file}.{output_format}"

        if output_format in ["mp4", "mkv", "webm", "avi", "mov", "flv", "wmv", "m4v"]:
            audio_aac_file = f"filtered-{input_file}.aac"
            ffmpeg.input(output_file).output(audio_aac_file, ar=44100, codec="aac").run()

            video_stream = ffmpeg.input(input_file).video
            audio_aac_stream = ffmpeg.input(audio_aac_file).audio
            ffmpeg.output(video_stream, audio_aac_stream, processed_file, vcodec="copy", acodec="copy").run()
            os.remove(audio_aac_file)
        else:
            sample_rate = 16000 if convert_to_mp3 else get_samplerate(input_file) 
            ffmpeg.input(output_file).output(processed_file, ac=1, ar=16000 if sample_rate < 16000 else sample_rate).run()

        os.remove(output_file)
        os.remove(audio_file)

        restore_metadata(input_file, processed_file)
        return processed_file

    except Exception as e:
        log_error(f"Error occurred during processing: {str(e)}")
        return None

# Streamlit UI
st.title("Audio Enhancement with Deep Filter")

uploaded_file = st.file_uploader("Upload a file", type=["mp4", "wav", "mp3", "aac", "m4a", "flac", "ogg", "opus", "wma", "webm", "mkv"])

if uploaded_file is not None:
    try:
        file_details = {"FileName": uploaded_file.name, "FileType": uploaded_file.type, "FileSize": uploaded_file.size}
        st.write(file_details)

        convert_to_mp3 = st.toggle("Convert to MP3", False)
        title = st.text_input("Title", "")
        artist = st.text_input("Artist", "")
        album = st.text_input("Album", "")

        args = {
            "title": title,
            "artist": artist,
            "album": album,
        }

        if st.button("Process File"):
            # generate a random file name to save the uploaded file
            file_path = f"temp-{str(uuid.uuid4())[:8]}.{uploaded_file.name.split('.')[-1]}"

            with open(file_path, "wb") as f:
                f.write(uploaded_file.getbuffer())

            output_file_path = process_input(file_path, convert_to_mp3=convert_to_mp3)

            # Override metadata if any
            if title or artist or album:
                override_metadata(output_file_path, title=title, artist=artist, album=album)

            if output_file_path and os.path.exists(output_file_path):
                data = open(output_file_path, "rb").read()
                os.remove(file_path)
                os.remove(output_file_path)

                # uploaded file name without extension
                download_name = "filtered-" + uploaded_file.name.split('.')[0] + "." + output_file_path.split(".")[-1]

                st.success("File processed successfully!")
                st.download_button(label="Download Processed File", 
                                    data=data,
                                    file_name=download_name)
            else:
                st.error("File processing failed.")
    except Exception as e:
        log_error(f"Error occurred during file processing: {str(e)}")