モールス信号を解読するには?

解決


CW  2004-06-27 12:55:04  No: 84216  IP: [192.*.*.*]

無線機からの信号をサウンドカードのマイク端子に入れて
モールス信号を解読(例えばトン・ツーはA)するソフトを
作成したいと思っています。
Web検索もして見ましたが希望する情報に行き当たりません。
まずは、マイク端子に入力された信号をVB6で受け取る事には
どうすれば良いでしょうか?  
使用するAPIやサンプルコードの所在等の情報があれば教えて下さい。
信号を文字として識別するのは、その後で考える事にします。

環境 VB6 SP5   WinXp

編集 削除
岡田 之仁  2004-06-27 16:24:20  No: 84217  IP: [192.*.*.*]

以前にも、ここの掲示板でマイク録音の件は書き込みをして
おりますが・・・

VB6等のみでは不可能ですが、尚、C言語ができないこと
には、無理です。
市販品の録音ツールでも、リアルタイム性のものは見たこと
がありません・・・録音した後、WAVEファイルに保存さ
れるようなものはあります。

よって、今回のには使えません。

マイクでの波形入力による簡単なパターンマッチングにする
か、トン・ツーの周波数特性をFFTを使ってピークを割り
出し、判断するか・・・

まぁ〜ピークさえ拾えれば、トン・ツーの判断は可能なので
・・・トン・ツーの組み合わせをテーブル化してやれば、文
字変換は可能となるでしょう・・・

よって、リアルタイムでの録音データの取得と、周波数成分
の判定、及び文字パターン認識の組み合わせになると思いま
す。

まずは、過去ログで検索してもらうか・・・リアルタイムで
の録音を行なうものを検索エンジン等で見つけることです。

ある程度ヒットすると思うのですが・・・

ご検討下さい。

以上。

編集 削除
CW  2004-06-27 17:53:10  No: 84218  IP: [192.*.*.*]

ありがとうございます。
昔、Cは多少やりましたが、もう忘れました。
VCは未経験です。
「マイク録音」に関して探して見ます。

編集 削除
岡田 之仁  2004-06-28 00:38:30  No: 84219  IP: [192.*.*.*]

よさそうなものがありました・・・
リアルタイムに録音・判定と言う流れには使えないかも
しれませんが・・・

http://www32.ocn.ne.jp/~kentaro/Programs/WaveIF/

ここには、録音は再生の説明が記載されていましたので
理解するには、いいページだと思います。

ご参考までに・・・

以上。

編集 削除
岡田 之仁  2004-06-28 00:43:55  No: 84220  IP: [192.*.*.*]

解釈に誤りがありました・・・訂正します。

http://www32.ocn.ne.jp/~kentaro/Programs/WaveIF/

は、リアルタム録音・判定は可能です。
OnDoneイベントで行なうことが可能でした。

ただし、VBの性能で処理時間を発生させてしまいます
ので、ビットレートの低速なものには、対応可能と思い
ますが、高速なものでは、難しいかもしれません。

とは、モールス信号をどう判定するか・・・文字変換部
分が大事になってきます。

以上。

編集 削除
CW  2004-06-28 06:41:10  No: 84221  IP: [192.*.*.*]

岡田 之仁 さん、再度ありがとうございます。
今、教えていただいたHPの内容を保存したばかりです。
今日は、これをじっくり読ませて頂きます。

編集 削除
CW  2004-06-28 19:58:32  No: 84222  IP: [192.*.*.*]

サンプル・コードが有ったのでマイク入力から
録音・再生は出来る様になりました。
FFTに関しても検索しましたがCのコードはありましたが
フリーで使えるDLLや用法の情報は発見出来ていません。
トン・ツーと言う信号を波形表示や短点 1・空白 1・長点 3・空白 7と言う
データに置き換えが出来ないとこれがAと判定が出来ませんね。
目的の山の高さはエベレスト以上の様です....。

編集 削除
ねろ  2004-06-29 08:28:14  No: 84223  IP: [192.*.*.*]

モールス信号のことは全くわかりませんが、昔の性能の悪い
ヘッドフォーンで耳で聞いている訳ですから、せいぜい
周波数的には高くても5KHz〜6KHz、この位の周波数でしたら
FFTを使わなくても出来そうです。
VBといってもメインの処理はCのDLLとなります。
CのDLLでWAVファイル読み込んでVBにMessageで渡しVBで波形表示する、この位は
簡単でしょう。Cの知識もあまり必要ありません。
まずWAVファイルの頭に付いているRIFFチャンクの読み込みからはじめます。
RIFFチャンクについては省略します。
ここにWAVファイルのサンプリング周波数、WAVファイルの長さなどが
書かれています。読み込んだデーターを大体次のように処理します。
PCMデーターは通常2'sコンプリと言う形で書かれています。
これも知っておく必要があります。
1、波形の負の部分は要りませんからデーターの最上位ビットが立っている
    データーを全て0とする
