見出し画像

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.
    """
    ...

It requires one argument: sound - the path to the file with the sound you'd like to play. This should be a local file or a URL. There's an optional second argument: block which is set to True by default. Setting it to False makes the function run asynchronously. You can manually specify a backend by passing its name as the third argument. You can browse available backends by using playsound3.AVAILABLE_BACKENDS. It is recommended to use the default value of None to let the library choose the best backend available.

https://github.com/sjmikler/playsound3?tab=readme-ov-file#documentation

もう、翻訳は躊躇なくCopilot先生に頼ります(^_^;)

"""システムで利用可能なオーディオバックエンドを使用して音声ファイルを再生します。

引数:
sound: 音声ファイルへのパスまたはURL。文字列またはpathlib.Pathを使用できます。
block: Trueの場合、音声の再生が終了するまで実行をブロックします。
Falseの場合、音声はバックグラウンドスレッドで再生されます。
backend: 使用するオーディオバックエンドの名前。自動選択にはNoneを使用します。
"""

1つの引数が必要です:sound - 再生したい音声ファイルのパスです。これはローカルファイルまたはURLである必要があります。オプションの2つ目の引数としてblockがあり、デフォルトではTrueに設定されています。Falseに設定すると、関数は非同期で実行されます。3つ目の引数としてバックエンドの名前を渡すことで手動で指定することもできます。利用可能なバックエンドはplaysound3.AVAILABLE_BACKENDSを使用して確認できます。ライブラリが利用可能な最適なバックエンドを選択できるように、デフォルト値のNoneを使用することをお勧めします。

ブロック

非同期処理とか、バックグラウンドスレッドとかは、分からないので、デフォルトのとおりTrueにしておきます。

バックエンド

AVAILABLE_BACKENDS

from playsound3 import AVAILABLE_BACKENDS
print(AVAILABLE_BACKENDS)

これを実行すると(利用可能なバックエンドとして)

['afplay', 'alsa_mpg123', 'ffplay', 'gst_play', 'gst_legacy', 'mci_winmm']

と出ました。わからん(まあ、おススメされている通りデフォルト値である
Noneにしておきましょう。)

次回は

 MP3音声再生の目途がついたので、gTTSと組み合わせて従来のライブラリの置き換えを試みます。

いいなと思ったら応援しよう!