Morse Code Messages with C#

Download full source code.

Every once in a while I get a simple idea that I want to implement just because it will be fun and I enjoy programming.

Here is a simple C# program that encodes Morse code messages and plays them on Windows and Linux.

For Linux, you need to add the mpg321 package.

sudo apt-get install mpg321

Or whatever package manager you use in your Linux.

I’m using two NuGet packages, NetCoreAudio to play audio files, and in Windows only NAudio to combine the files.

dotnet add package NetCoreAudio
dotnet add package NAudio

The code is very simple, it uses a strategy to choose between Windows and Linux methods of combining sound files. There are audio files for “dit”, “dah”, and silence.

Windows

If you are on Windows, the code uses NAudio to combine the audio files. It does this “correctly”, meaning it understands audio and combines the audio into a single audio file.

 1using NAudio.Wave;
 2
 3public class WindowsCombiner : ISymbolCombiner
 4{
 5    public void CombineSymbols(string sourceFileName, string destFileName)
 6    {
 7        using (var destFileStream = new FileStream(destFileName, FileMode.Append, FileAccess.Write))
 8        {
 9            using (Mp3FileReader sourceFile = new Mp3FileReader(sourceFileName))
10            {
11                Mp3Frame frame;
12
13                while ((frame = sourceFile.ReadNextFrame()) != null)
14                {
15                    destFileStream.Write(frame.RawData, 0, frame.RawData.Length);
16                    destFileStream.Flush();
17                }
18            }
19        }
20    }
21}

Linux

If you are on Linux, the NAudio library won’t work. It relies on some Windows specific libraries. Instead, the code simply concatenates the files together. This is not the “right” way to do it for audio, but it seems the MP3 format is pretty forgiving.

 1public class LinuxCombiner : ISymbolCombiner
 2{
 3    public void CombineSymbols(string sourceFileName, string destFileName)
 4    {
 5        using (var destFileStream = new FileStream(destFileName, FileMode.Append, FileAccess.Write))
 6        {
 7            using (var sourceFileStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read))
 8            {
 9                sourceFileStream.CopyTo(destFileStream);
10                destFileStream.Flush();
11            }
12        }
13    }
14}

The rest of the code

The rest of the code is simple enough; it determines the platform, chooses the right strategy, encodes the message, and plays it.

 1using NetCoreAudio;
 2
 3ISymbolCombiner combiner;
 4if (OperatingSystem.IsWindows())
 5{
 6    Console.WriteLine("Running on Windows");
 7    combiner = new WindowsCombiner();
 8}
 9else if (OperatingSystem.IsLinux())
10{
11    Console.WriteLine("Running on Linux");
12    combiner = new LinuxCombiner();
13}
14else
15{
16    throw new PlatformNotSupportedException("This OS is not supported.");
17}
18
19Console.WriteLine("Enter message to convert to Morse code:");
20string? message = Console.ReadLine();
21if (string.IsNullOrWhiteSpace(message))
22{
23    Console.WriteLine("No message entered. Exiting.");
24    return;
25}
26
27File.Create("morse.mp3").Dispose(); // create the file and release it
28Dictionary<char, string> morseCode = new()
29{
30    { 'A', ".-" }, { 'B', "-..." }, { 'C', "-.-." }, { 'D', "-.." },
31    { 'E', "." }, { 'F', "..-." }, { 'G', "--." }, { 'H', "...." },
32    { 'I', ".." }, { 'J', ".---" }, { 'K', "-.-" }, { 'L', ".-.." },
33    { 'M', "--" }, { 'N', "-." }, { 'O', "---" }, { 'P', ".--." },
34    { 'Q', "--.-" }, { 'R', ".-." }, { 'S', "..." }, { 'T', "-" },
35    { 'U', "..-" }, { 'V', "...-" }, { 'W', ".--" }, { 'X', "-..-" },
36    { 'Y', "-.--" }, { 'Z', "--.." }, { '0', "-----"}, { '1', ".----"},
37    { '2', "..---"}, { '3', "...--"}, { '4', "....-"}, { '5', "....."},
38    { '6', "-...."}, { '7', "--..."}, { '8', "---.."}, { '9', "----."},
39    { '.', ".-.-.-"}, { ',', "--..--"}, { '?', "..--.."}, { '\'', ".----."},
40    { '!', "-.-.--"}, { '/', "-..-."}, { '(', "-.--."}, { ')', "-.--.-"},
41    { '&', ".-..."}, { ':', "---..."}, { ';', "-.-.-."}, { '=', "-...-"},
42    { '+', ".-.-."}, { '-', "-....-"}, { '_', "..--.-"}, { '\"', ".-..-."}, 
43    { '$', "...-..-"}, { '@', ".--.-."}, { ' ', " "}
44}; 
45
46foreach (char letter in message.ToUpperInvariant())
47{
48    if (morseCode.TryGetValue(letter, out string? code))
49    {
50        foreach (char symbol in code)
51        {
52            if (symbol == '.')
53            {
54                combiner.CombineSymbols("short.mp3", "morse.mp3");
55            }
56            else if (symbol == '-')
57            {
58                combiner.CombineSymbols("long.mp3", "morse.mp3");
59            }
60            else if (symbol == ' ')
61            {
62                // Space between words
63                combiner.CombineSymbols("silence.mp3", "morse.mp3");
64                combiner.CombineSymbols("silence.mp3", "morse.mp3");
65                combiner.CombineSymbols("silence.mp3", "morse.mp3");
66            }
67        }
68        // Space between letters
69        combiner.CombineSymbols("silence.mp3", "morse.mp3");
70    }
71}
72
73var player = new Player();
74await player.Play("morse.mp3");
75Console.WriteLine("Press any key to exit.");
76Console.ReadKey();

There is also an interface for the strategy pattern.

1public interface ISymbolCombiner
2{
3    void CombineSymbols(string sourceFileName, string destFileName);
4}

There you go, a bit of fun with C#.

Download full source code.

comments powered by Disqus

Related