Psychopyで音を出したい:jitterが減るように

*注:まだうまくいってません

psychopyで音を出すのにjitterが大きい

psychopyは視覚刺激は概ね問題ないですが、音はjitterが大きくて誘発電位を取るのにはちょっと厳しいレベル(30 msとかその範囲)でした。

soundという関数(オブジェクト?)にまとまってますが、中ではpyo, pygameとかいうのを使ってるぽいです。

他によさげなライブラリ:sounddevice

jitterが大きくて困ってる人は他にもいるようで、ここのスレッドでsounddeviceが見込みがありそうだというのが見て取れました。

手前の環境でもwdm-ksとかその辺はなしでとりあえずsounddeviceをインポートしたところ、画面なしで音だけ出すとjitterが3 ms程度まで短縮しました。見込みありです。

インストールはpipでさくっと行けました。

お気づきの方はここで「ん?」と思うかも知れません。psychopy standaloneでインストールするとpipで追加できません(たぶん)なので、ここではanacondaでセットアップした環境での経験を出しています。

anacondaでpythonをセットアップしてもpipでpsychopyが追加できるのですね。つい最近知りました。

が、sounddeviceはインストールでトラブりやすい:portaudio.dllはどこだ?

ここで問題が1つありました。音の提示でwindowsのミキサーをスキップする(=命令して音がすぐ出る、おそらくjitterも減る)のに

WASAPI, ASIO, WDM-KS

とかいうのを(どれか1つ)利用する必要があるぽいですが、WASAPIは排他モードにするとこでどうもバグがあって、161121時点では多分ちゃんと使えません。ASIOは対応するハードが必要です。

でWDM-KSに期待ですが、

import sounddevice as sdsd.query_devices()

でMMEとかWASAPIは出てくるのですが、WDM-KSが出てきません(ASIOも)。どうもsounddeviceが利用しているportaudioというライブラリにいろいろ種類があるぽいです。

素でインストールされるportaudioのdllはいろいろライブラリが入っているsite-packagesの中の

_sounddevice_dataというフォルダの中にある

libportaudio32bit.dll (64bitだったら32が64になります)なのですが、これが古かったり読み込まれなかったりします。

古いぽい時はここに行ってダウンロードできます。

しかしファイルを入れ替えてもなおかつうまく行きませんでした。

どの掲示板を見たか忘れましたが、よそにあるportaudio.dllを先に見つけて読み込むことがあるようなのです。

適当にportaudio.dllをリネームしたりしましたが、うまく行きませんでした。一体どこによそのファイルはあるのでしょう?

で、sd.query_devices()でWDM-KSが出るようにするには?

sounddevice.pyの中身を一所懸命見てみると、最初の方にportaudioを読み込んでるぽい部分がありました(自分のでは315-328行)。

try: _lib = _ffi.dlopen('portaudio')except OSError: if _platform.system() == 'Darwin': _libname = 'libportaudio.dylib' elif _platform.system() == 'Windows': _libname = 'libportaudio' + _platform.architecture()[0] + '.dll' else: raise _lib = _ffi.dlopen(_os.path.join( _os.path.dirname(_os.path.abspath(__file__)), '_sounddevice_data', _libname ))

上記部分2行目の

'portaudio'

のとこを読ませたいdllのフルパスに変えたらよさげです。

上記部分を全部コメントアウトして、

lib_path = 'C:\\Users\\ユーザー名\\Anaconda2\\Lib\\site-packages\\_sounddevice_data\\libportaudio32bit.dll'_lib = _ffi.dlopen(lib_path)

(ひつこいですが、"32"は64bit環境は"64"にしてください。ファイルがちゃんとあることも要確認)

としたら、ようやく

In [2]: sd.query_devices()Out[2]: 0 Microsoft サウンド マッパー - Input, MME (2 in, 0 out)> 1 マイク (USB PnP Sound Device), MME (1 in, 0 out) 2 マイク配列 (Realtek High Defini, MME (2 in, 0 out) 3 Microsoft サウンド マッパー - Output, MME (0 in, 2 out)< 4 スピーカー (USB PnP Sound Devic, MME (0 in, 2 out) 5 スピーカー (Realtek High Defini, MME (0 in, 2 out) 6 プライマリ サウンド キャプチャ ドライバー, Windows DirectSound (2 in, 0 out) 7 マイク (USB PnP Sound Device), Windows DirectSound (1 in, 0 out) 8 マイク配列 (Realtek High Definition Audio(SST)), Windows DirectSound (2 in, 0 out) 9 プライマリ サウンド ドライバー, Windows DirectSound (0 in, 2 out) 10 スピーカー (USB PnP Sound Device), Windows DirectSound (0 in, 2 out) 11 スピーカー (Realtek High Definition Audio(SST)), Windows DirectSound (0 in, 2 out) 12 スピーカー (Realtek High Definition Audio(SST)), Windows WASAPI (0 in, 2 out) 13 スピーカー (USB PnP Sound Device), Windows WASAPI (0 in, 2 out) 14 マイク配列 (Realtek High Definition Audio(SST)), Windows WASAPI (2 in, 0 out) 15 マイク (USB PnP Sound Device), Windows WASAPI (1 in, 0 out) 16 Speakers 1 (Realtek HD Audio output with SST), Windows WDM-KS (0 in, 2 out) 17 Speakers 2 (Realtek HD Audio output with SST), Windows WDM-KS (0 in, 2 out) 18 PC スピーカー (Realtek HD Audio output with SST), Windows WDM-KS (2 in, 0 out) 19 Headphones 1 (Realtek HD Audio 2nd output with SST), Windows WDM-KS (0 in, 2 out) 20 Headphones 2 (Realtek HD Audio 2nd output with SST), Windows WDM-KS (0 in, 2 out) 21 PC スピーカー (Realtek HD Audio 2nd output with SST), Windows WDM-KS (2 in, 0 out) 22 マイク配列 (Realtek HD Audio Mic Array input), Windows WDM-KS (2 in, 0 out) 23 Headset Microphone (Realtek HD Audio Mic input), Windows WDM-KS (2 in, 0 out) 24 スピーカー (USB PnP Sound Device), Windows WDM-KS (0 in, 2 out) 25 マイク (USB PnP Sound Device), Windows WDM-KS (1 in, 0 out)

てな感じでWDM-KSが認識されたぽいです。

あとは?

マニュアルページを見たほうがよいですが、

音ファイルをnp.arrayに変換した変数(ここではmysnd)とか用意して

# デバイスの選択sd.default.device = [25, 24]# 音鳴らすsd.play(mysnd)

とかするとWDM-KSを通した音になるようです。

sd.query_devices()

とか

sd.query_hostapis()

とかいろいろ叩いて結果を眺めてみると何をしてるのか少しずつ分かってきました。

結果はまた追って記載したいと思います。