In this tutorial, we’ll create a simple desktop app to split audio files into smaller clips using Python. We’ll use Tkinter for the GUI and pydub for audio processing. By the end, you’ll have a fully functional audio splitter with progress updates and live logs.
You can see the full project here: AudioSplitter GitHub
1️⃣ Setup: Install Dependencies
First, make sure you have Python installed. Then, install the required libraries:
pip install pydub ttkbootstrap
Note: You also need FFmpeg installed. Download it from ffmpeg.org
and remember the path, e.g., C:\ffmpeg\bin.
2️⃣ Configure FFmpeg in Python
pydub needs FFmpeg to process audio. We also want to run it silently without opening extra windows.
import os
from pydub import AudioSegment
import subprocess
FFMPEG_DIR = r"C:\ffmpeg\bin" # Update your FFmpeg path
os.environ["PATH"] = FFMPEG_DIR + os.pathsep + os.environ.get("PATH", "")
# Prevent command window popup on Windows
_original_popen = subprocess.Popen
def silent_popen(*args, **kwargs):
kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW
return _original_popen(*args, **kwargs)
subprocess.Popen = silent_popen
AudioSegment.converter = os.path.join(FFMPEG_DIR, "ffmpeg.exe")
AudioSegment.ffprobe = os.path.join(FFMPEG_DIR, "ffprobe.exe")
✅ This ensures FFmpeg works silently in the background.
3️⃣ Import GUI & Helper Libraries
We will use Tkinter for the GUI and ttkbootstrap for styling. We also need threading for smooth UI updates.
import tkinter as tk
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
from ttkbootstrap.widgets.scrolled import ScrolledText
import threading, math
4️⃣ Define App Metadata
It's good to have app information for "About" dialogs and branding.
APP_NAME = "Audio Splitter"
APP_VERSION = "1.1.0"
APP_AUTHOR = "MateTools"
APP_WEBSITE = "https://matetools.gumroad.com"
5️⃣ Setup Tkinter App
Create the main window and apply a theme from ttkbootstrap:
app = tk.Tk()
style = tb.Style(theme="superhero")
app.title(f"{APP_NAME} {APP_VERSION}")
app.geometry("950x600")
Optionally, set an icon:
try:
app.iconbitmap("logo.ico") # replace with your icon
except:
pass
6️⃣ Helper Functions: UI & Logging
To safely update UI elements from threads, define a helper:
stop_event = threading.Event()
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)
7️⃣ Menus: Help & About
Add menus to show the user guide and about info:
def show_about():
messagebox.showinfo(
f"About {APP_NAME}",
f"{APP_NAME} v{APP_VERSION}\n🔊 Split audio files fast!\n🌐 {APP_WEBSITE}"
)
def show_help():
messagebox.showinfo(
f"{APP_NAME} - User Guide",
"1️⃣ Select audio file\n2️⃣ Choose output folder\n3️⃣ Configure settings\n4️⃣ Start splitting"
)
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)
8️⃣ GUI Layout: Input & Output
Create sections to select audio files and output folder, with options for prefix and clip length.
# Audio Input
audio_path = tk.StringVar()
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)
# Output Settings
output_dir = tk.StringVar()
file_prefix = tk.StringVar(value="audio")
clip_length = tk.IntVar(value=10)
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)
tb.Label(output_card, text="Prefix:").pack(side="left", padx=5)
tb.Entry(output_card, textvariable=file_prefix, width=15).pack(side="left")
tb.Label(output_card, text="Seconds:").pack(side="left", padx=5)
tb.Entry(output_card, textvariable=clip_length, width=5).pack(side="left")
9️⃣ Preview: Show Clips & Duration
Automatically calculate how many clips will be created:
preview_label = tb.Label(output_card, text="Total: --s | Clips: --")
preview_label.pack(side="left", padx=10)
def update_preview(*args):
try:
audio = AudioSegment.from_file(audio_path.get())
duration = len(audio) / 1000
clips = math.ceil(duration / clip_length.get())
preview_label.config(text=f"Total: {duration:.2f}s | Clips: {clips}")
except:
preview_label.config(text="Total: --s | Clips: --")
clip_length.trace_add("write", lambda *args: update_preview())
audio_path.trace_add("write", lambda *args: update_preview())
🔟 Log & Progress
Show live output and progress bar:
log_card = tb.Labelframe(app, text="Live Output", padding=15)
log_card.pack(fill="both", expand=True, padx=10, pady=10)
log = ScrolledText(log_card, height=10)
log.pack(fill="both", expand=True)
log.text.config(state="disabled")
progress = tb.Progressbar(app, maximum=100)
progress.pack(fill="x", padx=10, pady=5)
1️⃣1️⃣ Split Audio Function
The main function splits audio into clips and updates logs/progress:
def split_audio():
if not audio_path.get() or not output_dir.get():
messagebox.showerror("Error", "Select input and output")
return
stop_event.clear()
ui(progress.configure, value=0)
audio = AudioSegment.from_file(audio_path.get())
total_ms = len(audio)
step_ms = clip_length.get() * 1000
total_clips = math.ceil(total_ms / step_ms)
count = 0
for i in range(0, total_ms, step_ms):
if stop_event.is_set():
log_line("⏹ Stopped by user")
break
chunk = audio[i:i+step_ms]
filename = f"{file_prefix.get()}_{count:03d}.mp3"
out_path = os.path.join(output_dir.get(), filename)
chunk.export(out_path, format="mp3")
count += 1
progress_value = min((i + step_ms) / total_ms * 100, 100)
ui(progress.configure, value=progress_value)
log_line(f"Saved: {filename}")
ui(progress.configure, value=100)
messagebox.showinfo("Done", f"Created {count} clips")
1️⃣2️⃣ Start/Stop Buttons
Run the splitter in a separate thread to keep the GUI responsive:
bar = tb.Frame(app)
bar.pack(fill="x", padx=10, pady=5)
tb.Button(bar, text="Start", bootstyle="success",
command=lambda: threading.Thread(target=split_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)
1️⃣3️⃣ Run the App
Finally, start the Tkinter main loop:
app.mainloop()
✅ Congratulations! You now have a fully functional audio splitter with GUI, live logs, progress, and flexible output options.

Top comments (0)