2、スレッシュホールドレベルの設定
    雑音を排除する為にあるレベル以下を0とする、多分最大レベル
    (16ビットサンプルであればefff)の1/5程度以下のデーターを0とし、
    その他を1とします。これでデーターは単に0と1に並びとなります。
3、トンとツーの判別
    トンとツーの間にはたぶん空白がありますから、この空白を
    判別します、20Hz位を信号の有り無しの境として、20Hz分信号が
    無ければ空白と判別します。(サンプリングレートから計算)
    空白部以外の0をすべて1に変えます。
    ここまでやるとWAV波形は、0と1の矩形波のトン・ツーの波形と
    なります。後は大体トン・ツーとの長さを決めれば判断できるでしょう。
かなり概念的でいいかげんですが、大体こんなところからはじめます。
データーとしては1Ch分しかありませんから、多分PCIバスのA/Dコンバーター
のカードを使用すると、リアルタイムでも十分間に合うと思います。

編集 削除
CW  2004-06-29 09:28:57  No: 84224  IP: [192.*.*.*]

色々とありがとうございます。
説明していただいた情報は今の私には分からない事が多いです。

> WAVファイル読み込んでVBにMessageで渡しVBで波形表示する。
> 1、波形の負の部分は要りませんからデーターの最上位ビット....
...等に関しても手がけた事が無い分野です。

時間を掛けて少しずつ調べて行きます。
今までVB6ではテキストファイルの加工関係ばかりでしたので。

編集 削除
ねろ  2004-06-29 18:08:42  No: 84225  IP: [192.*.*.*]

書き方が悪かったようです。
MessageはAPIでは
SendMessageかPostMessageです
Wavの波形解析を行う場合は、情報理論とまではいかなくても
「サンプリングの定理」やWavファイルの大まかな知識は必要です。
ソフトウエアーの知識だけでは難しいかと。
またビット操作が必要なのでテキスト加工の知識はほとんど
役に立ちません。
岡田 之仁さんが「C言語ができないことには、無理です。」
と言われたのは単に処理時間の問題だけではなくこのことを、
おっしゃっていると思います。

編集 削除
CW  2004-06-29 19:27:45  No: 84226  IP: [192.*.*.*]

度々のフォローありがとうございます。
難問続出ですね。私ではとても無理と言う感が強いです。
提示していただいたキーワードに関しては少しずつでも勉強を
して行きたいと思います。

編集 削除
CW  2004-06-30 10:29:30  No: 84227  IP: [192.*.*.*]

色々とアドバイスありがとうございました。
お陰様でリアルタイムでのマイクからのモールス信号入力を 
Picture1.PSet にて波形を表示する処まで出来ました。
この波形を目で見てならモールスのどの文字かの判別が出来ます。
この後は波形から短点、長点、信号の切れ目(間隔)等の判断をして
文字(アルファベット、数字、カタカナ)に置きかえる処理方法を
考えて行きます。

編集 削除
ぴろあき  2004-06-30 10:59:23  No: 84228  IP: [192.*.*.*]

面白そうですね。
波形の計測・処理のプログラムをメシの種にしています。
モールス信号の事は、『トン』と『ツー』があるとしか知りませんが、
波形処理についてわからない事があったら聞いてください。

>FFTに関しても検索しましたがCのコードはありましたが
>フリーで使えるDLLや用法の情報は発見出来ていません。

フリーのDLL
http://hp.vector.co.jp/authors/VA014203/software/fftdll.htm

VBでFFTの方法が書かれている書籍
http://www.gihyo.co.jp/books/syoseki-contents.php/4-7741-0838-3

編集 削除
CW  2004-06-30 12:12:02  No: 84229  IP: [192.*.*.*]

情報をありがとうございます。
「フリーのDLL」の方は見させて頂きました。
まだ利用してとまでは行きませんが.....。
「モールス信号」に付いては下記などにも記載があります。
http://www1.odn.ne.jp/haru/data-list/morse.html

> 波形処理についてわからない事があったら聞いてください。

