Bash Morse code sound script

by: Artur Dziedziczak

April 19, 2021

Introduction

After 3 weeks of trying to setup Kubernetes + Nextcloud + static website in Minikube I decided to take a little break and focus on some Bash. The project I decided to make is as simple text to Morse [5] [4] script

Morse Beep Bash

The code is pretty easy to follow. First, I make reqular expression substitution for every letter of alphabet and numbers from 0 to 9. I also need some specyfic characters to escape spaces, in this case it’s character s. For every regular expression I need to end each Morse code character with some delimiter. I picked = so later I can pause signal generation when condition is true

After that my enhanced Morse code is piped to fold to end every character with new line and then again piped to xargs which invokes ffplay [1] that plays sine sound for specyfic period of time or use sleep when break is needed

Listing 1. Program which beeps Morse code for stdin
#/bin/sh

# dit - 0.1s
# dah - 3 * dit = 0.3s
# spacing between inter elements of Morse code - 1 dit
# space between letters = 3 dits
# space between words = 7 dits

sed \
	-e 's/a/.-=/g' \
	-e 's/b/-...=/g' \
	-e 's/c/-.-.=/g' \
	-e 's/d/-..=/g' \
	-e 's/e/.=/g' \
	-e 's/f/..-.=/g' \
	-e 's/g/--.=/g' \
	-e 's/h/....=/g' \
	-e 's/i/..=/g' \
	-e 's/j/.---=/g' \
	-e 's/k/-.-=/g' \
	-e 's/l/.-..=/g' \
	-e 's/m/--=/g' \
	-e 's/n/-.=/g' \
	-e 's/o/---=/g' \
	-e 's/p/.--.=/g' \
	-e 's/q/--.-=/g' \
	-e 's/r/.-.=/g' \
	-e 's/s/...=/g' \
	-e 's/t/-=/g' \
	-e 's/u/..-=/g' \
	-e 's/v/...-=/g' \
	-e 's/w/.--=/g' \
	-e 's/x/-..-=/g' \
	-e 's/y/-.--=/g' \
	-e 's/z/--..=/g' \
	-e 's/1/.----=/g' \
	-e 's/2/..---=/g' \
	-e 's/3/...--=/g' \
	-e 's/4/....-=/g' \
	-e 's/5/.....=/g' \
	-e 's/6/-....=/g' \
	-e 's/7/--...=/g' \
	-e 's/8/---..=/g' \
	-e 's/9/----.=/g' \
	-e 's/0/-----=/g' \
	-e 's/\s/s/g' | fold -w 1 | xargs -n1 -I {} bash -c '[[ {} == "-" ]] && { ffplay -f lavfi -i "sine=frequency=1000:duration=0.3" -nodisp  -autoexit; sleep 0.1; }; [[ {} == "." ]] &&
{ ffplay -f lavfi -i "sine=frequency=1000:duration=0.1" -nodisp  -autoexit; sleep 0.1; };  [[ {} == "s" ]] && { sleep 0.7; }; [[ {} == "=" ]] && { sleep 0.1; }'

Results

I recorded simple sos sos sos Morse code by using this script

Listing 2. Usage of Morse code script
echo "sos sos sos" | ./morse.sh

And recorded it to .wav file with arecord -vv -fdat morse.wav

Output sound recorded from my speakers

As you can see it’s really easy to make yourself simple more code translator which will make sounds from your speaker

Morse code audio sample data extraction

In the very end of evening I decided to also play around a bit with .dat file which can be produced from .wav

I really wanted to see the interval in which my Morse code plays "beep" sound and for that first I used sox [2] program to extract data from .wav;

Listing 3. Simple way to extract .dat from .wav
sox morse.wav morse.dat
Listing 4. Contents of morse.dat
head morse.dat; echo '... HERE BIG CONTENT WHICH HAS: ' $(du -h morse.dat) ' ...';  tail morse.dat

; Sample Rate 48000
; Channels 2
               0    0.99996948242   0.99996948242
   2.0833333e-05    0.99996948242   0.99996948242
   4.1666667e-05    0.99996948242   0.99996948242
        6.25e-05    0.99996948242   0.99996948242
   8.3333333e-05    0.99996948242   0.99996948242
   0.00010416667    0.99996948242   0.99996948242
        0.000125    0.99996948242   0.99996948242
   0.00014583333    0.99996948242   0.99996948242
... HERE BIG CONTENT WHICH HAS:  41M morse.dat  ...
       16.749792  -0.0001220703125 -0.0014953613281
       16.749813  -0.00076293945312 9.1552734375e-05
       16.749833  0.00030517578125               0
       16.749854  9.1552734375e-05 0.00076293945312
       16.749875  0.00042724609375 -6.103515625e-05
       16.749896  0.00030517578125 0.0020751953125
       16.749917  0.0010681152344 0.00094604492188
       16.749938  0.0018615722656 0.0021057128906
       16.749958     0.0029296875 0.0013427734375
       16.749979  0.0029907226562 0.0015258789062

Data visualization

First I started with some GNU Octave [3] code that is plotting amplitude of Morse code signal

Listing 5. Octave plotter for morse.dat
filename = "morse.dat";
skipped_rows = 34000;
skipped_columns = 0;

m = dlmread(filename, '' , skipped_rows, skipped_columns);

t = m(:, 1);
amplitude = m(:, 2);

plot(t, amplitude);
xlabel ("time[s]");
ylabel ("amplitude");
title ("morse.dat signal characteristic");
saveas (1, "morse-time-amplitude.png");

This was really easy and as you can see clearly SOS SOS SOS was generated properly

morse time amplitude
Figure 1. Plot of morse.dat

Second one is a bit more interesting as it shows spectrogram of sound. I love the end result of it. I generated sine wave with frequency of 1000Hz and on this diagram you can clearly see SOS generated with 1kHz

Listing 6. Sox command to generate spectrogram
sox morse.wav -n spectrogram
spectrogram
Figure 2. Spectrogram of morse.dat

Cool huh?

Conclusion

This was a small cool project that made just to refresh a bit from dust from kubernetes cave

As always I highly recommend to play around with Bash. It’s such a flexible scripting language. I love to use it whenever I have an oportunity

In 2 weeks I’m going back to Polish remote university mode but at least now everyday I wake up in the Netherlands

netherlands
Figure 3. Weekend with my girlfriend and friends in Amsterdam

Sources

[1] “Ffplay Documentation.” https://ffmpeg.org/ffplay.html

[2] “SoX - Sound eXchange | HomePage.” http://sox.sourceforge.net/

[3] “GNU Octave.” https://www.gnu.org/software/octave/index

[4] “Morse Code,” Wikipedia. https://en.wikipedia.org/w/index.php?title=Morse_code&oldid=1012730449, Mar. 2021

[5] Shouldaville - Shorts, “The Importance of Morse Code Spacing.” https://www.youtube.com/watch?v=OB1Kc4s0aNE, Mar. 2017