DEV Community

Mate Technologies
Mate Technologies

Posted on

Build a Beginner-Friendly Audio Splitter in Python 🎵

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
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

✅ 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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

Optionally, set an icon:

try:
    app.iconbitmap("logo.ico")  # replace with your icon
except:
    pass
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

🔟 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)
Enter fullscreen mode Exit fullscreen mode

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")
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

1️⃣3️⃣ Run the App

Finally, start the Tkinter main loop:

app.mainloop()
Enter fullscreen mode Exit fullscreen mode

✅ Congratulations! You now have a fully functional audio splitter with GUI, live logs, progress, and flexible output options.

Top comments (0)