まだ何をどの様にお尋ねすれば良いかが分からない状態です。
先ほど書いた様に信号を波形表示は出来る様になりました。
この波形データ(波形表示する前のデータからでも)を標準的には
    ・長点は短点の3倍の長さ
    ・1文字を構成する符号の長さは、1点分
    ・文字と文字の間隔は3点分
    ・語と語の間隔は、5点(7点)分 
..と言う様に判別してから文字に変換をすると言う手順が
必要なのですが、これらが出来ない状態で息詰まっています。

ある一定以上の値なら1に、未満なら0に置換し
1と0の連続する個数から相対的な長さ(短点か長点か)を判別すると
言う事かと思いますが、まだコードが書けてテスト出来る処までは
至っていません。

何かヒントやアドバイスがあれば是非お願いします。

編集 削除
ねろ  2004-06-30 13:03:04  No: 84230  IP: [192.*.*.*]

サンプリングの周波数はいくつに設定されていますか。

編集 削除
CW  2004-06-30 13:43:24  No: 84231  IP: [192.*.*.*]

ありがとうございます。
hdr.WaveFmt.wf
  .nSamplesPerSec = WaveIn.SamplesPerSec      ' サンプリング周波数。
では22050となります。

現状では岡田さんに教えて頂いた
http://www32.ocn.ne.jp/~kentaro/Programs/WaveIF/  
WaveIN  の  Private Sub WaveIn_OnDone() の中で
    ' データをファイルに保存します。
    If (fileRec <> 0) Then
        Put fileRec, , Buffer
        For i = 0 To UBound(Buffer) - 1 Step 12
           Picture2.PSet (x + j, y + Buffer(i) * 16), &HFFFF& '黄色
           j = j + 1
    Next i
End If

....として波形を表示させているだけです。

編集 削除
ぴろあき  2004-06-30 14:27:12  No: 84232  IP: [192.*.*.*]

なるほど、モールス信号について理解しました。
ってか、単純ですね(^^;)
暗号じゃないんだから、当たり前か。。。

FFTを使用するほどでもなさそうですね。
ねろさんがすでに提案している方法
ゼロ−クロッシング法の応用で、
周波数(周期)解析をするのが適していそうです。

#ゼロ−クロッシング法
#波形が、ゼロ線をクロスする点の時間間隔を測り、
#それを2倍して周期を見出す方法。

ゼロ線の替わりに、適当な境界線(仮に1/5)で判断するサンプル。

Dim Flag1 As Boolean    '現在の標本値(1 / 0)
Dim Flag2 As Boolean    '1点前の標本値(1 / 0)
Dim ZeroCount As Long   '0の連続標本数
Dim OneCount As Long    '1の連続標本数
Dim Kyoukai As Long     '最大値の1/5
Dim BitNum As Long      '分解能(符号有りの場合)

Kyoukai = (2 ^ (BitNum - 1)) / 5    '境界値の設定

If Buffer(i) > Kyoukai Then    '境界値以上
    Flag1 = True
    OneCount = OneCount + 1
Else                           '境界値以下
    Flag1 = False
    ZeroCount = ZeroCount + 1
End If

If Flag2 Xor Flag1 Then     '1から0(0から1)に変わった瞬間
    If Flag1 Then
        ZeroCount = 0       'カウンタリセット
    Else
        OneCount = 0        'カウンタリセット
    End If
    
    'ここに文字を判別するコードを挿入
    
End If

編集 削除
CW  2004-06-30 15:29:30  No: 84233  IP: [192.*.*.*]

皆さん、色々とありがとうございます。
ぴろあき  さん、に提示して頂いたサンプル・コードを
研究させて頂きます。結果はいずれ....。

編集 削除
ぴろあき  2004-06-30 15:46:45  No: 84234  IP: [192.*.*.*]

Flag2 = Flag1
を最後に入れるのを忘れてました。。。

編集 削除
ねろ  2004-06-30 16:08:21  No: 84235  IP: [192.*.*.*]

チャンネル数がちょっと判らないのですが12ビット22kサンプルの
リニアPCMですか。
ぴろあきさんさすがですね。
ただちょっと気になるのは、ツウーやトンといっても多分500Hzから2KHz位にの
信号でしょうから、それだけゼロクロッシングが起こるわけで、やはりここは
可聴域である20HZ位を音の有る無しの境にしては、たとえば
22.05*1000/60*20=7350サンプル、この間に一度も1にならなかったら
信号無しといことで、まあ雑音もあるでしょうから、7350サンプルの内に
1が73サンプル(1%)以下だったらそこは信号無しとするとか、いわば積分器のような
ものを作るというのはどうでしょうか。

