見出し画像

音源再生ライブラリ書き換え(2)

奇妙な「間延び」

の問題が解決したので、あらためてライブラリファイルを書き換えて行きます。とりあえず、sounddevice のplay wait stopといったメソッドを使って再生だけ試します。

from abc import ABC, abstractmethod
from threading import Thread

import customtkinter as ctk
import numpy as np
import sounddevice as sd
from pydub import AudioSegment


class CustomPlayer(ABC):
    @abstractmethod
    def play(self):
        pass


class MyPlayer2(CustomPlayer):
    def __init__(self):
        super().__init__()
        self.filename = None
        self.audio = None
        self.audio_data = None  # オーディオデータ
        self.sr = None  # サンプルレート
        self.is_playing = False

    def set_mp3file(self, filename):
        self.filename = filename
        self.audio = AudioSegment.from_mp3(filename)
        self.audio_data = np.array(self.audio.get_array_of_samples())
        if self.audio.channels == 2:
            self.audio_data = self.audio_data.reshape((-1, 2))
        self.sr = self.audio.frame_rate

    def play_audio(self):
        if self.filename is not None:
            if not self.is_playing:
                self.is_playing = True
                sd.play(self.audio_data, samplerate=self.sr)
                sd.wait()
                self.is_playing = False

    # 抽象メソッドを実装
    def play(self):
        if not self.is_playing:
            Thread(target=self.play_audio).start()

    def stop(self):
        # self.playback.stop()
        if self.is_playing:
            sd.stop()


if __name__ == "__main__":

    class App(ctk.CTk):

        def __init__(self, title):

            # main window
            super().__init__()
            self.title(title)

            # player
            self.player = MyPlayer2()
            self.player.set_mp3file("test2.mp3")

            # widget
            ctk.CTkButton(self, text="再生", command=self.player.play).pack(
                padx=50, pady=10
            )
            # mainloop
            self.protocol("WM_DELETE_WINDOW", self.on_closing)
            self.mainloop()

        def on_closing(self):
            # 閉じる前にやること
            self.player.stop()
            # 閉じる
            self.destroy()

    App("MyMP3Player2")

クリック⇒鳴った、再生成功。

ただ、just_playbackにあったようなduration プロパティとか、seekメソッドなどと、同じようなのがsounddeviceにあるかと思っていたら、

見た感じ、play wait stopといったメソッドと同列のところにはなさそうです。どうやら Streams using NumPy Arrays 

の中にあるメソッド名などに「それっぽい」のがあるように?見えます。
 ただStreamの概念・お作法を全然知らないので、勉強が必要。

まず、「動く」基本のコードから

import time

import numpy as np
import sounddevice as sd
from pydub import AudioSegment

start_time = time.time()

# 音声ファイルを読み込む
audio = AudioSegment.from_file("test2.mp3")
audio_data = np.array(audio.get_array_of_samples())

# ステレオデータの場合、2次元配列に変換する
if audio.channels == 2:
    audio_data = audio_data.reshape((-1, 2))

sr = audio.frame_rate

# 音声の再生
sd.play(audio_data, samplerate=sr)
sd.wait()

end_time = time.time()
print(f"{end_time - start_time:.3f}秒")

114.134秒(本体113秒)
「音声の再生」の2行をStreamを使った方法に書き換える。

# 音声の再生
# Create OutputStream
output_stream = sd.OutputStream(
    samplerate=sr, channels=audio.channels, dtype="int16"
)

# Start the stream
output_stream.start()

# Write data to the stream
output_stream.write(audio_data)

# Close the stream
output_stream.close()

これでも同様に最後まで再生できました。113.323秒。速いじゃない!

ライブラリの書き換えを考えたとき、pause とか resumeも欲しい。Copilotに聞いてみます。

なるほど、stream.write(data[start_pos:]) で開始位置指定して開始できる。フレームレート×秒数で開始位置の値になる。ということのようです。

 だんだんと目途が立ってきた気がします。

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