In this tutorial, we’ll build Audio Extended, a Python desktop application to extend audio files from minutes to hours with seamless looping and optional fade-in/out.
GitHub Source: https://github.com/rogers-cyber/AudioExtended
1️⃣ Setup Python Environment
Make sure you have Python 3.10+ installed. Then install the required libraries:
pip install pydub ttkbootstrap
You also need FFmpeg installed. Download it from https://ffmpeg.org/download.html
and note the bin folder path (e.g., C:\ffmpeg\bin).
2️⃣ Import Libraries and Setup FFmpeg
We need Python libraries for audio processing and GUI:
import sys
import os
from pathlib import Path
from pydub import AudioSegment
import subprocess
import tkinter as tk
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
from ttkbootstrap.widgets.scrolled import ScrolledText
import threading
import math
import datetime
Then configure FFmpeg:
FFMPEG_DIR = r"C:\ffmpeg\bin" # Update with your FFmpeg path
os.environ["PATH"] = FFMPEG_DIR + os.pathsep + os.environ.get("PATH", "")
AudioSegment.converter = os.path.join(FFMPEG_DIR, "ffmpeg.exe")
AudioSegment.ffprobe = os.path.join(FFMPEG_DIR, "ffprobe.exe")
3️⃣ Silence Console Windows for Subprocess
Windows often pops up extra console windows when using FFmpeg. We can prevent this:
_original_popen = subprocess.Popen
def silent_popen(*args, **kwargs):
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
return _original_popen(*args, **kwargs)
subprocess.Popen = silent_popen
4️⃣ Initialize Tkinter App
Set up the main GUI window:
app = tk.Tk()
style = tb.Style(theme="superhero")
app.title("Audio Extended v1.1.0")
app.geometry("950x600")
stop_event = threading.Event() # For safely stopping audio extension
5️⃣ Helpers and Logging
We’ll create small helper functions for UI updates and logging:
def ui(func, *args, **kwargs):
app.after(0, lambda: func(*args, **kwargs))
def log_line(text):
def _log():
log.text.config(state="normal")
log.text.insert("end", text + "\n")
log.text.see("end")
log.text.config(state="disabled")
ui(_log)
6️⃣ Menu Bar with About & Help
Add File and Help menus:
menubar = tb.Menu(app)
file_menu = tb.Menu(menubar, tearoff=0)
file_menu.add_command(label="Exit", command=app.quit)
help_menu = tb.Menu(menubar, tearoff=0)
help_menu.add_command(label="User Guide", command=show_help)
help_menu.add_command(label="About", command=show_about)
menubar.add_cascade(label="File", menu=file_menu)
menubar.add_cascade(label="Help", menu=help_menu)
app.config(menu=menubar)
You can define show_about() and show_help() to display info dialogs with instructions.
7️⃣ Input and Output Panels
Create GUI elements to select audio input and output folder:
audio_path = tk.StringVar()
output_dir = tk.StringVar()
file_prefix = tk.StringVar(value="extended")
input_card = tb.Labelframe(app, text="Audio Input", padding=15)
input_card.pack(fill="x", padx=10, pady=10)
tb.Entry(input_card, textvariable=audio_path).pack(side="left", fill="x", expand=True, padx=5)
tb.Button(input_card, text="Browse", bootstyle="info",
command=lambda: audio_path.set(filedialog.askopenfilename(filetypes=[("Audio","*.mp3 *.wav *.flac *.ogg")]))).pack(side="left", padx=5)
Similarly, create an output folder selection:
output_card = tb.Labelframe(app, text="Output Settings", padding=15)
output_card.pack(fill="x", padx=10, pady=10)
tb.Entry(output_card, textvariable=output_dir).pack(side="left", fill="x", expand=True, padx=5)
tb.Button(output_card, text="Browse", bootstyle="info", command=lambda: output_dir.set(filedialog.askdirectory())).pack(side="left", padx=5)
8️⃣ Duration Presets and Fade
Add preset durations and fade settings:
dur_presets = {"10 minutes": 10*60, "30 minutes": 30*60, "1 hour": 60*60, "2 hours": 2*60*60, "12 hours": 12*60*60}
target_option = tk.StringVar(value="Select Duration")
target_duration = tk.IntVar(value=0)
fade_var = tk.IntVar(value=3) # default fade seconds
9️⃣ Preview Audio Duration
Show original audio length and target duration:
preview_label = tb.Label(output_card, text="Audio Duration: -- | Target: --")
preview_label.pack(side="left", padx=10)
def update_preview(*args):
try:
audio = AudioSegment.from_file(audio_path.get())
duration = len(audio)/1000
preview_label.config(text=f"Audio: {format_time(duration)} | Target: {format_time(target_duration.get())}")
except:
preview_label.config(text="Audio Duration: -- | Target: --")
audio_path.trace_add("write", lambda *args: update_preview())
target_duration.trace_add("write", lambda *args: update_preview())
🔟 Extend Audio Function
The main function loops and applies fade to extend audio:
def extend_audio():
if not audio_path.get() or not output_dir.get():
messagebox.showerror("Error", "Select input and output")
return
audio = AudioSegment.from_file(audio_path.get())
target_ms = target_duration.get() * 1000
fade_ms = fade_var.get() * 1000
orig_len = len(audio)
if fade_ms * 2 < orig_len:
audio = audio.fade_in(fade_ms).fade_out(fade_ms)
extended_audio = AudioSegment.empty()
current_ms = 0
chunk_ms = 1000
while current_ms < target_ms:
if stop_event.is_set():
log_line("⏹ Stopped by user")
break
start = current_ms % orig_len
end = min(start + chunk_ms, orig_len)
extended_audio += audio[start:end]
current_ms += (end - start)
ui(progress.configure, value=min(current_ms / target_ms * 100, 100))
extended_audio = extended_audio[:target_ms]
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
out_file = os.path.join(output_dir.get(), f"{file_prefix.get()}_{timestamp}.mp3")
extended_audio.export(out_file, format="mp3")
log_line(f"Saved extended audio: {out_file}")
11️⃣ Add Start/Stop Buttons
bar = tb.Frame(app)
bar.pack(fill="x", padx=10, pady=5)
tb.Button(bar, text="Start", bootstyle="success", command=lambda: threading.Thread(target=extend_audio, daemon=True).start()).pack(side="left", padx=5)
tb.Button(bar, text="Stop", bootstyle="danger", command=lambda: stop_event.set()).pack(side="left", padx=5)
12️⃣ Run the App
Finally, start the Tkinter main loop:
app.mainloop()
✅ You’re Done!
You now have a fully working Audio Extended application that can extend audio seamlessly with fade-in/out and live progress updates.
For full source code and prebuilt EXE: https://github.com/rogers-cyber/AudioExtended

Top comments (0)