PythonでMP3再生(playsound3)
でも触れたようにこれまで使ってきた「読み上げ」機能を見直しているところです。
LinterとFormatter
まず、形式的なところから。使ってきたライブラリファイルに、black isort flake8の3点セットを順番に適用。
black isortの後に実行しているflake8はこれまで何も出力が無かったので、「black以上の仕事を何かしてくれているのかな?」と疑っていたのですが(笑) 今回は、的確な指摘をくれました。
> flake8 myspeech_lib.py
myspeech_lib.py:9:15: E711 comparison to None should be 'if cond is not None:'
import tempfile
import time
from gtts import gTTS
from pygame import mixer
def myspeech(mylang, mytext):
if mytext != None:
with tempfile.TemporaryFile(delete=True, dir=".", suffix=".mp3") as f:
# 文字列をmp3ファイルに保存
myobj = gTTS(text=mytext, lang=mylang, slow=False)
myobj.write_to_fp(f)
# mp3再生
mixer.init()
f.seek(0)
mixer.music.load(f)
time.sleep(0.3)
mixer.music.play(loops=1)
while mixer.music.get_busy():
time.sleep(0.1)
else:
myspeech("ja", "データが無いようですよ")
# テストコード
def main():
myspeech("en", "Good morning!")
myspeech("zh-TW", "早安!")
myspeech("ja", "おはよう!")
if __name__ == "__main__":
main()
9行目で
>if mytext != None:
とやっている部分を、!=ではなくて is not None と書くべきだ、という指摘。たしかにおっしゃるとおり。⇒修正入れておきました。
気になる箇所
さて、「そのうえで」ようやく「中身」の話です。
sleepとかseekとかmixer.music.get_busy()のwhileループとか出てくるのがどうも気になる。これは「音声再生」のために、「pygame」ライブラリの中の「mixer」モジュールを使っている箇所です。自分が気になって(引っかかって)いたのは「gTTSの使い方」ではなくて、「mp3の再生方法」なんだ、と自覚しました。
sleepとかseekとかget_busy()とか、こういうのはあまり見たくないし、他の人にも見せたくない。さもないと、「素人がわけもわからず無理やりひねくりまわしてでっち上げているコードなんて大丈夫なのかよ」と思われそうだし・・(^_^;)
MP3ファイル再生機能
pygame
さかのぼると年初にこんな記事書いていました。
そもそも当時なんでmp3の再生にpygameを使ったのだったかというと・・・。
playsound
たしか、playsoundというモジュールがよさそうだったんだけどメンテされていなかったからだっけな。
最新リリースが2021年7月24日で終わっています。
playsound3
ちょっと「周辺」を検索してみたら、playsoundならぬplaysoud3
というモジュールが新しく出ています。2024年5月7日に初リリース2.0.0.
こちらの最新リリースは2024年9月15日の2.2.2。
年初の当方記事「以降」にリリースされたもので、その後も、しっかり継続的にメンテされているようです。ライセンスもMIT License。これは試さなければ・・。
playsound3やってみる
というわけで、まず、pip install playsound3
します。テストコード
from playsound3 import playsound
playsound("test.mp3")
問題なく鳴りました。すばらしい! もう、これだけ・・・自分が描いたコードの中に、sleepもいらない、get_busyもwhileループもいらない。
これですよこれ、当方が求めていたものは・・。
ドキュメントへのリンク
関数の説明部(上記リンク先のドキュメントより)
def playsound(sound, block=True, backend=None) -> None:
"""Play a sound file using an audio backend availabile in your system.
Args:
sound: Path or URL to the sound file. Can be a string or pathlib.Path.
block: If True, the function will block execution until the sound finishes playing.
If False, sound will play in a background thread.
backend: Name of the audio backend to use. Use None for automatic selection.
"""
...
もう、翻訳は躊躇なくCopilot先生に頼ります(^_^;)
ブロック
非同期処理とか、バックグラウンドスレッドとかは、分からないので、デフォルトのとおりTrueにしておきます。
バックエンド
AVAILABLE_BACKENDS
from playsound3 import AVAILABLE_BACKENDS
print(AVAILABLE_BACKENDS)
これを実行すると(利用可能なバックエンドとして)
['afplay', 'alsa_mpg123', 'ffplay', 'gst_play', 'gst_legacy', 'mci_winmm']
と出ました。わからん(まあ、おススメされている通りデフォルト値である
Noneにしておきましょう。)
次回は
MP3音声再生の目途がついたので、gTTSと組み合わせて従来のライブラリの置き換えを試みます。