FlightGear next
morse.cxx
Go to the documentation of this file.
1// morse.cxx -- Morse code generation class
2//
3// Written by Curtis Olson, started March 2001.
4//
5// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20//
21
22
23#include <simgear/constants.h>
24
25#include "morse.hxx"
26
27#include <simgear/sound/sample.hxx>
28
29#include <cstdlib>
30#include <cstring>
31#include <utility>
32
33static const char DI = '1';
34static const char DIT = '1';
35static const char DA = '2';
36static const char DAH = '2';
37static const char END = '0';
38
39static const char alphabet[26][4] = {
40 { DI, DAH, END, END }, /* A */
41 { DA, DI, DI, DIT }, /* B */
42 { DA, DI, DA, DIT }, /* C */
43 { DA, DI, DIT, END }, /* D */
44 { DIT, END, END, END }, /* E */
45 { DI, DI, DA, DIT }, /* F */
46 { DA, DA, DIT, END }, /* G */
47 { DI, DI, DI, DIT }, /* H */
48 { DI, DIT, END, END }, /* I */
49 { DI, DA, DA, DAH }, /* J */
50 { DA, DI, DAH, END }, /* K */
51 { DI, DA, DI, DIT }, /* L */
52 { DA, DAH, END, END }, /* M */
53 { DA, DIT, END, END }, /* N */
54 { DA, DA, DAH, END }, /* O */
55 { DI, DA, DA, DIT }, /* P */
56 { DA, DA, DI, DAH }, /* Q */
57 { DI, DA, DIT, END }, /* R */
58 { DI, DI, DIT, END }, /* S */
59 { DAH, END, END, END }, /* T */
60 { DI, DI, DAH, END }, /* U */
61 { DI, DI, DI, DAH }, /* V */
62 { DI, DA, DAH, END }, /* W */
63 { DA, DI, DI, DAH }, /* X */
64 { DA, DI, DA, DAH }, /* Y */
65 { DA, DA, DI, DIT } /* Z */
66};
67
68static const char numerals[10][5] = {
69 { DA, DA, DA, DA, DAH }, // 0
70 { DI, DA, DA, DA, DAH }, // 1
71 { DI, DI, DA, DA, DAH }, // 2
72 { DI, DI, DI, DA, DAH }, // 3
73 { DI, DI, DI, DI, DAH }, // 4
74 { DI, DI, DI, DI, DIT }, // 5
75 { DA, DI, DI, DI, DIT }, // 6
76 { DA, DA, DI, DI, DIT }, // 7
77 { DA, DA, DA, DI, DIT }, // 8
78 { DA, DA, DA, DA, DIT } // 9
79};
80
81
82// constructor
85
86// destructor
89
90
91// allocate and initialize sound samples
92bool FGMorse::init() {
93 // Make Low DIT
96
97 // Make High DIT
100
101 // Make Low DAH
104
105 // Make High DAH
108
109 // Make SPACE
110 int i;
111 for ( i = 0; i < SPACE_SIZE; ++i ) {
112 space[ i ] = (unsigned char) ( 0.5 * 255 ) ;
113 }
114
115 return true;
116}
117
118
119// allocate and initialize sound samples
120bool FGMorse::cust_init(const int freq ) {
121 int i;
122
123 // Make DIT
124 make_tone( cust_dit, freq, DIT_SIZE - COUNT_SIZE, DIT_SIZE,
126
127 // Make DAH
128 make_tone( cust_dah, freq, DAH_SIZE - COUNT_SIZE, DAH_SIZE,
130
131 // Make SPACE
132 for ( i = 0; i < SPACE_SIZE; ++i ) {
133 space[ i ] = (unsigned char) ( 0.5 * 255 ) ;
134 }
135
136 return true;
137}
138
139
140// make a SGSoundSample morse code transmission for the specified string
141SGSoundSample *FGMorse::make_ident( const std::string& id, const int freq ) {
142
143 char *idptr = (char *)id.c_str();
144
145 int length = 0;
146 int i, j;
147
148 // 0. Select the frequency. If custom frequency, generate the
149 // sound fragments we need on the fly.
150 unsigned char *dit_ptr, *dah_ptr;
151
152 if ( freq == LO_FREQUENCY ) {
153 dit_ptr = lo_dit;
154 dah_ptr = lo_dah;
155 } else if ( freq == HI_FREQUENCY ) {
156 dit_ptr = hi_dit;
157 dah_ptr = hi_dah;
158 } else {
159 cust_init( freq );
160 dit_ptr = cust_dit;
161 dah_ptr = cust_dah;
162 }
163
164 // 1. Determine byte length of message
165 for ( i = 0; i < (int)id.length(); ++i ) {
166 if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
167 int c = (int)(idptr[i] - 'A');
168 for ( j = 0; j < 4 && alphabet[c][j] != END; ++j ) {
169 if ( alphabet[c][j] == DIT ) {
170 length += DIT_SIZE;
171 } else if ( alphabet[c][j] == DAH ) {
172 length += DAH_SIZE;
173 }
174 }
175 length += SPACE_SIZE;
176 } else if ( idptr[i] >= '0' && idptr[i] <= '9' ) {
177 int c = (int)(idptr[i] - '0');
178 for ( j = 0; j < 5; ++j) {
179 if ( numerals[c][j] == DIT ) {
180 length += DIT_SIZE;
181 } else if ( numerals[c][j] == DAH ) {
182 length += DAH_SIZE;
183 }
184 }
185 length += SPACE_SIZE;
186 } else {
187 // skip unknown character
188 }
189 }
190 // add 2x more space to the end of the string
191 length += 2 * SPACE_SIZE;
192
193 // 2. Allocate space for the message
194 auto buffer = std::unique_ptr<unsigned char, decltype(free)*>{
195 reinterpret_cast<unsigned char*>( malloc( length ) ),
196 free
197 };
198
199 // 3. Assemble the message;
200 unsigned char *buf_ptr = buffer.get();
201
202 for ( i = 0; i < (int)id.length(); ++i ) {
203 if ( idptr[i] >= 'A' && idptr[i] <= 'Z' ) {
204 int c = (int)(idptr[i] - 'A');
205 for ( j = 0; j < 4 && alphabet[c][j] != END; ++j ) {
206 if ( alphabet[c][j] == DIT ) {
207 memcpy( buf_ptr, dit_ptr, DIT_SIZE );
208 buf_ptr += DIT_SIZE;
209 } else if ( alphabet[c][j] == DAH ) {
210 memcpy( buf_ptr, dah_ptr, DAH_SIZE );
211 buf_ptr += DAH_SIZE;
212 }
213 }
214 memcpy( buf_ptr, space, SPACE_SIZE );
215 buf_ptr += SPACE_SIZE;
216 } else if ( idptr[i] >= '0' && idptr[i] <= '9' ) {
217 int c = (int)(idptr[i] - '0');
218 for ( j = 0; j < 5; ++j ) {
219 if ( numerals[c][j] == DIT ) {
220 memcpy( buf_ptr, dit_ptr, DIT_SIZE );
221 buf_ptr += DIT_SIZE;
222 } else if ( numerals[c][j] == DAH ) {
223 memcpy( buf_ptr, dah_ptr, DAH_SIZE );
224 buf_ptr += DAH_SIZE;
225 }
226 }
227 memcpy( buf_ptr, space, SPACE_SIZE );
228 buf_ptr += SPACE_SIZE;
229 } else {
230 // skip unknown character
231 }
232 }
233 memcpy( buf_ptr, space, SPACE_SIZE );
234 buf_ptr += SPACE_SIZE;
235 memcpy( buf_ptr, space, SPACE_SIZE );
236 buf_ptr += SPACE_SIZE;
237
238 // 4. create the simple sound and return
239 SGSoundSample *sample = new SGSoundSample( std::move(buffer), length,
241
242 sample->set_reference_dist( 10.0 );
243 sample->set_max_dist( 20.0 );
244
245 return sample;
246}
247
248FGMorse * FGMorse::_instance = NULL;
249
251{
252 if( _instance == NULL ) {
253 _instance = new FGMorse();
254 _instance->init();
255 }
256 return _instance;
257}
#define i(x)
static const int LO_FREQUENCY
Definition morse.hxx:107
SGSoundSample * make_ident(const std::string &id, const int freq=LO_FREQUENCY)
Definition morse.cxx:141
~FGMorse()
Definition morse.cxx:87
static const int BYTES_PER_SECOND
Definition morse.hxx:99
static const int SPACE_SIZE
Definition morse.hxx:106
static const int COUNT_SIZE
Definition morse.hxx:103
static const int DAH_SIZE
Definition morse.hxx:105
static const int TRANSITION_BYTES
Definition morse.hxx:102
static const int DIT_SIZE
Definition morse.hxx:104
static const int HI_FREQUENCY
Definition morse.hxx:108
static FGMorse * instance()
Definition morse.cxx:250
FGMorse()
Definition morse.cxx:83
static void make_tone(unsigned char *buf, int freq, int len, int total_len, int trans_len)
Make a tone of specified freq and total_len with trans_len ramp in and out and only the first len byt...
static const char DA
Definition morse.cxx:35
static const char END
Definition morse.cxx:37
static const char numerals[10][5]
Definition morse.cxx:68
static const char alphabet[26][4]
Definition morse.cxx:39
static const char DIT
Definition morse.cxx:34
static const char DI
Definition morse.cxx:33
static const char DAH
Definition morse.cxx:36