Only use QtMultimedia.QSoundEffect for audio.
This commit is contained in:
parent
c2826a8158
commit
b0f6995ef1
6 changed files with 57 additions and 179 deletions
10
README.md
10
README.md
|
@ -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/
|
||||||
|
|
||||||
|
|
14
generic.py
14
generic.py
|
@ -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)
|
||||||
|
|
22
menus.py
22
menus.py
|
@ -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)
|
||||||
|
|
186
pesterchum.py
186
pesterchum.py
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue