import os import subprocess from PyQt6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QFileDialog, QSlider, QListWidget from PyQt6.QtCore import Qt, QUrl from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput DEFAULT_SOUNDFONT = '/home/stan/Documents/Dev/Tests/MidPlay/SoundFonts/FinalFantasyVI.sf2' class MidPlay(QWidget): def __init__(self): super().__init__() self.current_file = None self.current_soundfont = DEFAULT_SOUNDFONT self.process = None self.media_player = QMediaPlayer() self.audio_output = QAudioOutput() self.media_player.setAudioOutput(self.audio_output) self.playlist = [] self.current_index = 0 self.current_volume = 50 self.init_ui() def init_ui(self): layout = QVBoxLayout() self.playlist_widget = QListWidget() self.playlist_widget.itemDoubleClicked.connect(self.play_selected) layout.addWidget(self.playlist_widget) self.play_button = QPushButton("Play") self.play_button.clicked.connect(self.play) layout.addWidget(self.play_button) self.stop_button = QPushButton("Stop") self.stop_button.clicked.connect(self.stop) layout.addWidget(self.stop_button) self.next_button = QPushButton("Next") self.next_button.clicked.connect(self.play_next) layout.addWidget(self.next_button) self.volume_slider = QSlider(Qt.Orientation.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(self.current_volume) self.volume_slider.valueChanged.connect(self.set_volume) layout.addWidget(self.volume_slider) self.status_label = QLabel("No file loaded") layout.addWidget(self.status_label) self.setLayout(layout) def add_to_playlist(self, file_path): self.playlist.append(file_path) self.playlist_widget.addItem(os.path.basename(file_path)) if not self.current_file: self.current_file = file_path self.play() def play_selected(self, item): index = self.playlist_widget.row(item) self.current_index = index self.current_file = self.playlist[index] self.play() def play(self): if not self.current_file: self.status_label.setText("No file selected") return self.stop() # Stop any current playback if self.current_file.lower().endswith(('.mid', '.midi')): self.play_midi() else: self.play_audio() def play_midi(self): self.media_player.stop() command = [ "fluidsynth", "-a", "pulseaudio", "-g", str(self.current_volume / 50), self.current_soundfont, self.current_file ] self.process = subprocess.Popen(command) self.status_label.setText(f"Playing MIDI: {os.path.basename(self.current_file)}") def play_audio(self): if self.process: self.process.terminate() self.process = None self.media_player.setSource(QUrl.fromLocalFile(self.current_file)) self.media_player.play() self.status_label.setText(f"Playing Audio: {os.path.basename(self.current_file)}") self.media_player.mediaStatusChanged.connect(self.handle_media_status_change) def stop(self): if self.process: self.process.terminate() self.process = None self.media_player.stop() self.status_label.setText("Playback stopped") def set_volume(self, value): self.current_volume = value self.audio_output.setVolume(value / 50) if self.process and self.current_file.lower().endswith(('.mid', '.midi')): self.update_midi_volume() def update_midi_volume(self): pass def play_next(self): if self.playlist: self.current_index = (self.current_index + 1) % len(self.playlist) self.current_file = self.playlist[self.current_index] self.play() def handle_media_status_change(self, status): if status == QMediaPlayer.MediaStatus.EndOfMedia: self.play_next() def closeEvent(self, event): self.stop() super().closeEvent(event) def showUI(self): self.setWindowTitle("MidPlay") super().show() def close(self): self.stop() super().close()