mieki256's diary



2024/09/17(火) [n年前の日記]

#1 [python] Pythonでwavファイルをループ再生したい

Windows10 x64 22H2 + Python 3.10.10 64bt を使って、wavファイルをループ再生したい。tkinterを使ってウインドウ表示して、ボタンを押したら、winsound を使って再生開始/停止をしたい。

経緯 :

自分はPCに、オーディオセレクタ SONY SB-A40 を繋いで、複数のヘッドフォンをその時々で切り替えて使っているのだけど。どうもここ最近接触が悪くて、うっかりすると左側 or 右側の音が鳴ってなかったりする。

ちゃんと左右の音が出ているのか、それっぽいwavファイルをbatファイル経由で鳴らして確認していたけれど、これだとループ再生させたり、途中で強制停止させることができない。

wavファイルをループ再生させつつ、ボタンをクリックしたら停止/再生ができる何かが欲しいなと思えてきた。いやまあ、探せばシンプルな再生アプリが見つかりそうだけど…。

AIに作ってもらった :

生成AIの Microsoft Copilot に、そういう処理をするPythonスクリプトを作ってもらった。

最初の生成結果はスレッドを使ってループ再生するスクリプトだったのだけど、ウインドウを閉じてもずっとループ再生してダメダメだった。そこで、「スレッドを使うな」だの「winsound.SND_LOOPを使え」だの何度も修正指示を出しみたところ、それらしいスクリプトにしてくれた。

_speakertestpy.pyw
wavfile = "speakertest.wav"

import tkinter as tk
from tkinter import filedialog
import winsound

class LoopPlayer:
    def __init__(self, root):
        self.root = root
        self.root.title("Speaker Test")
        self.root.geometry("270x130")
        self.is_playing = False
        self.file_path = wavfile

        self.play_button = tk.Button(root, text="Play", command=self.toggle_play)
        self.play_button.pack(pady=20, ipadx=40, ipady=8)

        self.file_label = tk.Label(root, text=self.file_path)
        self.file_label.pack()

        self.select_button = tk.Button(root, text="Select WAV", command=self.select_file)
        self.select_button.pack()

        self.toggle_play()
        self.root.bind("<Return>", (lambda event: self.toggle_play()))
        self.root.bind("<KeyPress-space>", (lambda event: self.toggle_play()))

    def select_file(self):
        self.file_path = filedialog.askopenfilename(filetypes=[("WAV files", "*.wav")])
        if self.file_path:
            self.file_label.config(text=self.file_path.split("/")[-1])

    def toggle_play(self):
        self.is_playing = not self.is_playing
        if self.is_playing:
            self.play_button.config(text="Stop")
            winsound.PlaySound(self.file_path, winsound.SND_FILENAME | winsound.SND_ASYNC | winsound.SND_LOOP)
        else:
            self.play_button.config(text="Play")
            winsound.PlaySound(None, winsound.SND_FILENAME)

if __name__ == "__main__":
    root = tk.Tk()
    app = LoopPlayer(root)
    root.mainloop()

speakertestpy_pyw_ss01.png

これでいいんじゃないかな…。winsound を使っているから、Windows上でしか動かないけれど…。

_winsound --- Windows 用の音声再生インターフェース - Python 3.10.15 ドキュメント

使っている wavファイルは以下。たしか MUSIC MAKERを使って自作したwavファイルだったような気がするので CC0/Public Domain ってことで。

_speakertest.wav

余談。Google gemini にも作ってもらったけれど、そちらのほうがサンプルスクリプトらしい分かりやすいコードを出してきた。クラスを無理矢理作ったりしないし、各行にコメント文を逐一入れて解説してくれた。生成AIと言っても、生成結果が結構違うのだな…。

batファイルで鳴らすやり方 :

一応メモ。今までは以下のbatファイルで鳴らしてた。再生が終わると Y/N を尋ねてきて、y なら再度再生、n なら終了する。

_speakertest_play.bat
@echo off
chcp 65001
:REPLAY
setlocal enabledelayedexpansion
set WAVFILE=D:\home\Music\speakertest\speakertest.wav
echo Play %WAVFILE%
PowerShell -c "(New-Object Media.SoundPlayer %WAVFILE%).PlaySync();"
endlocal
set /p yn_check="Retry ? (y/N): "
IF %yn_check:Y=Y%==Y goto REPLAY
IF %yn_check:N=N%==N goto END
:END

batファイルと言いつつ途中で PowerShell を呼び出してwavファイルを再生してるあたりが…。「だったら最初から PowerShellスクリプトで書けばいいじゃん。何やってんの」と言われそうだけど、PowerShellスクリプトは実行ポリシーを設定しないとそもそも実行できないので、そのあたりで悩んでしまってこうなったような気もする。

_PowerShellの実行ポリシーについて調査(その設定で本当に大丈夫ですか?) #ps1 - Qiita
_PowerShellの実行ポリシー変更 #Windows - Qiita

サウンド設定を呼び出せれば済む話 :

M/B に載ってるサウンド用チップが Realtek Audio なら、設定ダイアログ上に、左右から音が出てるか確認する機能が載っているので、それを使えば済んでしまうのだけど…。どこを辿れば呼び出せるのかよく分からなくて…。

Realtek Audio Console で検索すれば出てくるのかな?

まともなオーディオセレクタが欲しい :

オーディオセレクタ SONY AB-40 は、ステレオミニジャック対応で、4入力/2出力 or 2入力4出力なのだけど。この製品、もう売ってないのだよな…。売ってたとしても、結構なお値段。

代替になるオーディオセレクタが欲しいのだけど、製品ジャンル自体がマイナーなようで、日本メーカはこういう製品をもうどこも作ってない。中国製品の中から探すしか…。

以上、1 日分です。

過去ログ表示

Prev - 2024/09 -
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project