編集 削除
CW  2004-06-30 17:33:02  No: 84236  IP: [192.*.*.*]

ありがとうございます。(返信した積もりが送信出来ていなかった)
現在は点を書いて波形を描くために  Buffer(i) * 16  としています。
これだと Max 2192  Min 1904 の値になっているようです。
現在のコードではイメージとしては下図の様な波形です。
これはトン・ツー  で文字のAの積もりです。
符号と符号の区切り(点と点)は1で、文字と文字の区切りは3で
...とかの判別もいずれは必要な事ですが、

                   Max 2192
====[~~]==[~~~~~]====       <--- 1998  無音か符号では無い時は横線
     ~~    ~~~~~     Min 1904                       多少の高さあり

波形は符号がある箇所は長方形の様に表示され、符号で無い(無音に近い)時は横線になって表示されています。この値がほぼ 1998 かと思います。
ほぼ上下対象なので下側は無視して上側だけで符号の有無を判断かと。

ぴろあきさんのサンプル・コードにもトライ中ですがまだ未完です。

編集 削除
ねろ  2004-06-30 22:42:08  No: 84237  IP: [192.*.*.*]

16倍してMaxが2192と言う事は8bitのA/Dコンバーターですか。
とりあえず2020あたりをスレッシュホールドレベルとすると

'早い人が打って短点が約1/5秒と仮定すると誤差も含めて
'1/10秒間隔で0と1を見る

'早い人が打って短点が約1/5秒と仮定すると誤差も含めて
'1/10秒間隔で0と1を見る

Private Const MaxData = 22050                'とりあえず1秒録音時間
Private Const TutonData = MaxData * 0.1      '0.1秒間データーが無い場合は音なし
Private Const Kyoukai = 2020                 'スライスレベル
Private Const NoiseCount = TutonData * 0.01  'ノイズカウント
Private Sub Command1_Click()
    Dim Buffer(MaxData) As Long
    Dim TutonBuffer(TutonData) As Integer '1と0のデーターが入る0.1秒毎
    Dim OneCount As Integer  '1の連続標本数
    Dim t As Integer
    For n = 1 To UBound(Buffer)
       If n \ TutonData = n / TutonData Then
           '1/10秒に一回調べる
           t = t + 1
           'ノイズを考慮
           If OneCount > NoiseCount Then
               TutonBuffer(t) = 1
           Else
               TutonBuffer(t) = 0
           End If
          
          OneCount = 0
       End If
       If Buffer(n) > Kyoukai Then    '境界値以上
           OneCount = OneCount + 1
       End If
    Next
End Sub



実際は配列でなくファイルから読んで、ファイルに書くか波形表示。

編集 削除
CW  2004-07-01 06:38:08  No: 84238  IP: [192.*.*.*]

ねろさんをはじめ、皆さんありがとうございます。
今朝方、コードを拝見しました。
本日は提示していただいたコードを組み込み・テストさせて
頂きます。

編集 削除
ぴろあき  2004-07-01 10:08:16  No: 84239  IP: [192.*.*.*]

ゼロ−クロッシング法は、
それ自体が一種のローパスフィルターになりますので、
いい方法だと思っていました。
#今回の場合、境界値付近のさざなみを考慮すると複雑になるけど

なるほど。。。
『ツー』や『トン』を長周期の矩形波だと考えていました。
↓こういう波形だと思ってました。。。
____——__—————____
短周期だったのですね。。。
考えてみれば音なんだから当たり前ですね。。。

こういう波形であれば、
私のサンプルは何の役にもたちません(恥)。

そこいくとねろさんはさすがですね。
ただ、重箱のスミを突付くようなものですが、
私の名誉回復のために補足する事をお許しください。

Private Const Kyoukai1 = 2020                 'スライスレベル1
Private Const Kyoukai2 = 1976                 'スライスレベル2

If Buffer(n) > Kyoukai1 And Buffer(n) < Kyoukai2 Then    
    OneCount = OneCount + 1
End if

と書いたけど、まてよ。。。
MAX = 2192
MIN = 1904
の信号部ですが、当然サンプリングも細かいのだから、
1998とか、2000とかその間のデータも一杯あるわけですよね?
————■■——■■■■■————
↑こういう波形になるのかな?
とすると、1/10秒間隔じゃイカンかな。。。

■部分が私の予想通り短周期(高周波)の波であれば、
最低その周波数の倍以上の周波数で再サンプリングする必要がありますね。

編集 削除
CW  2004-07-01 11:10:50  No: 84240  IP: [192.*.*.*]

ありがとうございます。

> MAX = 2192
> MIN = 1904
> の信号部ですが、当然サンプリングも細かいのだから、
> 1998とか、2000とかその間のデータも一杯あるわけですよね?

そうです。  ————■■  の波形の ■ と見える中も
2192 〜 1904 まで細かく振っていて表示させた時には
 ■ に近い形で見える状況です。

先の WaveIF で保存した *.wav を後で読み込み表示する部分は下記の様にしています。

    lngFileLenB = FileLen("C:\Sound.wav")
    ReDim bytArray(lngFileLenB - 1)
    intFileNo = FreeFile
    
    Open strPath & "Sound.wav" For Binary As #intFileNo
    Get #intFileNo, , bytArray
    Close #intFileNo

    'Picture2  の BackColor は黒  
    'Picture2.Height 7215
    'Picture2.Width 15615
    
    y = -1700
    x = 1
    j = 0

    For i = 0 To UBound(bytArray) - 1 Step 12    ' Step が無いと横長波形になりすぎるので
        If j > 15500 Then
            y = y + 500
            j = 0
        End If
        Picture2.PSet (x + j, y + bytArray(i) *16),&HFFFF&  '黄色
        j = j + 1
    Next i


リアルタイムにマイクに信号が入って来る録音時は
WaveIn.BufferSize = 128  として上記のbytArray() を Buffer() を
置きかえたコードで波形を表示させています。

先の  ねろ  さんのコードも試しています。
Private Const Kyoukai = 2020 'スライスレベル を2120にして
       If bytArray(n) * 16 > Kyoukai Then  '境界値以上
            If j > 15500 Then
                y = y + 500
                j = 0
            End If
            Picture3.PSet (x + j, y), &HFFFF&         '黄色
...としてやると
————■■——■■■■■————  が

        ・      ー        ト  ツー  の様に表示されます。

まだ短点か長点かの識別と文字への変換は出来ていません。

編集 削除
ぴろあき  2004-07-01 11:39:55  No: 84241  IP: [192.*.*.*]

了解。
であれば、標準偏差をとる方法はどうでしょうか?

手順としてはこんな感じ
1.全データから1998を引く
2.0.1秒間の(中から数点置きに抽出した)データのRMSを取る
3.RMSの境界値で判断

#RMS = Root Mean Square
#全データを二乗して、総和して、平均をとって、ルートをかける
#今回の用途では二乗総和だけで十分ですね
#境界値の設定時にそれを考慮するだけですから、
#無駄な計算は速度を遅くするだけですから、なるべく省きます

昼休み明けたら、この線でサンプル作ってみますね。

編集 削除
CW  2004-07-01 13:35:31  No: 84242  IP: [192.*.*.*]

ありがとうございます。
ゼロ−クロッシング法やサンプリングや RMS など
知らない事ばかりで思うに任せないでいます。
実際の交信している信号もありますが、これは信号の打ち方に癖があったり
信号が弱くなったり、速度もばらつきがあったりします。
パソコンで作成されたモールスを自分で送信して、別の受信機で受信して
保存したファイルも作りました。
こう言うサンプル・データが必要でしょうか?

編集 削除
ぴろあき  2004-07-01 13:55:46  No: 84243  IP: [192.*.*.*]

>これは信号の打ち方に癖があったり
>信号が弱くなったり、速度もばらつきがあったりします。
そこが一番悩ましいところですよね。
境界値をいくつに設定するかは試行錯誤でしかできないと思います。

>こう言うサンプル・データが必要でしょうか?
あれば、より手助けできるでしょう。
ただ、Wavファイル扱ったことないので、
正直Txt形式か、
BufferをそのままPutしたような8bitバイナリの形式がいいです。

ざっくり。
Dim Souwa As Long           '2乗総和
Dim Flag10 As Boolean       'True = 1  False = 0
Dim ZeroCount As Long       '0の連続標本数
Dim OneCount As Long        '1の連続標本数
Dim TonTuCount As Long      '1文字のトンツー個数
Dim TonTuData() As Boolean  '1文字のトンツー
Dim GoFlag As Boolean       '語の終わりフラグ
Dim OutString As String     '出力文字
Const Kyoukai As Long = 500 '信号/無信号の境界値

