35.4. winsound ? Windows 用の音声再生インタフェース を使っている
Python Tuner (電気羊の羊小屋 )を見て、ふと思った。winsound.Beep(周波数:Hz, 鳴らす時間:ミリ秒) で、PCのスピーカーを鳴らすことができる。
440Hz といえば A(ラ) の音。基準の周波数。ギターをやっていたころは、よく聴いた音。音叉を咥えてもだえていたなぁ。
チューナーの基礎知識 みたいな機械的なチューナーを使ったりもしたが、直接耳で聴くほうが気持ちがいい。440Hz に洗脳されてしまっている。
import winsound
winsound.Beep(440,500)
440Hz の倍音は 880Hz。この音のつながりは、時報だ。NHK の時報みたいにしてみようと調べてみる。
NHKの時報について を見ると、57秒、58秒、59秒に 440Hz の音を 100ミリ秒ならし、0秒で 880Hz を鳴らすとある。PCで実際にやってみると、100ms だと気持ちよくないので少し伸ばして 150ms にしてみた。
import winsound
import time
def time_signal():
for i in range(3):
winsound.Beep(440,150)
time.sleep(0.85)
winsound.Beep(880,1400)
if __name__ == '__main__':
times_signal()
時報っぽい音に聞こえるかな。でも、880Hz の音を減衰させていくことができないから不自然。だんだんと小さくなって消えて欲しいのだが。。。
動作確認できたら、これを 適当なファイル名.pyw で保存して、Windows だったらタスクマネージャに登録して。毎時間時報がなるようにしてみた。拡張子 pyw にしておけば、黒いコマンドプロンプトの画面が表示されずに音が鳴る。
ところが、性能が低い PC で動かそうとすると、負荷が高いときに、ちゃんとブツブツになってちゃんとした音にならないときがある。なので、優先順位を上げてやったらどうだろうと調べる。
import win32api
import win32process
import win32con
pid = win32api.GetCurrentProcessId()
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
win32process.SetPriorityClass(handle, win32process.HIGH_PRIORITY_CLASS)
のようにすれば、起動したプロセスの優先順位を高くできる。これを使って、音を鳴らす前に、優先順位を上げておけば、多少はよくなるかなと。Windows の優先順位は次のようになっている。
リアルタイム win32process.IDLE_PRIORITY_CLASS
高 win32process.BELOW_NORMAL_PRIORITY_CLASS
通常以上 win32process.NORMAL_PRIORITY_CLASS
通常 win32process.ABOVE_NORMAL_PRIORITY_CLASS
通常以下 win32process.HIGH_PRIORITY_CLASS
低い win32process.REALTIME_PRIORITY_CLASS
優先順位の定数の名前を覚えるのも大変なので、下のようにして 0 ~ 5 の値を指定すると、優先順位が上下できるというようにするとよいかな。起動したあとに、優先順位を高に上げて、一呼吸待ってから音を鳴らし始める。毎時 59分55秒にタスクをしかける。
# -*- coding: utf-8 -*-
import winsound
import time
## http://code.activestate.com/recipes/496767/ (r1)
def setpriority(pid=None,priority=1):
""" Set The Priority of a Windows Process. Priority is a value between 0-5 where
2 is normal priority. Default sets the priority of the current
python process but can take any valid process ID. """
import win32api,win32process,win32con
priorityclasses = [win32process.IDLE_PRIORITY_CLASS,
win32process.BELOW_NORMAL_PRIORITY_CLASS,
win32process.NORMAL_PRIORITY_CLASS,
win32process.ABOVE_NORMAL_PRIORITY_CLASS,
win32process.HIGH_PRIORITY_CLASS,
win32process.REALTIME_PRIORITY_CLASS]
if pid == None:
pid = win32api.GetCurrentProcessId()
handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
win32process.SetPriorityClass(handle, priorityclasses[priority])
## end of http://code.activestate.com/recipes/496767/
def time_signal():
"""" 時報を鳴らす """
for i in range(3):
winsound.Beep(440,150)
time.sleep(0.85)
winsound.Beep(880,1400)
if __name__ == '__main__':
# 優先度を 4 : win32process.HIGH_PRIORITY_CLASS にセット
setpriority(None, 4)
# 1.5秒待って
time.sleep(1.5)
# 時報を鳴らす
time_signal()
ところが実際にやってみると、キーボードで入力していたり、Youtube を見ていたりしても、きれいに音がなってくれない。やっぱり性能が低い PC だと厳しい。Beep のハードウェア割り込みとタイマー割り込みで、そこに他の負荷がかかってダメなのかな。
winsound.PlaySound(sound, flags) であらかじめ用意しておいた wave ファイルを鳴らした方が、気持ち悪くならないかな。
NHKの時報音(もどき)をダウンロードして使ってみる(C で書かれた音を作るためのソースコードも入っている )。この音を、
winsound.PlaySound("nhk.wav", winsound.SND_FILENAME)
で鳴らすようにした。こっちの方がいいな。
ちなみに、できるだけ正確な時間になにかをしようとしたら、sleep で何秒待って、何かをするというのは厳しいかもね。自前で時間を拾って、一定時刻を過ぎていたら何かするというようにしないと、同じ間隔で何かするというのが、負荷状況によっては、あまり正確にできない可能性がある。