Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
fastrgv authored Feb 28, 2020
1 parent 641766e commit bd5e58d
Show file tree
Hide file tree
Showing 9 changed files with 602 additions and 0 deletions.
Binary file added 40wpmAZ.wav
Binary file not shown.
66 changes: 66 additions & 0 deletions READMEmorse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@

# Morse Audio to Text Translator Using Ada: MATTA


**ver 1.0.0 -- 29feb2020**

* Initial version.

## Description

This is a commandline utility that converts a WAV sound file containing morse code to English text. Pre-built binaries run on OSX, MsWindows, & GNU/linux. It is written in Ada, so can be rebuilt on any platform with an Ada compiler.

The input wav file must be monaural, with a 16-bit signed integer encoding, and a sample rate of 8000 Hz. Either sox or audacity can easily transform to this format. The wav file is expected to be international morse code, preferrably clean and properly spaced. Tonal frequency or wpm-speed does not seem to matter.

--------------------------------------------------------
## Usage Example

The user command requires the WAV file name, and integer-WPM estimate as input:

wav2txt 40wpmAZ.wav 40

English text is then printed out to the screen.

Note that the precompiled executables use suffixes that indicates the system:
.) _osx (MacOSX)
.) _gnu (linux)
.) .exe (MsWin)

========================================================
## How It Works:

A clean morse code sound file contains tonal beeps separated by periods of silence. After normalization, the sound wave peak amplitude is one, while the periods of silence have near zero peaks. The simple approach used here seeks to detect those changes in peak amplitude that signal dots, dashes, and spaces.

The (ideal) international morse code relative timings are defined as:
.) length of a dot = 1
.) length of a dash = 3
.) space after dot or dash = 1
.) space after a letter = 3
.) space after a word = 7

MATTA is not perfect, but computer-generated sound files can be reliably decoded.

See also the inline code comments.

Final note: many good apps can easily be found to generate morse code sound files from text.

--------------------------
## Legal Mumbo Jumbo:

Covered by the GNU GPL v3 as indicated in the sources:

Copyright (C) 2020 <[email protected]>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You may read the full text of the GNU General Public License
at <http://www.gnu.org/licenses/>.

15 changes: 15 additions & 0 deletions lcmp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

# use this to ensure a complete recompilation:
if [ -d ./obj/ ]; then
rm ./obj/*
else
mkdir obj
fi


export PATH=$HOME/opt/GNAT/2019/bin:$PATH


gnatmake wav2txt -o wav2txt_gnu -D $PWD/obj


17 changes: 17 additions & 0 deletions license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@

Copyright (C) 2020 <[email protected]>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You may read the full text of the GNU General Public License
at <http://www.gnu.org/licenses/>.


15 changes: 15 additions & 0 deletions ocmp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

# use this to ensure a complete recompilation:
if [ -d ./obj/ ]; then
rm ./obj/*
else
mkdir obj
fi


export PATH=$HOME/opt/GNAT/2019/bin:$PATH


gnatmake wav2txt -o wav2txt_osx -D $PWD/obj


156 changes: 156 additions & 0 deletions wav2txt-parse-decode.adb
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
--
-- Copyright (C) 2020 <[email protected]>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You may read the full text of the GNU General Public License
-- at <http://www.gnu.org/licenses/>.
--



separate( wav2txt.parse )


procedure decode is
-- morse(1..sindx) is converted to english(1..?)

use ada.strings.unbounded;

endOfWord : constant character := '/';
endOfLetr : constant character := '|';

package AssoChar is new
Ada.Containers.Ordered_Maps(Unbounded_String, Character);
use AssoChar;

mc: Map;
ok: boolean;
cur: Cursor;

token: unbounded_string;
mch,ech: character;
a,b,pindx: chrng := 0;

msgout : boolean := true; --false;

begin

-- "Train" the Map:
mc.insert( to_unbounded_string(".-"), 'A', cur, Ok );
mc.insert( to_unbounded_string("-..."), 'B', cur, Ok );
mc.insert( to_unbounded_string("-.-."), 'C', cur, Ok );
mc.insert( to_unbounded_string("-.."), 'D', cur, Ok );
mc.insert( to_unbounded_string("."), 'E', cur, Ok );

mc.insert( to_unbounded_string("..-."), 'F', cur, Ok );
mc.insert( to_unbounded_string("--."), 'G', cur, Ok );
mc.insert( to_unbounded_string("...."), 'H', cur, Ok );
mc.insert( to_unbounded_string(".."), 'I', cur, Ok );
mc.insert( to_unbounded_string(".---"), 'J', cur, Ok );

mc.insert( to_unbounded_string("-.-"), 'K', cur, Ok );
mc.insert( to_unbounded_string(".-.."), 'L', cur, Ok );
mc.insert( to_unbounded_string("--"), 'M', cur, Ok );
mc.insert( to_unbounded_string("-."), 'N', cur, Ok );
mc.insert( to_unbounded_string("---"), 'O', cur, Ok );

mc.insert( to_unbounded_string(".--."), 'P', cur, Ok );
mc.insert( to_unbounded_string("--.-"), 'Q', cur, Ok );
mc.insert( to_unbounded_string(".-."), 'R', cur, Ok );
mc.insert( to_unbounded_string("..."), 'S', cur, Ok );
mc.insert( to_unbounded_string("-"), 'T', cur, Ok );

mc.insert( to_unbounded_string("..-"), 'U', cur, Ok );
mc.insert( to_unbounded_string("...-"), 'V', cur, Ok );
mc.insert( to_unbounded_string(".--"), 'W', cur, Ok );
mc.insert( to_unbounded_string("-..-"), 'X', cur, Ok );
mc.insert( to_unbounded_string("-.--"), 'Y', cur, Ok );
mc.insert( to_unbounded_string("--.."), 'Z', cur, Ok );

mc.insert( to_unbounded_string(".----"), '1', cur, Ok );
mc.insert( to_unbounded_string("..---"), '2', cur, Ok );
mc.insert( to_unbounded_string("...--"), '3', cur, Ok );
mc.insert( to_unbounded_string("....-"), '4', cur, Ok );
mc.insert( to_unbounded_string("....."), '5', cur, Ok );
mc.insert( to_unbounded_string("-...."), '6', cur, Ok );
mc.insert( to_unbounded_string("--..."), '7', cur, Ok );
mc.insert( to_unbounded_string("---.."), '8', cur, Ok );
mc.insert( to_unbounded_string("----."), '9', cur, Ok );
mc.insert( to_unbounded_string("-----"), '0', cur, Ok );

mc.insert( to_unbounded_string(".-.-.-"), '.', cur, Ok ); --period
mc.insert( to_unbounded_string("--..--"), ',', cur, Ok );--comma
mc.insert( to_unbounded_string(".----."), ''', cur, Ok );--apostr
mc.insert( to_unbounded_string("-...-"), '=', cur, Ok );--equal
mc.insert( to_unbounded_string("---..."), ':', cur, Ok );--colon

mc.insert( to_unbounded_string("-..-."), '/', cur, Ok );--slash

mc.insert( to_unbounded_string(".-.-."), '+', cur, Ok );--plus
mc.insert( to_unbounded_string("-....-"), '-', cur, Ok );--minus

mc.insert( to_unbounded_string("-.--."), '(', cur, Ok );--openP
mc.insert( to_unbounded_string("-.--.-"), ')', cur, Ok );--closeP

mc.insert( to_unbounded_string("-.-.-."), ';', cur, Ok );--semiCol

-------- thru training; now process --------------------------

a:=1;
outer:
loop -- thru each letter of message

set_unbounded_string(token,"");
b:=a;
inner:
loop
mch:=morse(b);
exit inner when mch=endOfWord;
exit inner when mch=endOfLetr;
append(token, mch );
b:=b+1;
exit inner when b>=sindx;
end loop inner;

declare
begin
ech := element(mc,token);
exception
when others =>
ech:='~'; --symbol for Unknown
end; --declare

pindx:=pindx+1;
english(pindx):=ech;

if mch=endOfWord then
pindx:=pindx+1;
english(pindx):=' ';
end if;

exit outer when b>=sindx;

a:=b+1; --a should point to next VALID char

end loop outer;

if msgout then
new_line;
put_line("Message in English:");
for i in 1..pindx loop
put(english(i));
end loop;
new_line;
end if;

end decode;

Loading

0 comments on commit bd5e58d

Please sign in to comment.