'仮想受信イベント
Private Sub Command1_Click()
    'WaveBufferSize = 128の場合
    'リアルタイム用
    
    '二乗総和を求める
    Souwa = 0
    For i = 0 To 127 Step 8
        Souwa = Souwa + (buffer(i) - 1998) ^ 2
    Next i
    
    '信号部か無信号部かの判断部分
    If Souwa > Kyoukai Then         '1とみなす
        '直前の128点が0の場合
        If Flag10 = False Then
            Call TanTyou
        End If
        
        Flag10 = True
        OneCount = OneCount + 1
    Else                            '0とみなす
        If Flag10 Then
            Call TanTyou
        End If
        
        Flag10 = False
        ZeroCount = ZeroCount + 1
    End If
End Sub

'短点(短ブランク)か長点(長ブランク)か
Private Sub TanTyou()
    'Flag10の意味が逆になる事に注意!!
    '分かりずらければ、直前データのフラグを別に用意する事
    If Flag10 = False Then
        ZeroCount = 0
        TonTuCount = TonTuCount + 1
        ReDim Preserve TonTuData(TonTuCount - 1) As Boolean
        Select Case OneCount
            Case Is < 100       'ノイズ
                ZeroCount = OneCount
                Flag10 = False
            Case 101 To 6000    '短点
                TonTuData(TonTuCount - 1) = True
            Case Is > 6001      '長点
                TonTuData(TonTuCount - 1) = False
        End Select
        OneCount = 0
    Else
        OneCount = 0
        Select Case ZeroCount
            Case Is < 10         'ノイズ?
                '文字と文字の間隔は3点分
                '語と語の間隔は、5点(7点)分
                'これ以外の間隔って決まってないの?
                OneCount = ZeroCount
                Flag10 = True
            Case 11 To 6000      '短点1つ分のブランク
                '何もしない
            Case 6001 To 18000   '短点3つ分のブランク
                Call MojiHandan
            Case Is > 18001      '短点5つ分のブランク(
                GoFlag = True
                Call MojiHandan
        End Select
        ZeroCount = 0
        GoFlag = False
    End If
End Sub

'文字を判断する
Private Sub MojiHandan()
    
    Select Case TonTuCount
        Case 1
            Call Moji1
        Case 2
            Call Moji2
        '以下同じように
    
    
    
        Case 6
            Call Moji6
    End Select
    
    '語の区切りではスペースを挿入ひとつ開ける
    If GoFlag Then
        OutString = OutString & " "
    End If
    
    TonTuCount = 0
    Erase TonTuData
End Sub

'1つのトンツー信号で構成される文字
Private Sub Moji1()
    If TonTuData(0) Then
        OutString = "E"         '・
    Else
        OutString = "T"         '−
    End If
End Sub

'2つのトンツー信号で構成される文字
Private Sub Moji2()
    If TonTuData(0) Then
        If TonTuData(1) Then
            OutString = "I"     '・・
        Else
            OutString = "A"     '・−
        End If
    Else
        If TonTuData(1) Then
            OutString = "N"     '−・
        Else
            OutString = "M"     '−−
        End If
    End If
End Sub

編集 削除
ぴろあき  2004-07-01 16:40:12  No: 84244  IP: [192.*.*.*]

文字の判断は、下の方にした方がスマートかも。。。

'トンは下位バイトのビット
'ツーは上位バイトのビット
'として2バイトの値を計算
For i = 0 To TonTuCount
    If TonTuData(i) Then
        MojiTable = MojiTable + 2 ^ i
    Else
        MojiTable = MojiTable + (2 ^ i) * 256
    End If
Next i

