Последнее время я занимаюсь изучением азбуки Морзе с помощью данной программы. Но она рассчитана на изучение кодов кириллических букв, что является неактуальным в современной радиосвязи (все используют латинский алфавит, кроме нашей доблестной армии).
Такая ситуация меня не устроила, и было принято решение написать программу для генерации звукового кода Морзе из некоторого текста с настройкой скорости и возможностью добавления кодов динамически. Решение получилось достаточно оригинальным и гибким (ИМХО, конечно же). И я решил поделиться программой с общественностью: возможно, она будет кому-то полезна или покажется интересной.
В качестве инструмента реализации идеи был выбран С++ в связке с Qt.
Основная идея программы
Атомом (единицей времени) кода Морзе является точка, относительно нее формируется длительность всех остальных элементов:
- Тире равняется трем звучащим точкам;
- Пауза между элементами одного символа (знака) — одна незвучащая точка;
- Между знаками — три точки;
- Между словами — семь точек.
Как видите, любой код, основанный на азбуке морзе, можно представить в виде набора звучащих и незвучащих точек: от этой идеи я и отталкивался, причем такое решение мне показалось достаточно оригинальным.
Первоначальный вариант реализации
В первой версии программы комбинация звучащих и незвучащих точек хранилась в виде вектора с булевыми элементами, где true соответствовал включению звука, а false — выключению.
Как вы уже поняли, для получения конечного сигнала я всего лишь «дергал» звук с некоторой задержкой (с помощью таймера, равного длительности точки в миллисекундах) при бесконечно воспроизводящемся .wav файле с записью синуса. Но данный подход имел значительный минус и заключался он в том, что приходилось каждую точку загружать отдельно с помощью перегруженного оператора или специального метода. Из-за такого подхода пришлось писать отдельный макрос для каждой буквы (вроде такого — #define I DOT << false << DOT) и создать огромный жуткий switch для воспроизведения переданной строки. Это было ужасно, но если вам любопытно, то вы можете ознакомиться
с первой версией программы тут (у меня не получилось полностью загрузить на 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() и прочих нехороших вещей).
Остальную часть исходных кодов и заголовочные файлы не вижу смысла приводить в теле статьи, так как там все достаточно очевидно и прозрачно.
Полный набор исходников последней версии вы можете скачать на гитхабе. Написание графического интерфейса является тривиальной задачей, но все же, если будет создан GUI, то ссылку я добавлю. Если есть какие-то вопросы или замечания, пишите в комментариях — обязательно отвечу.
Комментарии (17)
Stas911
25.09.2015 17:38А кто и для чего сейчас Морзе использует?
UA3MQJ
26.09.2015 11:19+2Радиолюбители используют, как один из видов связи, которых очень много. Но в морзянке есть свои прелести:
- Телеграфный сигнал — это либо наличие несущей частоты в эфире, либо ее отсутствие. То есть по сути это генерация заданной частоты, усиление и подача этого сигнала в антенну. Сделать телеграфный передатчик — очень просто! Вот AM, FM или SSB — уже сложнее.
- Телеграфный сигнал занимает узкую полосу. Вся энергия сосредоточена на одной частоте (а не размазана по спектру, как в SSB или как в АМ не передается бессмысленная несущая). Можно сужать полосу приемника для улучшения приема. В итоге дальность связи увеличивается, по сравнению с голосом
- Аура таинственности, свой тайный язык. Осознание радости от того, что человеческий мозг сам может, без компьютера, декодировать цифровые сигналы. А еще очень удобно, если ты человек семейный. Вместо постоянной болтовни в микрофон, типа «ульяна анна тройка… пять девять… QRM… Мой QTH...», тихо колупаешь клоподавом, или автоматическим ключем, или вообще набираешь на клавиатуре текст, а ПК сам передает телеграфом. Прием, естественно, на слух (хотя ПК тоже может)
- При проведении связей голосом, зачастую все скатывается в болтовню. Целые диапазоны болтающих людей на больших мощностях. Со скромными антеннами и 100 ваттами зачастую и не пробиться. Тут как раз CW дает возможность провести связь. Лаконично и быстро. А еще, морзянка — универсальный международный язык. Нужны минимальные знания, чтобы проводить связи на английском языке (и никаких проблем с произношением).
Так что, не смотря на возможность голосовой и даже цифровой связи, телеграф до сих пор не потерял актуальности на любительских диапазонах.
BalinTomsk
25.09.2015 18:45В советские времена в 80-х учились на обычных автоматических ключах.
Для быстрой учебы pаспознать на слух учили песенные напевы типа: К — куда ты пошла. А — ай да.
На соревнованиях по скоростному приму-передачи радиограмм включалась еше такая дисциплина как метание гранат.Swamp_Dok
25.09.2015 20:42Да, часто учат с напевами, но руководитель местного радиоклуба говорит, что стоит учить без напевов, так как они в перспективе мешать будут.
itblogger
26.09.2015 07:41Эх, елки, столько лет прошло! Ночи в наушниках, днем на соревнованиях по охоте на лис, романтика!
Айда, баки текут, видала, гагарин, домики, есть, железисто, заводики, иди, как же так, лунатики, мама, номер, около, пила поет, решает?, семенить, так, (у не помню), (ф не помню), химичите, цапли-цапли, (ч не помню), (ш не помню, таа-таа-таа-таа), ща вам не ша, электроника, ы не надо, я мал я малSwamp_Dok
26.09.2015 07:46Да, как раз такие напевы используются в программе по которой я учу телеграф. Правда учу без напевов.
iUser
27.09.2015 09:15решает
унесло
филимончик
чаша тонет
шаровары
Вместо «заводиков» у нас были «закатики», вместо «как же так» — «как дела», вместо «цапли-цапли» — «цыпа-цыпа» и вместо «семенить» — «синее» :)
PapaTramp
Мы в мореходке учились на тренажере «Ручеёк» :)
Удобное было устройство, могло выдавать цифры, буквы и, по-моему, цифро-буквенные сочетания. Ну и скорость, само собой, можно было регулировать.