2024-07-20

QSoundEffect を利用した Wav Player ~ PySide6

PySide (Qt for Python) は、Qt(キュート)の Python バインディングで、GUI などを構築するためのクロスプラットフォームなライブラリです。Linux/X11, macOS および Microsoft Windows をサポートしています。配布ライセンスは LGPL で公開されています。

Wikipedia によると、wav を拡張子に持つファイルは、Microsoft とIBM により開発された RIFF waveform Audio Format (WAV) という音声ファイルフォーマットです。クリックやチャイムなど、効果音に利用されている比較的小さなサイズのファイルです。

PySide6 の QSoundEffect クラスは、マニュアル [1] によると、WAV ファイルのような低レイテンシな非圧縮のオーディオファイルを再生することができ、ユーザーのアクションに応答する「フィードバック 」タイプ(クリック音)のサウンド、例えば、仮想キーボードのクリック音、ポップアップダイアログの Yes / No の応答、あるいはゲームの効果音用途に適しているとあります。

さらに、低レイテンシが重要でない場合には、代わりに QMediaPlayer クラスの使用を検討してくださいともあります。

まずは QSoundEffect クラスの使い方を覚えようと、シンプルな Wav Player なるものを作ってみました。

下記の OS 環境で動作確認をしています。

RHEL 9.4 x86_64
Python 3.12.1
PySide6 6.7.2

なお、QSoundEffect クラスが含まれる QtMultimedia パッケージを利用するために、本 RHEL では追加で libva をインストールする必要がありました。

[bitwalk@rhel9 ~]$ rpm -qa | grep libva
libva-2.20.0-1.el9.x86_64
libva-devel-2.20.0-1.el9.x86_64
[bitwalk@rhel9 ~]$

サンプルを以下に示しました。ひとつにまとめたところ、200 行を越える長めのサンプルになってしまいました。

qt_soundeffect.py

サンプルの実行例を下記に示しました。

qt_soundeffect.py の実行例

WAV ファイルは、参考サイト [2] からダウンロードできるファイルを利用させていただきました。

サンプルの説明

WAV ファイルを読み込み、PLAY/STOP したり、ボリューム調整をする操作は、すべて QToolBar クラスを継承した MyToolBar クラスにまとめています。

class MyToolBar(QToolBar):
    wavSelected = Signal(str)
    wavPlay = Signal()
    wavStop = Signal()
    wavVolume = Signal(float)

    def __init__(self):
        super().__init__()

        but_folder = QToolButton()
        but_folder.setToolTip('Choose wav file.')
        ico_folder = get_icon(self, 'SP_DirIcon')
        but_folder.setIcon(ico_folder)
        but_folder.clicked.connect(self.file_dialog)
        self.addWidget(but_folder)

        self.but_play = but_play = QToolButton()
        but_play.setToolTip('Start playing wav file.')
        ico_play = get_icon(self, 'SP_MediaPlay')
        but_play.setIcon(ico_play)
        but_play.setEnabled(False)
        but_play.clicked.connect(self.wav_play)
        self.addWidget(but_play)
(以下省略)

QSoundEffect のインスタンスを扱うのは、QMainWindow クラスを継承した MyWavPlayer クラスです。ここでは QPlainTextEdit クラスを利用して、操作イベントのログ表示もしています。

class MyWavPlayer(QMainWindow):
    def __init__(self):
        super().__init__()
        icon_win = get_icon(self, 'SP_TitleBarMenuButton')
        self.setWindowIcon(icon_win)
        self.setWindowTitle('Wav Player')

        self.effect = None

        self.toolbar = toolbar = MyToolBar()
        toolbar.wavSelected.connect(self.source_selected)
        toolbar.wavPlay.connect(self.sound_play)
        toolbar.wavStop.connect(self.sound_stop)
        toolbar.wavVolume.connect(self.set_volume)
        self.addToolBar(toolbar)

        self.pte = pte = QPlainTextEdit()
        pte.setReadOnly(True)
        pte.setStyleSheet('QPlainTextEdit {background-color: white;}')

        self.setCentralWidget(pte)
(以下省略)

なお、QSoundEffect のインスタンスに読み込んだ WAV ファイルの変更ができなかったので、別の WAV ファイルを読み込む度に create_sound_effect メソッドでインスタンスを作り直しています。

    def create_sound_effect(self, wav_file: str):
        self.effect = QSoundEffect()
        self.effect.loopsRemainingChanged.connect(self.remaining_changed)
        self.effect.sourceChanged.connect(self.source_changed)
        self.effect.statusChanged.connect(self.status_changed)
        self.effect.volumeChanged.connect(self.volume_changed)

        self.effect.setSource(QUrl.fromLocalFile(wav_file))
        self.effect.setVolume(self.toolbar.getVolume())

PySide6 に組み込まれている標準のビットマップイメージ (Pixmap) を利用するために、名前を指定してアイコンを取得する関数を冒頭に記載しています。

def get_icon(parent, name: str) -> QIcon:
    pixmap = getattr(QStyle.StandardPixmap, name)
    icon = parent.style().standardIcon(pixmap)
    return icon

気づいたこと

QSoundEffect クラスのインスタンス effect について、二点、気になることがありました。

effect = QSoundEffect()

setSource メソッドで他の WAV ファイルを読み込んでも、再生されるサウンドに反映されなかった。

effect.setSource(QUrl.fromLocalFile(file))

再生ループで下記の無限ループの enum (QSoundEffect.Loop.Infinite) が利用できなかった。

effect.setLoopCount(QSoundEffect.Loop.Infinite)

使い方が間違っているのかもしれませんが、バグがもしれないので問い合わせてみることにします。

参考サイト

  1. QSoundEffect - Qt for Python
  2. フリーのBGMと動画やゲーム用音楽素材[Wave,MP3]

 

ブログランキング・にほんブログ村へ bitWalk's - にほんブログ村 にほんブログ村 IT技術ブログ オープンソースへ
にほんブログ村

オープンソース - ブログ村ハッシュタグ
#オープンソース



このエントリーをはてなブックマークに追加

0 件のコメント: