Morse Trainer

A Godot project.

Current Project State

A quiet place for the quiet morser

Try it now!

Downloads

Dev diary

The website that started it all

April 14th 2021

Inspiration

This project was born from stumbling upon this site, a Morse typing website where you interact with other real users by keying Morse code with the space bar.

What impressed me most with the site was the live transcription of keyed Morse, allowing me to judge whether or not my Morse was comprehensible to, at least, the bot charged with transcribing the Morse. It really made keying fun, as your mistakes were swiftly visible, and made keying feel more like an exercise in mind-to-hand agility than a chore.

However, immediately, a problem was clear; I couldn't key Morse, and worse, the site had no training grounds! The problem was obvious, the slower rooms (where you can key slowly) were filled with beginners who could barely express themselves. I was in that situation too, until I figured out that some rooms tended to be empty, which allowed me to practice in peace, and without bothering anyone. However, even those empty room tended to attract members looking for one on one discussions. Plus, rooms were limited and each had a different speed of increasing difficulty for a Morse beginner such as myself. These issues frustrated me.

Looking for a Solution

I soon started looking for some kind of Morse training solution, where I could practice my Morse keying with the exact same kind of Morse transcription as I found on that site. However, I could not find anything. Even worse, I could barely find any resources to practice keying! Every resource seemed to be focused on practicing the ear. It dawned on me that I might be the one who had to be the change I wanted to see in this particular world.

Planned Features

I identified a few things I'd like to improve upon.

  • Offline mode

  • Arbitrary WPM

  • Prompted training - WIP

  • Low Latency Multi-User experience - WIP

Offline Mode

If I could reproduce the functionality of the site without the other users I would already be quite happy with it. It would allow me to practice without bothering anyone.

Arbitrary WPM

The fact that the WPM (Words Per Minute, a measure of keying speed) was tied to the room and that the number of rooms was very limited meant that you could not practice at your preferred speed should you want to be alone!

Prompted Training

This is something that the software allows quite naturally once it is built. The possibility of having text prompts makes practice much more directed and maybe more fun. Although it loses the aspect of Morse code that you must have the text you are keying in your head instead of it being on a reference somewhere.

Low Latency Multi-User Experience

I realized after a few days that I was not receiving what users were sending live! The site actually waited until the whole message was keyed and then replayed the keying on my end. I thought that made it lose some luster. I put on my list that my multi-user implementation shall be as low latency as possible. It shall make a good technical challenge.


Implementation details

Godot Engine

I chose to write this application in Godot engine because I feel like I can wrap my head around Godot layout much better than I can css. The ability to export Godot apps to the web also means that I am not sacrificing web compatibility in punishment for not "getting" css, as I love the low friction of deploying to users on the web. Implementing this system in Godot also allows me to easily transfer the Morse Code system to a 2D game shall I find a good design idea.

Morse

The first issue I had with implementing Morse code transcription was that I needed some fairly precise Morse Code specifications so that my interpreter would understand correct Morse instead of some gross bastardization of it birthed by my mind. After a few minutes of research, I stumbled upon the Wikipedia article for Morse code which had a few interesting bits of information that would allow me to derive the necessary bits of data that I needed. The article mentions: "The dot duration is the basic unit of time measurement in Morse code transmission. The duration of a dash is three times the duration of a dot. Each dot or dash within a character is followed by period of signal absence, called a space, equal to the dot duration. The letters of a word are separated by a space of duration equal to three dots, and the words are separated by a space equal to seven dots. " This was quite exactly what I needed! I had some relative timing specifications for Morse, but now I needed to figure out the exact timings in ms for a given speed given in WPM. I found out that the standard word for speed measurement is "PARIS". WPM could therefore be understood as Parises per Minute. A quick calculation reveals that PARIS is 50 dots long and that a dot has therefore a length of 1200/WPM milliseconds.

I then implemented it such that a key pressed less than one-and-a-half dots long was interpreted as a dot and more interpreted as a dash. A seven dots wait between letters meant that a space should be inserted and a 10 dots wait meant that the line was finished. This was all moderately complex to model algorithmically however, which is why I implemented this behavior as a Finite State Machine.

Finite State Machine Morse Transcriber

Finite State Machines are a simplified model of computation. The rules are simple: You have a current state, and a set of allowed next states based on input. Each state has their own set of allowed next states. This allows for extremely intuitive modelling of certain types of problems, where there is a relatively big number of states, but only a small set of possible inputs. Each state only has to concern itself with the states it can transition too, and the triggers of that transition. The state machine only concerns itself with holding its current state, executing state transitions and forwarding input to the current state.

My particular state machine only has three possible input events. Pressing the key, releasing the key, and the expiry of a timer. Furthermore, a state is only subject to a maximum of two different events, because pressing a key always results in going to a state that is exclusive to that event, allowing only key release afterwards. The same is true for the release event. This makes the problem extremely well suited to a Finite State Machine model.

The state machine pictured henceforth is my model of a Morse Transcriber, yielding raw Morse code from the mechanics of a key and the tracking of time. Because output is bound to the states you arrive at, this is an example of a Moore Machine. The particular transition leading to a state is unimportant, only that this state was reached. This is by contrast to a Mealy Machine in which transitions are what yield output.

Example output from this state machine: ".... . .-.. .-.. --- / .. .... . .-. . \n"

A wrapper around this state machine converts the Morse into proper letters, and replaces slashes by spaces.

As a final note, I am using dit and dah in the state machine diagram to express what I called respectively dots and dashes in this blog post. Dits and Dahs are what these are called in the Morse world.

Periodic updates

April 17th update

The app is currently in a "working prototype" state. It currently serves as a sandbox in which you can key Morse and it will transcribe it to you in plain English. You have a little Morse reference panel on the right and you can change the WPM to any integer value you feel able to tackle.

I found a nice little monospaced typewriter font called Gabriele on this nifty website, and spent some time styling the app in some nice simple black and white. I even drew an empty and checked checkbox! Can't say I'm not dedicated :')

Internals-wise, I do not really like the Morse interpretation code, it does however do the job correctly. My next few steps would be to refactor the Morse interpreter into something modular and then work on a prompted training implementation.

May 25th update

I have refactored the internal Morse interpreter into a finite state machine, which makes it much more agreeable to work with.

In other news, I have stopped development on this project for now as I realize that the Web export of this project has broken audio due to engine (through browser API) issues. Being able to share this project as a website was a driving factor in my development therefore I will wait for Godot to have this issue fixed to resume development. It remains for now an excellent offline Morse Trainer native app however.

July 15th update

The broken audio was due to my build script mostly! I was wondering why the audio would not loop past the length of a single playback of the wav file! It was because I thought the .import files were generated from the assets, but they actually contained important config information, including the fact that the audio file was meant to be looping. By including the .import files in the build script the issue was fixed! However, the audio still seems to crackle in chrome, but oddly it does not seem to be the case in Firefox. I am pretty certain the issue is out of my hands then. In any case, the issue is absent in the native exports.

In other news, I have published the project to Itch.io!

Thank you for reading!

Project Evolution Gallery

Prototype

March 11th 2021

Before Styling

March 16th 2021

Styled

April 17th 2021