'2バイトの値を元に文字決定
Select Case MojiTable
    Case 258    '・−
        OutString = "A"
    Case 2055   '−・・・
        OutString = "B"
    Case 2565   '−・−・
        OutString = "C"
    Case 1027   '−・・
        OutString = "D"
    Case 1      '・
        OutString = "E"
    Case 525     '・・−・
        OutString = "F"
    Case 1537    '−−・
        OutString = "G"
    Case 15      '・・・・
        OutString = "H"
    Case 3       '・・
        OutString = "I"
    Case 1800    '・−−−
        OutString = "J"
    Case 1282    '−・−
        OutString = "K"
    Case 1035    '・−・・
        OutString = "L"
    Case 768     '−−
        OutString = "M"
    Case 513     '−・
        OutString = "N"
    Case 1792    '−−−
        OutString = "O"
    Case 1545    '・−−・
        OutString = "P"
    Case 3330    '−−・−
        OutString = "Q"
    Case 517     '・−・
        OutString = "R"
    Case 7       '・・・
        OutString = "S"
    Case 256     '−
        OutString = "T"
    Case 262     '・・−
        OutString = "U"
    Case 270     '・・・−
        OutString = "V"
    Case 772     '・−−
        OutString = "W"
    Case 2310    '−・・−
        OutString = "X"
    Case 2820    '−・−−
        OutString = "Y"
    Case 3075    '−−・・
        OutString = "Z"
    Case 3856    '・−−−−
        OutString = "1"
    Case 1816    '・・−−−
        OutString = "2"
    Case796      '・・・−−
        OutString = "3"
    Case 286     '・・・・−
        OutString = "4"
    Case 31     '・・・・・
        OutString = "5"
    Case 4111   '−・・・・
        OutString = "6"
    Case 6151   '−−・・・
        OutString = "7"
    Case 7171   '−−−・・
        OutString = "8"
    Case 7681   '−−−−・
        OutString = "9"
    Case 3840   '−−−−−
        OutString = "0"
    Case 2581   '・−・−・
        OutString = "+"
    Case 8478   '−・・・・−
        OutString = "-"
    Case 2310   '−・・−
        OutString = "*"
    Case 4621   '−・・−・
        OutString = "/"
    Case 4366   '−・・・−
        OutString = "="
    Case 5641   '−・−−・
        OutString = "("
    Case 11538  '−・−−・−
        OutString = ")"
    Case 7713   '・−−−−・  ←
        OutString = "'"
    Case 4653   '・−・・−・
        OutString = "''"
    Case 7713   '・−−−−・  ←
        OutString = ";"
    Case 14343  '−−−・・・
        OutString = ":"
    Case 13068  '−−・・−−
        OutString = ","
    Case 5418   '・−・−・−
        OutString = "."
    Case 3123   '・・−−・・
        OutString = "?"
    Case 255    '・・・・・・・・
        '訂正
        'データを貯めてるならLeft$(文字列, Len$(文字列-1))
        '書き出してるなら、BSキー(Chr$(8))を送る
End Select

#下記ページを元にテーブル作ったけど、
#『)』と『;』が同じなのは間違いだよね。。。
http://www1.odn.ne.jp/haru/data-list/morse.html

編集 削除
ぴろあき  2004-07-01 16:43:17  No: 84245  IP: [192.*.*.*]

訂正
>MojiTable = MojiTable + (2 ^ i) * 256
MojiTable = MojiTable + (2 ^ (i + 1)) * 256

それと一番上にMojiTable = 0を忘れずに。

編集 削除
CW  2004-07-01 17:57:16  No: 84246  IP: [192.*.*.*]

詳しいサンプル・コードをありがとうございます。
組み込みしてテスト中ですが、まだ文字を表示出来ません。(まだ10分程度のテスト)

    If GoFlag Then
        OutString = OutString & " "   '文字を表示させるには
        Label5.Caption = OutString    '<=== とすれば良いのでしょうか?
        Label5.Refresh               
    End If

もう少しトライして見ます。

>> こう言うサンプル・データが必要でしょうか?
> あれば、より手助けできるでしょう。
> ただ、Wavファイル扱ったことないので、
> 正直Txt形式か、
> BufferをそのままPutしたような8bitバイナリの形式がいいです。

これはWaveIn での録音時の ~Record.tmp で良いかと思います。
これと*.wav をバイナリー・エデイタで比べるとヘッダが無いだけのようです。
サンプルデータでテストしていただける様でしたらメイルでお送りします。
メイルアドレスは少し前に書いて置きました。

> #下記ページを元にテーブル作ったけど、
> #『)』と『;』が同じなのは間違いだよね。。。

) −・−−・−  と
; ・−−−−・   ですか、これを見た範囲では同じでは無いですね。
実際の交信で良く使う特殊文字は /  と  ?  位で  (  ):;等は無しです。

編集 削除
CW  2004-07-02 14:59:42  No: 84247  IP: [192.*.*.*]

ひろあきさん、ねろさん、岡田 之仁さん、
皆さん、ありがとうございました。お陰様でモールス信号を解析し
文字として表示出来る様になりました。
現在は自分で送信し、受信すると言うノイズの少ない、また符号も
パソコンで送出した定格的な符号での解析では100%がOKでした。
実際の交信を録音したデータではノイズが多い、符号の乱れが多い、速度が
ばらつくなどで解析率は極端に落ちてしまいます。
これらは実際にテスト時にパラメータなどにて適宜調整をするしか無いかと
思っています。

