Program for generating Morse code
Recently, I have been studying Morse code using this program . But it is designed to study codes of Cyrillic letters, which is irrelevant in modern radio communications (everyone uses the Latin alphabet, except for our valiant army).
This situation did not suit me, and it was decided to write a program to generate Morse code 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 it will seem interesting.
C ++ in conjunction with Qt was chosen as a tool for implementing the idea.
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:
- A dash equals three sounding dots;
- A pause between the elements of one symbol (sign) is one sounding point;
- Between the signs there are three points;
- Between the words - seven points.
As you can see, any code based on the Morse code can be represented as a set of sounding and not sounding dots: I started from this idea, and such a decision seemed to me rather original.
Initial implementation
In the first version of the program, the combination of sounding and 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 “pulled” the sound with some delay (using a timer equal to the duration of a point in milliseconds) with an infinitely reproducing .wav file with sine recording. But this approach had a significant minus and it consisted in the fact that each point had to be loaded 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 switchto play the transmitted string. It was terrible, but if you are curious, then you can familiarize yourself
with the first version of the program here (I couldn’t fully download the local repository on GitHub - only the latest version).
A piece of the 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 (actually, the generation of a sound code):
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 bulky, and my perfectionism could no longer look at these monstrous constructions. After thinking a little, I came to the conclusion that I had a good idea, but storing codes in the form of macros is very inconvenient and, if this problem is solved, then everything will be fine. As a result, QMap was used to store codes:
//Хранит соответствующие комбинации точек и тире символов
QMap codes_;
This approach turned out to be very convenient. Now I just used the current playable character as a key and get a
code ready for playback (a set of Boolean values), however, the playback algorithm was a bit more complicated: I had to enter a counter for the current character element and a character counter in the line:
New play 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 in a row to Play () and other bad things).
The rest of the source codes and header files do not see any reason to bring 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 the github . Writing a graphical interface is a trivial task, but still, if a GUI is created, I will add a link. If you have any questions or comments, write in the comments - I will definitely answer.