PyAudioの再生に関する記事を検索するとまるでコピペしたかのようなサンプルプログラムが紹介されています。ここでそんなコードを書いても芸がないのでTkinterを使った再生のコードを紹介します。
まずは外観。
仕様
再生するファイルは固定です。(必ず用意してください) 再生ボタンを押すとファイルの音声データを全部再生します。 再生中は停止ボタンで再生を停止できます。
ソース
# -*- coding: utf-8 -*-
import pyaudio
import sys
import tkinter as tk
import wave
import time
DEVICE_INDEX = 0
CHUNK = 512
FORMAT = pyaudio.paInt16 # 16bit
CHANNELS = 1 # monaural
RATE = 44100 # sampling frequency [Hz]
REC_TIME = 5 # sec
MAX_FRAME = int(REC_TIME * RATE / CHUNK)
WAVE_FILENAME = 'fine.wav'
g_stopReq = False
g_playing = False
g_playedSize = 0
g_audio = pyaudio.PyAudio()
g_wf = wave.open(WAVE_FILENAME, "rb")
# g_stream = None とするとすっとNoneのまま
#一旦オープンしてクローズする
g_stream = g_audio.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True,
input_device_index = DEVICE_INDEX,
frames_per_buffer=CHUNK)
g_stream.close()
g_btnPlay = None
g_btnStop = None
g_root = None
#ボタンの有効無効の処理
def btnCtrl():
global g_playing, g_btnPlay , g_btnStop
if g_playing == True:
g_btnPlay .configure(state = 'disable')
g_btnStop.configure(state = 'normal')
else:
g_btnPlay .configure(state = 'normal')
g_btnStop.configure(state = 'disable')
def closeAudio():
global g_stream
g_stream.stop_stream()
g_stream.close()
g_audio.terminate()
def finish():
global g_playing
g_playing = False
btnCtrl()
closeAudio()
g_wf.close()
def callback(in_data, frame_count, time_info, status):
global g_stream,g_playing, g_stopReq, g_playedSize, g_root
data = g_wf.readframes(frame_count)
if g_stopReq == True:
g_stopReq = False
g_root.after(100, finish)
return (data, pyaudio.paAbort)
g_playedSize += int(len(data) / g_wf.getsampwidth())
# print(g_wf.getnframes(), ' ', g_playedSize)
if g_playedSize >= g_wf.getnframes():
# print("done")
g_root.after(100, finish)
return (data, pyaudio.paContinue)
#ボタンをクリックしたときのイベントハンドラー
def play_clicked():
global g_playing, g_audio,g_stream, g_playedSize,g_wf
g_playing = True
g_wf = wave.open(WAVE_FILENAME, "rb")
g_audio = pyaudio.PyAudio()
g_playedSize = 0
g_stream = g_audio.open(format=g_audio.get_format_from_width(g_wf.getsampwidth()),
channels=g_wf.getnchannels(),
rate=g_wf.getframerate(),
output=True,
stream_callback=callback)
g_stream.start_stream()
btnCtrl()
def stop_clicked():
global g_stopReq
g_stopReq = True
# btnCtrl()
def main():
global g_frame,g_playing, g_btnPlay , g_btnStop, g_root
g_root = tk.Tk()
g_root.title("オーディオ再生")
g_root.geometry("250x36")
g_btnPlay = tk.Button(
g_root,
text='再生',
compound=tk.TOP,
command=play_clicked)
g_btnPlay.grid(row = 0,column = 0)
g_btnStop = tk.Button(
g_root,
text='停止',
state = 'disable',
compound=tk.TOP,
command= stop_clicked)
g_btnStop.grid(row = 0,column = 1)
g_root.mainloop()
if __name__ == "__main__":
main()
コールバック関数です。ちょっと厄介でした。
def callback(in_data, frame_count, time_info, status):
global g_stream,g_playing, g_stopReq, g_playedSize, g_root
data = g_wf.readframes(frame_count)
if g_stopReq == True:
g_stopReq = False
g_root.after(100, finish)
return (data, pyaudio.paAbort)
g_playedSize += int(len(data) / g_wf.getsampwidth())
# print(g_wf.getnframes(), ' ', g_playedSize)
if g_playedSize >= g_wf.getnframes():
# print("done")
g_root.after(100, finish)
return (data, pyaudio.paContinue)
コールバック関数内で再生が終了した判断をしないと状態がずっと再生中になってしまいます。
現在のフレームがファイルで定義してあるフレーム数以上になれば再生の終了です。厳密には、
再生の最後を出そうとしているところです。タイマーで100ms後に終了の処理ffinish()をします。
停止の処理は、 return (data, pyaudio.paAbort)
次のコールバック関数が呼ばれないようにしています。録音ができれば再生は簡単だと表ちましたが、手こずりました。
|