Windows 11 における音声再生の自動フェードインのキャンセル(常時ゼロ再生)(Python-Sounddevice)

2023/12/17

最近 PC を更新し Windows 11 に乗り換えましたが、Windows 付属メディアプレイヤーの一時停止から再生再開するときに1秒程度音量が下がってしまうという問題があります。参考にしたサイトによると、単純に常時ひたすらゼロデータを再生し続けるオーディオアプリを実行させておくだけで解決できるようです。

たまたま 別の検討 で python-sounddevice を使ったことがあり、それを極限まで簡略化しただけのものを作ってみました。

なお、手元ではこの方法で、Windows 自身のサウンド(ダイアログ警告音など)や、Windows 付属メディアプレイヤーの再生開始がもっさりだったり一時停止の解除にワンクッション待たされる現象も、解消されました。どちらも、どうやら、再生する音声がない状態がある程度(数秒?)続くとカーネルミキサーがスリープしてしまい、一時停止解除したときにカーネルミキサーが再度アクティブになりきるまでストリームデータの送り込みが待たされる都合上で起きているように見えます。

目次


python-sounddevice を使う例のソースコード

実行には Python, sounddevice, numpy が必要です。

sd.play を使ったシンプルな例

import sounddevice as sd
import numpy as np

# サンプリングレート
fs = 48000

swav = np.zeros(fs)

while True:
    sd.play(swav, blocking=True) # 再生
    sd.wait() # play()の処理が終わるまで待機

exit()

上記を Python ソースコードのファイルとして保存し、実行するだけです。効果が出るのは実行中だけです。
実行しても画面上ではうんともすんとも言いません。GUIはありません。無限ループですので、終了は Ctrl+C か、コマンドプロンプト画面そのものを終了させることで行います。
デバイスの初期化と開放が while ループの都度行われるため、CPU 負荷がいくぶん高いようです。

ほんの少しですが CPU 負荷を下げるためゼロデータ再生長さを減らすとともに sleep を入れて都合3.5~4秒に1回程度の頻度にする:

import sounddevice as sd
import numpy as np
import time

# サンプリングレート
fs = 48000

swav = np.zeros(fs // 2)

while True:
    sd.play(swav, blocking=True) # 再生
    sd.wait() # play()の処理が終わるまで待機
    time.sleep(2.5)

exit()

sd.OutputStream を使って無限に再生する例

ストリームを使って無限に再生する。python-sounddevice の正弦波を再生し続けるサンプル https://python-sounddevice.readthedocs.io/en/0.4.6/examples.html#play-a-sine-signal を簡略化して単にデフォルトデバイスでゼロデータを再生するようにしたもの。このほうがデバイスの初期化と開放を繰り返さないので連続再生であっても CPU 負荷が軽い。

import sys
import numpy as np
import sounddevice as sd

samplerate = sd.query_devices(None, 'output')['default_samplerate']

def callback(outdata, frames, time, status):
    if status:
        print(status, file=sys.stderr)
    outdata[:] = np.zeros((frames, 1))


if __name__ == '__main__':
    with sd.OutputStream(device=None, channels=1, callback=callback,
                         samplerate=samplerate):
        print('#' * 51)
        print('infinitely playing zero sound. press Return to quit')
        print('#' * 51)
        
        try:
            input()
        except KeyboardInterrupt:
            exit()
        except Exception as e:
            exit(type(e).__name__ + ': ' + str(e))


# simplified from https://python-sounddevice.readthedocs.io/en/0.4.6/examples.html#play-a-sine-signal

2024/01/28 import sys が抜けていたので修正。

なお、Realtek の PC 内臓オーディオでは PC にイヤホンを抜き差ししたときに論理オーディオデバイスそのものが変更されるようで、その切り替えのタイミングで output underflow という表示(コールバック関数の status に入れられるもの)が出ることがあります。イヤホン挿入状態でこのプログラムを起動してからイヤホンを抜くと、イヤホン用の論理デバイスが消滅するためコールバック関数の呼び出しが止まってしまうこともあるようです。この種のデバイス動的変更に追随できないのは python-sounddevice がバックエンドで使っている PortAudio の仕様制約のようです。

もう少し親切に、使用デバイス名の表示と、動作中であることがわかるようにANSIエスケープシーケンスでくるくる回す(unix系由来のダウンローダーとかによくあるやつ)のを追加。この例では main を関数に分ける意味がないのでべた書きに変更。

import sys
import numpy as np
import sounddevice as sd

i = 0
s = ['-', '\\', '|', '/']

def callback(outdata, frames, time, status):
    global i
    if i > 31:
        i = 0
    if status:
        print(status, file=sys.stderr)
    outdata[:] = np.zeros((frames, 1))
    if i%4 == 0:
        print(s[i//8] + "\033[0G", end='', flush=True, file=sys.stderr)
        #print("\033[1A", end='', flush=True, file=sys.stderr) 
    i+=1


device = sd.query_devices(None, 'output')
#print(device)
samplerate = device['default_samplerate']

with sd.OutputStream(device=device['index'], channels=1, callback=callback,
                     samplerate=samplerate):
    print('#' * 51)
    print('infinitely playing zero sound. press enter to quit.')
    print('device:', device['name'])
    print('samplerate:', samplerate)
    print('#' * 51)
    
    try:
        input()
    except KeyboardInterrupt:
        exit()
    except Exception as e:
        exit(type(e).__name__ + ': ' + str(e))

そのほかの手段

常時ひたすらゼロデータを再生し続けるのは、他にもたとえば次のような方法もあります。

一つ目は普段使いには大げさですし、二つ目は DTM をやる人以外はハードルが高いかもしれません。
これ専用の極小な Win32 アプリを作ってみたいと思うのですが、MME とか WASAPI とかタスクバー常駐のさせ方とか、不勉強でよくわからないので、今すぐにはできません。いずれ、やってみたいなとは思っています。


参考にしたサイト


略歴


トップページ / 計算機関係の雑多なこと / Windows 11 における音声再生の自動フェードインのキャンセル(常時ゼロ再生)(Python-Sounddevice)
このサイトについて・著者連絡先