#python #python-2.7 #tkinter
#python #python-2.7 #tkinter
Вопрос:
Предположим, я использую mp3play
модуль для воспроизведения файлов mp3, и, используя ttk.Progressbar
, я хочу показать количество (продолжительность) воспроизводимой музыки. Есть ли какой-либо код для его достижения?
Я также хочу, чтобы таймер a показывал продолжительность воспроизводимой музыки.
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()
Ответ №1:
Просматривая код mp3play
модуля, mp3play.load()
возвращает AudioClip
объект. Этот объект имеет методы seconds()
и milliseconds()
, которые обеспечивают длину клипа в секундах или миллисекундах соответственно.
Вы можете сохранить время начала воспроизведения и сравнить его с текущим временем и общей длиной клипа, чтобы определить состояние progressbar.
# assuming time would me measured in milliseconds
start = time()
while playing:
# progress measured in percentages
progress = 100 * (time() - start)/ clip.milliseconds()
Комментарии:
1. Неработающий человек, не могли бы вы объяснить мне правильный код, и еще 1 вещь mp3play.load.seconds() возвращает неправильную продолжительность времени, например, я тестировал mp3-файл продолжительностью 4: 36 минут, и он вернул 6: 29 минут @Nysten
Ответ №2:
Похоже, что модуль mp3play использует библиотеку Windows winmm. В частности, он использует функцию mciSendString
для управления мультимедийной системой.
Одним из вариантов достижения желаемого было бы использовать status
команду для периодического извлечения текущей позиции воспроизведения и отображения ее по своему усмотрению.
Казалось бы, наиболее целесообразно изменить обе версии AudioClip
класса из библиотеки mp3play.
Изменение библиотеки mp3play
Класс AudioClip в windows.py
Сначала в строке 59 windows.py вы можете увидеть функцию, которая использует команду status
def _mode(self):
err, buf = self._mci.directsend('status %s mode' % self._alias)
return buf
Мы можем написать новую функцию на основе этого примера, которая получит текущую позицию воспроизведения:
def current_position(self):
err, buf = self._mci.directsend('status %s position' % self._alias)
return buf
Эта функция вернет строку, кодирующую число, представляющее текущую позицию в миллисекундах.
Класс AudioClip в init.py
Следующий шаг — изменить AudioClip
класс в строке 12 __init__py, добавив следующую функцию:
def current_position(self):
"""Get current position of clip in milliseconds."""
return int(self._clip.current_position())
Пример CLI
Теперь мы можем протестировать его с помощью простого скрипта:
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()
Вывод на консоль выглядит следующим образом:
>python test.py
Position: 0 / 174392
Position: 905 / 174392
Position: 1906 / 174392
Position: 2906 / 174392
Position: 3907 / 174392
Пример графического интерфейса
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 "
:d" % (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()
Скриншот:
Комментарии:
1. не могли бы вы, пожалуйста, объяснить мне, например, код файла и как включить его в progressbar @DanMasek
2. @TigerKing Хорошо, вот так.
3. не могли бы вы, пожалуйста, объяснить «self.music.current_position()», потому что у mp3play нет такого атрибута, как current_position() @DanMasek
4. @TigerKing Вам необходимо изменить библиотеку mp3play и добавить эти функции, как описано в первой части ответа.
5. спасибо за всю вашу помощь, но все же осталась одна ошибка, вы написали строку в своем коде
label_text = "%s / %s (%0.2f %%)" % (format_duration(pos_ms), format_duration(total_ms), progress_percent)
, но когда я включаю ее в свою программу, python говоритglobal name 'format_duration' is not defined
@DanMasek