数日前までは糸口も掴めないままに、こちらに質問させて頂きました。
1週間も立たない内にこれだけの解析が出来た事は感謝に堪えません。
これもひとえに皆さんが資料やサンプルコードを速やかに提供していただいた
お陰です。ありがとうございました。今後ともよろしくお願いします。

編集 削除
ねろ  2004-07-02 22:02:25  No: 84248  IP: [192.*.*.*]

もう見ていないかも知れないけど
雑音ですが、これはマイクの感度とも密接な関係が有ります。
VBの画面にスライダーをつけて、スレッシュホールドを変えられる様にします。
又私の前のコードで雑音を1%としましたがこれもスライダーで変えられるように
します。
問題は長符と短符ですが、初期設定での処理は無理です。
クロック抽出に拠るフェーズロックと言う方法でやってみたらいかがですか?
(私が勝手に付けた名前)
まず符号の長さをデーター先読みで長符=短符*3になる所まで探します。
ぴったりは有りませんからとりあえず+−20%位を考えます。
つまり  長符*0.8 > 短符  <長符*1.2 となった時に、短符の長さと
長府の長さを見つけたことになります。
長さを見つけると今度は今まで処理していなかったデーターを今の位置まで
どちらに近いかで短、長に分けます。そこで一旦見つけた長さを捨てて、
再び同じことを繰り返します。つまりダイナミックに短符の長さを
探すわけです。
簡単なサンプルを書いてみました、とりあえずデーターは
1200,3000,1000,3500,4000........の様に
ONの数OFFの数と交互に並んでいるとします、実際はファイルからの
読み込みとなります。

Dim Max As Integer, Min As Integer
Private Sub Command1_Click()
    Dim Buff(22050) As Integer
    Dim Pointer As Integer                'どこまで処理したか
    Dim BMax As Integer, BMin As Integer  '一番最後のクロック
    Min = 22000  '初期値セット  大きな値を適当に
    Max = 0      '初期値セット  最小値をセットする
 
    For n = 1 To UBound(Buff)
        '一回毎にクロック抽出を試みる
        If GetClockWidth(Buff(n)) <> 0 Then
            'クロックが抽出出来たら処理を進める
            Pointer = Pointer + 1
            For m = Pointer To n
                '溜まっているデータ−を一気に処理
                'どちらの長さに近いか見る
                If Abs(Min * 3 - Buff(m)) < Abs(Min - Buff(m)) Then
                     If Abs(Min * 5 - Buff(m)) < Abs(Min * 3 - Buff(m)) Then
                        Buff(m) = 5  '長音空白  'バッファを書き換える
                     Else
                        Buff(m) = 3  '長音  'バッファを書き換える
                     End If
                Else
                    Buff(m) = 1  '単音  'バッファを書き換える
                End If
                BMax = Max: BMin = Min
            Next
        End If
    Next
    
    '最後にクロックが決まらずに未処理のデータ−が残っていたら
    '一番最後のクロックを垂れ流す
    If Pointer < UBound(Buff) Then
        For n = Pointer + 1 To UBound(Buff)
            If Abs(BMax - Buff(m)) < Abs(BMin - Buff(m)) Then
                Buff(m) = 3  '長符
            Else
                Buff(m) = 1  '単符
            End If
        Next
    End If
End Sub
Private Function GetClockWidth(d As Integer)
    'クロック抽出
    If d > Max Then
        Max = d   '最大値
    End If
    If (d < Min) Then
        Min = d   '最小値
    End If
    'もし最小値の3倍が最大値の+−20%のウインドウに入ったら
    'クロック抽出成功
    If (Min * 3 > Max * 0.8) And (Min * 3 < Max * 1.2) Then
        GetClockWidth = Min  '短符の長さ発見
        'クロック抽出成功の一回毎にクリアする
        Min = 22000 
        Max = 0 
    Else
        GetClockWidth = 0
    End If
End Function
大体こんなことで。

編集 削除
CW  2004-07-02 22:48:19  No: 84249  IP: [192.*.*.*]

ねろさん、ありがとうございます。
この掲示板は毎日、複数回見に来ています。
自分の質問以外も大変参考になる事が多いです。
差し当たりは条件の良い時の欧文、和文の信号の解析は出来る様になりました。
今回、提示していただいたコードを追加、組み込み出来るか、不安ですが
明日以降にトライさせて頂きます。

編集 削除