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.