The invention of the telegraph as the first electrical telecommunications system is an important landmark in the history of communication, but while the tech itself is very interesting hardware, from the coding point of view I’m more interested in the Morse code used to send messages with it.

Morse code consists of dots, dashes and spaces which when linearly combined and transmitted make up letters, words and sentences. Named after Samuel Finley Breese Morse who helped co-develop it, it was later refined by Friedrich Clemens Gerke and after the adoption by the Deutsch-Österreichischer Telegraphenverein (German-Austrian Telegraph Society) in 1851, we’ve got the International Morse code in 1865, which, while slowly declining in usage and making way for better ways of communication, stayed in use up to this days and that’s the alphabet set we are gonna use to code our text-to-morse translator in Javascript.

We have 26 letters and 10 numerals available. Dots and dash sequences (dot vocalized as “dit” and dash as “dah”) are assigned to letters based on how commonly they are used – shorter combinations are assigned to the most used letters. To keep it simple we will not be integrating the prosigns in this version (like SOS = …—…)

We are translating text into an audible audio signal over the Javascript Audio API, using the OscillatorNode and a GainNode connected to it – with this two we have all the tools needed to simulate the telegraph behavior (we could go further and even simulate the communication between two telegraph devices over a socket connection or even better with WebRTC which is ideal since a telegraph is basically a p2p connection, but let’s leave this for a part 2 maybe).

With the above info all we have to do is to convert the text into a sequence of dots, dashes and spaces which can be then looped over and by altering the gainNode volume for each character in the sentence we get the telegraph behavior.

If we consider that we have a time unit of X ms, the rules for emitting the signals are:

dot = 1 unit of sound
dash = 3 units of sound
sign space = 1 unit of silence
letter space = 3 units of silence
word space = 7 units of silence

Morse code also does not distinguish between upper and lowercase, so we can transform all text to lowercase and just work with that. With this rules in mind I can define a few constants to concatenate into the morse sequence that will be interpreted by the oscillator:

const SEQUENCE_SIGNS = {        
    DIT: ".",        
    DAH: "-",        
    SIGN_SPACE: "x",        
    LETTER_SPACE: "xxx",        
    WORD_SPACE: "xxxxxxx",      
};

For the common test string “PARIS” using the above sign set we get a sequence (let’s us “x” to represent a space unit for clarity):

.x-x-x.xxx.x-xxx.x-x.xxx.x.xxx.x.x.

All that is left to do is to loop over it and toggle the gainNode volume on and off. A way to do this in a JS is to transform it into an array and loop over using a promise inside a reduce(). This way the timeout has time to resolve and the loop won’t fly over it until the signal played for the given duration:

sequence.split("").reduce(async (acc, val) => {
  await acc;
  return new Promise(res => {
    gainNode.gain.setTargetAtTime(val === SEQUENCE_SIGNS.SIGN_SPACE ? 0 : volume, audioCtx.currentTime, TIME_CONSTANT);
    let duration = val === SEQUENCE_SIGNS.DAH ? TIME_UNIT * 3 : TIME_UNIT;
    setTimeout(() => {
      gainNode.gain.setTargetAtTime(0, audioCtx.currentTime, TIME_CONSTANT);
      res();
    }, duration);
  });
}, Promise.resolve());

And we end up with a very basic morse code interpreter – you can check it’s simple source or just play with it:

how I use chrome devtools