PyQt6音乐播放器崩溃

-1 投票
1 回答
35 浏览
提问于 2025-04-14 16:04

我通过点击“添加到播放列表”来加载播放列表。当我点击列表中的任何一项时,播放器运行得很好。但是如果我尝试点击列表中的另一首曲子,程序就会崩溃。

我注意到了以下几点:

  1. 如果我点击某首曲子,然后再点击一次,所有功能都正常,我可以从列表中选择其他曲子而不会崩溃。
  2. 如果我点击某首曲子,然后用滑块或按钮快进音乐,我也可以选择列表中的其他曲子而不会崩溃。
  3. 但是如果我点击某首曲子,然后直接点击另一首,而没有先快进之前选择的曲子,程序就会崩溃。
  4. 我还注意到每次选择新曲子时都会出现这种错误:[mp3float @ 000001A17DE3A040] 无法更新跳过样本的时间戳。

我尝试修复这个问题,但没有成功。谢谢你的帮助。

import os
import sys
from PyQt6.QtCore import Qt, QUrl, QTimer
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput, QAudio
from PyQt6.QtWidgets import QApplication, QWidget, QPushButton, QSlider, QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, \
    QListWidget, QListWidgetItem


class MusicPlayer(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Music Player")
        self.setGeometry(100, 100, 400, 200)
        self.initUI()
        self.initPlayer()
        self.initSlider()
        self.initTimer()

    def initTimer(self):
        self.tmr0 = QTimer()
        self.tmr0.timeout.connect(self.on_time)
        # self.tmr0.setInterval(5000)
        self.tmr0.start(1)

    def on_time(self):
        if not self.position_slider.isSliderDown():
            pos = self.player.position()
            self.position_slider.setSliderPosition(pos)

    def initSlider(self):
        self.position_slider.setMaximum(self.player.duration())
        self.position_slider.setToolTip("Позиция трека")

    def initPlayer(self):
        self.player = QMediaPlayer()
        self.playlist = []
        self.audio_output = QAudioOutput()
        self.player.setAudioOutput(self.audio_output)
        self.saved_volume = 0.5
        self.audio_output.setVolume(self.saved_volume)

    def initUI(self):

        self.play_button = QPushButton("Play")
        self.play_button.clicked.connect(self.play_music)

        self.pause_button = QPushButton("Pause")
        self.pause_button.clicked.connect(self.pause_music)

        self.stop_button = QPushButton("Stop")
        self.stop_button.clicked.connect(self.stop_music)

        self.volume_slider = QSlider(Qt.Orientation.Horizontal)
        self.volume_slider.setValue(50)
        self.volume_slider.setMinimum(0)
        self.volume_slider.setMaximum(100)
        self.volume_slider.setToolTip("Volume")
        self.volume_slider.valueChanged.connect(self.set_volume)

        self.position_slider = QSlider(Qt.Orientation.Horizontal)
        self.position_slider.setToolTip("Position")
        # self.position_slider.sliderMoved.connect(self.set_position)
        self.position_slider.sliderReleased.connect(self.on_slider_release)

        self.backward_button = QPushButton("<< 10 sec")
        self.backward_button.clicked.connect(self.backward_music)

        self.forward_button = QPushButton("10 sec >>")
        self.forward_button.clicked.connect(self.forward_music)

        self.select_file_button = QPushButton("Add to playlist")
        self.select_file_button.clicked.connect(self.select_file)

        self.clear_playlist_button = QPushButton("Clear playlist")
        self.clear_playlist_button.clicked.connect(self.clear_playlist)

        self.playlist_widget = QListWidget()
        self.playlist_widget.itemDoubleClicked.connect(self.play_selected_track)

        self.track_label = QLabel("Track name")

        vbox = QVBoxLayout()
        hbox1 = QHBoxLayout()
        hbox2 = QHBoxLayout()
        hbox3 = QHBoxLayout()

        hbox1.addWidget(self.play_button)
        hbox1.addWidget(self.pause_button)
        hbox1.addWidget(self.stop_button)
        hbox1.addWidget(self.volume_slider)

        hbox2.addWidget(self.backward_button)
        hbox2.addWidget(self.position_slider)
        hbox2.addWidget(self.forward_button)

        hbox3.addWidget(self.track_label)
        hbox3.addWidget(self.select_file_button)
        hbox3.addWidget(self.clear_playlist_button)

        vbox.addWidget(self.playlist_widget)
        vbox.addLayout(hbox3)
        vbox.addLayout(hbox1)
        vbox.addLayout(hbox2)
        self.setLayout(vbox)

    def select_file(self):
        folder_path = QFileDialog.getExistingDirectory(self, "Выбрать папку с музыкальными файлами", "")
        if folder_path:
            files = [os.path.join(folder_path, file) for file in os.listdir(folder_path) if
                     file.endswith(('.mp3', '.wav', '.ogg'))]
            file_names = [file for file in os.listdir(folder_path) if file.endswith(('.mp3', '.wav', '.ogg'))]
            for file in files:
                self.playlist.append(file)

            for file_name in file_names:
                item = QListWidgetItem(file_name)
                self.playlist_widget.addItem(item)

    def play_music(self):
        item = self.playlist_widget.currentItem()
        index = self.playlist_widget.row(item)
        if self.player.playbackState() == QMediaPlayer.PlaybackState.PausedState:
            self.player.play()
        else:
            if (self.playlist):
                url = QUrl.fromLocalFile(self.playlist[index])  # Создаем объект QUrl из строки с путем к файлу
                self.player.durationChanged.connect(self.initSlider)
                self.player.setSource(url)
                self.audio_output.setVolume(self.saved_volume)
                self.player.play()

    def play_selected_track(self, item):
        index = self.playlist_widget.row(item)
        if 0 <= index < len(self.playlist):
            url = QUrl.fromLocalFile(self.playlist[index])
            self.player.setSource(url)
            self.player.durationChanged.connect(self.initSlider)
            self.audio_output.setVolume(self.saved_volume)
            self.player.play()

    def pause_music(self):
        self.player.pause()

    def stop_music(self):
        self.player.stop()

    def set_volume(self):
        volume = self.volume_slider.value()
        self.saved_volume = self.real_volume(volume)
        self.audio_output.setVolume(self.saved_volume)

    """Метод конвертации значения слайдера (от 0 до 100) 
        к виду (от 0.0 до 1.0) и преобразование шкалы громкости
         в логарифмическую(удобную для восприятия человеком)"""

    def real_volume(self, slider_value):
        return QAudio.convertVolume(
            slider_value * .01,
            QAudio.VolumeScale.LogarithmicVolumeScale,
            QAudio.VolumeScale.LinearVolumeScale
        )
    def backward_music(self):
        position_m = max(0, self.player.position() - 10000)
        self.player.setPosition(position_m)

    def forward_music(self):
        position_m = min(self.player.duration(), self.player.position() + 10000)
        self.player.setPosition(position_m)

    def on_slider_release(self):
        self.player.setPosition(self.position_slider.value())

    def clear_playlist(self):
        self.playlist_widget.clear()
        self.playlist.clear()


app = QApplication(sys.argv)
playerM = MusicPlayer()
playerM.show()
sys.exit(app.exec())

我想在选择新曲子之前重置源,但我没有找到相关的命令。我希望能够在不崩溃的情况下切换曲子。我还注意到它在第180行: self.player.setSource(url)崩溃了。

1 个回答

0

我找到了一种解决办法。在我设置新的音源之前,我会先停止播放器,然后检查播放器是否已经停止。接着,我会用一个延迟调用一个函数,这个延迟是通过QTimer.singleShot来实现的。

self.player.stop()
        if self.player.playbackState() == QMediaPlayer.PlaybackState.StoppedState:
            QTimer.singleShot(1, lambda: self.source_setter(url))

def source_setter(self, url):
    self.player.setSource(url)
    self.player.play()

撰写回答