In this tutorial, we’ll build a modern desktop music player using Python — featuring playlist management, album art rotation, audio visualization, drag-and-drop support, and VLC-powered playback.
We’ll build PulsePlayer, a professional Spotify-style music player with a clean architecture.
👉 Source Code:
https://github.com/rogers-cyber/PulsePlayer
👉 Download EXE:
https://github.com/rogers-cyber/PulsePlayer/releases/tag/v1.0.1
🚀 What You’ll Build
Spotify-style music player UI
Playlist management
Audio playback with VLC
Album art extraction
Lyrics display
Audio visualizer
Drag & drop support
Loop and playback controls
Smooth rotating album artwork
📦 Step 1 — Install Dependencies
Create requirements.txt:
ttkbootstrap
python-vlc
Pillow
tinytag
numpy
tkinterdnd2
pyaudio
Install:
pip install -r requirements.txt
You must also install VLC Media Player on your system.
🧠 Step 2 — Import Required Libraries
These libraries handle:
UI (Tkinter + ttkbootstrap)
Audio playback (VLC)
Images (Pillow)
Metadata (TinyTag)
Visualization (NumPy)
import sys
import os
import io
import random
import threading
import tkinter as tk
from tkinter import filedialog, messagebox
import ttkbootstrap as tb
from ttkbootstrap.constants import *
from pathlib import Path
from PIL import Image, ImageTk, ImageDraw
from tinytag import TinyTag
import vlc
import numpy as np
from tkinterdnd2 import TkinterDnD
Optional audio support:
try:
import pyaudio
PYAUDIO_AVAILABLE = True
except:
PYAUDIO_AVAILABLE = False
⚙️ Step 3 — App Configuration
Store app settings in constants.
APP_NAME = "PulsePlayer"
SUPPORTED_AUDIO = (".mp3", ".wav", ".flac", ".m4a", ".ogg")
ROTATION_SPEED = 0.4
FPS_DELAY = 16
Why?
Easy to update later
Keeps code clean
Central configuration
🛠 Step 4 — Create Audio Utility Functions
This handles:
Time formatting
Album art extraction
Lyrics reading
Audio validation
Format Time
class AudioUtils:
@staticmethod
def format_time(sec):
sec = int(sec)
return f"{sec//60:02d}:{sec%60:02d}"
Converts seconds → MM:SS.
Extract Album Art
@staticmethod
def extract_album_art(path):
try:
tag = TinyTag.get(path, image=True)
if tag.images and tag.images.front_cover:
img = Image.open(io.BytesIO(tag.images.front_cover.data))
return img.resize((250, 250))
except:
pass
return None
Reads album art from MP3 metadata.
Validate Audio Files
@staticmethod
def is_valid_audio(path):
return path.lower().endswith(SUPPORTED_AUDIO)
Prevents invalid files from being added.
📂 Step 5 — Build Playlist Manager
Responsible for:
Adding files
Filtering search results
class PlaylistManager:
def __init__(self):
self.playlist = []
def add_files(self, files):
valid = [f for f in files if AudioUtils.is_valid_audio(f)]
self.playlist.extend(valid)
def filter(self, query):
if not query:
return self.playlist
return [
f for f in self.playlist
if query.lower() in os.path.basename(f).lower()
]
This keeps file logic separate from the UI.
🎧 Step 6 — Create Music Player Engine (Core Logic)
This controls:
Playback
Volume
Track switching
Looping
We keep this separate from GUI → clean architecture.
Initialize VLC Player
class MusicPlayerEngine:
def __init__(self):
self.vlc_instance = vlc.Instance("--no-video", "--quiet")
self.player = self.vlc_instance.media_player_new()
self.filtered_playlist = []
self.current_index = -1
self.loop_mode = False
self.single_loop = False
Load and Play Track
def load_track(self, path):
media = self.vlc_instance.media_new(path)
self.player.set_media(media)
def play(self):
self.player.play()
VLC handles decoding and playback.
Seek and Time Control
def get_time(self):
return self.player.get_time() / 1000
def seek(self, sec):
self.player.set_time(int(sec * 1000))
Used by the progress bar.
📊 Step 7 — Build Audio Visualizer
We create animated bars reacting to playback.
class AudioVisualizer:
def __init__(self, canvas, num_bars=50):
self.canvas = canvas
self.num_bars = num_bars
self.bars = []
Create Bars
for i in range(self.num_bars):
x0 = i * 5
x1 = x0 + 3
bar = self.canvas.create_rectangle(x0, 100, x1, 100, fill="#1DB954")
self.bars.append(bar)
Each bar updates continuously.
Animate Visualizer
def update(self, root, engine):
if engine.is_playing():
heights = [random.randint(10, 100) for _ in range(self.num_bars)]
This simulates audio activity.
🖥 Step 8 — Build Main GUI Application
This handles:
Layout
Controls
User interaction
Initialize Window
class SpotifyPlayerApp:
def __init__(self):
self.root = TkinterDnD.Tk()
self.root.geometry("1200x680")
self.root.title(APP_NAME)
tb.Style("darkly")
We use a modern dark theme.
Create Layout Panels
left = tb.Frame(self.root)
left.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
right = tb.Frame(self.root)
right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
Left → playlist
Right → player controls
🔍 Step 9 — Playlist UI
Search Box
search = tb.Entry(left)
search.pack(fill=tk.X)
Playlist Listbox
self.listbox = tk.Listbox(left)
self.listbox.pack(fill=tk.BOTH, expand=True)
self.listbox.bind("<Double-1>", self.play_selected)
Double-click to play.
🎵 Step 10 — Playback Controls
tb.Button(controls, text="▶", command=self.play_selected)
tb.Button(controls, text="⏸", command=self.pause)
tb.Button(controls, text="⏹", command=self.stop)
tb.Button(controls, text="⏭", command=self.next_track)
These call engine methods.
🖼 Step 11 — Album Art with Circular Mask
We turn square images into circles.
def _apply_circle_mask(self, img):
size = img.size
mask = Image.new("L", size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, size[0], size[1]), fill=255)
result = img.copy()
result.putalpha(mask)
return result
🔄 Step 12 — Animate Album Rotation
def animate_album(self):
self.rotation_angle = (self.rotation_angle + ROTATION_SPEED) % 360
rotated = self.album_original.rotate(
self.rotation_angle,
resample=Image.BICUBIC
)
Creates Spotify-style rotating artwork.
⏱ Step 13 — Progress Bar & Track Time
def update_progress_gui(self):
length = self.engine.get_length()
pos = self.engine.get_time()
self.progress_var.set(pos)
Updates every 500ms.
🎯 Step 14 — Run the Application
if __name__ == "__main__":
app = SpotifyPlayerApp()
app.run()
Launches the music player.
🎉 Final Result
You now have a professional desktop music player with:
Clean architecture
Modern UI
VLC playback engine
Metadata support
Visual effects
Playlist system
📥 Get the Full Project
👉 Source Code:
https://github.com/rogers-cyber/PulsePlayer
👉 Download Windows Build:
https://github.com/rogers-cyber/PulsePlayer/releases/tag/v1.0.1
❤️ If You Learned Something
⭐ Star the repository
🚀 Share the article
🎵 Build your own custom music player features!

Top comments (0)