Groovy+JsynでDTMF発信する

気がついたら数ヶ月もかいてませんでした.
なにもしていないってわけでもなくて,さいきんはtwitterにgistかvimeoのリンクはってそれでおわりってパターンばかり.
ウェブログ離れってのもあながち無いってわけではないなと実感するこのごろ,みなさんいかがお過しでしょうか,どうも.おれです.

というわけで昨晩思いつきでやってみたDTMF(Dual Tone Multi Freqency)をGroovyとJsynでというお話.

DTMFてのはデュアルにトーンでマルチなフリーケンシーでというもので,もっとカンタンにいえば電話のプッシュ音のことです.つまり電話のプッシュ音はデュアルなトーンをマルチなフリーケンシーになっている,もっとカンタンにいえば2つの周波数の正弦波を組み合わせて電話のプッシュ音ができてるっていうことです.つまり電話のプッシュ音は2つの周波数のSineWaveってことですね.もっとカンタンにいうとDTMFっていうことなんですね.

その2つの正弦波の組み合わせで0から9とシャープ記号,ポートピア連続殺人事件でおなじみのコメ記号,AからDまでのアルファベットを表現するのがDTMFです.あんまり詳しいはなしをすると90年代中頃までぐらいのラジオライフみたいな話になってしまうのでググってみたほうがいいと思います.というかじぶんもあまり詳しいはなしはできません.

DTMF with Groovy from nbqx on Vimeo.

とりあえず117にかけてますが失敗してます.ちなみに何度かテストしてるときに1度だけコールすることができました.
twitterでmiura_offさんともお話したのですが,以前「探偵ナイトスクープ」で合唱団員2人でDTMF発信するのをやっててけっこう大変ぽいかんじだった覚えがあります.そんなカンタンにはできないのかもしれません.

http://twitter.com/miura_off/status/68004528225665024:twitter
http://twitter.com/nbqx/status/68110846202621952:twitter
http://twitter.com/miura_off/status/68116821663952897:twitter

以下Groovyのコードです.わかりやすさ重視のため,おかしなことはしていません.
せめて数字・記号・アルファベットから2つの周波数をひっぱるとこあたりはクロージャのメモ化してもいいかもです.連続でDTMF発信したりとてつもなく長い電話番号に発信しない限りは必要ないんじゃと個人的には思いますが…

import com.softsynth.jsyn.*

//groovy script for phone call
class DualToneMultiFrequency{
	def num
	def buf
	SineOscillator high
	SineOscillator low
	AddUnit mixer
	LineOut out

	public DualToneMultiFrequency(String str){
		Synth.startEngine(0)
		num = str.toList()

		high = new SineOscillator()
		low = new SineOscillator()
		mixer = new AddUnit()
		out = new LineOut()

		buf = num.collect{x-> dtmfMatrix[x]}
	}

	def exec = {
		high.output.connect(0,mixer.inputA,0)
		low.output.connect(mixer.inputB)

		mixer.output.connect(0,out.input,0)
		mixer.output.connect(0,out.input,1)

		high.start()
		low.start()
		mixer.start()

		buf.each{
			dial(it)
		}

		out.stop()
		Synth.stopEngine()
	}

	def dial = {x->
		high.with{
			frequency.set(x.higher)
			amplitude.set(0.5)
		}
		low.with{
			frequency.set(x.lower)
			amplitude.set(0.5)
		}

		out.start()
		Synth.sleepForTicks(80)

		out.stop()
		Synth.sleepForTicks(60)
	}

	def dtmfMatrix = [
		"1":[higher:1209, lower:697],
		"2":[higher:1336, lower:697],
		"3":[higher:1477, lower:697],
		"4":[higher:1209, lower:770],
		"5":[higher:1336, lower:770],
		"6":[higher:1477, lower:770],
		"7":[higher:1209, lower:852],
		"8":[higher:1336, lower:852],
		"9":[higher:1477, lower:852],
		"*":[higher:1209, lower:941],
		"0":[higher:1336, lower:941],
		"#":[higher:1477, lower:941],
		"A":[higher:1633, lower:697],
		"B":[higher:1633, lower:770],
		"C":[higher:1633, lower:852],
		"D":[higher:1633, lower:941]
	]

}

def dtmf = new DualToneMultiFrequency("117")
dtmf.exec()