2

Suppose I use mp3play module to play mp3 files, and using ttk.Progressbar, I want to show the amount(duration) of music played. Is there any code to achieve it?

I also want a timer a to show the duration of music played.

import ttk
import mp3play
self.music = mp3play.load('filename')
self.fr=ttk.Frame()
self.fr.pack(expand=True, fill=BOTH, side=TOP)
self.seek=ttk.Progressbar(self.fr, orient='horizontal', mode='determinate', length=500)
self.seek.place(x=50, y=325)
self.seek.start()
SiHa
  • 7,830
  • 13
  • 34
  • 43
Dibyendu Das
  • 23
  • 1
  • 9

2 Answers2

3

Looking at the code of mp3playmodule, mp3play.load() returns an AudioClip object. This object has the methods seconds() and milliseconds() that provide the length of the clip in seconds or milliseconds respectively.

You can save the time when you started playing and compare it to the current time and the total length of the clip to determine the status of the progressbar.

# assuming time would me measured in milliseconds
start = time()
while playing:
    # progress measured in percentages
    progress = 100 * (time() - start)/ clip.milliseconds()
  • Not working man could u explain me with proper code, and 1 more thing mp3play.load.seconds() is returning the wrong duration of time for e.g I tested for a mp3 file of duration 4:36 mins and it returned 6:29 mins @Nysten – Dibyendu Das Sep 30 '16 at 16:38
1

It appears that the mp3play module uses the Windows winmm library. Specifically, it uses function mciSendString to control the multimedia system.

One option to achieve what you want would be to use the status command to periodically retrieve the current playback position and display it as you like.

It would seem most appropriate to modify both versions of the AudioClip class from the mp3play library.


Modifying mp3play Library

Class AudioClip in windows.py

First, on line 59 of windows.py you can see a function that uses the status command

    def _mode(self):
        err, buf = self._mci.directsend('status %s mode' % self._alias)
        return buf

We can write a new function based on this example, which will get the current playback position:

    def current_position(self):
        err, buf = self._mci.directsend('status %s position' % self._alias)
        return buf

This function will return a string encoding a number representing the current position in milliseconds.

Class AudioClip in init.py

The next step is to modify AudioClip class on line 12 of __init__py, adding the following function:

    def current_position(self):
        """Get current position of clip in milliseconds."""
        return int(self._clip.current_position())

CLI Example

Now we can test it with a simple script:

import time
import mp3play

clip = mp3play.load(r'test.mp3')

clip.play()

for i in range(5):
    print "Position: %d / %d" % (clip.current_position(), clip.milliseconds())
    time.sleep(1)

clip.stop()

The console output looks as follows:

>python test.py
Position: 0 / 174392
Position: 905 / 174392
Position: 1906 / 174392
Position: 2906 / 174392
Position: 3907 / 174392

GUI Example

import tkinter as tk
from tkinter import ttk

import mp3play

# ================================================================================

def format_duration(ms):
    total_s = ms / 1000
    total_min = total_s / 60
    remain_s = total_s % 60
    return "%0d:%02d" % (total_min, remain_s)

# ================================================================================

class SimplePlayer(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        # Variables we use to dynamically update the text of the labels
        self.music_title = tk.StringVar()
        self.music_progress = tk.StringVar()

        self.fr=ttk.Frame()
        self.fr.pack(expand=True, fill=tk.BOTH, side=tk.TOP)

        # Label to display the song title
        self.title_lbl = ttk.Label(self.fr, textvariable = self.music_title)
        self.title_lbl.pack()

        # Playback progress bar
        self.progress_bar = ttk.Progressbar(self.fr, orient='horizontal', mode='determinate', length=500)
        self.progress_bar.pack()

        # Shows the progress numerically
        self.progress_lbl = ttk.Label(self.fr, textvariable = self.music_progress)
        self.progress_lbl.pack()


    def start(self, music_file):
        self.music = mp3play.load(music_file)

        # Update the title
        self.music_title.set(music_file)

        # Start playback
        self.music.play()

        # Start periodically updating the progress bar and progress label
        self.update_progress()

    def update_progress(self):
        pos_ms = self.music.current_position()
        total_ms = self.music.milliseconds()
        progress_percent = pos_ms / float(total_ms) * 100

        # Update the label
        label_text = "%s / %s   (%0.2f %%)" % (format_duration(pos_ms), format_duration(total_ms), progress_percent)
        self.music_progress.set(label_text)

        # Update the progress bar
        self.progress_bar["value"] = progress_percent

        # Schedule next update in 100ms        
        self.after(100, self.update_progress)

# ================================================================================

app = SimplePlayer()

app.start('test.mp3')
app.mainloop()

Screenshot:

Screenshot of running GUI example

Dan Mašek
  • 17,852
  • 6
  • 57
  • 85
  • could you pls explain me with the code e.g of a file and how to incorporate it to a progressbar @DanMasek – Dibyendu Das Sep 30 '16 at 17:20
  • @TigerKing OK, there you go. – Dan Mašek Sep 30 '16 at 20:10
  • could u pls explain "self.music.current_position()" bcoz mp3play doesnot has any attribute like current_position() @DanMasek – Dibyendu Das Oct 01 '16 at 14:09
  • @TigerKing You need to modify the mp3play library and add those functions, as described in the first part of the answer. – Dan Mašek Oct 01 '16 at 14:51
  • thank you for all you help, but yet one error left, u wrote a line in your code `label_text = "%s / %s (%0.2f %%)" % (format_duration(pos_ms), format_duration(total_ms), progress_percent)` but when i incorporate it in my program python says `global name 'format_duration' is not defined` @DanMasek – Dibyendu Das Oct 02 '16 at 11:55
  • @tigerking That function is defined in the beginning of the GUI example. – Dan Mašek Oct 02 '16 at 12:17
  • thank u, and sorry but there's one more error python is giving attribute error because it says my class doesnot has any instance of attribute 'after' – Dibyendu Das Oct 02 '16 at 15:39
  • That's a [tkinter method](http://stackoverflow.com/questions/25753632/tkinter-how-to-use-after-method). It should be available if the class is derived from the tkinter widget. – Dan Mašek Oct 02 '16 at 16:05
  • 1 last problem mp3play.seconds() is not returning the exact duration of mp3 files, i have tested for 2 files, 1 was of duration 4:22 minutes but it returned 5:20 mins and other was of duration 4:36 minutes but it returned 6:28 mins @DanMasek – Dibyendu Das Oct 03 '16 at 06:26
  • @TigerKing Hard to tell, it showed me the same duration for the test file as WinAMP. It could be an issue due to VBR encoding and missing/incorrect mp3id duration tag. – Dan Mašek Oct 03 '16 at 11:33