#!ruby
# -*- encoding: UTF-8 -*-
=begin
入力をモールス符号に変換
入力は [A-Za-z0-9 ]
出力は OutputWav
=end
OutputWav = 'Morse.wav'
Morse = {
' ' => '0000', # 文字間隔は短点3つ分、語間隔は短点7つ分 4 = 7-3
'A' => '・-',
'B' => '-・・・',
'C' => '-・-・',
'D' => '-・・',
'E' => '・',
'F' => '・・-・',
'G' => '--・',
'H' => '・・・・',
'I' => '・・',
'J' => '・---',
'K' => '-・-',
'L' => '・-・・',
'M' => '--',
'N' => '-・',
'O' => '---',
'P' => '・--・',
'Q' => '--・-',
'R' => '・-・',
'S' => '・・・',
'T' => '-',
'U' => '・・-',
'V' => '・・・-',
'W' => '・--',
'X' => '-・・-',
'Y' => '-・--',
'Z' => '--・・',
'0' => '-----',
'1' => '・----',
'2' => '・・---',
'3' => '・・・--',
'4' => '・・・・-',
'5' => '・・・・・',
'6' => '-・・・・',
'7' => '--・・・',
'8' => '---・・',
'9' => '----・',
}
Morse2 = {
'・' => '1',
'-' => '2' # '111'
}
# str = 'JJY JJY N N N N N'.strip.upcase
str = gets.strip.upcase
soundData = ''
str.each_char{|ch|
next unless Morse[ch]
soundData << Morse[ch].chars.map{|x| Morse2[x] }.join('0')
soundData << '000'
}
soundData.sub!( /0+$/, '' )
# puts soundData
# wav Output
Samp_freq = 8000 # サンプリングレート 8KHz
Numb_Ch = 1 # チャンネル数 1
DotSec = 60.0 / 50.0 / 17.0 # 17 WPM
DotLen = (DotSec * Samp_freq).to_i
Morse_freq = 770 # Wav モールス周波数 770Hz
# 無音1Dot, 有音1Dot(短音), 有音3Dot(長音)
wavData0 = "\x80" * DotLen
wavData1 = ""
SoundVol = 0.6
DotLen.times{|x| wavData1 << [SoundVol * 0x80 * Math.sin( x * 2 * Math::PI * Morse_freq / Samp_freq ) + 0x80].pack('C') }
wavData2 = ""
(3*DotLen).times{|x| wavData2 << [SoundVol * 0x80 * Math.sin( x * 2 * Math::PI * Morse_freq / Samp_freq ) + 0x80].pack('C') }
soundData.prepend('00') # wav ガード
soundData << '00' # wav ガード
wavDataSize = soundData.chars.inject(0){|result, item|
result +
case item
when '0'; wavData0.size
when '1'; wavData1.size
when '2'; wavData2.size
end
}
File.open( OutputWav, 'wb' ){|fh|
fh.write( "RIFF" )
fh.write( [28 + wavDataSize+8].pack('V') )
fh.write( "WAVEfmt " )
fh.write( [16].pack('V') )
fh.write( [1, Numb_Ch, Samp_freq, Samp_freq, 1, 8].pack('vvVVvv') )
fh.write( "data" )
fh.write( [wavDataSize].pack('V') )
soundData.chars{|ch|
case ch
when '0'; fh.write( wavData0 )
when '1'; fh.write( wavData1 )
when '2'; fh.write( wavData2 )
end
}
}
IyFydWJ5CiMgLSotIGVuY29kaW5nOiBVVEYtOCAtKi0KCj1iZWdpbgoJ5YWl5Yqb44KS44Oi44O844Or44K556ym5Y+344Gr5aSJ5o+bCgnlhaXlipvjga8gW0EtWmEtejAtOSBdCgnlh7rlipvjga8gT3V0cHV0V2F2Cj1lbmQKCglPdXRwdXRXYXYgPSAnTW9yc2Uud2F2JwoKCU1vcnNlID0gewoJCScgJyA9PiAnMDAwMCcsCSMg5paH5a2X6ZaT6ZqU44Gv55+t54K5M+OBpOWIhuOAgeiqnumWk+malOOBr+efreeCuTfjgaTliIYgNCA9IDctMwoJCSdBJyA9PiAn44O777yNJywKCQknQicgPT4gJ++8jeODu+ODu+ODuycsCgkJJ0MnID0+ICfvvI3jg7vvvI3jg7snLAoJCSdEJyA9PiAn77yN44O744O7JywKCQknRScgPT4gJ+ODuycsCgkJJ0YnID0+ICfjg7vjg7vvvI3jg7snLAoJCSdHJyA9PiAn77yN77yN44O7JywKCQknSCcgPT4gJ+ODu+ODu+ODu+ODuycsCgkJJ0knID0+ICfjg7vjg7snLAoJCSdKJyA9PiAn44O777yN77yN77yNJywKCQknSycgPT4gJ++8jeODu++8jScsCgkJJ0wnID0+ICfjg7vvvI3jg7vjg7snLAoJCSdNJyA9PiAn77yN77yNJywKCQknTicgPT4gJ++8jeODuycsCgkJJ08nID0+ICfvvI3vvI3vvI0nLAoJCSdQJyA9PiAn44O777yN77yN44O7JywKCQknUScgPT4gJ++8je+8jeODu++8jScsCgkJJ1InID0+ICfjg7vvvI3jg7snLAoJCSdTJyA9PiAn44O744O744O7JywKCQknVCcgPT4gJ++8jScsCgkJJ1UnID0+ICfjg7vjg7vvvI0nLAoJCSdWJyA9PiAn44O744O744O777yNJywKCQknVycgPT4gJ+ODu++8je+8jScsCgkJJ1gnID0+ICfvvI3jg7vjg7vvvI0nLAoJCSdZJyA9PiAn77yN44O777yN77yNJywKCQknWicgPT4gJ++8je+8jeODu+ODuycsCgkJJzAnID0+ICfvvI3vvI3vvI3vvI3vvI0nLAoJCScxJyA9PiAn44O777yN77yN77yN77yNJywKCQknMicgPT4gJ+ODu+ODu++8je+8je+8jScsCgkJJzMnID0+ICfjg7vjg7vjg7vvvI3vvI0nLAoJCSc0JyA9PiAn44O744O744O744O777yNJywKCQknNScgPT4gJ+ODu+ODu+ODu+ODu+ODuycsCgkJJzYnID0+ICfvvI3jg7vjg7vjg7vjg7snLAoJCSc3JyA9PiAn77yN77yN44O744O744O7JywKCQknOCcgPT4gJ++8je+8je+8jeODu+ODuycsCgkJJzknID0+ICfvvI3vvI3vvI3vvI3jg7snLAoJfQoJTW9yc2UyID0gewoJCSfjg7snID0+ICcxJywKCQkn77yNJyA9PiAnMicJCSMgJzExMScKCX0KCiMJc3RyID0gJ0pKWSBKSlkgIE4gTiBOIE4gTicuc3RyaXAudXBjYXNlCglzdHIgPSBnZXRzLnN0cmlwLnVwY2FzZQoKCXNvdW5kRGF0YSA9ICcnCglzdHIuZWFjaF9jaGFye3xjaHwKCQluZXh0CXVubGVzcyBNb3JzZVtjaF0KCQlzb3VuZERhdGEgPDwgTW9yc2VbY2hdLmNoYXJzLm1hcHt8eHwgTW9yc2UyW3hdIH0uam9pbignMCcpCgkJc291bmREYXRhIDw8ICcwMDAnCgl9Cglzb3VuZERhdGEuc3ViISggLzArJC8sICcnICkKIwlwdXRzIHNvdW5kRGF0YQoKIyB3YXYgT3V0cHV0CgoJU2FtcF9mcmVxID0gODAwMAkjIOOCteODs+ODl+ODquODs+OCsOODrOODvOODiCA4S0h6CglOdW1iX0NoID0gMQkJCSMg44OB44Oj44Oz44ON44Or5pWwIDEKCURvdFNlYyA9IDYwLjAgLyA1MC4wIC8gMTcuMAkJIyAxNyBXUE0KCURvdExlbiA9IChEb3RTZWMgKiBTYW1wX2ZyZXEpLnRvX2kKCglNb3JzZV9mcmVxID0gNzcwCSMgV2F2IOODouODvOODq+OCueWRqOazouaVsCA3NzBIegoKIyDnhKHpn7MxRG90LCDmnInpn7MxRG90KOefremfsyksIOaciemfszNEb3Qo6ZW36Z+zKQoJd2F2RGF0YTAgPSAiXHg4MCIgKiBEb3RMZW4KCXdhdkRhdGExID0gIiIKCVNvdW5kVm9sID0gMC42CglEb3RMZW4udGltZXN7fHh8IHdhdkRhdGExIDw8IFtTb3VuZFZvbCAqIDB4ODAgKiBNYXRoLnNpbiggeCAqIDIgKiBNYXRoOjpQSSAqIE1vcnNlX2ZyZXEgLyBTYW1wX2ZyZXEgKSArIDB4ODBdLnBhY2soJ0MnKSB9Cgl3YXZEYXRhMiA9ICIiCgkoMypEb3RMZW4pLnRpbWVze3x4fCB3YXZEYXRhMiA8PCBbU291bmRWb2wgKiAweDgwICogTWF0aC5zaW4oIHggKiAyICogTWF0aDo6UEkgKiBNb3JzZV9mcmVxIC8gU2FtcF9mcmVxICkgKyAweDgwXS5wYWNrKCdDJykgfQoKCXNvdW5kRGF0YS5wcmVwZW5kKCcwMCcpCQkjIHdhdiDjgqzjg7zjg4kKCXNvdW5kRGF0YSA8PCAnMDAnCQkJIyB3YXYg44Ks44O844OJCgoJd2F2RGF0YVNpemUgPSBzb3VuZERhdGEuY2hhcnMuaW5qZWN0KDApe3xyZXN1bHQsIGl0ZW18CgkJcmVzdWx0ICsKCQljYXNlIGl0ZW0KCQl3aGVuICcwJzsJd2F2RGF0YTAuc2l6ZQoJCXdoZW4gJzEnOwl3YXZEYXRhMS5zaXplCgkJd2hlbiAnMic7CXdhdkRhdGEyLnNpemUKCQllbmQKCX0KCglGaWxlLm9wZW4oIE91dHB1dFdhdiwgJ3diJyApe3xmaHwKCQlmaC53cml0ZSggIlJJRkYiICkKCQlmaC53cml0ZSggWzI4ICsgd2F2RGF0YVNpemUrOF0ucGFjaygnVicpICkKCQlmaC53cml0ZSggIldBVkVmbXQgIiApCgkJZmgud3JpdGUoIFsxNl0ucGFjaygnVicpICkKCQlmaC53cml0ZSggWzEsIE51bWJfQ2gsIFNhbXBfZnJlcSwgU2FtcF9mcmVxLCAxLCA4XS5wYWNrKCd2dlZWdnYnKSApCgoJCWZoLndyaXRlKCAiZGF0YSIgKQoJCWZoLndyaXRlKCBbd2F2RGF0YVNpemVdLnBhY2soJ1YnKSApCgkJc291bmREYXRhLmNoYXJze3xjaHwKCQkJY2FzZSBjaAoJCQl3aGVuICcwJzsJZmgud3JpdGUoIHdhdkRhdGEwICkKCQkJd2hlbiAnMSc7CWZoLndyaXRlKCB3YXZEYXRhMSApCgkJCXdoZW4gJzInOwlmaC53cml0ZSggd2F2RGF0YTIgKQoJCQllbmQKCQl9Cgl9Cgo=