Tkinterを使った再生
 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)
次のコールバック関数が呼ばれないようにしています。録音ができれば再生は簡単だと表ちましたが、手こずりました。