OLのスタートチャイマー

1. はじめに

OL(オリエンテーリング)のスタート時にスタートチャイマーを使うことがあります。これは、公式な現在時刻を示すとともに、スタートのタイミングを音で知らせてくれる大きな時計板です。スタートは、多くの場合、2分毎の00分に行われるため、その数秒前に呼び鈴がなり、スタート時に別の音で知らせてます。

主に子供向けにオリエンテーリングを開催してきているのですが、いつもスタートチャイマーは借りてばかり。それなら自前で用意しようと思いました。

これを、最初はハードウエアで作ろうと思いました。時計の心臓部はRaspbery piで、表示部は大型7セブLEDで作れば、技術的には可能です。しかし、大型7セグのLEDの価格を見てビックリ。1個2000円程度~でした。時計の性質上、LEDは6個必要です。この他、部品等を考えると、予算は2万円を超えそうです。また、ハードウエアを作る作業時間を考えると(これは、楽しくもあるのですが)、ちょっとしり込みしてしまいました。

それなら、ソフトウエアで作って、タブレットPCに表示させるのでも良いのではないか?と思いました。正規のスタートチャイマーより小さくて存在感に欠けますが、機能として十分でしょう。

というのが、モチベーションで、スタートチャイマーをソフトウエアで作ってみることにします。

2. Python にて作ってみる

まずは、勉強もかねてPythonにて作ってみることにしました。
時計の部分は、簡単なデジタル時計Pythonスクリプトのページを参考に、音を出す部分は、モリカトロン開発者ブログを参考にさせていただきました。

こちらが、そのコードです。ここでは、音を出す部分で、pyaudioパッケージを使用しています。

from tkinter import *
from datetime import datetime
import numpy as np  # install : conda install numpy
import pyaudio      # install : conda install pyaudio
import time

# オーディオ準備
SAMPLE_RATE = 44100
def play(s: pyaudio.Stream, freq: float, duration: float):
  samples = np.sin(np.arange(int(duration * SAMPLE_RATE)) * freq * np.pi * 2 / SAMPLE_RATE)
  s.write(samples.astype(np.float32).tostring())
p = pyaudio.PyAudio()

# ストリームを開く
stream = p.open(format=pyaudio.paFloat32,
                channels=1,
                rate=SAMPLE_RATE,
                frames_per_buffer=1024,
                output=True)

# キャンバス準備
c = Canvas(width = 1000, height = 700, background = '#000000')
c.pack()
try:
    while True:
        now = datetime.now()
        s = '{0:0>2d}:{1:0>2d}:{2:0>2d}'.format(now.hour, now.minute, now.second)
        c.create_rectangle(0, 0, 1000, 700, outline = '#000000', fill = '#000000')
        c.create_text(500, 350, text = s, font = ('', 200), fill = 'red')
        c.update()
        time.sleep(0.2)

        if not now.minute % 2 == 0 and now.second == 0:
          play(stream, 261.626, 2.0)  # note#60 C4 ド

        if not now.minute % 2 == 0 and now.second == 55:
          play(stream, 261.626, 0.5)  # note#60 C4 ド

        if not now.minute % 2 == 0 and now.second == 57:
          play(stream, 261.626, 0.2)  # note#60 C4 ド

        if not now.minute % 2 == 0 and now.second == 58:
          play(stream, 261.626, 0.2)  # note#60 C4 ド

        if not now.minute % 2 == 0 and now.second == 59:
          play(stream, 261.626, 0.2)  # note#60 C4 ド

except:
    pass
    

実行すると、ちゃんと時刻が表示され、音もなります。

しかし、時間が経つと秒の表示が飛び飛びになり、音も正規の時刻からずれたり鳴らなかったりします。これでは、スタートチャイマーとして使えません。

このプログラムでは、音を毎回作成しているので、処理が重いのかと思い、pygameを使って、予め用意した*.wavファイルを実行するようにしてみましたが、やっぱり症状が同じ。。。

インタプリタだから駄目なのかとおもい、pyinstallerで*.exeファイルを作ろうとしましたが、こちらは何故か上手くコンパイルができず。。。

マルチスレッドとか使えば良いのかもしれませんが、この作業は手っ取り早く終わらせたかったので、ここで断念することにしました。

3. HTML + Javascriptで作ってみる

かといって、スタートチャイマーを諦めきれなかったので、今度はHTML+Javascriptで作ってみることにしました。時計部はできるとしても、果たして音が出るのか心配でしたが、簡単に調べただけでもHTML5で音が扱えることが分かり一安心。早速作ってみることに。

時計部に関しては、にしし ふぁくとりーのページ、音関係はJavaScript で Beep 音を鳴らす方法を参考にさせていただきました。

できあがったhtml(index.html)コードがこちら。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">

		<style type="text/css">
		<!--
		span.time1 {font-size: 15em; color:red;}
		-->
		</style>

		<title>START TIMER</title>

	</head>
<body>

	<span class="time1"><p id="RealtimeClockArea2">時計表示</p></span>

       <button onclick="beep()">START</button>
  
	<script src="start_t.js"></script>

</body>
</html>

javascript(start_t.js)はこちら。

function set2fig(num) {
 
   var ret;
   if( num < 10 ) { ret = "0" + num; }
   else { ret = num; }
   return ret;
}
function showClock2() {
   var nowTime = new Date();
   var nowHour = set2fig( nowTime.getHours() );
   var nowMin  = set2fig( nowTime.getMinutes() );
   var nowSec  = set2fig( nowTime.getSeconds() );
   var msg = nowHour + ":" + nowMin + ":" + nowSec;
   document.getElementById("RealtimeClockArea2").innerHTML = msg;
   
   if( nowSec == 0){
	   beep();
	}
   if( nowSec % 55 == 0){
	   beep();
	}
   if( nowSec % 57 == 0){
	   beep();
	}
   if( nowSec % 58 == 0){
	   beep();
	}
   if( nowSec % 59 == 0){
	   beep();
	}
}

function beep(){

	var base64 = "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"

  var sound = new Audio("data:audio/wav;base64," + base64);

  sound.play();
}


setInterval('showClock2()',1000);

時計は表示されるのですが、何故か音が鳴るときもあれば、鳴らないときも。。。強制的に一度音を出さないと上手く鳴りません。ですので、ボタンを置いて強制的に一度音を出すようにしています。何が原因か未だにわからず。。。

でも何とか完成。良かった。

Add a Comment

メールアドレスが公開されることはありません。