Music is more than sound; it’s an emotion, a narrative, a refuge. Imagine wielding the power to design your musical universe, where every note and rhythm aligns with your desires. In this post, you will see the synergy of Python and Delphi, where we will unveil a music player that transcends expectations.
This music player app will have an option for users to create playlists as well as play, stop, and pause songs. Users can even monitor song durations and real-time timestamps. Users can easily adjust the volume and navigate through their music in 10-second intervals. Throughout this journey, we’ll introduce you to advanced Delphi components that seamlessly integrate Python’s versatility with Delphi’s strength.
Table of Contents
How to Build a Feature-Packed Music Player With DelphiFMX?
Let’s go over the building of a music player app in a step by step manner.
What Are the Prerequisites for this Project?
Before we dive into building our feature-packed music player with DelphiFMX, let’s ensure we have all the necessary tools and components in place.
First and foremost, make sure you have Delphi Software installed. Delphi will be our creative canvas, allowing us to craft a music player with an enticing user interface that sings with functionality.
Next up, you’ll need the Delphi4PythonExporter tool. This nifty utility acts as the bridge connecting Delphi and Python, making the integration seamless and painless.
You’ll require a text editor or an integrated development environment (IDE) that supports Python programming to code in Python. We highly recommend PyScripter, a user-friendly environment that harmoniously blends Python coding within Delphi. If you haven’t already set up these tools, consider exploring our article “Powerful Python GUI Project Setup” to help you get started on the right foot.
Finally, you will need a codec pack to playback of all your music and video files. For this, we will need the K-Lite Codec Pack, which is a free software bundle shipped with decoders needed to view any movie, video, or music file. For this tutorial, you will need to download and install the basic codec pack from their official website.
With these prerequisites in place, you’ll be all set to embark on the journey of creating a feature-packed music player that will elevate your music experience to new heights. And if you’re eager to dive right in, you can access the complete code and resources for this tutorial from our GitHub repository at the following link:
https://github.com/Embarcadero/PythonBlogExamples/tree/main/Music_Player
How to Use the Delphi IDE to Create a Stunning GUI for this App?
Let’s start by launching our Delphi app and creating a new application. Search for the Create New tab on your welcome page and click on Multi-Device Application. Next, opt for the Blank Application and click on OK. For this tutorial, we’ve named our project “MusicPlayerProject.”
If you’re not well-acquainted with the different sections of the Delphi IDE, we suggest referring to our complimentary eBook bundle. This resource comprehensively covers the Delphi Python EcoSystem and all Python GUI offerings.
Now, we will start off by naming our form. Right-click on the form and select Quick Edit. Here, we will set the name of our form as MusicPlayerWindow
with the caption “Music Player.” We will also rename the source file of our project from Unit1.pas
to MusicPlayer.pas
to help us keep track.
Next, let’s resize our form. Select your form and head over to the Object Inspector. Under the properties tab, search for the ClientWidth
and ClientHeight
properties and adjust the sizes accordingly.
We will add a few tabs to the form for this project. So, head over to the Palette and search for the TTabControl
object. Drag and Drop this object to your form and adjust its size accordingly. Next, right-click on the TTabControl
object and add two tabs to the form: Songs
and Now Playing
. The Songs
tab will display all the songs in the app, while the Now Playing
tab will serve as the main music player. We will also add a TRectangle
component to the top of the form that will serve as the placeholder for the title and a button (which we will define later).
Here is what our form looks like:
Note: We will be customizing the text style of each label using the TextSettings
property of the component. This will help us customize the feel of the form.
Now, let’s add a few labels to the form. Search for the TLabel
component in the Palette and add it to the form. We will add a few of these components to indicate multiple things, including filename, song directory, artist, and time. We will also use them as placeholders to indicate multiple other components. Here is what our form looks like:
Next, let’s add a few buttons. Head to the Palette, search for the TButton
component and add a few buttons to the form. Here, we will add a Create Playlist
button, forward
and backward
buttons (which will change the time by 10 seconds), and Pause
, Play
, and Stop
for the music player. Additionally, for each player button, we are going to customize their appearance by heading over to the Object Inspector and changing their style using the StyleLookup
property:
This is what our form looks like so far:
Now, let’s add a few TTrackBar
components. One track bar component will help adjust the volume of our music player, while the other will serve as a tracker to track the progress of our music. We will also add a TImage
component that will help display the album cover of our music file. Here is what our form looks like:
Finally, we’ll add a TOpenDialog
to help select files we want to play. We will also add a TTimer
and a TMediaPlayer
component to help us play our music files. The placement of these components does not matter as they will be invisible:
Now that our Now Playing
tab is complete, head over to the Songs
tab and add a TListBox
component. This will serve as a placeholder for all our music files.
Now that our form is ready, the last step is to add functionality to each button. To do this, double-click on each button on the form. This will generate an OnClick
method for that button and create a procedure in the .pas
file, enabling us to program the button.
Due to the Delphi4PythonExporter’s lack of runtime implementation, we must include at least one comment (//
) in each procedure to preserve its function when we export the form.
How to Add Functionality to this GUI?
With our forms now ready, we can begin exporting our forms. Navigate to Tools > Export To Python
and click on Export Current Entire Project
.
Here we will give our project the title Music Player
. Now, select the directory of your choosing and click on Export.
Delphi will generate two Python and one .pyfmx
file. The MusicPlayerProject.py
file will be used to run the application, whereas the MusicPlayer.py
file will contain the class of our form. The MusicPlayer.pyfmx
contains the visual information of our form. Below are the contents of each Python file.
MusicPlayerProject.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from delphifmx import * from MusicPlayer import MusicPlayerWindow def main(): Application.Initialize() Application.Title = 'Music Player' Application.MainForm = MusicPlayerWindow(Application) Application.MainForm.Show() Application.Run() Application.MainForm.Destroy() if __name__ == '__main__': main() |
MusicPlayer.py:
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 |
import os from delphifmx import * class MusicPlayerWindow(Form): def __init__(self, owner): self.top_rectangle = None self.top_heading = None self.create_playlist = None self.tab_ctrl = None self.songs_tab = None self.audio_list_box = None self.now_playing_tab = None self.audio_embedded_image = None self.audio_track_bar = None self.play_btn = None self.pause_btn = None self.stop_btn = None self.fwd_btn = None self.bwd_btn = None self.volume_track_bar = None self.vol_label = None self.location_label = None self.current_time_label = None self.song_name_label = None self.artist_label = None self.duration_label = None self.open_audio_dialog = None self.media_player = None self.timer = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "MusicPlayer.pyfmx")) def create_playlistClick(self, Sender): pass def audio_list_boxChange(self, Sender): pass def play_btnClick(self, Sender): pass def pause_btnClick(self, Sender): pass def stop_btnClick(self, Sender): pass def fwd_btnClick(self, Sender): pass def bwd_btnClick(self, Sender): pass def volumeChange(self, Sender): pass def update_current_time(self, Sender): pass |
The only thing we need to do now is start adding functionality to our forms. Start by opening up MusicPlayer.py
in the text editor of your choice and importing the TinyTag library:
1 2 3 |
# Additional Imports from tinytag import TinyTag |
Next, head over to the __init__
function and start by adding a custom style for the form. You’ll first need to obtain the free eBook bundle, which includes various styles. Download the eBook and extract the FMX styles ZIP file to your preferred directory. Then select the style you wish to use; in this instance, we’ll opt for transparent.style
from the bundle. In addition, we will also set the default value of the volume bar to 100. Our __init__
function looks like:
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 |
class MusicPlayerWindow(Form): def __init__(self, owner): # Initialize all GUI elements self.top_rectangle = None self.top_heading = None self.create_playlist = None self.tab_ctrl = None self.songs_tab = None self.audio_list_box = None self.now_playing_tab = None self.audio_embedded_image = None self.audio_track_bar = None self.play_btn = None self.pause_btn = None self.open_audio_dialog = None self.media_player = None self.timer = None self.stop_btn = None self.fwd_btn = None self.bwd_btn = None self.nxt_btn = None self.volume_track_bar = None self.vol_label = None self.location_label = None self.current_time_label = None self.song_name_label = None self.artist_label = None self.duration_label = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "MusicPlayer.pyfmx")) # Set up the style manager and apply a custom style self.__sm = StyleManager() self.__sm.SetStyleFromFile(os.path.join(os.getcwd(), "StylesTransparent.style")) # Set the initial position of TrackBar to the middle (50%) self.volume_track_bar.Value = 100 |
Now, let’s program our Play
, Pause
, and Stop
buttons. Head over to the play_btnClick
function and start by turning the button off after it is pressed. Next, we will enable the Stop
and Pause
buttons, while calling the media player to play the music. Here is what our function looks like:
1 2 3 4 5 6 7 |
def play_btnClick(self, Sender): # Handle play button click self.play_btn.Enabled = False self.pause_btn.Enabled = True self.stop_btn.Enabled = True self.media_player.Play() |
Similarly, we can add functionalities for our Stop
and Pause
buttons. Here is what the functions look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def pause_btnClick(self, Sender): # Handle pause button click self.play_btn.Enabled = True self.pause_btn.Enabled = False self.media_player.Stop() def stop_btnClick(self, Sender): # Handle stop button click self.stop_btn.Enabled = False self.pause_btn.Enabled = False self.play_btn.Enabled = True self.media_player.FileName = self.open_audio_dialog.FileName |
Next, let’s add some functionality to the forward and backward buttons. Navigate to the fwd_btnClick
function and start by getting the CurrentTime
of the music:
1 2 3 4 |
def fwd_btnClick(self, Sender): # Handle forward button click current_time_seconds = self.media_player.CurrentTime / 10000000 |
Now add 10
seconds to the current time and then check if the duration is less than the duration of the song. If this condition is satisfied, we set the current time to the new time. Here is what the function looks like:
1 2 3 4 5 6 7 8 |
def fwd_btnClick(self, Sender): # Handle forward button click current_time_seconds = self.media_player.CurrentTime / 10000000 new_time_seconds = current_time_seconds + 10 if new_time_seconds < self.tag.duration: self.media_player.CurrentTime = round(new_time_seconds * 10000000) |
Similarly, we can program the bwd_btnClick
function but instead check if the new time is less than 0
. Here is what the function looks like:
1 2 3 4 5 6 7 8 |
def bwd_btnClick(self, Sender): # Handle backward button click current_time_seconds = self.media_player.CurrentTime / 10000000 new_time_seconds = current_time_seconds - 10 if new_time_seconds >= 0: self.media_player.CurrentTime = round(new_time_seconds * 10000000) |
Next, lets add some functionality to the volume track bar. Head over to the volumeChange
function and start by getting the current volume stated in the bar. Next, assign the new volume value to the media player. Here is our final volumeChange
function:
1 2 3 4 5 |
def volumeChange(self, Sender): # Handle volume control change volume = self.volume_track_bar.Value / 100.0 self.media_player.Volume = volume |
Now, let’s head over to the update_current_time
function and use it to display the current time using the media_player
. We will also display the current time in our current_time_label
:
1 2 3 4 5 6 7 8 9 10 11 |
def update_current_time(self, Sender): # Update the current playback time current_time_seconds = self.media_player.CurrentTime / 10000000 self.audio_track_bar.Value = current_time_seconds # Format the current time as MM:SS minutes = int(current_time_seconds // 60) seconds = int(current_time_seconds % 60) self.current_time_label.Text = f"{minutes:02}:{seconds:02}" |
Next, we will move on to the create_playlistClick
function. We will use this function to populate our playlist in the Songs
tab. So, we will start by opening up the dialog box for file selection. Next, if the user selects the song, we will append it to the ListBoxItem
and add it to our playlist. Here is what the function looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def create_playlistClick(self, Sender): # Open a file dialog to select audio files and populate the playlist if self.open_audio_dialog.Execute(): self.audio_list_box.Clear() mp3_files_list = self.open_audio_dialog.Files.ToList() self.listbox_song_paths = [] self.listbox_items = [] for mp3_file_path in mp3_files_list: self.listbox_song_paths.append(mp3_file_path) mp3_file_name = os.path.splitext(os.path.basename(mp3_file_path))[0] lb_item_audio_name = ListBoxItem(self.audio_list_box) lb_item_audio_name.SetProps(Parent=self.audio_list_box, Height=40, Text=mp3_file_name) self.listbox_items.append(lb_item_audio_name) |
We are finally ready to add the main code to our Media player. Head over to the audio_list_boxChange
function and start by retrieving the item selected in the list box:
1 2 3 4 |
def audio_list_boxChange(self, Sender): # Handle selection of an audio item in the list box selected_lb_item = self.audio_list_box.Selected |
Next, change the tab to the Now Playing
tab and use TinyTag to retrieve information about the selected song:
1 2 3 4 5 6 7 8 9 10 |
self.tab_ctrl.TabIndex = 1 mp3_file_path = self.listbox_song_paths[self.listbox_items.index(selected_lb_item)] # Use TinyTag to retrieve audio file information self.tag = TinyTag.get(mp3_file_path, image=True) mins = self.tag.duration // 60 sec = self.tag.duration % 60 self.duration_label.Text = f"{int(mins)}:{int(sec)}" |
Next, set the various labels we have with information about the song and update the embedded image if there is one available:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# Set various labels and update the embedded image if available self.audio_track_bar.Max = self.tag.duration self.artist_label.Text = "Artist: {}".format(self.tag.artist) self.location_label.Text = "Location: {}".format(mp3_file_path) self.song_name_label.Text = "Song Name: {}".format(selected_lb_item.Text) image_data = self.tag.get_image() if image_data is not None: bs = BytesStream(image_data) self.audio_embedded_image.Bitmap.LoadFromStream(bs) else: self.audio_embedded_image.Bitmap = None |
Finally, load and play the selected audio file. Here is what our function looks like:
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 |
def audio_list_boxChange(self, Sender): # Handle selection of an audio item in the list box selected_lb_item = self.audio_list_box.Selected self.tab_ctrl.TabIndex = 1 mp3_file_path = self.listbox_song_paths[self.listbox_items.index(selected_lb_item)] # Use TinyTag to retrieve audio file information self.tag = TinyTag.get(mp3_file_path, image=True) mins = self.tag.duration // 60 sec = self.tag.duration % 60 self.duration_label.Text = f"{int(mins)}:{int(sec)}" # Set various labels and update the embedded image if available self.audio_track_bar.Max = self.tag.duration self.artist_label.Text = "Artist: {}".format(self.tag.artist) self.location_label.Text = "Location: {}".format(mp3_file_path) self.song_name_label.Text = "Song Name: {}".format(selected_lb_item.Text) image_data = self.tag.get_image() if image_data is not None: bs = BytesStream(image_data) self.audio_embedded_image.Bitmap.LoadFromStream(bs) else: self.audio_embedded_image.Bitmap = None # Load and play the selected audio file self.media_player.FileName = mp3_file_path self.media_player.Play() # Set up a timer to update the current playback time self.timer.Interval = 1000 # Set the interval to 1000 milliseconds (1 second) self.timer.Enabled = True # Enable playback control buttons self.pause_btn.Enabled = True self.stop_btn.Enabled = True |
Here is what our final MusicPlayer.py
file looks like:
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 |
import os from delphifmx import * from tinytag import TinyTag class MusicPlayerWindow(Form): def __init__(self, owner): # Initialize all GUI elements self.top_rectangle = None self.top_heading = None self.create_playlist = None self.tab_ctrl = None self.songs_tab = None self.audio_list_box = None self.now_playing_tab = None self.audio_embedded_image = None self.audio_track_bar = None self.play_btn = None self.pause_btn = None self.open_audio_dialog = None self.media_player = None self.timer = None self.stop_btn = None self.fwd_btn = None self.bwd_btn = None self.nxt_btn = None self.volume_track_bar = None self.vol_label = None self.location_label = None self.current_time_label = None self.song_name_label = None self.artist_label = None self.duration_label = None self.LoadProps(os.path.join(os.path.dirname(os.path.abspath(__file__)), "MusicPlayer.pyfmx")) # Set up the style manager and apply a custom style self.__sm = StyleManager() self.__sm.SetStyleFromFile(os.path.join(os.getcwd(), "StylesTransparent.style")) # Set the initial position of TrackBar to the middle (50%) self.volume_track_bar.Value = 100 self.tag = None def create_playlistClick(self, Sender): # Open a file dialog to select audio files and populate the playlist if self.open_audio_dialog.Execute(): self.audio_list_box.Clear() mp3_files_list = self.open_audio_dialog.Files.ToList() self.listbox_song_paths = [] self.listbox_items = [] for mp3_file_path in mp3_files_list: self.listbox_song_paths.append(mp3_file_path) mp3_file_name = os.path.splitext(os.path.basename(mp3_file_path))[0] lb_item_audio_name = ListBoxItem(self.audio_list_box) lb_item_audio_name.SetProps(Parent=self.audio_list_box, Height=40, Text=mp3_file_name) self.listbox_items.append(lb_item_audio_name) def audio_list_boxChange(self, Sender): # Handle selection of an audio item in the list box selected_lb_item = self.audio_list_box.Selected self.tab_ctrl.TabIndex = 1 mp3_file_path = self.listbox_song_paths[self.listbox_items.index(selected_lb_item)] # Use TinyTag to retrieve audio file information self.tag = TinyTag.get(mp3_file_path, image=True) mins = self.tag.duration // 60 sec = self.tag.duration % 60 self.duration_label.Text = f"{int(mins)}:{int(sec)}" # Set various labels and update the embedded image if available self.audio_track_bar.Max = self.tag.duration self.artist_label.Text = "Artist: {}".format(self.tag.artist) self.location_label.Text = "Location: {}".format(mp3_file_path) self.song_name_label.Text = "Song Name: {}".format(selected_lb_item.Text) image_data = self.tag.get_image() if image_data is not None: bs = BytesStream(image_data) self.audio_embedded_image.Bitmap.LoadFromStream(bs) else: self.audio_embedded_image.Bitmap = None # Load and play the selected audio file self.media_player.FileName = mp3_file_path self.media_player.Play() # Set up a timer to update the current playback time self.timer.Interval = 1000 # Set the interval to 1000 milliseconds (1 second) self.timer.Enabled = True # Enable playback control buttons self.pause_btn.Enabled = True self.stop_btn.Enabled = True def update_current_time(self, Sender): # Update the current playback time current_time_seconds = self.media_player.CurrentTime / 10000000 self.audio_track_bar.Value = current_time_seconds # Format the current time as MM:SS minutes = int(current_time_seconds // 60) seconds = int(current_time_seconds % 60) self.current_time_label.Text = f"{minutes:02}:{seconds:02}" def play_btnClick(self, Sender): # Handle play button click self.play_btn.Enabled = False self.pause_btn.Enabled = True self.stop_btn.Enabled = True self.media_player.Play() def pause_btnClick(self, Sender): # Handle pause button click self.play_btn.Enabled = True self.pause_btn.Enabled = False self.media_player.Stop() def stop_btnClick(self, Sender): # Handle stop button click self.stop_btn.Enabled = False self.pause_btn.Enabled = False self.play_btn.Enabled = True self.media_player.FileName = self.open_audio_dialog.FileName def fwd_btnClick(self, Sender): # Handle forward button click current_time_seconds = self.media_player.CurrentTime / 10000000 new_time_seconds = current_time_seconds + 10 if new_time_seconds < self.tag.duration: self.media_player.CurrentTime = round(new_time_seconds * 10000000) def bwd_btnClick(self, Sender): # Handle backward button click current_time_seconds = self.media_player.CurrentTime / 10000000 new_time_seconds = current_time_seconds - 10 if new_time_seconds >= 0: self.media_player.CurrentTime = round(new_time_seconds * 10000000) def volumeChange(self, Sender): # Handle volume control change volume = self.volume_track_bar.Value / 100.0 self.media_player.Volume = volume |
What Are the Final Results?
Now that everything is complete, it’s time to test out our app. Open up MusicPlayerProject.py
and run the file.
Next, click the Create Playlist
button and select the files you want to play. Now navigate to the Songs
tab to see your playlist:
Finally, double-click on a song to start playing:
What Have You Learned in this Article?
Conclusively, in this tutorial, we’ve transformed a basic music player into a versatile tool. You’ve learned to craft playlists effortlessly, fine-tune playback, and enhance your music experience with song duration and timestamps.
But this is just the beginning. Delphi opens doors to endless possibilities. Whether you’re a novice or an experienced developer, it’s time to harness the power of Delphi. Elevate your software development skills, create exceptional applications, and leave your digital mark.
What Are Some Relevant FAQs?
What is DelphiFMX, and why should I use it for building a music player?
DelphiFMX is a framework for creating cross-platform applications with Delphi. It provides a powerful and user-friendly way to build applications with rich user interfaces. Using it for a music player allows you to create a visually appealing and feature-packed player easily.
Can I use other programming languages besides Python with DelphiFMX?
DelphiFMX primarily supports the Delphi programming language, but you can use external libraries like the Python4Delphi bridge to incorporate Python into your Delphi applications, as demonstrated in this tutorial.
Are there any licensing requirements for using Delphi and Python together?
Delphi and Python can be used together without any additional licensing requirements. However, make sure to review the licenses of any third-party libraries or components you use in your project.
Can I customize the appearance and behavior of Delphi components to match the design of my music player?
Yes, Delphi components are highly customizable. You can adjust properties such as colors, fonts, sizes, and styles to achieve the desired look and feel for your music player’s user interface.
What are some commonly used Delphi components for building a music player?
For a music player, you might use components like TMediaPlayer, TListBox for playlists, TButton for playback controls, TProgressBar for tracking song progress, and TTrackBar for volume control, among others.