diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8adf24af2..c2dac7fa8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -102,6 +102,7 @@ set(sdrbase_SOURCES
sdrbase/dsp/upchannelizer.cpp
sdrbase/dsp/channelmarker.cpp
sdrbase/dsp/ctcssdetector.cpp
+ sdrbase/dsp/cwkeyer.cpp
sdrbase/dsp/dspcommands.cpp
sdrbase/dsp/dspengine.cpp
sdrbase/dsp/dspdevicesourceengine.cpp
@@ -194,6 +195,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/upchannelizer.h
sdrbase/dsp/channelmarker.h
sdrbase/dsp/complex.h
+ sdrbase/dsp/cwkeyer.h
sdrbase/dsp/decimators.h
sdrbase/dsp/dspcommands.h
sdrbase/dsp/dspengine.h
diff --git a/sdrbase/dsp/cwkeyer.cpp b/sdrbase/dsp/cwkeyer.cpp
new file mode 100644
index 000000000..796ecde33
--- /dev/null
+++ b/sdrbase/dsp/cwkeyer.cpp
@@ -0,0 +1,293 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 as version 3 of the License, or //
+// //
+// 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "cwkeyer.h"
+
+const char m_asciiToMorse[][128] = {
+ {-1}, // 0
+ {-1}, // 1
+ {-1}, // 2
+ {-1}, // 3
+ {-1}, // 4
+ {-1}, // 5
+ {-1}, // 6
+ {-1}, // 7
+ {-1}, // 8
+ {-1}, // 9
+ {-1}, // 10
+ {-1}, // 11
+ {-1}, // 12
+ {-1}, // 13
+ {-1}, // 14
+ {-1}, // 15
+ {-1}, // 16
+ {-1}, // 17
+ {-1}, // 18
+ {-1}, // 19
+ {-1}, // 20
+ {-1}, // 21
+ {-1}, // 22
+ {-1}, // 23
+ {-1}, // 24
+ {-1}, // 25
+ {-1}, // 26
+ {-1}, // 27
+ {-1}, // 28
+ {-1}, // 29
+ {-1}, // 30
+ {-1}, // 31
+ {-1}, // 32
+ {1,0,1,0,1,1,-1}, // 33 !
+ {0,1,0,0,1,0,-1}, // 34 "
+ {-1}, // 35
+ {-1}, // 36
+ {-1}, // 37
+ {-1}, // 38
+ {0,1,1,1,1,0,-1}, // 39 '
+ {1,0,1,1,0,1,-1}, // 40 (
+ {1,0,1,1,0,1,-1}, // 41 )
+ {-1}, // 42
+ {0,1,0,1,0,-1}, // 43 +
+ {1,1,0,0,1,1,-1}, // 44 ,
+ {1,0,0,0,0,1,-1}, // 45 -
+ {0,1,0,1,0,1,-1}, // 46 .
+ {1,0,0,1,0,-1}, // 47 /
+ {1,1,1,1,1,-1}, // 48 0
+ {0,1,1,1,1,-1}, // 49 1
+ {0,0,1,1,1,-1}, // 50 2
+ {0,0,0,1,1,-1}, // 51 3
+ {0,0,0,0,1,-1}, // 52 4
+ {0,0,0,0,0,-1}, // 53 5
+ {1,0,0,0,0,-1}, // 54 6
+ {1,1,0,0,0,-1}, // 55 7
+ {1,1,1,0,0,-1}, // 56 8
+ {1,1,1,1,0,-1}, // 57 9
+ {1,1,1,0,0,0,-1}, // 58 :
+ {1,0,1,0,1,0,-1}, // 59 ;
+ {-1}, // 60 <
+ {1,0,0,0,1,-1}, // 61 =
+ {-1}, // 62 >
+ {0,0,1,1,0,0,-1}, // 63 ?
+ {0,1,1,0,1,0,-1}, // 64 @
+ {0,1,-1}, // 65 A
+ {1,0,0,0,-1}, // 66 B
+ {1,0,1,0,-1}, // 67 C
+ {1,0,0,-1}, // 68 D
+ {0,-1}, // 69 E
+ {0,0,1,0,-1}, // 70 F
+ {1,1,0,-1}, // 71 G
+ {0,0,0,0,-1}, // 72 H
+ {0,0,-1}, // 73 I
+ {0,1,1,1,-1}, // 74 J
+ {1,0,1,-1}, // 75 K
+ {0,1,0,0,-1}, // 76 L
+ {1,1,-1}, // 77 M
+ {1,0,-1}, // 78 N
+ {1,1,1,-1}, // 79 O
+ {0,1,1,0,-1}, // 80 P
+ {1,1,0,1,-1}, // 81 Q
+ {0,1,0,-1}, // 82 R
+ {0,0,0,-1}, // 83 S
+ {1,-1}, // 84 T
+ {0,0,1,-1}, // 85 U
+ {0,0,0,1,-1}, // 86 V
+ {0,1,1,-1}, // 87 W
+ {1,0,0,1,-1}, // 88 X
+ {1,0,1,1,-1}, // 89 Y
+ {1,1,0,0,-1}, // 90 Z
+ {-1}, // 91 [
+ {-1}, // 92 \
+ {-1}, // 93 ]
+ {-1}, // 94 ^
+ {-1}, // 95 _
+ {-1}, // 96 `
+ {0,1,-1}, // 97 A
+ {1,0,0,0,-1}, // 98 B
+ {1,0,1,0,-1}, // 99 C
+ {1,0,0,-1}, // 100 D
+ {0,-1}, // 101 E
+ {0,0,1,0,-1}, // 102 F
+ {1,1,0,-1}, // 103 G
+ {0,0,0,0,-1}, // 104 H
+ {0,0,-1}, // 105 I
+ {0,1,1,1,-1}, // 106 J
+ {1,0,1,-1}, // 107 K
+ {0,1,0,0,-1}, // 108 L
+ {1,1,-1}, // 109 M
+ {1,0,-1}, // 110 N
+ {1,1,1,-1}, // 111 O
+ {0,1,1,0,-1}, // 112 P
+ {1,1,0,1,-1}, // 113 Q
+ {0,1,0,-1}, // 114 R
+ {0,0,0,-1}, // 115 S
+ {1,-1}, // 116 T
+ {0,0,1,-1}, // 117 U
+ {0,0,0,1,-1}, // 118 V
+ {0,1,1,-1}, // 119 W
+ {1,0,0,1,-1}, // 120 X
+ {1,0,1,1,-1}, // 121 Y
+ {1,1,0,0,-1}, // 122 Z
+ {-1}, // 123 {
+ {-1}, // 124 |
+ {-1}, // 125 }
+ {-1}, // 126 ~
+ {-1}, // 127 DEL
+};
+
+CWKeyer::CWKeyer() :
+ m_sampleRate(48000),
+ m_textPointer(0),
+ m_elementPointer(0),
+ m_elementSpace(false),
+ m_characterSpace(false),
+ m_key(false),
+ m_dot(false),
+ m_dash(false),
+ m_elementOn(false),
+ m_mode(CWKey),
+ m_keyState(KeySilent)
+{
+ setWPM(13);
+}
+
+CWKeyer::~CWKeyer()
+{
+}
+
+void CWKeyer::setWPM(int wpm)
+{
+ if ((wpm > 0) && (wpm < 21))
+ {
+ m_wpm = wpm;
+ m_dotLength = (int) (m_sampleRate / (2.4f * wpm));
+ }
+}
+
+void CWKeyer::setDot(bool dotOn)
+{
+ if (dotOn)
+ {
+ m_dash = false;
+ m_dot = true;
+ }
+ else
+ {
+ m_dot = false;
+ }
+}
+
+void CWKeyer::setDash(bool dashOn)
+{
+ if (dashOn)
+ {
+ m_dot = false;
+ m_dash = true;
+ }
+ else
+ {
+ m_dash = false;
+ }
+}
+
+int CWKeyer::getSample()
+{
+ if (m_mode == CWKey)
+ {
+ return m_key ? 1 : 0;
+ }
+ else if (m_mode == CWIambic)
+ {
+ switch (m_keyState)
+ {
+ case KeySilent:
+ if (m_dot)
+ {
+ m_keyState = KeyDot;
+ m_elementPointer = 0;
+ }
+ else if (m_dash)
+ {
+ m_keyState = KeyDash;
+ m_elementPointer = 0;
+ }
+
+ m_key = false;
+ break;
+ case KeyDot:
+ if (m_elementPointer < m_dotLength) // dot key
+ {
+ m_key = true;
+ m_elementPointer++;
+ }
+ else if (m_elementPointer < 2*m_dotLength) // dot silence
+ {
+ m_key = false;
+ m_elementPointer++;
+ }
+ else // end
+ {
+ if (m_dash)
+ {
+ m_elementPointer = 0;
+ m_keyState = KeyDash;
+ }
+ else if (!m_dot)
+ {
+ m_keyState = KeySilent;
+ }
+
+ m_elementPointer = 0;
+ m_key = false;
+ }
+ break;
+ case KeyDash:
+ if (m_elementPointer < 3*m_dotLength) // dash key
+ {
+ m_key = true;
+ m_elementPointer++;
+ }
+ else if (m_elementPointer < 4*m_dotLength) // dash silence
+ {
+ m_key = false;
+ m_elementPointer++;
+ }
+ else // end
+ {
+ if (m_dot)
+ {
+ m_elementPointer = 0;
+ m_keyState = KeyDot;
+ }
+ else if (!m_dash)
+ {
+ m_keyState = KeySilent;
+ }
+
+ m_elementPointer = 0;
+ m_key = false;
+ }
+ break;
+ default:
+ m_elementPointer = 0;
+ m_key = false;
+ break;
+ }
+
+ return m_key ? 1 : 0;
+ }
+}
+
diff --git a/sdrbase/dsp/cwkeyer.h b/sdrbase/dsp/cwkeyer.h
new file mode 100644
index 000000000..b05890375
--- /dev/null
+++ b/sdrbase/dsp/cwkeyer.h
@@ -0,0 +1,78 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 F4EXB //
+// written by Edouard Griffiths //
+// //
+// 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 as version 3 of the License, or //
+// //
+// 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 V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_DSP_CWKEYER_H_
+#define SDRBASE_DSP_CWKEYER_H_
+
+#include
+#include "util/export.h"
+
+class SDRANGEL_API CWKeyer : public QObject {
+ Q_OBJECT
+
+public:
+ typedef enum
+ {
+ CWText,
+ CWKey,
+ CWIambic
+ } CWMode;
+
+ typedef enum
+ {
+ KeySilent,
+ KeyDot,
+ KeyDash
+ } CWKeyState;
+
+ CWKeyer();
+ ~CWKeyer();
+
+ void setSampleRate(int sampleRate) { m_sampleRate = sampleRate; }
+ void setWPM(int wpm);
+ void setText(QString& text) { m_text = text; }
+ void setMode(CWMode mode) { m_mode = mode; }
+
+ void setKey(bool key) { m_key = key; };
+ void setDot(bool dotOn);
+ void setDash(bool dashOn);
+
+ int getSample();
+ bool eom();
+
+private:
+ int m_sampleRate;
+ int m_wpm;
+ int m_dotLength; //!< dot length in samples
+ QString m_text;
+ int m_textPointer;
+ int m_elementPointer;
+ bool m_elementSpace;
+ bool m_characterSpace;
+ bool m_key;
+ bool m_dot;
+ bool m_dash;
+ bool m_elementOn;
+ CWMode m_mode;
+ CWKeyState m_keyState;
+
+ static const char m_asciiToMorse[][128];
+};
+
+
+
+#endif /* SDRBASE_DSP_CWKEYER_H_ */
diff --git a/sdrbase/gui/cwkeyergui.ui b/sdrbase/gui/cwkeyergui.ui
index 68559172d..10ac04079 100644
--- a/sdrbase/gui/cwkeyergui.ui
+++ b/sdrbase/gui/cwkeyergui.ui
@@ -1,582 +1,598 @@
-
-
- GLSpectrumGUI
-
-
-
- 0
- 0
- 375
- 60
-
-
-
-
- Sans Serif
- 8
-
-
-
- Oscilloscope
-
-
-
- 2
-
-
- 2
-
-
- 2
-
-
- 2
-
-
- 3
-
- -
-
-
- 3
-
-
-
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- Audio tone
-
-
- Histogram
-
-
-
- :/mono.png:/mono.png
-
-
-
- 16
- 16
-
-
-
- true
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
- Audio tone volume
-
-
- 240
-
-
- 1
-
-
-
- -
-
-
- 1.0
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
- CW speed (WPM)
-
-
- 0
-
-
- 20
-
-
- 1
-
-
-
- -
-
-
- CW speed display (WPM)
-
-
- 13
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- Morse key
-
-
- Max Hold
-
-
-
- :/morsekey.png:/morsekey.png
-
-
-
- 16
- 16
-
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
- Morse key assignment
-
-
-
-
- 0
-
-
- -
-
- 1
-
-
- -
-
- 2
-
-
- -
-
- 3
-
-
- -
-
- 4
-
-
- -
-
- 5
-
-
- -
-
- 6
-
-
- -
-
- 7
-
-
- -
-
- 8
-
-
- -
-
- 9
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- Iambic key
-
-
- Max Hold
-
-
-
- :/iambickey.png:/iambickey.png
-
-
-
- 16
- 16
-
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
- Iambic key dot assignment
-
-
-
-
- 0
-
-
- -
-
- 1
-
-
- -
-
- 2
-
-
- -
-
- 3
-
-
- -
-
- 4
-
-
- -
-
- 5
-
-
- -
-
- 6
-
-
- -
-
- 7
-
-
- -
-
- 8
-
-
- -
-
- 9
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 30
- 16777215
-
-
-
- Iambic key dash assignment
-
-
-
-
- 0
-
-
- -
-
- 1
-
-
- -
-
- 2
-
-
- -
-
- 3
-
-
- -
-
- 4
-
-
- -
-
- 5
-
-
- -
-
- 6
-
-
- -
-
- 7
-
-
- -
-
- 8
-
-
- -
-
- 9
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- Play text in a loop
-
-
- Inv
-
-
-
- :/playloop.png:/playloop.png
-
-
-
- 16
- 16
-
-
-
- true
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
- 24
- 24
-
-
-
- Play / pause text
-
-
- Waterfall
-
-
-
- :/play.png
- :/pause.png:/play.png
-
-
-
- 16
- 16
-
-
-
- true
-
-
- false
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
-
- -
-
-
-
-
-
- CW text
-
-
-
- -
-
-
-
- 24
- 24
-
-
-
-
- 24
- 24
-
-
-
- Clear CW text
-
-
-
-
-
-
- :/clear.png:/clear.png
-
-
-
- 16
- 16
-
-
-
-
-
-
-
-
-
-
- ButtonSwitch
- QToolButton
-
-
-
-
- morseKey
- playLoop
-
-
-
-
-
-
+
+
+ CWKeyerGUI
+
+
+
+ 0
+ 0
+ 375
+ 60
+
+
+
+
+ Sans Serif
+ 8
+
+
+
+ CW Keyer
+
+
+
+ 2
+
+
+ 3
+
+ -
+
+
+ 3
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 24
+ 24
+
+
+
+ Audio tone
+
+
+ Histogram
+
+
+
+ :/mono.png:/mono.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ Audio tone volume
+
+
+ 240
+
+
+ 1
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ 1.0
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+ CW speed (WPM)
+
+
+ 0
+
+
+ 20
+
+
+ 1
+
+
+
+ -
+
+
+
+ 9
+
+
+
+ CW speed display (WPM)
+
+
+ 13
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 24
+ 24
+
+
+
+ Morse key
+
+
+ Max Hold
+
+
+
+ :/morsekey.png:/morsekey.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 16777215
+
+
+
+
+ 9
+
+
+
+ Morse key assignment
+
+
-
+
+ 0
+
+
+ -
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 3
+
+
+ -
+
+ 4
+
+
+ -
+
+ 5
+
+
+ -
+
+ 6
+
+
+ -
+
+ 7
+
+
+ -
+
+ 8
+
+
+ -
+
+ 9
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 24
+ 24
+
+
+
+ Iambic key
+
+
+ Max Hold
+
+
+
+ :/iambickey.png:/iambickey.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 16777215
+
+
+
+
+ 9
+
+
+
+ Iambic key dot assignment
+
+
-
+
+ 0
+
+
+ -
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 3
+
+
+ -
+
+ 4
+
+
+ -
+
+ 5
+
+
+ -
+
+ 6
+
+
+ -
+
+ 7
+
+
+ -
+
+ 8
+
+
+ -
+
+ 9
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 16777215
+
+
+
+
+ 9
+
+
+
+ Iambic key dash assignment
+
+
-
+
+ 0
+
+
+ -
+
+ 1
+
+
+ -
+
+ 2
+
+
+ -
+
+ 3
+
+
+ -
+
+ 4
+
+
+ -
+
+ 5
+
+
+ -
+
+ 6
+
+
+ -
+
+ 7
+
+
+ -
+
+ 8
+
+
+ -
+
+ 9
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 24
+ 24
+
+
+
+ Play text in a loop
+
+
+ Inv
+
+
+
+ :/playloop.png:/playloop.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 24
+ 24
+
+
+
+ Play / pause text
+
+
+ Waterfall
+
+
+
+ :/play.png
+ :/pause.png:/play.png
+
+
+
+ 16
+ 16
+
+
+
+ true
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
-
+
+
+ CW text
+
+
+
+ -
+
+
+
+ 24
+ 24
+
+
+
+
+ 24
+ 24
+
+
+
+ Clear CW text
+
+
+
+
+
+
+ :/clear.png:/clear.png
+
+
+
+ 16
+ 16
+
+
+
+
+
+
+
+
+
+
+ ButtonSwitch
+ QToolButton
+
+
+
+
+ morseKey
+ playLoop
+
+
+
+
+
+