📜 ⬆️ ⬇️

Program to generate a Morse code

image

Recently, I have been studying Morse code with this program . But it is designed to study the codes of Cyrillic letters, which is irrelevant in modern radio communications (all use the Latin alphabet, except for our valiant army).

This situation did not suit me, and it was decided to write a program to generate a Morse code for sound from some text with speed settings and the ability to add codes dynamically. The solution turned out to be quite original and flexible (IMHO, of course). And I decided to share the program with the public: perhaps it will be useful to someone or seem interesting.
')
C ++ was chosen as a tool for implementing the idea in conjunction with Qt.

The main idea of ​​the program


The atom (unit of time) of the Morse code is a point, the duration of all other elements is formed relative to it:

  1. A dash equals three sounding points;
  2. The pause between elements of one character (sign) is one non-sounding point;
  3. Between the signs - three points;
  4. Between the words - seven points.

As you can see, any code based on Morse code can be represented as a set of sounding and non-sounding points: I was repelled by this idea, and this solution seemed to me to be quite original.

The initial implementation


In the first version of the program, a combination of sounding and non-sounding points was stored in the form of a vector with boolean elements, where true corresponded to turning on the sound and false to turning off.

As you already understood, to get the final signal, I just “jerked” the sound with some delay (using a timer equal to the point duration in milliseconds) with an infinitely reproducible .wav file with a sine recording. But this approach had a significant minus and it was that we had to load each point separately using an overloaded operator or a special method. Because of this approach, I had to write a separate macro for each letter (like #define I DOT << false << DOT) and create a huge creepy switch to play the transmitted string. It was awful, but if you're curious, you can read
with the first version of the program here (I didn’t manage to fully load the local repository on GitHub - only the latest version).

A piece of creepy switch:
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; //    


And this is how the sound was turned on and off (the sound code generation itself):
 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; } } 


Final version


These macros turned out to be very cumbersome, and my perfectionism could no longer look at these monstrous constructions. After thinking a bit, I came to the conclusion that I have a good idea, but storing codes in the form of macros is very inconvenient and, if this problem is solved, everything will be fine. As a result, QMap was used to store codes:

 //       QMap<QChar, QBitArray> codes_; 

This approach was very convenient. Now I just used the current playable character as the key and got ready
to reproduce the code (a set of boolean values), the playback algorithm is a bit more complicated: you need to enter the counter of the current character element and the character counter in the string:

New playback implementation:
 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; } 


The stop_ flag was introduced to prevent the program from working incorrectly (two calls to Play () in a row and other bad things).
The rest of the source codes and header files do not see any reason to cite in the body of the article, since everything is quite obvious and transparent there.

You can download the full set of sources for the latest version on github . Writing a graphical interface is a trivial task, but still, if a GUI is created, then I will add a link. If you have any questions or comments, write in the comments - be sure to answer.

Source: https://habr.com/ru/post/267605/


All Articles