最近、私はこのプログラムを使用してモールス信号を研究しています。 しかし、それは現代の無線通信には関係のないキリル文字のコードを研究するように設計されています(私たちの勇敢な軍隊を除き、誰もがラテンアルファベットを使用します)。
この状況は私には合わず、速度設定とコードを動的に追加する機能を備えたテキストからモールス信号を生成するプログラムを作成することにしました。 ソリューションは非常に独創的で柔軟であることが判明しました(もちろん、IMHO)。 そして、私はこのプログラムを一般の人々と共有することにしました。おそらく誰かに役立つか、面白いように思えるかもしれません。
Q ++と組み合わせたC ++が、アイデアを実装するためのツールとして選択されました。
プログラムの主なアイデア
モールス符号のアトム(時間の単位)はポイントであり、他のすべての要素の持続時間はそれに対して形成されます:
- ダッシュは、3つのサウンドドットに相当します。
- 1つのシンボル(記号)の要素間の休止は、1つの発音ポイントです。
- 標識の間には3つのポイントがあります。
- 言葉の間-7点。
ご覧のとおり、モールス符号に基づいたコードは、音付きのドットと音なしのドットのセットとして表すことができます。私はこのアイデアから始めました。
初期実装
プログラムの最初のバージョンでは、サウンディングポイントとサウンディングポイントの組み合わせは、ブール要素を持つベクトルの形式で保存され、 trueはサウンドオンに対応し、 falseはオフに対応していました。
既に理解したように、最終的な信号を取得するために、サイン録音で無限に再生する.wavファイルを使用して、少し遅れて(ミリ秒単位でタイマーを使用して)サウンドを「プル」しました。 しかし、このアプローチには大きなマイナスがあり、オーバーロードされた演算子または特別なメソッドを使用して各ポイントを個別にロードする必要があったという事実がありました。 このアプローチのため、各文字に個別のマクロ(#define I DOT << false << DOTなど)を作成し、送信された文字列を再生するために巨大な不気味なスイッチを作成する必要がありました。 それはひどいものでしたが、好奇心が強いなら、あなたは自分自身に慣れることができます
プログラムの最初のバージョンはこちらです (GitHubのローカルリポジトリを完全にダウンロードできませんでした-最新バージョンのみ)。
不気味なスイッチの一部:
bool Morse::StringToMorse (QString &line) { line += '\0'; for (int i = 0; i < line.size () - 1; ++i) { switch (line.at(i).unicode ()) { case 'A': *this << A; if (line.at (i + 1) == ' ') continue; else *this << MINI_SPACE; break; case 'B': *this << B; if (line.at (i + 1) == ' ') continue; else *this << MINI_SPACE; break; //
そして、これがサウンドのオン/オフの切り替え方法です(実際には、サウンドコードの生成)。
void Morse::PlayLinePoints () { QTimer::singleShot (duration_point_, this, SLOT ( Mute () )); sound_.play (); } void Morse::Mute () { if (line_points_.empty ()) { // sound_.stop (); return; } if (line_points_.at (0)) { // sound_.setMuted (false); line_points_.remove (0); QTimer::singleShot (duration_point_, this, SLOT ( Mute () )); return; } else { sound_.setMuted (true); // line_points_.remove (0); QTimer::singleShot (duration_point_, this, SLOT ( Mute () )); return; } }
最終版
これらのマクロは非常にかさばることが判明し、私の完璧主義ではこれらの巨大な構造を見ることができなくなりました。 少し考えた後、私は良いアイデアがあったという結論に達しましたが、マクロの形でコードを保存することは非常に不便であり、この問題が解決されれば、すべてがうまくいきます。 その結果、QMapはコードの保存に使用されました。
// QMap<QChar, QBitArray> codes_;
このアプローチは非常に便利であることが判明しました。 今、私は現在のプレイ可能なキャラクターをキーとして使用し、準備ができました
ただし、コード(ブール値のセット)を再現するには、再生アルゴリズムがもう少し複雑です。現在の文字要素のカウンターと行に文字カウンターを入力する必要がありました。
新しいプレイの実装:
void Morse::MiniSpace () { if (stop_) { this->Stop (); return; } sound_.setMuted (true); ++id_element_; // if ( id_element_ == codes_.value ( string_to_play_.at (id_char_) ).size () ) { ++id_char_; id_element_ = 0; QTimer::singleShot (duration_dot_ * 3, this, SLOT ( Mute() )); // return; } QTimer::singleShot (duration_dot_, this, SLOT ( Mute() )); // } void Morse::Space () { if (stop_) { this->Stop (); return; } sound_.setMuted (true); // 7 // , 4 QTimer::singleShot (duration_dot_ * 4, this, SLOT ( Mute() )); } void Morse::Mute () { if (stop_) { this->Stop (); return; } if (id_char_ == string_to_play_.size ()) { // this->Stop (); return; } if (string_to_play_.at (id_char_) == ' ') { Space(); ++id_char_; // return; } if (codes_.find ( string_to_play_.at (id_char_) ) == codes_.end ()) { qDebug() << string_to_play_.at (id_char_) << ": No code!"; sound_.stop (); return; } sound_.setMuted (false); // if ( codes_.value ( string_to_play_.at (id_char_) ).at (id_element_)) { QTimer::singleShot (duration_dot_, this, SLOT ( MiniSpace() )); // } else { QTimer::singleShot (duration_dot_ * 3, this, SLOT ( MiniSpace() )); // } } bool Morse::Play () { if (!stop_) return false; if (string_to_play_ == "") return false; stop_ = false; id_char_ = 0; id_element_ = 0; sound_.setMuted (true); // sound_.play (); Mute (); } void Morse::Stop () { if (stop_) return; sound_.stop (); id_char_ = 0; id_element_ = 0; stop_ = true; }
stop_フラグは、プログラムが正しく動作しないようにするために導入されました(Play()への2回の呼び出しと他の悪いこと)。
ソースコードとヘッダーファイルの残りの部分には、記事の本文を取り込む理由がありません。すべてが非常に明白で透過的だからです。
最新バージョンのソースの完全なセットをgithubからダウンロードできます。 グラフィカルインターフェイスの作成は簡単な作業ですが、GUIが作成された場合は、リンクを追加します。 質問やコメントがあれば、コメントを書いてください-私は間違いなく答えます。