В мире информатики азбука Морзе - одна из тех старых технологий, которые все еще остаются крутыми. Мы все смотрели фильмы о Второй мировой войне, где правительства отправляют телеграфы, используя азбуку Морзе, для передачи сообщений на огромные расстояния. Мы, наверное, также смотрели фильмы о флоте, где командиры кораблей посылают знаменитый сигнал «SOS», когда корабль попадает в беду. Эта технология была новаторской, когда была разработана, и актуальна до сих пор.
Поскольку меня это интересовало, я подумал, что было бы здорово создать код Морзе с помощью программы, если бы я мог. Я немного погуглил и обнаружил, что несколько человек использовали API веб-аудио для генерации кода Морзе с помощью Javascript. Затем я потратил последующее время на чтение (и кодирование) с таймерами Javascript и API веб-аудио, играя с различными методами отправки сообщений с помощью света (цвета) и звука.
И, в конце концов, поскольку многое из этого было довольно крутым, я решил написать об этом пост.
В оставшейся части этого поста мы расскажем о некоторых интересных способах создания кода Морзе с помощью Javascript. Я собираюсь рассмотреть реализации с использованием как API веб-аудио, так и функции setTimeout JavaScript.
Немного истории о азбуке Морзе
Код Морзе (произносится как Морс в Морсель, а не Моррис, как имя, как моя жена описывала мне) может быть определен как закодированный язык точек и тире, которые соответствуют заранее заданной таблице. персонажей. Символы включают алфавит (a-z), а также цифры (0–9) и некоторые знаки препинания. Точки и тире, составляющие азбуку Морзе, могут передаваться через все, что может генерировать различный сигнал. Это делает его действительно мощным, потому что пока и отправитель, и получатель понимают азбуку Морзе, сообщения можно отправлять на большие расстояния с помощью фонарика или радио. С изобретением телеграфа это стало еще более мощным, поскольку сообщения могли передаваться на очень большие расстояния еще в начале 1900-х годов.
Азбука Морзе также широко используется в вооруженных силах США (и в других странах) более 100 лет. Некоторые известные фильмы о войне, в которых они представлены, включают Охоту за красным октябрем и Игра в имитацию.
Я рекомендую заглянуть на Страницу азбуки Морзе в Википедии и Страницу телеграфной Википедии, чтобы узнать больше.
История веб-аудио
Теперь, когда у вас есть некоторый опыт работы с азбукой Морзе, давайте поговорим о том, как можно использовать Javascript для передачи его с помощью цветов и звуков.
По мере развития браузеров звук всегда был проблемой. Первоначальный веб-браузер имел минимальную поддержку звука с определенными элементами. Когда был разработан флэш-носитель, он представлял собой кросс-браузерное решение, но по-прежнему требовал от пользователей установки программного обеспечения. Плагины для Flash-носителей также были неоптимальными.
В HTML5 элемент ‹audio› исправил множество проблем, но имел огромные ограничения, если вы хотели создавать свои собственные звуки из веб-приложений. Элемент ‹audio› не давал вам точного контроля над звуками и манипуляциями, как это сделал бы ди-джей.
С появлением Web Audio API все предыдущие проблемы были решены, поскольку он предоставил основу для (почти) любого типа звуковой работы, о которой вы только можете подумать.
Знакомство с API веб-аудио
В следующем разделе я попытаюсь показать высокоуровневое представление API веб-аудио. Я рекомендую заглянуть на страницы здесь для получения дополнительной информации. Вы также можете проверить историю W3C API веб-аудио здесь.
Хорошо, давайте начнем с самого начала ...
API веб-аудио - это просто виртуальный способ создания звуковой системы. Это можно считать аналогичным тому, что ди-джей использует при создании «миксов».
API веб-аудио на самом деле представляет собой набор узлов, которые являются разными частями виртуальной сети. Вы создаете эту сеть для имитации звуков и подключения источника (записанного или сгенерированного звука) к месту назначения (динамикам). Вот отличная общая диаграмма, которую я скопировал со страниц MDN здесь:
Общая аудиосеть, созданная с помощью API веб-аудио, называется аудиографом. API веб-аудио называет этот звуковой график AudioContext, в котором звук может запускаться в текущем сеансе браузера. В каждом браузере есть AudioContext, и вам нужно знать, как ссылаться на него, чтобы использовать Web Audio API.
Помимо звука, вы также можете создавать визуализации звука с помощью Analyzer Node API веб-аудио.
Если все это кажется трудным для понимания, я рекомендую вам посмотреть следующее видео, в котором рассматриваются основы.
Звук Морзе
Теперь, когда вы познакомились с веб-аудио и кодом Морзе, приступим к кодированию! В процессе изучения азбуки Морзе я создал приложение, которое использует API веб-аудио для генерации звуков точка и тире, которые вы обычно слышите по телеграфу или радиопередаче. Чтобы создать приложение, я проконсультировался с сообщением в блоге здесь и связанным с ним Gist здесь, чтобы лучше понять, как все это связать. Приложение построено на Angular и размещено на Firebase.
Здесь можно поиграть с запущенной версией приложения. Вы также можете просмотреть исходный код приложения на GitHub здесь.
Поскольку приложение следует базовой структуре Angular, я не собираюсь выполнять стандартные операции «ng new» и настройку приложения. Я просто расскажу, как главный компонент работает с веб-API. Ознакомьтесь с исходным кодом, чтобы узнать, как было создано приложение, по ссылке GitHub, которую я предоставил выше.
Само приложение просто принимает текст, воспроизводит текст как код Морзе, а также выводит переведенный результат, как показано на следующем снимке экрана.
Итак, давайте рассмотрим настройку…
Прежде всего, я должен отметить, что API веб-аудио сегодня поддерживается большинством современных браузеров, но могут быть небольшие различия для конкретной реализации браузера. Код, который я здесь описываю, создан для Google Chrome.
В качестве меры безопасности Chrome не воспроизводит звук, если предварительно не сработает жест. Это имеет смысл, поскольку вы не хотите, чтобы приложения могли подключаться к аудио на ваших компьютерах без вашего согласия и т. Д. Поэтому для этого основная веб-форма моего приложения создает Аудиоконтекст с onSubmit, который привязан к основной форме, принимающей ввод. Вот код:
Здесь метод createContext создает аудиограф, о котором мы говорили. Сначала мы создаем экземпляр AudioContext, осциллятора и узла усиления со следующим:
this.audioContext = new AudioContext(); this.oscillator = this.audioContext.createOscillator(); this.gain = this.audioContext.createGain();
Затем мы устанавливаем значение для узла усиления равным «0», чтобы имитировать его как выключенное (чтобы он не воспроизводил звук). Затем мы устанавливаем частоту (высоту тона) осциллятора, подключаем осциллятор к узлу усиления и подключаем узел усиления на динамики (назначение звука) со следующим:
this.gain.gain.value = 0; this.oscillator.frequency.value = 750; this.oscillator.connect(this.gain); this.gain.connect(this.audioContext.destination);
Наконец, мы устанавливаем скорость, с которой будут воспроизводиться звуки, и запускаем узел осциллятора. Это важно, потому что оно становится значением, которое мы устанавливаем для «планирования» звуков в сети.
this.dot = 1.2 / this.rate; this.oscillator.start(0);
Результирующий звуковой график должен выглядеть примерно так, как на следующей диаграмме:
На приведенном здесь графике все узлы существуют в аудиоконтексте. Три узла, перечисленные здесь, являются лишь частью аудиограммы. Осциллятор подключается к усилению, который затем создает выходной сигнал, который отправляется на динамики (аудио назначения).
После настройки Audio Graph нам нужно заняться созданием звуков. Здесь мы собираемся «запланировать» звуки, имитируя включение и выключение узла усиления. Мы делаем это, буквально устанавливая значение усиления на «0» или «1» через определенные промежутки времени. Думайте об этом как о буквально включении и выключении громкости динамика. Мы делаем это следующим образом:
generateMorse(time: any, phrase: string) { phrase = phrase.toUpperCase(); this.morseDisplay = []; for (const p of phrase) { if (p === ' ') { time += 3 * this.dot; } else if (this.MORSE[p] !== undefined) { time = this.createSound(time, this.MORSE[p]); time += 2 * this.dot; } const morseOuput = new MorseOutput(); morseOuput.morseText = p; morseOuput.morseValue = this.MORSE[p]; this.morseDisplay.push(morseOuput); } return time; }
Метод generateMorse использует время AudioContext со свойством audioContext.currentTime. AudioContext имеет внутренние часы, которые постоянно считают после создания. Мы собираемся использовать метод audioContext.setValueAtTime для «планирования» звуков звука с использованием этих часов. Вот почему время передается в качестве параметра методу generateMorse.
Массив MORSE - это просто набор пар ключ-значение, которые соотносят введенный символ со значением кода Морзе.
Также обратите внимание на использование значения точки для планирования времени. Это определяет частоту (темп), с которой программа будет воспроизводить «точки» и «тире».
С помощью метода generateMorse цикл for просматривает переданную ему фразу, а затем вызывает метод createSound. В этом методе происходит все волшебство.
createSound(time: any, char: string) { for (const c of char) { switch (c) { case '.': this.gain.gain.setValueAtTime(1.0, time); time += this.dot; this.gain.gain.setValueAtTime(0.0, time); break; case '-': this.gain.gain.setValueAtTime(1.0, time); time += 3 * this.dot; this.gain.gain.setValueAtTime(0.0, time); break; } time += this.dot; } return time; }
Этот метод вызывает метод узла усиления setValueAtTime, который «планирует» воспроизведение звуков в созданном аудиографе. Значение return важно, потому что оно заставляет цикл событий Javascript использовать генерацию звука как операцию в стеке. Если вы не включите return, тогда область действия Javascript пропустит время, и вы не услышите ни звука.
Собирая все вместе, конечный продукт выглядит так:
Проверьте работающую версию приложения или выполните git clone и поиграйте с кодом самостоятельно.
Морзе Лайт
В дополнение к звуковому приложению, которое я создал выше, я также создал второе приложение Angular, которое генерирует азбуку Морзе с помощью света. Технически приложение просто использует элемент холста HTML и перерисовывает круг с желтым и белым, чтобы имитировать включение фонарика, включенного и выкл.. Кроме того, когда отображается индикатор кода Морзе, соответствующий перевод «буква в морзе» выводится во времени справа от нарисованного индикатора.
Рабочая версия приложения доступна здесь. Вы также можете ознакомиться с исходным кодом на GitHub здесь.
Вот скриншот приложения в действии:
Как и в случае со звуковым приложением, я не собираюсь вдаваться в основы создания начальной структуры с помощью Angular CLI. Я просто собираюсь сосредоточиться на основной логике приложения и рекомендую вам просмотреть проект в GitHub, чтобы узнать больше о том, как реальный проект структурирован и т. Д.
Для базовой презентации света я использую async / await и цикл обработки событий Javascript для имитации того, что свет включен и выключен. Приложение в основном принимает фразу в качестве входных данных, а затем выполняет синхронизированные вызовы метода, который возвращает обещание. Поскольку я использую async / await, основной цикл событий Javascript вынужден ждать, пока это обещание не будет выполнено с заданным временем. Если вы не знакомы с async / await, рекомендую посмотреть мой пост здесь.
Приложение выполняет большую часть работы с помощью метода передачи и метода фонарика.
Во-первых, метод передачи вызывается кнопкой «отправить» в основной форме ввода. В этом методе используются вызовы async / await, как я первоначально объяснил, для управления синхронизацией последовательностей включения и выключения света.
async transmit() { // time = 1200 / words per minute // 20 words per minute // follows a 3 to 1 ratio // 60 milliseconds for one dot // 180 milliseconds for a dash // multiplied by factor of 4 to slow it down here const dot = 60 * 4; const dash = 180 * 4; this.showMorse = ''; const messageUpper = this.message.toUpperCase(); for (const char of messageUpper) { this.showMorse = this.showMorse + '(' + char + ') '; const morseValue = this.morseTranslation[char]; for (const morse of morseValue) { this.showMorse = this.showMorse + ' ' + morse; if (morse === '.') { // dot await this.flashlight('yellow', dot); // show white light to show when flash is finished await this.flashlight('white', 60); } else { // dash at 3 X 60 or 180 await this.flashlight('yellow', dash); // show white light to show when flash is finished await this.flashlight('white', 60); } } } }
Как видно из этого кода, метод async вызывает flashlight. Вызов имеет ожидание, которое блокирует основной цикл событий, заставляя программу ждать, прежде чем изменить цвет света. В зависимости от переданного значения цвета вызов фонарика также управляет цветом. Таким образом, желтый имитирует включенный свет, а белый - выключенный. Если вы передадите это со строкой кода Морзе в форме точек = ”.” и тире = ”-“, то вы сможете пройти по этой строке и смоделировать соответствующие значения on и off.
flashlight(color: String, time: any): Promise<any> { return new Promise(resolve => { setTimeout(function() { // this.drawLight(color); const c: any = document.getElementById('flashlight'); const ctx = c.getContext('2d'); ctx.beginPath(); ctx.arc(c.width / 2, c.height - 50, 50, 0, 2 * Math.PI); ctx.fillStyle = color; ctx.fill(); ctx.stroke(); resolve(true); }, time); }); }
Метод фонарик просто окрашивает элемент холст в течение определенного периода времени. Настоящая магия заключается в том, что async / await блокирует основной поток, вызывая ожидание, прежде чем рисование / перерисовка холста изменит цвет индикаторов.
Собирая все вместе, компонент Morse Light выглядит следующим образом:
Заключение
Лично все это было интересным способом узнать азбуку Морзе. Я надеюсь, что созданные мной ссылки и приложения помогут вам понять некоторые основы веб-аудио, а также время событий в Javascript.
Первоначально опубликовано на https://rhythmandbinary.com 19 января 2019 г.