まるぼ実験場

アプリの開発日記を載せるサイトでしたが、ただの技術ブログになりました。

Pyaudioをループしたときに通知領域のマイクアイコンが荒ぶっていた問題が今更解決した

marubodiary.hateblo.jp
この大昔作ったネタアプリだが、最後に大問題を残したままなのだった。
・起動中に通知領域のマイクが荒ぶる問題
これの解決にようやく取り組む気になってそして解決したので、問題解決版のソースコードを書いておく。

結論

音声入力と画像描画を、スレッドに分けて処理した。

import pygame
from pygame.locals import *
import sys
import pyaudio
import numpy as np
import threading

#pyaudio初期化
chunk = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100

p = pyaudio.PyAudio()
stream = p.open(format = FORMAT,channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = chunk)
# 閾値
threshold = 0.025
# 音データ格納用配列
x = np.empty(chunk)

#pygame初期化
pygame.init()
screen = pygame.display.set_mode((500,500))
pygame.display.set_caption("VTuber?")

#画像取得
#基本
bg = pygame.image.load("base.png").convert_alpha()
image_rect = bg.get_rect()
#目
me1 = pygame.image.load("me.png").convert_alpha()
me2 = pygame.image.load("me2.png").convert_alpha()
me3 = pygame.image.load("me3.png").convert_alpha()
#口
kuti1 = pygame.image.load("kuti.png").convert_alpha()
kuti2 = pygame.image.load("kuti2.png").convert_alpha()
#髪
kami = pygame.image.load("kami.png").convert_alpha()
#フォント
font = pygame.font.Font(None, 20) 

#タイマー変数
Timer = 0

#描画周期設定
Clock = pygame.time.Clock()
FPS = 30

	
def draw():
	while True:
		pygame.display.update()
		
		#時間経過
		Timer = pygame.time.get_ticks()
		# 画像生成
		ImageOut(screen, image_rect, bg, Select_Eye(Timer), Select_mouse(x, threshold), Select_Add())
		
		#デバッグ用
		#DebugGraph(screen, Timer)

		pygame.display.flip()
		Clock.tick(FPS)                     #画面更新

def streamread():
	global x
	while True:
		# 音データの取得
		data = stream.read(chunk)
		
		# ndarrayに変換
		x = np.frombuffer(data, dtype="int16") / 32768.0


def main():
	while True:
	# 終了用のイベント処理
		for event in pygame.event.get():
			# 閉じるボタンが押されたときの処理
			if event.type == QUIT:
				stream.close()
				p.terminate()
				pygame.quit()
				sys.exit()

#----------------
# パーツ選択
#----------------
def Select_Eye(Timer):
	
	# 瞬き(力技。。。もうちょい自然な見せ方があるはず
	if ((Timer % 2100) <= 160):
		put_me = me2        #目(閉じ)描画
	else:
		put_me = me1        #目描画
	
	#キー押下によって目の描画オブジェクトを変更する
	pressed_key = pygame.key.get_pressed()
	if pressed_key[K_q]:
		put_me = me3            #目(><)描画
	
	return put_me

def Select_mouse(x, threshold):
	#音声認識によって口の描画オブジェクトを変更する
	if x.max() > threshold:
		put_kuti = kuti1      #音声入力があるときの口描画
	else:
		put_kuti = kuti2      #何もないときの口描画
		
	return put_kuti
	
def Select_Add():
	#一番上に描画する画像(アクセサリーなど)
	put_add = kami      #髪描画
	
	return put_add
	
#----------------
# 描画
#----------------
def ImageOut(screen, image_rect, bg, me, kuti, add):
	screen.fill((0, 255, 0, 0))         # 画面の背景色(緑)
	screen.blit(bg, image_rect)         # ベース画像の描画
	screen.blit(me, image_rect)     # 目画像の描画
	screen.blit(kuti, image_rect)   # 口画像の描画
	screen.blit(add, image_rect)     # 上部画像の描画
	
	return

#----------------
# デバッグ用表示
#----------------
def DebugGraph(screen, Timer):
	print(Timer)
	
	return

#スレッド作成
thread1 = threading.Thread(target=draw)
thread2 = threading.Thread(target=streamread)
thread1.setDaemon(True)
thread2.setDaemon(True)
thread1.start()
thread2.start()

if __name__ == "__main__":
	main()