Only use QtMultimedia.QSoundEffect for audio.

This commit is contained in:
Dpeta 2023-03-14 17:52:11 +01:00
parent c2826a8158
commit b0f6995ef1
No known key found for this signature in database
GPG key ID: 51227517CEA0030C
6 changed files with 57 additions and 179 deletions

View file

@ -88,8 +88,6 @@ Pesterchum is a Python script. This means that as long as you have Python instal
- [PyQt6] (prefered) or [PyQt5] (legacy) - [PyQt6] (prefered) or [PyQt5] (legacy)
- Qt6 only supports maintained 64 bit operating systems, like Windows 10 or later for Windows. ([Qt 6.3 Supported Platforms](https://doc.qt.io/qt-6/supported-platforms.html)) - Qt6 only supports maintained 64 bit operating systems, like Windows 10 or later for Windows. ([Qt 6.3 Supported Platforms](https://doc.qt.io/qt-6/supported-platforms.html))
- Qt5 supports Windows 7 or later, but is past its EOL for non-commercial use. ([Qt 5.15 Supported Platforms](https://doc.qt.io/qt-6/supported-platforms.html)) - Qt5 supports Windows 7 or later, but is past its EOL for non-commercial use. ([Qt 5.15 Supported Platforms](https://doc.qt.io/qt-6/supported-platforms.html))
- (Optional) [pygame-ce] or [pygame] can provide an alternative audio backend for certain systems.
- Useful for Linux systems that don't meet the Qt6 requirements, as Qt5 Multimedia has a GStreamer dependency.
- (Optional) [certifi] can provide alternative root certificates for TLS certificate validation. - (Optional) [certifi] can provide alternative root certificates for TLS certificate validation.
- Useful for MacOS, as Python doesn't use the system-provided certificates because of MacOS' outdated SSL library. Also miscellaneous systems without usable root certificates. - Useful for MacOS, as Python doesn't use the system-provided certificates because of MacOS' outdated SSL library. Also miscellaneous systems without usable root certificates.
@ -102,9 +100,9 @@ Pesterchum is a Python script. This means that as long as you have Python instal
- On macOS it's also possible to install (a more recent version of) Python via [Brew](https://brew.sh/). - On macOS it's also possible to install (a more recent version of) Python via [Brew](https://brew.sh/).
2. Install Pesterchum's dependencies with pip, run: ``python -m pip install -r requirements.txt`` 2. Install Pesterchum's dependencies with pip, run: ``python -m pip install -r requirements.txt``
- If this fails, try running ``python -m pip install -U pip setuptools wheel`` to update pip, setuptools & wheel and then trying again. - If this fails, try running ``python -m pip install -U pip setuptools wheel`` to update pip, setuptools & wheel and then trying again.
- Alternatively, many linux distros also have packages for pyqt and pygame. - Alternatively, many linux distros also have packages for PyQt6.
- Debian: [python3-pyqt6](https://packages.debian.org/testing/python/python3-pyqt6), [python3-pygame](https://packages.debian.org/testing/python/python3-pygame) - Debian: [python3-pyqt6](https://packages.debian.org/testing/python/python3-pyqt6)
- Arch: [python-pyqt6](https://archlinux.org/packages/extra/x86_64/python-pyqt6/), [python-pygame](https://archlinux.org/packages/community/x86_64/python-pygame/) - Arch: [python-pyqt6](https://archlinux.org/packages/extra/x86_64/python-pyqt6/)
3. Download [this repository's source](https://github.com/Dpeta/pesterchum-alt-servers/archive/refs/heads/main.zip), or choose the "Source Code" option on any release, and extract the archive to a folder of your choice. 3. Download [this repository's source](https://github.com/Dpeta/pesterchum-alt-servers/archive/refs/heads/main.zip), or choose the "Source Code" option on any release, and extract the archive to a folder of your choice.
- Alternatively, clone the repository with git. - Alternatively, clone the repository with git.
4. Navigate your terminal to the folder you chose with ``cd /folder/you/chose``. 4. Navigate your terminal to the folder you chose with ``cd /folder/you/chose``.
@ -116,8 +114,6 @@ Pesterchum is a Python script. This means that as long as you have Python instal
[pip]: https://pypi.org/project/pip/ [pip]: https://pypi.org/project/pip/
[PyQt5]: https://pypi.org/project/PyQt5/ [PyQt5]: https://pypi.org/project/PyQt5/
[PyQt6]: https://pypi.org/project/PyQt6/ [PyQt6]: https://pypi.org/project/PyQt6/
[pygame]: https://pypi.org/project/pygame/
[pygame-ce]: https://pypi.org/project/pygame-ce/
[certifi]: https://pypi.org/project/certifi/ [certifi]: https://pypi.org/project/certifi/
[GStreamer]: https://gstreamer.freedesktop.org/ [GStreamer]: https://gstreamer.freedesktop.org/

View file

@ -160,20 +160,6 @@ class MovingWindow(QtWidgets.QFrame):
self.moving = None self.moving = None
class NoneSound:
def __init__(self, *args, **kwargs):
pass
def play(self):
pass
def setVolume(self, v):
pass
def set_volume(self, v):
pass
class WMButton(QtWidgets.QPushButton): class WMButton(QtWidgets.QPushButton):
def __init__(self, icon, parent=None): def __init__(self, icon, parent=None):
super().__init__(icon, "", parent) super().__init__(icon, "", parent)

View file

@ -1567,15 +1567,19 @@ class PesterOptions(QtWidgets.QDialog):
self.audioDeviceBox = QtWidgets.QComboBox(self) self.audioDeviceBox = QtWidgets.QComboBox(self)
current_audio_device = self.config.audioDevice() current_audio_device = self.config.audioDevice()
active_index = None active_index = None
try: if hasattr(QtMultimedia, "QMediaDevices"):
for i, output in enumerate(QtMultimedia.QMediaDevices.audioOutputs()): # PyQt6
self.audioDeviceBox.addItem(f"{output.description()}", output.id()) try:
if output.id() == current_audio_device: for i, output in enumerate(QtMultimedia.QMediaDevices.audioOutputs()):
active_index = i self.audioDeviceBox.addItem(f"{output.description()}", output.id())
if active_index is not None: if output.id() == current_audio_device:
self.audioDeviceBox.setCurrentIndex(active_index) active_index = i
except AttributeError: if active_index is not None:
PchumLog.warning("Can't get audio devices, not using PyQt6 QtMultimedia?") self.audioDeviceBox.setCurrentIndex(active_index)
except AttributeError:
PchumLog.warning(
"Can't get audio devices, not using PyQt6 QtMultimedia?"
)
layout_sound = QtWidgets.QVBoxLayout(widget) layout_sound = QtWidgets.QVBoxLayout(widget)
layout_sound.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) layout_sound.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)

View file

@ -46,7 +46,6 @@ from generic import (
PesterList, PesterList,
CaseInsensitiveDict, CaseInsensitiveDict,
MovingWindow, MovingWindow,
NoneSound,
WMButton, WMButton,
) )
from convo import PesterTabWindow, PesterConvo from convo import PesterTabWindow, PesterConvo
@ -64,11 +63,20 @@ from randomer import RandomHandler, RANDNICK
from toast import PesterToastMachine, PesterToast from toast import PesterToastMachine, PesterToast
try: try:
from PyQt6 import QtCore, QtGui, QtWidgets from PyQt6 import QtCore, QtGui, QtWidgets, QtMultimedia
from PyQt6.QtGui import QAction, QActionGroup from PyQt6.QtGui import QAction, QActionGroup
# Give Linux QtMultimedia warning.
if ostools.isLinux():
print(
"QtMultimedia audio is a bit silly/goofy on Linux and relies on an appropriate"
" backend being availible."
"\nIf it doesn't work, try installing your distro's equivalent"
" of the qt6-multimedia-backend/qt6-multimedia/gstreamer packages."
)
except ImportError: except ImportError:
print("PyQt5 fallback (pesterchum.py)") print("PyQt5 fallback (pesterchum.py)")
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia
from PyQt5.QtWidgets import QAction, QActionGroup from PyQt5.QtWidgets import QAction, QActionGroup
# Data directory # Data directory
@ -142,60 +150,6 @@ BOTNAMES.extend(SERVICES)
# Command line arguments # Command line arguments
_ARGUMENTS = parser.parse_args() _ARGUMENTS = parser.parse_args()
# Import audio module
# Qt6.4's ffmpeg audio backend makes using QtMultimedia on linux less risky
try:
# PyQt6, QtMultimedia is prefered.
from PyQt6 import QtMultimedia
print("Audio module is PyQt6 QtMultimedia.")
except ImportError:
if ostools.isWin32() or ostools.isOSX():
# PyQt5 QtMultimedia has native backends for MacOS and Windows
try:
from PyQt5 import QtMultimedia
print(
"Using PyQt5 QtMultimedia as sound module. (fallback, PyQt6 QtMultimedia not availible)"
)
except ImportError:
try:
import pygame
print(
"Using pygame as sound module. (fallback, PyQt6 QtMultimedia and PyQt5 QtMultimedia not availible)"
)
except ImportError:
print(
"All possible audio modules failed to import."
"\nPossible audio modules in order of preference (Windows/MacOS): PyQt6 QtMultimedia > PyQt5 QtMultimedia > pygame"
)
# Linux or misc.
else:
# PyQt5 QtMultimedia needs gstreamer on linux, so pygame is prefered.
try:
import pygame
print(
"Using pygame as sound module. (fallback, PyQt6 QtMultimedia not availible)"
)
except ImportError:
try:
from PyQt5 import QtMultimedia
print(
"Using PyQt5 QtMultimedia as sound module. (fallback, PyQt6 QtMultimedia and pygame not availible)"
)
print(
"PyQt5 Multimedia will silently fail without GStreamer with relevant"
" plugins on Linux, pygame is prefered when using PyQt5."
)
except ImportError:
print(
"All possible audio modules failed to import."
"\nLPossible audio modules in order of preference (Linux/Unknown): PyQt6 QtMultimedia > pygame > PyQt5 QtMultimedia"
)
class waitingMessageHolder: class waitingMessageHolder:
def __init__(self, mainwindow, **msgfuncs): def __init__(self, mainwindow, **msgfuncs):
@ -1372,8 +1326,6 @@ class PesterWindow(MovingWindow):
self.honk = True self.honk = True
self.modes = "" self.modes = ""
self.sound_type = None
self.randhandler = RandomHandler(self) self.randhandler = RandomHandler(self)
try: try:
@ -2202,69 +2154,28 @@ class PesterWindow(MovingWindow):
self._setup_sounds() self._setup_sounds()
self.setVolume(self.config.volume()) self.setVolume(self.config.volume())
def _setup_sounds(self, soundclass=None): def _setup_sounds(self):
"""Set up the event sounds for later use.""" """Set up the event sounds for later use."""
# Set up the sounds we're using. # Define and load sounds
try: try:
# Pygame self.alarm = QtMultimedia.QSoundEffect()
soundclass = pygame.mixer.Sound # pylint: disable=used-before-assignment self.alarm.setSource(
except (NameError, AttributeError): QtCore.QUrl.fromLocalFile(self.theme["main/sounds/alertsound"])
try: )
# QtMultimedia self.memosound = QtMultimedia.QSoundEffect()
soundclass = QtMultimedia.QSoundEffect self.memosound.setSource(
except (NameError, AttributeError): QtCore.QUrl.fromLocalFile(self.theme["main/sounds/memosound"])
# death )
soundclass = NoneSound self.namesound = QtMultimedia.QSoundEffect()
PchumLog.warning("No sound module loaded?") self.namesound.setSource(QtCore.QUrl.fromLocalFile("themes/namealarm.wav"))
self.ceasesound = QtMultimedia.QSoundEffect()
self.sound_type = soundclass self.ceasesound.setSource(
QtCore.QUrl.fromLocalFile(self.theme["main/sounds/ceasesound"])
# These get redefined if sound works )
self.alarm = NoneSound() self.honksound = QtMultimedia.QSoundEffect()
self.memosound = NoneSound() self.honksound.setSource(QtCore.QUrl.fromLocalFile("themes/honk.wav"))
self.namesound = NoneSound()
self.ceasesound = NoneSound()
self.honksound = NoneSound()
# Use the class we chose to build the sound set.
try:
if "pygame" in globals():
if soundclass == pygame.mixer.Sound:
self.alarm = soundclass(self.theme["main/sounds/alertsound"])
self.memosound = soundclass(self.theme["main/sounds/memosound"])
self.namesound = soundclass("themes/namealarm.wav")
self.ceasesound = soundclass(self.theme["main/sounds/ceasesound"])
self.honksound = soundclass("themes/honk.wav")
if "QtMultimedia" in globals():
if soundclass == QtMultimedia.QSoundEffect:
self.alarm = soundclass()
self.memosound = soundclass()
self.namesound = soundclass()
self.ceasesound = soundclass()
self.honksound = soundclass()
self.alarm.setSource(
QtCore.QUrl.fromLocalFile(self.theme["main/sounds/alertsound"])
)
self.memosound.setSource(
QtCore.QUrl.fromLocalFile(self.theme["main/sounds/memosound"])
)
self.namesound.setSource(
QtCore.QUrl.fromLocalFile("themes/namealarm.wav")
)
self.ceasesound.setSource(
QtCore.QUrl.fromLocalFile(self.theme["main/sounds/ceasesound"])
)
self.honksound.setSource(
QtCore.QUrl.fromLocalFile("themes/honk.wav")
)
except: except:
PchumLog.exception("Warning: Error loading sounds!") PchumLog.exception("Warning: Error loading sounds!")
self.alarm = NoneSound()
self.memosound = NoneSound()
self.namesound = NoneSound()
self.ceasesound = NoneSound()
self.honksound = NoneSound()
self.sounds = [ self.sounds = [
self.alarm, self.alarm,
@ -2282,12 +2193,7 @@ class PesterWindow(MovingWindow):
vol = vol_percent / 100.0 vol = vol_percent / 100.0
for sound in self.sounds: for sound in self.sounds:
try: try:
if "pygame" in globals(): sound.setVolume(vol)
if self.sound_type == pygame.mixer.Sound:
sound.set_volume(vol)
if "QtMultimedia" in globals():
if self.sound_type == QtMultimedia.QSoundEffect:
sound.setVolume(vol)
except Exception as err: except Exception as err:
PchumLog.warning("Couldn't set volume: %s", err) PchumLog.warning("Couldn't set volume: %s", err)
@ -2298,23 +2204,21 @@ class PesterWindow(MovingWindow):
if "QtMultimedia" not in globals(): if "QtMultimedia" not in globals():
PchumLog.warning("Not using QtMultimedia, can't set audio device.") PchumLog.warning("Not using QtMultimedia, can't set audio device.")
return return
for output in QtMultimedia.QMediaDevices.audioOutputs(): if hasattr(QtMultimedia, "QMediaDevices"):
if device_id == output.id(): # PyQt6
for sound in self.sounds: for output in QtMultimedia.QMediaDevices.audioOutputs():
sound.setAudioDevice(output) if device_id == output.id():
for sound in self.sounds:
if sound:
sound.setAudioDevice(output)
def canSetVolume(self): def canSetVolume(self):
"""Returns the state of volume setting capabilities.""" """Returns the state of volume setting capabilities."""
# If the volume can be changed by Pesterchum. # If the volume can be changed by Pesterchum.
if self.sound_type is None: for sound in self.sounds:
# We haven't initialized yet. if sound:
return False return True
elif self.sound_type == NoneSound: return False # All None. . .
# Sound is dead
return False
else:
# We can set volume
return True
def changeTheme(self, theme): def changeTheme(self, theme):
# check theme # check theme
@ -4113,14 +4017,6 @@ class MainProgram(QtCore.QObject):
msgbox.setIcon(QtWidgets.QMessageBox.Icon.Critical) msgbox.setIcon(QtWidgets.QMessageBox.Icon.Critical)
msgbox.exec() msgbox.exec()
# If we're using pygame for sound we need to init
if "pygame" in globals():
# we could set the frequency higher but i love how cheesy it sounds
try:
pygame.mixer.init()
except Exception as err:
print("Warning: No sound! (pygame error: %s)" % err)
self.widget = PesterWindow(options, parent=self, app=self.app) self.widget = PesterWindow(options, parent=self, app=self.app)
# self.widget.show() <== Already called in showLoading() # self.widget.show() <== Already called in showLoading()

View file

@ -9,9 +9,6 @@ import PyInstaller.__main__
is_64bit = sys.maxsize > 2**32 is_64bit = sys.maxsize > 2**32
# is_linux = sys.platform.startswith("linux") # is_linux = sys.platform.startswith("linux")
exclude_modules = [] exclude_modules = []
# if is_linux == False:
# print("Not Linux, excluding pygame.")
# exclude_modules.append('pygame')
add_data = [ add_data = [
"quirks;quirks", "quirks;quirks",
"smilies;smilies", "smilies;smilies",

View file

@ -1,5 +1,4 @@
certifi==2022.12.7 certifi==2022.12.7
pygame-ce
PyQt5==5.15.7 PyQt5==5.15.7
PyQt5-Qt5==5.15.2 PyQt5-Qt5==5.15.2
PyQt5-sip==12.11.0 PyQt5-sip==12.11.0