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 行を越える長めのサンプルになってしまいました。
サンプルの実行例を下記に示しました。
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)
使い方が間違っているのかもしれませんが、バグがもしれないので問い合わせてみることにします。
参考サイト
にほんブログ村
#オープンソース
0 件のコメント:
コメントを投稿