1 /*
2 Copyright (C) 2001-2006 Simon Baldwin (simon_baldwin@yahoo.com)
3 Copyright (C) 2011-2017 Kamil Ignacak (acerion@wp.pl)
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 /**
22 \file libcw_gen.c
23
24 \brief Generate pcm samples according to tones from tone queue, and
25 send them to audio sink.
26
27 Functions operating on one of core elements of libcw: a generator.
28
29 Generator is an object that has access to audio sink (soundcard,
30 console buzzer, null audio device) and that can play dots and
31 dashes using the audio sink.
32
33 You can request generator to produce audio by using *_play_*()
34 functions.
35
36 The inner workings of the generator seem to be quite simple:
37 1. dequeue tone from tone queue
38 2. recalculate tone length in usecs into length in samples
39 3. for every sample in tone, calculate sine wave sample and
40 put it in generator's constant size buffer
41 4. if buffer is full of sine wave samples, push it to audio sink
42 5. since buffer is shorter than (almost) any tone, you will
43 recalculate contents of the buffer and push it to audio sink
44 multiple times per tone
45 6. if you iterated over all samples in tone, but you still didn't
46 fill up that last buffer, go to step #1
47 7. if there are no more tones in queue, pad the buffer with silence,
48 and push the buffer to audio sink.
49
50 Looks simple, right? But it's the little details that ruin it all.
51 One of the details is tone's slopes.
52 */
53
54
55
56
57
58 #include "config.h"
59
60 #include <stdlib.h>
61 #include <unistd.h>
62 #include <stdbool.h>
63 #include <math.h>
64 #include <signal.h>
65 #include <errno.h>
66 #include <inttypes.h> /* uint32_t */
67
68 #if defined(HAVE_STRING_H)
69 # include <string.h>
70 #endif
71
72 #if defined(HAVE_STRINGS_H)
73 # include <strings.h>
74 #endif
75
76
77
78
79
80 #include "libcw_gen.h"
81 #include "libcw_debug.h"
82 #include "libcw_utils.h"
83 #include "libcw_signal.h"
84 #include "libcw_data.h"
85
86 #include "libcw_null.h"
87 #include "libcw_console.h"
88 #include "libcw_oss.h"
89
90
91
92
93
94 #ifndef M_PI /* C99 may not define M_PI */
95 #define M_PI 3.14159265358979323846
96 #endif
97
98
99
100
101
102 /* From libcw_debug.c. */
103 extern cw_debug_t cw_debug_object;
104 extern cw_debug_t cw_debug_object_ev;
105 extern cw_debug_t cw_debug_object_dev;
106
107
108
109
110
111 /* Most of audio systems (excluding console) should be configured to
112 have specific sample rate. Some audio systems (with connection with
113 given hardware) can support several different sample rates. Values of
114 supported sample rates are standardized. Here is a list of them to be
115 used by this library.
116 When the library configures given audio system, it tries if the system
117 will accept a sample rate from the table, starting from the first one.
118 If a sample rate is accepted, rest of sample rates is not tested anymore. */
119 const unsigned int cw_supported_sample_rates[] = {
120 44100,
121 48000,
122 32000,
123 22050,
124 16000,
125 11025,
126 8000,
127 0 /* guard */
128 };
129
130
131
132
133
134 /* Every audio system opens an audio device: a default device, or some
135 other device. Default devices have their default names, and here is
136 a list of them. It is indexed by values of "enum cw_audio_systems". */
137 static const char *default_audio_devices[] = {
138 (char *) NULL, /* CW_AUDIO_NONE */
139 CW_DEFAULT_NULL_DEVICE, /* CW_AUDIO_NULL */
140 CW_DEFAULT_CONSOLE_DEVICE,
141 CW_DEFAULT_OSS_DEVICE,
142 CW_DEFAULT_ALSA_DEVICE,
143 CW_DEFAULT_PA_DEVICE,
144 (char *) NULL }; /* just in case someone decided to index the table with CW_AUDIO_SOUNDCARD */
145
146
147
148
149
150 /* Generic constants - common for all audio systems (or not used in some of systems). */
151
152 static const long int CW_AUDIO_VOLUME_RANGE = (1 << 15); /* 2^15 = 32768 */
153 static const int CW_AUDIO_SLOPE_LEN = 5000; /* Length of a single slope (rising or falling) in standard tone. [us] */
154
155 /* Shortest length of time (in microseconds) that is used by libcw for
156 idle waiting and idle loops. If a libcw function needs to wait for
157 something, or make an idle loop, it should call
158 usleep(N * gen->quantum_len)
159
160 This is also length of a single "forever" tone. */
161 static const int CW_AUDIO_QUANTUM_LEN_INITIAL = 100; /* [us] */
162
163
164
165
166
167 static int cw_gen_new_open_internal(cw_gen_t *gen, int audio_system, const char *device);
168 static void *cw_gen_dequeue_and_play_internal(void *arg);
169 static int cw_gen_calculate_sine_wave_internal(cw_gen_t *gen, cw_tone_t *tone);
170 static int cw_gen_calculate_amplitude_internal(cw_gen_t *gen, cw_tone_t *tone);
171 static int cw_gen_write_to_soundcard_internal(cw_gen_t *gen, cw_tone_t *tone, int queue_rv);
172 static int cw_gen_play_valid_character_internal(cw_gen_t *gen, char character, int partial);
173 static void cw_gen_recalculate_slopes_internal(cw_gen_t *gen);
174
175
176
177
178
179 /**
180 \brief Get a copy of readable label of current audio system
181
182 Get a copy of human-readable string describing audio system
183 associated currently with given \p gen.
184
185 The function returns newly allocated pointer to one of following
186 strings: "None", "Null", "Console", "OSS", "ALSA", "PulseAudio",
187 "Soundcard".
188
189 The returned pointer is owned by caller.
190
191 Notice that the function returns a new pointer to newly allocated
192 string. cw_generator_get_audio_system_label() returns a pointer to
193 static string owned by library.
194
195 \param gen - generator for which to check audio system label
196
197 \return audio system's label
198 */
cw_gen_get_audio_system_label_internal(cw_gen_t * gen)199 char *cw_gen_get_audio_system_label_internal(cw_gen_t *gen)
200 {
201 char *s = strdup(cw_get_audio_system_label(gen->audio_system));
202 if (!s) {
203 cw_vdm ("failed to strdup() audio system label for audio system %d\n", gen->audio_system);
204 }
205
206 return s;
207 }
208
209
210
211
212
213 /**
214 \brief Start a generator
215 */
cw_gen_start_internal(cw_gen_t * gen)216 int cw_gen_start_internal(cw_gen_t *gen)
217 {
218 gen->phase_offset = 0.0;
219
220 /* This should be set to true before launching
221 cw_gen_dequeue_and_play_internal(), because loop in the
222 function run only when the flag is set. */
223 gen->do_dequeue_and_play = true;
224
225 gen->client.thread_id = pthread_self();
226
227 if (gen->audio_system == CW_AUDIO_NULL
228 || gen->audio_system == CW_AUDIO_CONSOLE
229 || gen->audio_system == CW_AUDIO_OSS
230 || gen->audio_system == CW_AUDIO_ALSA
231 || gen->audio_system == CW_AUDIO_PA) {
232
233 /* cw_gen_dequeue_and_play_internal() is THE
234 function that does the main job of generating
235 tones. */
236 int rv = pthread_create(&gen->thread.id, &gen->thread.attr,
237 cw_gen_dequeue_and_play_internal,
238 (void *) gen);
239 if (rv != 0) {
240 gen->do_dequeue_and_play = false;
241
242 cw_debug_msg ((&cw_debug_object), CW_DEBUG_STDLIB, CW_DEBUG_ERROR,
243 "libcw: failed to create %s generator thread", cw_get_audio_system_label(gen->audio_system));
244 return CW_FAILURE;
245 } else {
246 gen->thread.running = true;
247
248 /* For some yet unknown reason you have to put
249 usleep() here, otherwise a generator may
250 work incorrectly */
251 usleep(100000);
252 #ifdef LIBCW_WITH_DEV
253 cw_dev_debug_print_generator_setup(gen);
254 #endif
255 return CW_SUCCESS;
256 }
257 } else {
258 gen->do_dequeue_and_play = false;
259
260 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_SOUND_SYSTEM, CW_DEBUG_ERROR,
261 "libcw: unsupported audio system %d", gen->audio_system);
262 return CW_FAILURE;
263 }
264 }
265
266
267
268
269
270 /**
271 \brief Set audio device name or path
272
273 Set path to audio device, or name of audio device. The path/name
274 will be associated with given generator \p gen, and used when opening
275 audio device.
276
277 Use this function only when setting up a generator.
278
279 Function creates its own copy of input string.
280
281 \param gen - generator to be updated
282 \param device - device to be assigned to generator \p gen
283
284 \return CW_SUCCESS on success
285 \return CW_FAILURE on errors
286 */
cw_gen_set_audio_device_internal(cw_gen_t * gen,const char * device)287 int cw_gen_set_audio_device_internal(cw_gen_t *gen, const char *device)
288 {
289 /* this should be NULL, either because it has been
290 initialized statically as NULL, or set to
291 NULL by generator destructor */
292 assert (!gen->audio_device);
293 assert (gen->audio_system != CW_AUDIO_NONE);
294
295 if (gen->audio_system == CW_AUDIO_NONE) {
296 gen->audio_device = (char *) NULL;
297 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_SOUND_SYSTEM, CW_DEBUG_ERROR,
298 "libcw: no audio system specified");
299 return CW_FAILURE;
300 }
301
302 if (device) {
303 gen->audio_device = strdup(device);
304 } else {
305 gen->audio_device = strdup(default_audio_devices[gen->audio_system]);
306 }
307
308 if (!gen->audio_device) {
309 cw_debug_msg ((&cw_debug_object), CW_DEBUG_STDLIB, CW_DEBUG_ERROR,
310 "libcw: malloc()");
311 return CW_FAILURE;
312 } else {
313 return CW_SUCCESS;
314 }
315 }
316
317
318
319
320
321 /**
322 \brief Silence the generator
323
324 Force an audio sink currently used by generator \p gen to go
325 silent.
326
327 The function does not clear/flush tone queue, nor does it stop the
328 generator. It just makes sure that audio sink (console / OSS / ALSA
329 / PulseAudio) does not produce a sound of any frequency and any
330 volume.
331
332 You probably want to call cw_tq_flush_internal(gen->tq) before
333 calling this function.
334
335 \param gen - generator using an audio sink that should be silenced
336
337 \return CW_SUCCESS on success
338 \return CW_FAILURE on failure to silence an audio sink
339 */
cw_gen_silence_internal(cw_gen_t * gen)340 int cw_gen_silence_internal(cw_gen_t *gen)
341 {
342 if (!gen) {
343 /* this may happen because the process of finalizing
344 usage of libcw is rather complicated; this should
345 be somehow resolved */
346 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_WARNING,
347 "libcw: called the function for NULL generator");
348 return CW_SUCCESS;
349 }
350
351 if (!(gen->thread.running)) {
352 /* Silencing a generator means enqueueing and playing
353 a tone with zero frequency. We shouldn't do this
354 when a "dequeue-and-play-a-tone" function is not
355 running (anymore). This is not an error situation,
356 so return CW_SUCCESS. */
357 return CW_SUCCESS;
358 }
359
360 /* Somewhere there may be a key in "down" state and we need to
361 make it go "up", regardless of audio sink (even for
362 CDW_AUDIO_NULL!). Otherwise the key may stay in "down"
363 state forever. */
364 cw_tone_t tone;
365 CW_TONE_INIT(&tone, 0, gen->quantum_len, CW_SLOPE_MODE_NO_SLOPES);
366 int status = cw_tq_enqueue_internal(gen->tq, &tone);
367
368 if (gen->audio_system == CW_AUDIO_NULL
369 || gen->audio_system == CW_AUDIO_OSS
370 || gen->audio_system == CW_AUDIO_ALSA
371 || gen->audio_system == CW_AUDIO_PA) {
372
373 /* Allow some time for playing the last tone. */
374 usleep(2 * gen->quantum_len);
375
376 } else if (gen->audio_system == CW_AUDIO_CONSOLE) {
377 /* sine wave generation should have been stopped
378 by a code generating dots/dashes, but
379 just in case...
380
381 TODO: is it still necessary after adding the
382 quantum of silence above? */
383 cw_console_silence(gen);
384 } else {
385 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR,
386 "libcw: called silence() function for generator without audio system specified");
387 }
388
389 if (gen->audio_system == CW_AUDIO_ALSA) {
390 /* "Stop a PCM dropping pending frames. " */
391 cw_alsa_drop(gen);
392 }
393
394 //gen->do_dequeue_and_play = false;
395
396 return status;
397 }
398
399
400
401
402
403 /**
404 \brief Create new generator
405
406 testedin::test_cw_gen_new_delete_internal()
407 */
cw_gen_new_internal(int audio_system,const char * device)408 cw_gen_t *cw_gen_new_internal(int audio_system, const char *device)
409 {
410 #ifdef LIBCW_WITH_DEV
411 fprintf(stderr, "libcw build %s %s\n", __DATE__, __TIME__);
412 #endif
413
414 cw_assert (audio_system != CW_AUDIO_NONE, "can't create generator with audio system \"NONE\"");
415
416 cw_gen_t *gen = (cw_gen_t *) malloc(sizeof (cw_gen_t));
417 if (!gen) {
418 cw_debug_msg ((&cw_debug_object), CW_DEBUG_STDLIB, CW_DEBUG_ERROR,
419 "libcw: malloc()");
420 return (cw_gen_t *) NULL;
421 }
422
423 gen->tq = cw_tq_new_internal();
424 if (!gen->tq) {
425 cw_gen_delete_internal(&gen);
426 return (cw_gen_t *) NULL;
427 } else {
428 /* Because libcw_tq.c/cw_tq_enqueue_internal()/pthread_kill(tq->gen->thread.id, SIGALRM); */
429 gen->tq->gen = gen;
430 }
431
432 gen->audio_device = NULL;
433 //gen->audio_system = audio_system;
434 gen->audio_device_is_open = false;
435 gen->dev_raw_sink = -1;
436
437
438 /* Essential sending parameters. */
439 gen->send_speed = CW_SPEED_INITIAL,
440 gen->frequency = CW_FREQUENCY_INITIAL;
441 gen->volume_percent = CW_VOLUME_INITIAL;
442 gen->volume_abs = (gen->volume_percent * CW_AUDIO_VOLUME_RANGE) / 100;
443 gen->gap = CW_GAP_INITIAL;
444 gen->weighting = CW_WEIGHTING_INITIAL;
445
446
447 gen->parameters_in_sync = false;
448
449
450 gen->do_dequeue_and_play = false;
451
452
453 gen->buffer = NULL;
454 gen->buffer_n_samples = -1;
455
456 gen->oss_version.x = -1;
457 gen->oss_version.y = -1;
458 gen->oss_version.z = -1;
459
460
461 gen->client.name = (char *) NULL;
462
463 gen->tone_slope.len = CW_AUDIO_SLOPE_LEN;
464 gen->tone_slope.shape = CW_TONE_SLOPE_SHAPE_RAISED_COSINE;
465 gen->tone_slope.amplitudes = NULL;
466 gen->tone_slope.n_amplitudes = 0;
467
468 #ifdef LIBCW_WITH_PULSEAUDIO
469 gen->pa_data.s = NULL;
470
471 gen->pa_data.ba.prebuf = (uint32_t) -1;
472 gen->pa_data.ba.tlength = (uint32_t) -1;
473 gen->pa_data.ba.minreq = (uint32_t) -1;
474 gen->pa_data.ba.maxlength = (uint32_t) -1;
475 gen->pa_data.ba.fragsize = (uint32_t) -1;
476 #endif
477
478 gen->open_device = NULL;
479 gen->close_device = NULL;
480 gen->write = NULL;
481
482 pthread_attr_init(&gen->thread.attr);
483 /* Thread must be joinable in order to make a safe call to
484 pthread_kill(thread_id, 0). pthreads are joinable by
485 default, but I take this explicit call as a good
486 opportunity to make this comment. */
487 pthread_attr_setdetachstate(&gen->thread.attr, PTHREAD_CREATE_JOINABLE);
488 gen->thread.running = false;
489
490
491 gen->dot_len = 0;
492 gen->dash_len = 0;
493 gen->eom_space_len = 0;
494 gen->eoc_space_len = 0;
495 gen->eow_space_len = 0;
496
497 gen->additional_space_len = 0;
498 gen->adjustment_space_len = 0;
499
500
501 gen->quantum_len = CW_AUDIO_QUANTUM_LEN_INITIAL;
502
503
504 gen->buffer_sub_start = 0;
505 gen->buffer_sub_stop = 0;
506
507
508 gen->key = (cw_key_t *) NULL;
509
510
511 int rv = cw_gen_new_open_internal(gen, audio_system, device);
512 if (rv == CW_FAILURE) {
513 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_SOUND_SYSTEM, CW_DEBUG_ERROR,
514 "libcw: failed to open audio device for audio system '%s' and device '%s'", cw_get_audio_system_label(audio_system), device);
515 cw_gen_delete_internal(&gen);
516 return (cw_gen_t *) NULL;
517 }
518
519 if (audio_system == CW_AUDIO_NULL
520 || audio_system == CW_AUDIO_CONSOLE) {
521
522 ; /* the two types of audio output don't require audio buffer */
523 } else {
524 gen->buffer = (cw_sample_t *) malloc(gen->buffer_n_samples * sizeof (cw_sample_t));
525 if (!gen->buffer) {
526 cw_debug_msg ((&cw_debug_object), CW_DEBUG_STDLIB, CW_DEBUG_ERROR,
527 "libcw: malloc()");
528 cw_gen_delete_internal(&gen);
529 return (cw_gen_t *) NULL;
530 }
531 }
532
533 /* Set slope that late, because it uses value of sample rate.
534 The sample rate value is set in
535 cw_gen_new_open_internal(). */
536 rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_RAISED_COSINE, CW_AUDIO_SLOPE_LEN);
537 if (rv == CW_FAILURE) {
538 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR,
539 "libcw: failed to set slope");
540 cw_gen_delete_internal(&gen);
541 return (cw_gen_t *) NULL;
542 }
543
544 cw_sigalrm_install_top_level_handler_internal();
545
546 return gen;
547 }
548
549
550
551
552
553 /**
554 \brief Delete a generator
555
556 testedin::test_cw_gen_new_delete_internal()
557 */
cw_gen_delete_internal(cw_gen_t ** gen)558 void cw_gen_delete_internal(cw_gen_t **gen)
559 {
560 cw_assert (gen, "generator is NULL");
561
562 if (!*gen) {
563 return;
564 }
565
566 if ((*gen)->do_dequeue_and_play) {
567 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG,
568 "libcw: you forgot to call cw_generator_stop()");
569 cw_gen_stop_internal(*gen);
570 }
571
572 /* Wait for "write" thread to end accessing output
573 file descriptor. I have come up with value 500
574 after doing some experiments.
575
576 FIXME: magic number. I think that we can come up
577 with algorithm for calculating the value. */
578 usleep(500);
579
580 free((*gen)->audio_device);
581 (*gen)->audio_device = NULL;
582
583 free((*gen)->buffer);
584 (*gen)->buffer = NULL;
585
586 if ((*gen)->close_device) {
587 (*gen)->close_device(*gen);
588 } else {
589 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG, "libcw: WARNING: NULL function pointer, something went wrong");
590 }
591
592 pthread_attr_destroy(&((*gen)->thread.attr));
593
594 free((*gen)->client.name);
595 (*gen)->client.name = NULL;
596
597 free((*gen)->tone_slope.amplitudes);
598 (*gen)->tone_slope.amplitudes = NULL;
599
600 cw_tq_delete_internal(&((*gen)->tq));
601
602 (*gen)->audio_system = CW_AUDIO_NONE;
603
604 free(*gen);
605 *gen = NULL;
606
607 return;
608 }
609
610
611
612
613
614 /**
615 \brief Stop a generator
616
617 Empty generator's tone queue.
618 Silence generator's audio sink.
619 Stop generator' "dequeue and play" thread function.
620 If the thread does not stop in one second, kill it.
621
622 You have to use cw_gen_start_internal() if you want to enqueue and
623 play tones with the same generator again.
624
625 It seems that only silencing of generator's audio sink may fail,
626 and this is when this function may return CW_FAILURE. Otherwise
627 function returns CW_SUCCESS.
628
629 \return CW_SUCCESS if all four actions completed (successfully)
630 \return CW_FAILURE if any of the four actions failed (see note above)
631 */
cw_gen_stop_internal(cw_gen_t * gen)632 int cw_gen_stop_internal(cw_gen_t *gen)
633 {
634 if (!gen) {
635 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_WARNING,
636 "libcw: called the function for NULL generator");
637 /* Not really a runtime error, so return
638 CW_SUCCESS. */
639 return CW_SUCCESS;
640 }
641
642 cw_tq_flush_internal(gen->tq);
643
644 int rv = cw_gen_silence_internal(gen);
645 if (rv != CW_SUCCESS) {
646 return CW_FAILURE;
647 }
648
649 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_INFO,
650 "libcw/gen: gen->do_dequeue_and_play = false");
651 gen->do_dequeue_and_play = false;
652
653 if (!gen->thread.running) {
654 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_INFO, "libcw: EXIT: seems that thread function was not started at all");
655
656 /* Don't call pthread_kill() on non-initialized
657 thread.id. The generator wasn't even started, so
658 let's return CW_SUCCESS. */
659 return CW_SUCCESS;
660 }
661
662 /* "while (gen->do_dequeue_and_play)" loop in thread function
663 may be in a state where dequeue() function returned IDLE
664 state, and the loop is waiting for new tone.
665
666 This is to wake up cw_signal_wait_internal() function that
667 may be waiting idle for signal in "while ()" loop in thread
668 function. */
669 pthread_kill(gen->thread.id, SIGALRM);
670
671 /* This piece of comment was put before code using
672 pthread_kill(), and may apply only to that version. But it
673 may turn out that it will be valid for code using
674 pthread_join() as well, so I'm keeping it for now.
675
676 "
677 Sleep a bit to postpone closing a device. This way we can
678 avoid a situation when "do_dequeue_and_play" is set to false
679 and device is being closed while a new buffer is being
680 prepared, and while write() tries to write this new buffer
681 to already closed device.
682
683 Without this sleep(), writei() from ALSA library may
684 return "File descriptor in bad state" error - this
685 happened when writei() tried to write to closed ALSA
686 handle.
687
688 The delay also allows the generator function thread to stop
689 generating tone (or for tone queue to get out of CW_TQ_IDLE
690 state) and exit before we resort to killing generator
691 function thread.
692 "
693 */
694
695
696 #if 0 /* Old code using pthread_kill() instead of pthread_join().
697 This code is unused since before 2015-08-30. */
698
699 struct timespec req = { .tv_sec = 1, .tv_nsec = 0 };
700 cw_nanosleep_internal(&req);
701
702 /* Check if generator thread is still there. Remember that
703 pthread_kill(id, 0) is unsafe for detached threads: if thread
704 has finished, the ID may be reused, and may be invalid at
705 this point. */
706 rv = pthread_kill(gen->thread.id, 0);
707 if (rv == 0) {
708 /* thread function didn't return yet; let's help it a bit */
709 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_WARNING, "libcw: EXIT: forcing exit of thread function");
710 rv = pthread_kill(gen->thread.id, SIGKILL);
711 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_WARNING, "libcw: EXIT: pthread_kill() returns %d/%s", rv, strerror(rv));
712 } else {
713 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_INFO, "libcw: EXIT: seems that thread function exited voluntarily");
714 }
715
716 gen->thread.running = false;
717 return CW_SUCCESS;
718 #else
719
720
721
722 #define CW_DEBUG_TIMING_JOIN 1
723
724 #if CW_DEBUG_TIMING_JOIN /* Debug code to measure how long it takes to join threads. */
725 struct timeval before, after;
726 gettimeofday(&before, NULL);
727 #endif
728
729
730
731 rv = pthread_join(gen->thread.id, NULL);
732
733
734
735 #if CW_DEBUG_TIMING_JOIN /* Debug code to measure how long it takes to join threads. */
736 gettimeofday(&after, NULL);
737 cw_debug_msg ((&cw_debug_object), CW_DEBUG_GENERATOR, CW_DEBUG_INFO, "libcw/gen: joining thread took %d us", cw_timestamp_compare_internal(&before, &after));
738 #endif
739
740
741
742 if (rv == 0) {
743 gen->thread.running = false;
744 return CW_SUCCESS;
745 } else {
746 cw_debug_msg ((&cw_debug_object), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR, "libcw/gen: failed to join threads: \"%s\"", strerror(rv));
747 return CW_FAILURE;
748 }
749 #endif
750 }
751
752
753
754
755
756 /**
757 \brief Open audio system
758
759 A wrapper for code trying to open audio device specified by
760 \p audio_system. Open audio system will be assigned to given
761 generator. Caller can also specify audio device to use instead
762 of a default one.
763
764 \param gen - freshly created generator
765 \param audio_system - audio system to open and assign to the generator
766 \param device - name of audio device to be used instead of a default one
767
768 \return CW_SUCCESS on success
769 \return CW_FAILURE otherwise
770 */
cw_gen_new_open_internal(cw_gen_t * gen,int audio_system,const char * device)771 int cw_gen_new_open_internal(cw_gen_t *gen, int audio_system, const char *device)
772 {
773 /* FIXME: this functionality is partially duplicated in
774 src/cwutils/cw_common.c/cw_generator_new_from_config() */
775
776 /* This function deliberately checks all possible values of
777 audio system name in separate 'if' clauses before it gives
778 up and returns CW_FAILURE. PA/OSS/ALSA are combined with
779 SOUNDCARD, so I have to check all three of them (because \p
780 audio_system may be set to SOUNDCARD). And since I check
781 the three in separate 'if' clauses, I can check all other
782 values of audio system as well. */
783
784 if (audio_system == CW_AUDIO_NULL) {
785
786 const char *dev = device ? device : default_audio_devices[CW_AUDIO_NULL];
787 if (cw_is_null_possible(dev)) {
788 cw_null_configure(gen, dev);
789 return gen->open_device(gen);
790 }
791 }
792
793 if (audio_system == CW_AUDIO_PA
794 || audio_system == CW_AUDIO_SOUNDCARD) {
795
796 const char *dev = device ? device : default_audio_devices[CW_AUDIO_PA];
797 if (cw_is_pa_possible(dev)) {
798 cw_pa_configure(gen, dev);
799 return gen->open_device(gen);
800 }
801 }
802
803 if (audio_system == CW_AUDIO_OSS
804 || audio_system == CW_AUDIO_SOUNDCARD) {
805
806 const char *dev = device ? device : default_audio_devices[CW_AUDIO_OSS];
807 if (cw_is_oss_possible(dev)) {
808 cw_oss_configure(gen, dev);
809 return gen->open_device(gen);
810 }
811 }
812
813 if (audio_system == CW_AUDIO_ALSA
814 || audio_system == CW_AUDIO_SOUNDCARD) {
815
816 const char *dev = device ? device : default_audio_devices[CW_AUDIO_ALSA];
817 if (cw_is_alsa_possible(dev)) {
818 cw_alsa_configure(gen, dev);
819 return gen->open_device(gen);
820 }
821 }
822
823 if (audio_system == CW_AUDIO_CONSOLE) {
824
825 const char *dev = device ? device : default_audio_devices[CW_AUDIO_CONSOLE];
826 if (cw_is_console_possible(dev)) {
827 cw_console_configure(gen, dev);
828 return gen->open_device(gen);
829 }
830 }
831
832 /* there is no next audio system type to try */
833 return CW_FAILURE;
834 }
835
836
837
838
839
840 /**
841 \brief Dequeue tones and push them to audio output
842
843 Function dequeues tones from tone queue associated with generator
844 and then sends them to preconfigured audio output (soundcard, NULL
845 or console).
846
847 Function dequeues tones (or waits for new tones in queue) and
848 pushes them to audio output as long as
849 generator->do_dequeue_and_play is true.
850
851 The generator must be fully configured before calling this
852 function.
853
854 \param arg - generator (casted to (void *)) to be used for generating tones
855
856 \return NULL pointer
857 */
cw_gen_dequeue_and_play_internal(void * arg)858 void *cw_gen_dequeue_and_play_internal(void *arg)
859 {
860 cw_gen_t *gen = (cw_gen_t *) arg;
861
862 cw_tone_t tone;
863 CW_TONE_INIT(&tone, 0, 0, CW_SLOPE_MODE_STANDARD_SLOPES);
864
865 while (gen->do_dequeue_and_play) {
866 int tq_rv = cw_tq_dequeue_internal(gen->tq, &tone);
867 if (tq_rv == CW_TQ_NDEQUEUED_IDLE) {
868
869 /* Tone queue has been totally drained with
870 previous call to dequeue(). No point in
871 making next iteration of while() and
872 calling the function again. So don't call
873 it, wait for signal from enqueue() function
874 informing that a new tone appeared in tone
875 queue. */
876
877 /* A SIGALRM signal may also come from
878 cw_gen_stop_internal() that gently asks
879 this function to stop idling and nicely
880 return. */
881
882 /* TODO: can we / should we specify on which
883 signal exactly we are waiting for? */
884 cw_signal_wait_internal();
885 continue;
886 }
887
888
889 cw_key_ik_increment_timer_internal(gen->key, tone.len);
890
891 #ifdef LIBCW_WITH_DEV
892 cw_debug_ev ((&cw_debug_object_ev), 0, tone.frequency ? CW_DEBUG_EVENT_TONE_HIGH : CW_DEBUG_EVENT_TONE_LOW);
893 #endif
894
895 if (gen->audio_system == CW_AUDIO_NULL) {
896 cw_null_write(gen, &tone);
897 } else if (gen->audio_system == CW_AUDIO_CONSOLE) {
898 cw_console_write(gen, &tone);
899 } else {
900 cw_gen_write_to_soundcard_internal(gen, &tone, tq_rv);
901 }
902
903 /*
904 When sending text from text input, the signal:
905 - allows client code to observe moment when state of tone
906 queue is "low/critical"; client code then can add more
907 characters to the queue; the observation is done using
908 cw_wait_for_tone_queue_critical();
909
910 - allows client code to observe any dequeue event
911 by waiting for signal in cw_wait_for_tone() /
912 cw_tq_wait_for_tone_internal()
913 */
914 pthread_kill(gen->client.thread_id, SIGALRM);
915
916 /* Generator may be used by iambic keyer to measure
917 periods of time (lengths of Mark and Space) - this
918 is achieved by enqueueing Marks and Spaces by keyer
919 in generator.
920
921 At this point the generator has finished generating
922 a tone of specified length. A duration of Mark or
923 Space has elapsed. Inform iambic keyer that the
924 tone it has enqueued has elapsed.
925
926 (Whether iambic keyer has enqueued any tones or
927 not, and whether it is waiting for the
928 notification, is a different story. We will let the
929 iambic keyer function called below to decide what
930 to do with the notification. If keyer is in idle
931 graph state, it will ignore the notification.)
932
933 Notice that this mechanism is needed only for
934 iambic keyer. Inner workings of straight key are
935 much more simple, the straight key doesn't need to
936 use generator as a timer. */
937 if (!cw_key_ik_update_graph_state_internal(gen->key)) {
938 /* just try again, once */
939 usleep(1000);
940 cw_key_ik_update_graph_state_internal(gen->key);
941 }
942
943 #ifdef LIBCW_WITH_DEV
944 cw_debug_ev ((&cw_debug_object_ev), 0, tone.frequency ? CW_DEBUG_EVENT_TONE_LOW : CW_DEBUG_EVENT_TONE_HIGH);
945 #endif
946
947 } /* while (gen->do_dequeue_and_play) */
948
949 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_INFO,
950 "libcw: EXIT: generator stopped (gen->do_dequeue_and_play = %d)", gen->do_dequeue_and_play);
951
952 /* Some functions in client thread may be waiting for the last
953 SIGALRM from the generator thread to continue/finalize their
954 business. Let's send the SIGALRM right before exiting. */
955
956 /* This small delay before sending signal turns out to be helpful.
957
958 TODO: this is one of most mysterious comments in this code
959 base. What was I thinking? */
960 struct timespec req = { .tv_sec = 0, .tv_nsec = CW_NSECS_PER_SEC / 2 };
961 cw_nanosleep_internal(&req);
962
963 pthread_kill(gen->client.thread_id, SIGALRM);
964 gen->thread.running = false;
965 return NULL;
966 }
967
968
969
970
971
972 /**
973 \brief Calculate a fragment of sine wave
974
975 Calculate a fragment of sine wave, as many samples as can be fitted
976 in generator buffer's subarea.
977
978 There will be (gen->buffer_sub_stop - gen->buffer_sub_start + 1)
979 samples calculated and put into gen->buffer[], starting from
980 gen->buffer[gen->buffer_sub_start].
981
982 The function takes into account all state variables from gen,
983 so initial phase of new fragment of sine wave in the buffer matches
984 ending phase of a sine wave generated in previous call.
985
986 \param gen - generator that generates sine wave
987 \param tone - generated tone
988
989 \return number of calculated samples
990 */
cw_gen_calculate_sine_wave_internal(cw_gen_t * gen,cw_tone_t * tone)991 int cw_gen_calculate_sine_wave_internal(cw_gen_t *gen, cw_tone_t *tone)
992 {
993 assert (gen->buffer_sub_stop <= gen->buffer_n_samples);
994
995 /* We need two separate iterators to correctly generate sine wave:
996 -- i -- for iterating through output buffer (generator
997 buffer's subarea), it can travel between buffer
998 cells delimited by start and stop (inclusive);
999 -- t -- for calculating phase of a sine wave; 't' always has to
1000 start from zero for every calculated subarea (i.e. for
1001 every call of this function);
1002
1003 Initial/starting phase of generated fragment is always retained
1004 in gen->phase_offset, it is the only "memory" of previously
1005 calculated fragment of sine wave (to be precise: it stores phase
1006 of last sample in previously calculated fragment).
1007 Therefore iterator used to calculate phase of sine wave can't have
1008 the memory too. Therefore it has to always start from zero for
1009 every new fragment of sine wave. Therefore a separate t. */
1010
1011 double phase = 0.0;
1012 int t = 0;
1013
1014 for (int i = gen->buffer_sub_start; i <= gen->buffer_sub_stop; i++) {
1015 phase = (2.0 * M_PI
1016 * (double) tone->frequency * (double) t
1017 / (double) gen->sample_rate)
1018 + gen->phase_offset;
1019 int amplitude = cw_gen_calculate_amplitude_internal(gen, tone);
1020
1021 gen->buffer[i] = amplitude * sin(phase);
1022
1023 tone->sample_iterator++;
1024
1025 t++;
1026 }
1027
1028 phase = (2.0 * M_PI
1029 * (double) tone->frequency * (double) t
1030 / (double) gen->sample_rate)
1031 + gen->phase_offset;
1032
1033 /* "phase" is now phase of the first sample in next fragment to be
1034 calculated.
1035 However, for long fragments this can be a large value, well
1036 beyond <0; 2*Pi) range.
1037 The value of phase may further accumulate in different
1038 calculations, and at some point it may overflow. This would
1039 result in an audible click.
1040
1041 Let's bring back the phase from beyond <0; 2*Pi) range into the
1042 <0; 2*Pi) range, in other words lets "normalize" it. Or, in yet
1043 other words, lets apply modulo operation to the phase.
1044
1045 The normalized phase will be used as a phase offset for next
1046 fragment (during next function call). It will be added phase of
1047 every sample calculated in next function call. */
1048
1049 int n_periods = floor(phase / (2.0 * M_PI));
1050 gen->phase_offset = phase - n_periods * 2.0 * M_PI;
1051
1052 return t;
1053 }
1054
1055
1056
1057
1058
1059 /**
1060 \brief Calculate value of a single sample of sine wave
1061
1062 This function calculates an amplitude (a value) of a single sample
1063 in sine wave PCM data.
1064
1065 Actually "calculation" is a bit too big word. The function is just
1066 a three-level-deep decision tree, deciding which of precalculated
1067 values to return. There are no complicated arithmetical
1068 calculations being made each time the function is called, so the
1069 execution time should be pretty small.
1070
1071 The precalcuated values depend on some factors, so the values
1072 should be re-calculated each time these factors change. See
1073 cw_generator_set_tone_slope() for list of these factors.
1074
1075 A generator stores some of information needed to get an amplitude
1076 of every sample in a sine wave - this is why we have \p gen. If
1077 tone's slopes are non-rectangular, the length of slopes is defined
1078 in generator. If a tone is non-silent, the volume is also defined
1079 in generator.
1080
1081 However, decision tree for getting the amplitude also depends on
1082 some parameters that are strictly bound to tone, such as what is
1083 the shape of slopes for a given tone - this is why we have \p tone.
1084 The \p also stores iterator of samples - this is how we know for
1085 which sample to calculate the amplitude.
1086
1087 \param gen - generator used to generate a sine wave
1088 \param tone - tone being generated
1089
1090 \return value of a sample of sine wave, a non-negative number
1091 */
cw_gen_calculate_amplitude_internal(cw_gen_t * gen,cw_tone_t * tone)1092 int cw_gen_calculate_amplitude_internal(cw_gen_t *gen, cw_tone_t *tone)
1093 {
1094 #if 0
1095 int amplitude = 0;
1096 /* Blunt algorithm for calculating amplitude;
1097 for debug purposes only. */
1098 if (tone->frequency) {
1099 amplitude = gen->volume_abs;
1100 } else {
1101 amplitude = 0;
1102 }
1103
1104 return amplitude;
1105 #else
1106
1107 if (tone->frequency <= 0) {
1108 return 0;
1109 }
1110
1111
1112 int amplitude = 0;
1113
1114 /* Every tone, regardless of slope mode (CW_SLOPE_MODE_*), has
1115 three components. It has rising slope + plateau + falling
1116 slope.
1117
1118 There can be four variants of rising and falling slope
1119 length, just as there are four CW_SLOPE_MODE_* values.
1120
1121 There can be also tones with zero-length plateau, and there
1122 can be also tones with zero-length slopes. */
1123
1124 if (tone->sample_iterator < tone->rising_slope_n_samples) {
1125 /* Beginning of tone, rising slope. */
1126 int i = tone->sample_iterator;
1127 amplitude = gen->tone_slope.amplitudes[i];
1128 assert (amplitude >= 0);
1129
1130 } else if (tone->sample_iterator >= tone->rising_slope_n_samples
1131 && tone->sample_iterator < tone->n_samples - tone->falling_slope_n_samples) {
1132
1133 /* Middle of tone, plateau, constant amplitude. */
1134 amplitude = gen->volume_abs;
1135 assert (amplitude >= 0);
1136
1137 } else if (tone->sample_iterator >= tone->n_samples - tone->falling_slope_n_samples) {
1138 /* Falling slope. */
1139 int i = tone->n_samples - tone->sample_iterator - 1;
1140 assert (i >= 0);
1141 amplitude = gen->tone_slope.amplitudes[i];
1142 assert (amplitude >= 0);
1143
1144 } else {
1145 cw_assert (0, "->sample_iterator out of bounds:\n"
1146 "tone->sample_iterator: %d\n"
1147 "tone->n_samples: %"PRId64"\n"
1148 "tone->rising_slope_n_samples: %d\n"
1149 "tone->falling_slope_n_samples: %d\n",
1150 tone->sample_iterator,
1151 tone->n_samples,
1152 tone->rising_slope_n_samples,
1153 tone->falling_slope_n_samples);
1154 }
1155
1156 assert (amplitude >= 0);
1157 return amplitude;
1158 #endif
1159 }
1160
1161
1162
1163
1164
1165 /**
1166 \brief Set parameters of tones generated by generator
1167
1168 Most of variables related to slope of tones is in tone data type,
1169 but there are still some variables that are generator-specific, as
1170 they are common for all tones. This function sets two of these
1171 variables.
1172
1173
1174 A: If you pass to function conflicting values of \p slope_shape and
1175 \p slope_len, the function will return CW_FAILURE. These
1176 conflicting values are rectangular slope shape and larger than zero
1177 slope length. You just can't have rectangular slopes that have
1178 non-zero length.
1179
1180
1181 B: If you pass to function '-1' as value of both \p slope_shape and
1182 \p slope_len, the function won't change any of the related two
1183 generator's parameters.
1184
1185
1186 C1: If you pass to function '-1' as value of either \p slope_shape
1187 or \p slope_len, the function will attempt to set only this
1188 generator's parameter that is different than '-1'.
1189
1190 C2: However, if selected slope shape is rectangular, function will
1191 set generator's slope length to zero, even if value of \p
1192 slope_len is '-1'.
1193
1194
1195 D: Notice that the function allows non-rectangular slope shape with
1196 zero length of the slopes. The slopes will be non-rectangular, but
1197 just unusually short.
1198
1199
1200 The function should be called every time one of following
1201 parameters change:
1202
1203 \li shape of slope,
1204 \li length of slope,
1205 \li generator's sample rate,
1206 \li generator's volume.
1207
1208 There are four supported shapes of slopes:
1209 \li linear (the only one supported by libcw until version 4.1.1),
1210 \li raised cosine (supposedly the most desired shape),
1211 \li sine,
1212 \li rectangular.
1213
1214 Use CW_TONE_SLOPE_SHAPE_* symbolic names as values of \p slope_shape.
1215
1216 FIXME: first argument of this public function is gen, but no
1217 function provides access to generator variable.
1218
1219 \param gen - generator for which to set tone slope parameters
1220 \param slope_shape - shape of slope: linear, raised cosine, sine, rectangular
1221 \param slope_len - length of slope [microseconds]
1222
1223 \return CW_SUCCESS on success
1224 \return CW_FAILURE on failure
1225 */
cw_generator_set_tone_slope(cw_gen_t * gen,int slope_shape,int slope_len)1226 int cw_generator_set_tone_slope(cw_gen_t *gen, int slope_shape, int slope_len)
1227 {
1228 assert (gen);
1229
1230 /* Handle conflicting values of arguments. */
1231 if (slope_shape == CW_TONE_SLOPE_SHAPE_RECTANGULAR
1232 && slope_len > 0) {
1233
1234 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR,
1235 "libcw: requested a rectangular slope shape, but also requested slope len > 0");
1236
1237 return CW_FAILURE;
1238 }
1239
1240 /* Assign new values from arguments. */
1241 if (slope_shape != -1) {
1242 gen->tone_slope.shape = slope_shape;
1243 }
1244 if (slope_len != -1) {
1245 gen->tone_slope.len = slope_len;
1246 }
1247
1248
1249 /* Override of slope length. */
1250 if (slope_shape == CW_TONE_SLOPE_SHAPE_RECTANGULAR) {
1251 gen->tone_slope.len = 0;
1252 }
1253
1254
1255 int slope_n_samples = ((gen->sample_rate / 100) * gen->tone_slope.len) / 10000;
1256 cw_assert (slope_n_samples >= 0, "negative slope_n_samples: %d", slope_n_samples);
1257
1258
1259 /* Reallocate the table of slope amplitudes only when necessary.
1260
1261 In practice the function will be called foremost when user
1262 changes volume of tone (and then the function may be
1263 called several times in a row if volume is changed in
1264 steps). In such situation the size of amplitudes table
1265 doesn't change. */
1266
1267 if (gen->tone_slope.n_amplitudes != slope_n_samples) {
1268
1269 /* Remember that slope_n_samples may be zero. In that
1270 case realloc() would equal to free(). We don't
1271 want to have NULL ->amplitudes, so don't modify
1272 ->amplitudes for zero-length slopes. Since with
1273 zero-length slopes we won't be referring to
1274 ->amplitudes[], it is ok that the table will not
1275 be up-to-date. */
1276
1277 if (slope_n_samples > 0) {
1278 gen->tone_slope.amplitudes = realloc(gen->tone_slope.amplitudes, sizeof(float) * slope_n_samples);
1279 if (!gen->tone_slope.amplitudes) {
1280 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR,
1281 "libcw: failed to realloc() table of slope amplitudes");
1282 return CW_FAILURE;
1283 }
1284 }
1285
1286 gen->tone_slope.n_amplitudes = slope_n_samples;
1287 }
1288
1289 cw_gen_recalculate_slopes_internal(gen);
1290
1291 return CW_SUCCESS;
1292 }
1293
1294
1295
1296
1297
1298 /**
1299 \brief Recalculate amplitudes of PCM samples that form tone's slopes
1300
1301 TODO: consider writing unit test code for the function.
1302
1303 \param gen - generator
1304 */
cw_gen_recalculate_slopes_internal(cw_gen_t * gen)1305 void cw_gen_recalculate_slopes_internal(cw_gen_t *gen)
1306 {
1307 /* The values in amplitudes[] change from zero to max (at
1308 least for any sane slope shape), so naturally they can be
1309 used in forming rising slope. However they can be used in
1310 forming falling slope as well - just iterate the table from
1311 end to beginning. */
1312 for (int i = 0; i < gen->tone_slope.n_amplitudes; i++) {
1313
1314 if (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_LINEAR) {
1315 gen->tone_slope.amplitudes[i] = 1.0 * gen->volume_abs * i / gen->tone_slope.n_amplitudes;
1316
1317 } else if (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_SINE) {
1318 float radian = i * (M_PI / 2.0) / gen->tone_slope.n_amplitudes;
1319 gen->tone_slope.amplitudes[i] = sin(radian) * gen->volume_abs;
1320
1321 } else if (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_RAISED_COSINE) {
1322 float radian = i * M_PI / gen->tone_slope.n_amplitudes;
1323 gen->tone_slope.amplitudes[i] = (1 - ((1 + cos(radian)) / 2)) * gen->volume_abs;
1324
1325 } else if (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_RECTANGULAR) {
1326 /* CW_TONE_SLOPE_SHAPE_RECTANGULAR is covered
1327 before entering this "for" loop. */
1328 cw_assert (0, "we shouldn't be here, calculating rectangular slopes");
1329
1330 } else {
1331 cw_assert (0, "unsupported slope shape %d", gen->tone_slope.shape);
1332 }
1333 }
1334
1335 return;
1336 }
1337
1338
1339
1340
1341
1342 /**
1343 \brief Write tone to soundcard
1344 */
cw_gen_write_to_soundcard_internal(cw_gen_t * gen,cw_tone_t * tone,int queue_rv)1345 int cw_gen_write_to_soundcard_internal(cw_gen_t *gen, cw_tone_t *tone, int queue_rv)
1346 {
1347 assert (queue_rv != CW_TQ_NDEQUEUED_IDLE);
1348
1349 if (queue_rv == CW_TQ_NDEQUEUED_EMPTY) {
1350 /* All tones have been already dequeued from tone
1351 queue.
1352
1353 \p tone does not represent a valid tone to play. At
1354 first sight there is no need to write anything to
1355 soundcard. But...
1356
1357 It may happen that during previous call to the
1358 function there were too few samples in a tone to
1359 completely fill a buffer (see #needmoresamples tag
1360 below).
1361
1362 We need to fill the buffer until it is full and
1363 ready to be sent to audio sink.
1364
1365 Since there are no new tones for which we could
1366 generate samples, we need to generate silence
1367 samples.
1368
1369 Padding the buffer with silence seems to be a good
1370 idea (it will work regardless of value (Mark/Space)
1371 of last valid tone). We just need to know how many
1372 samples of the silence to produce.
1373
1374 Number of these samples will be stored in
1375 samples_to_write. */
1376
1377 /* We don't have a valid tone, so let's construct a
1378 fake one for purposes of padding. */
1379
1380 /* Required length of padding space is from end of
1381 last buffer subarea to end of buffer. */
1382 tone->n_samples = gen->buffer_n_samples - (gen->buffer_sub_stop + 1);;
1383
1384 tone->len = 0; /* This value matters no more, because now we only deal with samples. */
1385 tone->frequency = 0; /* This fake tone is a piece of silence. */
1386
1387 /* The silence tone used for padding doesn't require
1388 any slopes. A slope falling to silence has been
1389 already provided by last non-fake and non-silent
1390 tone. */
1391 tone->slope_mode = CW_SLOPE_MODE_NO_SLOPES;
1392 tone->rising_slope_n_samples = 0;
1393 tone->falling_slope_n_samples = 0;
1394
1395 tone->sample_iterator = 0;
1396
1397 //fprintf(stderr, "++++ length of padding silence = %d [samples]\n", tone->n_samples);
1398
1399 } else { /* tq_rv == CW_TQ_DEQUEUED */
1400
1401 /* Recalculate tone parameters from microseconds into
1402 samples. After this point the samples will be all
1403 that matters. */
1404
1405 /* 100 * 10000 = 1.000.000 usecs per second. */
1406 tone->n_samples = gen->sample_rate / 100;
1407 tone->n_samples *= tone->len;
1408 tone->n_samples /= 10000;
1409
1410 //fprintf(stderr, "++++ length of regular tone = %d [samples]\n", tone->n_samples);
1411
1412 /* Length of a single slope (rising or falling). */
1413 int slope_n_samples= gen->sample_rate / 100;
1414 slope_n_samples *= gen->tone_slope.len;
1415 slope_n_samples /= 10000;
1416
1417 if (tone->slope_mode == CW_SLOPE_MODE_RISING_SLOPE) {
1418 tone->rising_slope_n_samples = slope_n_samples;
1419 tone->falling_slope_n_samples = 0;
1420
1421 } else if (tone->slope_mode == CW_SLOPE_MODE_FALLING_SLOPE) {
1422 tone->rising_slope_n_samples = 0;
1423 tone->falling_slope_n_samples = slope_n_samples;
1424
1425 } else if (tone->slope_mode == CW_SLOPE_MODE_STANDARD_SLOPES) {
1426 tone->rising_slope_n_samples = slope_n_samples;
1427 tone->falling_slope_n_samples = slope_n_samples;
1428
1429 } else if (tone->slope_mode == CW_SLOPE_MODE_NO_SLOPES) {
1430 tone->rising_slope_n_samples = 0;
1431 tone->falling_slope_n_samples = 0;
1432
1433 } else {
1434 cw_assert (0, "unknown tone slope mode %d", tone->slope_mode);
1435 }
1436
1437 tone->sample_iterator = 0;
1438 }
1439
1440
1441 /* Total number of samples to write in a loop below. */
1442 int64_t samples_to_write = tone->n_samples;
1443
1444 #if 0
1445 fprintf(stderr, "++++ entering loop, tone->frequency = %d, buffer->n_samples = %d, tone->n_samples = %d, samples_to_write = %d\n",
1446 tone->frequency, gen->buffer_n_samples, tone->n_samples, samples_to_write);
1447 fprintf(stderr, "++++ entering loop, expected ~%f loops\n", 1.0 * samples_to_write / gen->buffer_n_samples);
1448 int debug_loop = 0;
1449 #endif
1450
1451
1452 // cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG, "libcw: %lld samples, %d us, %d Hz", tone->n_samples, tone->len, gen->frequency);
1453 while (samples_to_write > 0) {
1454
1455 int64_t free_space = gen->buffer_n_samples - gen->buffer_sub_start;
1456 if (samples_to_write > free_space) {
1457 /* There will be some tone samples left for
1458 next iteration of this loop. But this
1459 buffer will be ready to be pushed to audio
1460 sink. */
1461 gen->buffer_sub_stop = gen->buffer_n_samples - 1;
1462 } else if (samples_to_write == free_space) {
1463 /* How nice, end of tone samples aligns with
1464 end of buffer (last sample of tone will be
1465 placed in last cell of buffer).
1466
1467 But the result is the same - a full buffer
1468 ready to be pushed to audio sink. */
1469 gen->buffer_sub_stop = gen->buffer_n_samples - 1;
1470 } else {
1471 /* There will be too few samples to fill a
1472 buffer. We can't send an unready buffer to
1473 audio sink. We will have to somehow pad the
1474 buffer. */
1475 gen->buffer_sub_stop = gen->buffer_sub_start + samples_to_write - 1;
1476 }
1477
1478 /* How many samples of audio buffer's subarea will be
1479 calculated in a given cycle of "calculate sine
1480 wave" code? */
1481 int buffer_sub_n_samples = gen->buffer_sub_stop - gen->buffer_sub_start + 1;
1482
1483
1484 #if 0
1485 fprintf(stderr, "++++ loop #%d, buffer_sub_n_samples = %d\n", ++debug_loop, buffer_sub_n_samples);
1486 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG,
1487 "libcw: sub start: %d, sub stop: %d, sub len: %d, to calculate: %d", gen->buffer_sub_start, gen->buffer_sub_stop, buffer_sub_n_samples, samples_to_write);
1488 #endif
1489
1490
1491 int calculated = cw_gen_calculate_sine_wave_internal(gen, tone);
1492 cw_assert (calculated == buffer_sub_n_samples,
1493 "calculated wrong number of samples: %d != %d",
1494 calculated, buffer_sub_n_samples);
1495
1496
1497 if (gen->buffer_sub_stop == gen->buffer_n_samples - 1) {
1498
1499 /* We have a buffer full of samples. The
1500 buffer is ready to be pushed to audio
1501 sink. */
1502 gen->write(gen);
1503 gen->buffer_sub_start = 0;
1504 gen->buffer_sub_stop = 0;
1505 #if CW_DEV_RAW_SINK
1506 cw_dev_debug_raw_sink_write_internal(gen);
1507 #endif
1508 } else {
1509 /* #needmoresamples
1510 There is still some space left in the
1511 buffer, go fetch new tone from tone
1512 queue. */
1513
1514 gen->buffer_sub_start = gen->buffer_sub_stop + 1;
1515
1516 cw_assert (gen->buffer_sub_start <= gen->buffer_n_samples - 1,
1517 "sub start out of range: sub start = %d, buffer n samples = %d",
1518 gen->buffer_sub_start, gen->buffer_n_samples);
1519 }
1520
1521 samples_to_write -= buffer_sub_n_samples;
1522
1523 #if 0
1524 if (samples_to_write < 0) {
1525 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG, "samples left = %d", samples_to_write);
1526 }
1527 #endif
1528
1529 } /* while (samples_to_write > 0) { */
1530
1531 //fprintf(stderr, "++++ left loop, %d loops, samples left = %d\n", debug_loop, (int) samples_to_write);
1532
1533 return 0;
1534 }
1535
1536
1537
1538
1539
1540 /**
1541 \brief Set sending speed of generator
1542
1543 See libcw.h/CW_SPEED_{INITIAL|MIN|MAX} for initial/minimal/maximal value
1544 of send speed.
1545
1546 errno is set to EINVAL if \p new_value is out of range.
1547
1548 testedin::test_parameter_ranges()
1549
1550 \param gen - generator for which to set the speed
1551 \param new_value - new value of send speed to be assigned to generator
1552
1553 \return CW_SUCCESS on success
1554 \return CW_FAILURE on failure
1555 */
cw_gen_set_speed_internal(cw_gen_t * gen,int new_value)1556 int cw_gen_set_speed_internal(cw_gen_t *gen, int new_value)
1557 {
1558 if (new_value < CW_SPEED_MIN || new_value > CW_SPEED_MAX) {
1559 errno = EINVAL;
1560 return CW_FAILURE;
1561 }
1562
1563 if (new_value != gen->send_speed) {
1564 gen->send_speed = new_value;
1565
1566 /* Changes of send speed require resynchronization. */
1567 gen->parameters_in_sync = false;
1568 cw_gen_sync_parameters_internal(gen);
1569 }
1570
1571 return CW_SUCCESS;
1572 }
1573
1574
1575
1576
1577
1578 /**
1579 \brief Set frequency of generator
1580
1581 Set frequency of sound wave generated by generator.
1582 The frequency must be within limits marked by CW_FREQUENCY_MIN
1583 and CW_FREQUENCY_MAX.
1584
1585 See libcw.h/CW_FREQUENCY_{INITIAL|MIN|MAX} for initial/minimal/maximal
1586 value of frequency.
1587
1588 errno is set to EINVAL if \p new_value is out of range.
1589
1590 \param gen - generator for which to set new frequency
1591 \param new_value - new value of frequency to be assigned to generator
1592
1593 \return CW_SUCCESS on success
1594 \return CW_FAILURE on failure
1595 */
cw_gen_set_frequency_internal(cw_gen_t * gen,int new_value)1596 int cw_gen_set_frequency_internal(cw_gen_t *gen, int new_value)
1597 {
1598 if (new_value < CW_FREQUENCY_MIN || new_value > CW_FREQUENCY_MAX) {
1599 errno = EINVAL;
1600 return CW_FAILURE;
1601 } else {
1602 gen->frequency = new_value;
1603 return CW_SUCCESS;
1604 }
1605 }
1606
1607
1608
1609
1610
1611 /**
1612 \brief Set volume of generator
1613
1614 Set volume of sound wave generated by generator.
1615 The volume must be within limits marked by CW_VOLUME_MIN and CW_VOLUME_MAX.
1616
1617 Note that volume settings are not fully possible for the console speaker.
1618 In this case, volume settings greater than zero indicate console speaker
1619 sound is on, and setting volume to zero will turn off console speaker
1620 sound.
1621
1622 See libcw.h/CW_VOLUME_{INITIAL|MIN|MAX} for initial/minimal/maximal
1623 value of volume.
1624 errno is set to EINVAL if \p new_value is out of range.
1625
1626 \param gen - generator for which to set a volume level
1627 \param new_value - new value of volume to be assigned to generator
1628
1629 \return CW_SUCCESS on success
1630 \return CW_FAILURE on failure
1631 */
cw_gen_set_volume_internal(cw_gen_t * gen,int new_value)1632 int cw_gen_set_volume_internal(cw_gen_t *gen, int new_value)
1633 {
1634 if (new_value < CW_VOLUME_MIN || new_value > CW_VOLUME_MAX) {
1635 errno = EINVAL;
1636 return CW_FAILURE;
1637 } else {
1638 gen->volume_percent = new_value;
1639 gen->volume_abs = (gen->volume_percent * CW_AUDIO_VOLUME_RANGE) / 100;
1640
1641 cw_generator_set_tone_slope(gen, -1, -1);
1642
1643 return CW_SUCCESS;
1644 }
1645 }
1646
1647
1648
1649
1650
1651 /**
1652 \brief Set sending gap of generator
1653
1654 See libcw.h/CW_GAP_{INITIAL|MIN|MAX} for initial/minimal/maximal
1655 value of gap.
1656 errno is set to EINVAL if \p new_value is out of range.
1657
1658 \param gen - generator for which to set gap
1659 \param new_value - new value of gap to be assigned to generator
1660
1661 \return CW_SUCCESS on success
1662 \return CW_FAILURE on failure
1663 */
cw_gen_set_gap_internal(cw_gen_t * gen,int new_value)1664 int cw_gen_set_gap_internal(cw_gen_t *gen, int new_value)
1665 {
1666 if (new_value < CW_GAP_MIN || new_value > CW_GAP_MAX) {
1667 errno = EINVAL;
1668 return CW_FAILURE;
1669 }
1670
1671 if (new_value != gen->gap) {
1672 gen->gap = new_value;
1673 /* Changes of gap require resynchronization. */
1674 gen->parameters_in_sync = false;
1675 cw_gen_sync_parameters_internal(gen);
1676 }
1677
1678 return CW_SUCCESS;
1679 }
1680
1681
1682
1683
1684
1685 /**
1686 \brief Set sending weighting for generator
1687
1688 See libcw.h/CW_WEIGHTING_{INITIAL|MIN|MAX} for initial/minimal/maximal
1689 value of weighting.
1690 errno is set to EINVAL if \p new_value is out of range.
1691
1692 \param gen - generator for which to set new weighting
1693 \param new_value - new value of weighting to be assigned for generator
1694
1695 \return CW_SUCCESS on success
1696 \return CW_FAILURE on failure
1697 */
cw_gen_set_weighting_internal(cw_gen_t * gen,int new_value)1698 int cw_gen_set_weighting_internal(cw_gen_t *gen, int new_value)
1699 {
1700 if (new_value < CW_WEIGHTING_MIN || new_value > CW_WEIGHTING_MAX) {
1701 errno = EINVAL;
1702 return CW_FAILURE;
1703 }
1704
1705 if (new_value != gen->weighting) {
1706 gen->weighting = new_value;
1707
1708 /* Changes of weighting require resynchronization. */
1709 gen->parameters_in_sync = false;
1710 cw_gen_sync_parameters_internal(gen);
1711 }
1712
1713 return CW_SUCCESS;
1714 }
1715
1716
1717
1718
1719
1720 /**
1721 \brief Get sending speed from generator
1722
1723 \param gen - generator from which to get the parameter
1724
1725 \return current value of the generator's send speed
1726 */
cw_gen_get_speed_internal(cw_gen_t * gen)1727 int cw_gen_get_speed_internal(cw_gen_t *gen)
1728 {
1729 return gen->send_speed;
1730 }
1731
1732
1733
1734
1735
1736 /**
1737 \brief Get frequency from generator
1738
1739 Function returns "frequency" parameter of generator,
1740 even if the generator is stopped, or volume of generated sound is zero.
1741
1742 \param gen - generator from which to get the parameter
1743
1744 \return current value of generator's frequency
1745 */
cw_gen_get_frequency_internal(cw_gen_t * gen)1746 int cw_gen_get_frequency_internal(cw_gen_t *gen)
1747 {
1748 return gen->frequency;
1749 }
1750
1751
1752
1753
1754
1755 /**
1756 \brief Get sound volume from generator
1757
1758 Function returns "volume" parameter of generator,
1759 even if the generator is stopped.
1760
1761 \param gen - generator from which to get the parameter
1762
1763 \return current value of generator's sound volume
1764 */
cw_gen_get_volume_internal(cw_gen_t * gen)1765 int cw_gen_get_volume_internal(cw_gen_t *gen)
1766 {
1767 return gen->volume_percent;
1768 }
1769
1770
1771
1772
1773
1774
1775
1776
1777 /**
1778 \brief Get sending gap from generator
1779
1780 \param gen - generator from which to get the parameter
1781
1782 \return current value of generator's sending gap
1783 */
cw_gen_get_gap_internal(cw_gen_t * gen)1784 int cw_gen_get_gap_internal(cw_gen_t *gen)
1785 {
1786 return gen->gap;
1787 }
1788
1789
1790
1791
1792
1793 /**
1794 \brief Get sending weighting from generator
1795
1796 \param gen - generator from which to get the parameter
1797
1798 \return current value of generator's sending weighting
1799 */
cw_gen_get_weighting_internal(cw_gen_t * gen)1800 int cw_gen_get_weighting_internal(cw_gen_t *gen)
1801 {
1802 return gen->weighting;
1803 }
1804
1805
1806
1807
1808
1809 /**
1810 \brief Get timing parameters for sending
1811
1812 Return the low-level timing parameters calculated from the speed, gap,
1813 tolerance, and weighting set. Parameter values are returned in
1814 microseconds.
1815
1816 Use NULL for the pointer argument to any parameter value not required.
1817
1818 \param gen
1819 \param dot_len
1820 \param dash_len
1821 \param eom_space_len
1822 \param eoc_space_len
1823 \param eow_space_len
1824 \param additional_space_len
1825 \param adjustment_space_len
1826 */
cw_gen_get_send_parameters_internal(cw_gen_t * gen,int * dot_len,int * dash_len,int * eom_space_len,int * eoc_space_len,int * eow_space_len,int * additional_space_len,int * adjustment_space_len)1827 void cw_gen_get_send_parameters_internal(cw_gen_t *gen,
1828 int *dot_len,
1829 int *dash_len,
1830 int *eom_space_len,
1831 int *eoc_space_len,
1832 int *eow_space_len,
1833 int *additional_space_len, int *adjustment_space_len)
1834 {
1835 cw_gen_sync_parameters_internal(gen);
1836
1837 if (dot_len) *dot_len = gen->dot_len;
1838 if (dash_len) *dash_len = gen->dash_len;
1839
1840 if (eom_space_len) *eom_space_len = gen->eom_space_len;
1841 if (eoc_space_len) *eoc_space_len = gen->eoc_space_len;
1842 if (eow_space_len) *eow_space_len = gen->eow_space_len;
1843
1844 if (additional_space_len) *additional_space_len = gen->additional_space_len;
1845 if (adjustment_space_len) *adjustment_space_len = gen->adjustment_space_len;
1846
1847 return;
1848 }
1849
1850
1851
1852
1853
1854 /**
1855 \brief Play a mark (Dot or Dash)
1856
1857 Low level primitive to play a tone for mark of the given type, followed
1858 by the standard inter-mark space.
1859
1860 Function sets errno to EINVAL if an argument is invalid, and
1861 returns CW_FAILURE.
1862
1863 Function also returns CW_FAILURE if adding the element to queue of
1864 tones failed.
1865
1866 \param gen - generator to be used to play a mark and inter-mark space
1867 \param mark - mark to send: Dot (CW_DOT_REPRESENTATION) or Dash (CW_DASH_REPRESENTATION)
1868
1869 \return CW_FAILURE on failure
1870 \return CW_SUCCESS on success
1871 */
cw_gen_play_mark_internal(cw_gen_t * gen,char mark)1872 int cw_gen_play_mark_internal(cw_gen_t *gen, char mark)
1873 {
1874 int status;
1875
1876 /* Synchronize low-level timings if required. */
1877 cw_gen_sync_parameters_internal(gen);
1878 /* TODO: do we need to synchronize here receiver as well? */
1879
1880 /* Send either a dot or a dash mark, depending on representation. */
1881 if (mark == CW_DOT_REPRESENTATION) {
1882 cw_tone_t tone;
1883 CW_TONE_INIT(&tone, gen->frequency, gen->dot_len, CW_SLOPE_MODE_STANDARD_SLOPES);
1884 status = cw_tq_enqueue_internal(gen->tq, &tone);
1885 } else if (mark == CW_DASH_REPRESENTATION) {
1886 cw_tone_t tone;
1887 CW_TONE_INIT(&tone, gen->frequency, gen->dash_len, CW_SLOPE_MODE_STANDARD_SLOPES);
1888 status = cw_tq_enqueue_internal(gen->tq, &tone);
1889 } else {
1890 errno = EINVAL;
1891 status = CW_FAILURE;
1892 }
1893
1894 if (!status) {
1895 return CW_FAILURE;
1896 }
1897
1898 /* Send the inter-mark space. */
1899 cw_tone_t tone;
1900 CW_TONE_INIT(&tone, 0, gen->eom_space_len, CW_SLOPE_MODE_NO_SLOPES);
1901 if (!cw_tq_enqueue_internal(gen->tq, &tone)) {
1902 return CW_FAILURE;
1903 } else {
1904 return CW_SUCCESS;
1905 }
1906 }
1907
1908
1909
1910
1911
1912 /**
1913 \brief Play end-of-character space
1914
1915 The function plays space of length 2 Units. The function is
1916 intended to be used after inter-mark space has already been played.
1917
1918 In such situation standard inter-mark space (one Unit) and
1919 end-of-character space (two Units) form a full standard
1920 end-of-character space (three Units).
1921
1922 Inter-character adjustment space is added at the end.
1923
1924 \param gen
1925
1926 \return CW_SUCCESS on success
1927 \return CW_FAILURE on failure
1928 */
cw_gen_play_eoc_space_internal(cw_gen_t * gen)1929 int cw_gen_play_eoc_space_internal(cw_gen_t *gen)
1930 {
1931 /* Synchronize low-level timing parameters. */
1932 cw_gen_sync_parameters_internal(gen);
1933
1934 /* Delay for the standard end of character period, plus any
1935 additional inter-character gap */
1936 cw_tone_t tone;
1937 CW_TONE_INIT(&tone, 0, gen->eoc_space_len + gen->additional_space_len, CW_SLOPE_MODE_NO_SLOPES);
1938 return cw_tq_enqueue_internal(gen->tq, &tone);
1939 }
1940
1941
1942
1943
1944
1945 /**
1946 \brief Play end-of-word space
1947
1948 The function should be used to play a regular ' ' character.
1949
1950 The function plays space of length 5 Units. The function is
1951 intended to be used after inter-mark space and end-of-character
1952 space have already been played.
1953
1954 In such situation standard inter-mark space (one Unit) and
1955 end-of-character space (two Units) and end-of-word space (five
1956 units) form a full standard end-of-word space (seven Units).
1957
1958 Inter-word adjustment space is added at the end.
1959
1960 \param gen
1961
1962 \return CW_SUCCESS on success
1963 \return CW_FAILURE on failure
1964 */
cw_gen_play_eow_space_internal(cw_gen_t * gen)1965 int cw_gen_play_eow_space_internal(cw_gen_t *gen)
1966 {
1967 /* Synchronize low-level timing parameters. */
1968 cw_gen_sync_parameters_internal(gen);
1969
1970 /* Send silence for the word delay period, plus any adjustment
1971 that may be needed at end of word. Make it in two tones,
1972 and here is why.
1973
1974 Let's say that 'tone queue low watermark' is one element
1975 (i.e. one tone).
1976
1977 In order for tone queue to recognize that a 'low tone
1978 queue' callback needs to be called, the level in tq needs
1979 to drop from 2 to 1.
1980
1981 Almost every queued character guarantees that there will be
1982 at least two tones, e.g for 'E' it is dash + following
1983 space. But what about a ' ' character?
1984
1985 If we play ' ' character as single tone, there is only one
1986 tone in tone queue, and the tone queue manager can't
1987 recognize when the level drops from 2 to 1 (and thus the
1988 'low level' callback won't be called).
1989
1990 If we play ' ' character as two separate tones (as we do
1991 this in this function), the tone queue manager can
1992 recognize level dropping from 2 to 1. Then the passing of
1993 critical level can be noticed, and "low level" callback can
1994 be called.
1995
1996 BUT: Sometimes the first tone is dequeued before/during the
1997 second one is enqueued, and we can't recognize 2->1 event.
1998
1999 So, to be super-sure that there is a recognizable event of
2000 passing tone queue level from 2 to 1, we split the eow
2001 space into N parts and enqueue them. This way we have N + 1
2002 tones per space, and client applications that rely on low
2003 level threshold == 1 can correctly work when enqueueing
2004 spaces.
2005
2006 At 60 wpm length of gen->eow_space_len is 100000 [us], so
2007 it's large enough to safely divide it by small integer
2008 value. */
2009
2010 int enqueued = 0;
2011
2012 cw_tone_t tone;
2013 #if 0
2014 /* This section is incorrect. Enable this section only for
2015 tests. This section "implements" a bug that was present in
2016 libcw until version 6.4.1 and that is now tested by
2017 src/libcw/tests/libcw_test_tq_short_space.c */
2018 int n = 1; /* No division. Old situation causing an error in
2019 client applications. */
2020 #else
2021 int n = 2; /* "small integer value" - used to have more tones per eow space. */
2022 #endif
2023 CW_TONE_INIT(&tone, 0, gen->eow_space_len / n, CW_SLOPE_MODE_NO_SLOPES);
2024 for (int i = 0; i < n; i++) {
2025 int rv = cw_tq_enqueue_internal(gen->tq, &tone);
2026 if (rv) {
2027 enqueued++;
2028 } else {
2029 return CW_FAILURE;
2030 }
2031 }
2032
2033 CW_TONE_INIT(&tone, 0, gen->adjustment_space_len, CW_SLOPE_MODE_NO_SLOPES);
2034 int rv = cw_tq_enqueue_internal(gen->tq, &tone);
2035 if (rv) {
2036 enqueued++;
2037 } else {
2038 return CW_FAILURE;
2039 }
2040
2041 cw_debug_msg ((&cw_debug_object), CW_DEBUG_GENERATOR, CW_DEBUG_DEBUG,
2042 "libcw: enqueued %d tones per eow space, tq len = %d",
2043 enqueued, cw_tq_length_internal(gen->tq));
2044
2045 return CW_SUCCESS;
2046 }
2047
2048
2049
2050
2051
2052 /**
2053 \brief Play the given representation
2054
2055 Function plays given \p representation using given \p
2056 generator. Every mark from the \p representation is followed by a
2057 standard inter-mark space.
2058
2059 If \p partial is false, the representation is treated as a complete
2060 (non-partial) data, and a standard end-of-character space is played
2061 at the end (in addition to last inter-mark space). Total length of
2062 space at the end (inter-mark space + end-of-character space) is ~3
2063 Units.
2064
2065 If \p partial is true, the standard end-of-character space is not
2066 appended. However, the standard inter-mark space is played at the
2067 end.
2068
2069 Function sets errno to EAGAIN if there is not enough space in tone
2070 queue to enqueue \p representation.
2071
2072 Function validates \p representation using
2073 cw_representation_is_valid(). Function sets errno to EINVAL if \p
2074 representation is not valid.
2075
2076 \param gen - generator used to play the representation
2077 \param representation - representation to play
2078 \param partial
2079
2080 \return CW_FAILURE on failure
2081 \return CW_SUCCESS on success
2082 */
cw_gen_play_representation_internal(cw_gen_t * gen,const char * representation,bool partial)2083 int cw_gen_play_representation_internal(cw_gen_t *gen, const char *representation, bool partial)
2084 {
2085 if (!cw_representation_is_valid(representation)) {
2086 errno = EINVAL;
2087 return CW_FAILURE;
2088 }
2089
2090 /* Before we let this representation loose on tone generation,
2091 we'd really like to know that all of its tones will get queued
2092 up successfully. The right way to do this is to calculate the
2093 number of tones in our representation, then check that the space
2094 exists in the tone queue. However, since the queue is comfortably
2095 long, we can get away with just looking for a high water mark. */
2096 if (cw_tq_length_internal(gen->tq) >= gen->tq->high_water_mark) {
2097 errno = EAGAIN;
2098 return CW_FAILURE;
2099 }
2100
2101 /* Play the marks. Every mark is followed by end-of-mark
2102 space. */
2103 for (int i = 0; representation[i] != '\0'; i++) {
2104 if (!cw_gen_play_mark_internal(gen, representation[i])) {
2105 return CW_FAILURE;
2106 }
2107 }
2108
2109 /* Check if we should append end-of-character space at the end
2110 (in addition to last end-of-mark space). */
2111 if (!partial) {
2112 if (!cw_gen_play_eoc_space_internal(gen)) {
2113 return CW_FAILURE;
2114 }
2115 }
2116
2117 return CW_SUCCESS;
2118 }
2119
2120
2121
2122
2123
2124 /**
2125 \brief Look up and play a given ASCII character as Morse code
2126
2127 If \p partial is set, the end-of-character space is not appended
2128 after last mark of Morse code.
2129
2130 Function sets errno to ENOENT if \p character is not a recognized character.
2131
2132 \param gen - generator to be used to play character
2133 \param character - character to play
2134 \param partial
2135
2136 \return CW_SUCCESS on success
2137 \return CW_FAILURE on failure
2138 */
cw_gen_play_valid_character_internal(cw_gen_t * gen,char character,int partial)2139 int cw_gen_play_valid_character_internal(cw_gen_t *gen, char character, int partial)
2140 {
2141 if (!gen) {
2142 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_GENERATOR, CW_DEBUG_ERROR,
2143 "libcw: no generator available");
2144 return CW_FAILURE;
2145 }
2146
2147 /* ' ' character (i.e. end-of-word space) is a special case. */
2148 if (character == ' ') {
2149 return cw_gen_play_eow_space_internal(gen);
2150 }
2151
2152 /* Lookup the character, and play it. */
2153 const char *representation = cw_character_to_representation_internal(character);
2154 if (!representation) {
2155 errno = ENOENT;
2156 return CW_FAILURE;
2157 }
2158
2159 if (!cw_gen_play_representation_internal(gen, representation, partial)) {
2160 return CW_FAILURE;
2161 } else {
2162 return CW_SUCCESS;
2163 }
2164 }
2165
2166
2167
2168
2169
2170 /**
2171 \brief Look up and play a given ASCII character as Morse
2172
2173 The end of character delay is appended to the Morse sent.
2174
2175 On success the function returns CW_SUCCESS.
2176 On failure the function returns CW_FAILURE and sets errno.
2177
2178 errno is set to ENOENT if the given character \p c is not a valid
2179 Morse character.
2180 errno is set to EBUSY if current audio sink or keying system is
2181 busy.
2182 errno is set to EAGAIN if the generator's tone queue is full, or if
2183 there is insufficient space to queue the tones for the character.
2184
2185 This routine returns as soon as the character has been successfully
2186 queued for sending; that is, almost immediately. The actual sending
2187 happens in background processing. See cw_wait_for_tone() and
2188 cw_wait_for_tone_queue() for ways to check the progress of sending.
2189
2190 \param gen - generator to play with
2191 \param c - character to play
2192
2193 \return CW_SUCCESS on success
2194 \return CW_FAILURE on failure
2195 */
cw_gen_play_character_internal(cw_gen_t * gen,char c)2196 int cw_gen_play_character_internal(cw_gen_t *gen, char c)
2197 {
2198 /* The call to _is_valid() is placed outside of
2199 cw_gen_play_valid_character_internal() for performance
2200 reasons.
2201
2202 Or to put it another way:
2203 cw_gen_play_valid_character_internal() was created to be
2204 called in loop for all characters of validated string, so
2205 there was no point in validating all characters separately
2206 in that function. */
2207
2208 if (!cw_character_is_valid(c)) {
2209 errno = ENOENT;
2210 return CW_FAILURE;
2211 } else {
2212 return cw_gen_play_valid_character_internal(gen, c, false);
2213 }
2214 }
2215
2216
2217
2218
2219
2220 /**
2221 \brief Look up and play a given ASCII character as Morse code
2222
2223 "partial" means that the "end of character" delay is not appended
2224 to the Morse code sent by the function, to support the formation of
2225 combination characters.
2226
2227 On success the function returns CW_SUCCESS.
2228 On failure the function returns CW_FAILURE and sets errno.
2229
2230 errno is set to ENOENT if the given character \p c is not a valid
2231 Morse character.
2232 errno is set to EBUSY if the audio sink or keying system is busy.
2233 errno is set to EAGAIN if the tone queue is full, or if there is
2234 insufficient space to queue the tones for the character.
2235
2236 This routine queues its arguments for background processing. See
2237 cw_wait_for_tone() and cw_wait_for_tone_queue() for ways to check
2238 the progress of sending.
2239
2240 \param gen - generator to use
2241 \param c - character to play
2242
2243 \return CW_SUCCESS on success
2244 \return CW_FAILURE on failure
2245 */
cw_gen_play_character_parital_internal(cw_gen_t * gen,char c)2246 int cw_gen_play_character_parital_internal(cw_gen_t *gen, char c)
2247 {
2248 /* The call to _is_valid() is placed outside of
2249 cw_gen_play_valid_character_internal() for performance
2250 reasons.
2251
2252 Or to put it another way:
2253 cw_gen_play_valid_character_internal() was created to be
2254 called in loop for all characters of validated string, so
2255 there was no point in validating all characters separately
2256 in that function. */
2257
2258 if (!cw_character_is_valid(c)) {
2259 errno = ENOENT;
2260 return CW_FAILURE;
2261 } else {
2262 return cw_gen_play_valid_character_internal(gen, c, true);
2263 }
2264 }
2265
2266
2267
2268
2269
2270 /**
2271 \brief Play a given ASCII string in Morse code
2272
2273 errno is set to ENOENT if any character in the string is not a
2274 valid Morse character.
2275
2276 errno is set to EBUSY if audio sink or keying system is busy.
2277
2278 errno is set to EAGAIN if the tone queue is full or if the tone
2279 queue runs out of space part way through queueing the string.
2280 However, an indeterminate number of the characters from the string
2281 will have already been queued.
2282
2283 For safety, clients can ensure the tone queue is empty before
2284 queueing a string, or use cw_gen_play_character_internal() if they
2285 need finer control.
2286
2287 This routine queues its arguments for background processing, the
2288 actual sending happens in background processing. See
2289 cw_wait_for_tone() and cw_wait_for_tone_queue() for ways to check
2290 the progress of sending.
2291
2292 \param gen - generator to use
2293 \param string - string to play
2294
2295 \return CW_SUCCESS on success
2296 \return CW_FAILURE on failure
2297 */
cw_gen_play_string_internal(cw_gen_t * gen,const char * string)2298 int cw_gen_play_string_internal(cw_gen_t *gen, const char *string)
2299 {
2300 /* Check the string is composed of sendable characters. */
2301 if (!cw_string_is_valid(string)) {
2302 errno = ENOENT;
2303 return CW_FAILURE;
2304 }
2305
2306 /* Send every character in the string. */
2307 for (int i = 0; string[i] != '\0'; i++) {
2308 if (!cw_gen_play_valid_character_internal(gen, string[i], false))
2309 return CW_FAILURE;
2310 }
2311
2312 return CW_SUCCESS;
2313 }
2314
2315
2316
2317
2318
2319 /**
2320 \brief Reset essential sending parameters to their initial values
2321
2322 \param gen
2323 */
cw_gen_reset_send_parameters_internal(cw_gen_t * gen)2324 void cw_gen_reset_send_parameters_internal(cw_gen_t *gen)
2325 {
2326 cw_assert (gen, "generator is NULL");
2327
2328 gen->send_speed = CW_SPEED_INITIAL;
2329 gen->frequency = CW_FREQUENCY_INITIAL;
2330 gen->volume_percent = CW_VOLUME_INITIAL;
2331 gen->volume_abs = (gen->volume_percent * CW_AUDIO_VOLUME_RANGE) / 100;
2332 gen->gap = CW_GAP_INITIAL;
2333 gen->weighting = CW_WEIGHTING_INITIAL;
2334
2335 gen->parameters_in_sync = false;
2336
2337 return;
2338
2339 }
2340
2341
2342
2343
2344
2345 /**
2346 \brief Synchronize generator's low level timing parameters
2347
2348 \param gen - generator
2349 */
cw_gen_sync_parameters_internal(cw_gen_t * gen)2350 void cw_gen_sync_parameters_internal(cw_gen_t *gen)
2351 {
2352 cw_assert (gen, "generator is NULL");
2353
2354 /* Do nothing if we are already synchronized. */
2355 if (gen->parameters_in_sync) {
2356 return;
2357 }
2358
2359 /* Set the length of a Dot to be a Unit with any weighting
2360 adjustment, and the length of a Dash as three Dot lengths.
2361 The weighting adjustment is by adding or subtracting a
2362 length based on 50 % as a neutral weighting. */
2363 int unit_length = CW_DOT_CALIBRATION / gen->send_speed;
2364 int weighting_length = (2 * (gen->weighting - 50) * unit_length) / 100;
2365 gen->dot_len = unit_length + weighting_length;
2366 gen->dash_len = 3 * gen->dot_len;
2367
2368 /* End-of-mark space length is one Unit, perhaps adjusted.
2369 End-of-character space length is three Units total.
2370 End-of-word space length is seven Units total.
2371
2372 WARNING: notice how the eoc and eow spaces are
2373 calculated. They aren't full 3 units and 7 units. They are
2374 2 units (which takes into account preceding eom space
2375 length), and 5 units (which takes into account preceding
2376 eom *and* eoc space length). So these two lengths are
2377 *additional* ones, i.e. in addition to (already existing)
2378 eom and/or eoc space. Whether this is good or bad idea to
2379 calculate them like this is a separate topic. Just be aware
2380 of this fact.
2381
2382 The end-of-mark length is adjusted by 28/22 times
2383 weighting length to keep PARIS calibration correctly
2384 timed (PARIS has 22 full units, and 28 empty ones).
2385 End-of-mark and end of character delays take
2386 weightings into account. */
2387 gen->eom_space_len = unit_length - (28 * weighting_length) / 22; /* End-of-mark space, a.k.a. regular inter-mark space. */
2388 gen->eoc_space_len = 3 * unit_length - gen->eom_space_len;
2389 gen->eow_space_len = 7 * unit_length - gen->eoc_space_len;
2390 gen->additional_space_len = gen->gap * unit_length;
2391
2392 /* For "Farnsworth", there also needs to be an adjustment
2393 delay added to the end of words, otherwise the rhythm is
2394 lost on word end.
2395 I don't know if there is an "official" value for this,
2396 but 2.33 or so times the gap is the correctly scaled
2397 value, and seems to sound okay.
2398
2399 Thanks to Michael D. Ivey <ivey@gweezlebur.com> for
2400 identifying this in earlier versions of libcw. */
2401 gen->adjustment_space_len = (7 * gen->additional_space_len) / 3;
2402
2403 cw_debug_msg ((&cw_debug_object), CW_DEBUG_PARAMETERS, CW_DEBUG_INFO,
2404 "libcw: send usec timings <%d [wpm]>: dot: %d, dash: %d, %d, %d, %d, %d, %d",
2405 gen->send_speed, gen->dot_len, gen->dash_len,
2406 gen->eom_space_len, gen->eoc_space_len,
2407 gen->eow_space_len, gen->additional_space_len, gen->adjustment_space_len);
2408
2409 /* Generator parameters are now in sync. */
2410 gen->parameters_in_sync = true;
2411
2412 return;
2413 }
2414
2415
2416
2417
2418
2419 /**
2420 Helper function intended to hide details of tone queue and of
2421 enqueueing a tone from cw_key module.
2422
2423 'key' is a verb here. The function should be called only on "key
2424 down" (begin mark) event from hardware straight key.
2425
2426 The function is called in very specific context, see cw_key module
2427 for details.
2428
2429 \param gen - generator
2430
2431 \return CW_SUCCESS on success
2432 \return CW_FAILURE on failure
2433 */
cw_gen_key_begin_mark_internal(cw_gen_t * gen)2434 int cw_gen_key_begin_mark_internal(cw_gen_t *gen)
2435 {
2436 /* In case of straight key we don't know at all how long the
2437 tone should be (we don't know for how long the key will be
2438 closed).
2439
2440 Let's enqueue a beginning of mark (rising slope) +
2441 "forever" (constant) tone. The constant tone will be played
2442 until function receives CW_KEY_STATE_OPEN key state. */
2443
2444 cw_tone_t tone;
2445 CW_TONE_INIT(&tone, gen->frequency, gen->tone_slope.len, CW_SLOPE_MODE_RISING_SLOPE);
2446 int rv = cw_tq_enqueue_internal(gen->tq, &tone);
2447
2448 if (rv == CW_SUCCESS) {
2449
2450 CW_TONE_INIT(&tone, gen->frequency, gen->quantum_len, CW_SLOPE_MODE_NO_SLOPES);
2451 tone.forever = true;
2452 rv = cw_tq_enqueue_internal(gen->tq, &tone);
2453
2454 cw_debug_msg ((&cw_debug_object_dev), CW_DEBUG_TONE_QUEUE, CW_DEBUG_DEBUG,
2455 "libcw: tone queue: len = %"PRIu32"", cw_tq_length_internal(gen->tq));
2456 }
2457
2458 return rv;
2459 }
2460
2461
2462
2463
2464
2465 /**
2466 Helper function intended to hide details of tone queue and of
2467 enqueueing a tone from cw_key module.
2468
2469 'key' is a verb here. The function should be called only on "key
2470 up" (begin space) event from hardware straight key.
2471
2472 The function is called in very specific context, see cw_key module
2473 for details.
2474
2475 \param gen - generator
2476
2477 \return CW_SUCCESS on success
2478 \return CW_FAILURE on failure
2479 */
cw_gen_key_begin_space_internal(cw_gen_t * gen)2480 int cw_gen_key_begin_space_internal(cw_gen_t *gen)
2481 {
2482 if (gen->audio_system == CW_AUDIO_CONSOLE) {
2483 /* Play just a bit of silence, just to switch
2484 buzzer from playing a sound to being silent. */
2485 cw_tone_t tone;
2486 CW_TONE_INIT(&tone, 0, gen->quantum_len, CW_SLOPE_MODE_NO_SLOPES);
2487 return cw_tq_enqueue_internal(gen->tq, &tone);
2488 } else {
2489 /* For soundcards a falling slope with volume from max
2490 to zero should be enough, but... */
2491 cw_tone_t tone;
2492 CW_TONE_INIT(&tone, gen->frequency, gen->tone_slope.len, CW_SLOPE_MODE_FALLING_SLOPE);
2493 int rv = cw_tq_enqueue_internal(gen->tq, &tone);
2494
2495 if (rv == CW_SUCCESS) {
2496 /* ... but on some occasions, on some
2497 platforms, some sound systems may need to
2498 constantly play "silent" tone. These four
2499 lines of code are just for them.
2500
2501 It would be better to avoid queueing silent
2502 "forever" tone because this increases CPU
2503 usage. It would be better to simply not to
2504 queue any new tones after "falling slope"
2505 tone. Silence after the last falling slope
2506 would simply last on itself until there is
2507 new tone on queue to play. */
2508 CW_TONE_INIT(&tone, 0, gen->quantum_len, CW_SLOPE_MODE_NO_SLOPES);
2509 tone.forever = true;
2510 rv = cw_tq_enqueue_internal(gen->tq, &tone);
2511 }
2512
2513 return rv;
2514 }
2515 }
2516
2517
2518
2519
2520
2521 /**
2522 Helper function intended to hide details of tone queue and of
2523 enqueueing a tone from cw_key module.
2524
2525 'key' is a verb here. It indicates, that the function should be
2526 called on hardware key events only. Since we enqueue symbols, we
2527 know that they have limited, specified length. This means that the
2528 function should be called for events from iambic keyer.
2529
2530 'Pure' means without any end-of-mark spaces.
2531
2532 The function is called in very specific context, see cw_key module
2533 for details.
2534
2535 \param gen - generator
2536 \param symbol - symbol to enqueue (Space/Dot/Dash)
2537
2538 \return CW_SUCCESS on success
2539 \return CW_FAILURE on failure
2540 */
cw_gen_key_pure_symbol_internal(cw_gen_t * gen,char symbol)2541 int cw_gen_key_pure_symbol_internal(cw_gen_t *gen, char symbol)
2542 {
2543 cw_tone_t tone;
2544
2545 if (symbol == CW_DOT_REPRESENTATION) {
2546 CW_TONE_INIT(&tone, gen->frequency, gen->dot_len, CW_SLOPE_MODE_STANDARD_SLOPES);
2547
2548 } else if (symbol == CW_DASH_REPRESENTATION) {
2549 CW_TONE_INIT(&tone, gen->frequency, gen->dash_len, CW_SLOPE_MODE_STANDARD_SLOPES);
2550
2551 } else if (symbol == CW_SYMBOL_SPACE) {
2552 CW_TONE_INIT(&tone, 0, gen->eom_space_len, CW_SLOPE_MODE_NO_SLOPES);
2553
2554 } else {
2555 cw_assert (0, "unknown key symbol '%d'", symbol);
2556 }
2557
2558 return cw_tq_enqueue_internal(gen->tq, &tone);
2559 }
2560
2561
2562
2563
2564
2565 /* *** Unit tests *** */
2566
2567
2568
2569
2570
2571 #ifdef LIBCW_UNIT_TESTS
2572
2573
2574 #include "libcw_test.h"
2575
2576
2577
2578
2579
2580 /**
2581 tests::cw_gen_new_internal()
2582 tests::cw_gen_delete_internal()
2583 */
test_cw_gen_new_delete_internal(void)2584 unsigned int test_cw_gen_new_delete_internal(void)
2585 {
2586 int p = fprintf(stdout, "libcw/gen: cw_gen_new/start/stop/delete_internal():\n");
2587 fflush(stdout);
2588
2589 /* Arbitrary number of calls to a set of tested functions. */
2590 int n = 100;
2591
2592 /* new() + delete() */
2593 for (int i = 0; i < n; i++) {
2594 fprintf(stderr, "libcw/gen: generator test 1/4, loop #%d/%d\n", i, n);
2595
2596 cw_gen_t *gen = cw_gen_new_internal(CW_AUDIO_NULL, NULL);
2597 cw_assert (gen, "failed to initialize generator (loop #%d)", i);
2598
2599 /* Try to access some fields in cw_gen_t just to be
2600 sure that the gen has been allocated properly. */
2601 cw_assert (gen->buffer_sub_start == 0, "buffer_sub_start in new generator is not at zero");
2602 gen->buffer_sub_stop = gen->buffer_sub_start + 10;
2603 cw_assert (gen->buffer_sub_stop == 10, "buffer_sub_stop didn't store correct new value");
2604
2605 cw_assert (gen->client.name == (char *) NULL, "initial value of generator's client name is not NULL");
2606
2607 cw_assert (gen->tq, "tone queue is NULL");
2608
2609 cw_gen_delete_internal(&gen);
2610 cw_assert (gen == NULL, "delete() didn't set the pointer to NULL (loop #%d)", i);
2611 }
2612
2613
2614 n = 5;
2615
2616
2617 /* new() + start() + delete() (skipping stop() on purpose). */
2618 for (int i = 0; i < n; i++) {
2619 fprintf(stderr, "libcw/gen: generator test 2/4, loop #%d/%d\n", i, n);
2620
2621 cw_gen_t *gen = cw_gen_new_internal(CW_AUDIO_NULL, NULL);
2622 cw_assert (gen, "failed to initialize generator (loop #%d)", i);
2623
2624 int rv = cw_gen_start_internal(gen);
2625 cw_assert (rv, "failed to start generator (loop #%d)", i);
2626
2627 cw_gen_delete_internal(&gen);
2628 cw_assert (gen == NULL, "delete() didn't set the pointer to NULL (loop #%d)", i);
2629 }
2630
2631
2632 /* new() + stop() + delete() (skipping start() on purpose). */
2633 fprintf(stderr, "libcw/gen: generator test 3/4\n");
2634 for (int i = 0; i < n; i++) {
2635 cw_gen_t *gen = cw_gen_new_internal(CW_AUDIO_NULL, NULL);
2636 cw_assert (gen, "failed to initialize generator (loop #%d)", i);
2637
2638 int rv = cw_gen_stop_internal(gen);
2639 cw_assert (rv, "failed to stop generator (loop #%d)", i);
2640
2641 cw_gen_delete_internal(&gen);
2642 cw_assert (gen == NULL, "delete() didn't set the pointer to NULL (loop #%d)", i);
2643 }
2644
2645
2646 /* Inner loop limit. */
2647 int m = n;
2648
2649
2650 /* new() + start() + stop() + delete() */
2651 for (int i = 0; i < n; i++) {
2652 fprintf(stderr, "libcw/gen: generator test 4/4, loop #%d/%d\n", i, n);
2653
2654 cw_gen_t *gen = cw_gen_new_internal(CW_AUDIO_NULL, NULL);
2655 cw_assert (gen, "failed to initialize generator (loop #%d)", i);
2656
2657 for (int j = 0; j < m; j++) {
2658 int rv = cw_gen_start_internal(gen);
2659 cw_assert (rv, "failed to start generator (loop #%d-%d)", i, j);
2660
2661 rv = cw_gen_stop_internal(gen);
2662 cw_assert (rv, "failed to stop generator (loop #%d-%d)", i, j);
2663 }
2664
2665 cw_gen_delete_internal(&gen);
2666 cw_assert (gen == NULL, "delete() didn't set the pointer to NULL (loop #%d)", i);
2667 }
2668
2669
2670 p = fprintf(stdout, "libcw/gen: cw_gen_new/start/stop/delete_internal():");
2671 CW_TEST_PRINT_TEST_RESULT(false, p);
2672 fflush(stdout);
2673
2674 return 0;
2675 }
2676
2677
2678
2679
test_cw_generator_set_tone_slope(void)2680 unsigned int test_cw_generator_set_tone_slope(void)
2681 {
2682 int p = fprintf(stdout, "libcw/gen: cw_generator_set_tone_slope():");
2683
2684 int audio_system = CW_AUDIO_NULL;
2685
2686 /* Test 0: test property of newly created generator. */
2687 {
2688 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2689 cw_assert (gen, "failed to initialize generator in test 0");
2690
2691
2692 cw_assert (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_RAISED_COSINE,
2693 "new generator has unexpected initial slope shape %d", gen->tone_slope.shape);
2694 cw_assert (gen->tone_slope.len == CW_AUDIO_SLOPE_LEN,
2695 "new generator has unexpected initial slope length %d", gen->tone_slope.len);
2696
2697
2698 cw_gen_delete_internal(&gen);
2699 }
2700
2701
2702
2703 /* Test A: pass conflicting arguments.
2704
2705 "A: If you pass to function conflicting values of \p
2706 slope_shape and \p slope_len, the function will return
2707 CW_FAILURE. These conflicting values are rectangular slope
2708 shape and larger than zero slope length. You just can't
2709 have rectangular slopes that have non-zero length." */
2710 {
2711 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2712 cw_assert (gen, "failed to initialize generator in test A");
2713
2714
2715 int rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_RECTANGULAR, 10);
2716 cw_assert (!rv, "function accepted conflicting arguments");
2717
2718
2719 cw_gen_delete_internal(&gen);
2720 }
2721
2722
2723
2724 /* Test B: pass '-1' as both arguments.
2725
2726 "B: If you pass to function '-1' as value of both \p
2727 slope_shape and \p slope_len, the function won't change
2728 any of the related two generator's parameters." */
2729 {
2730 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2731 cw_assert (gen, "failed to initialize generator in test B");
2732
2733
2734 int shape_before = gen->tone_slope.shape;
2735 int len_before = gen->tone_slope.len;
2736
2737 int rv = cw_generator_set_tone_slope(gen, -1, -1);
2738 cw_assert (rv, "failed to set tone slope");
2739
2740 cw_assert (gen->tone_slope.shape == shape_before,
2741 "tone slope shape changed from %d to %d", shape_before, gen->tone_slope.shape);
2742
2743 cw_assert (gen->tone_slope.len == len_before,
2744 "tone slope length changed from %d to %d", len_before, gen->tone_slope.len);
2745
2746
2747 cw_gen_delete_internal(&gen);
2748 }
2749
2750
2751
2752 /* Test C1
2753
2754 "C1: If you pass to function '-1' as value of either \p
2755 slope_shape or \p slope_len, the function will attempt to
2756 set only this generator's parameter that is different than
2757 '-1'." */
2758 {
2759 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2760 cw_assert (gen, "failed to initialize generator in test C1");
2761
2762
2763 /* At the beginning of test these values are
2764 generator's initial values. As test progresses,
2765 some other values will be expected after successful
2766 calls to tested function. */
2767 int expected_shape = CW_TONE_SLOPE_SHAPE_RAISED_COSINE;
2768 int expected_len = CW_AUDIO_SLOPE_LEN;
2769
2770
2771 /* At this point generator should have initial values
2772 of its parameters (yes, that's test zero again). */
2773 cw_assert (gen->tone_slope.shape == expected_shape,
2774 "new generator has unexpected initial slope shape %d", gen->tone_slope.shape);
2775 cw_assert (gen->tone_slope.len == expected_len,
2776 "new generator has unexpected initial slope length %d", gen->tone_slope.len);
2777
2778
2779 /* Set only new slope shape. */
2780 expected_shape = CW_TONE_SLOPE_SHAPE_LINEAR;
2781 int rv = cw_generator_set_tone_slope(gen, expected_shape, -1);
2782 cw_assert (rv, "failed to set linear slope shape with unchanged slope length");
2783
2784 /* At this point only slope shape should be updated. */
2785 cw_assert (gen->tone_slope.shape == expected_shape,
2786 "failed to set new shape of slope; shape is %d", gen->tone_slope.shape);
2787 cw_assert (gen->tone_slope.len == expected_len,
2788 "failed to preserve slope length; length is %d", gen->tone_slope.len);
2789
2790
2791 /* Set only new slope length. */
2792 expected_len = 30;
2793 rv = cw_generator_set_tone_slope(gen, -1, expected_len);
2794 cw_assert (rv, "failed to set positive slope length with unchanged slope shape");
2795
2796 /* At this point only slope length should be updated
2797 (compared to previous function call). */
2798 cw_assert (gen->tone_slope.shape == expected_shape,
2799 "failed to preserve shape of slope; shape is %d", gen->tone_slope.shape);
2800 cw_assert (gen->tone_slope.len == expected_len,
2801 "failed to set new slope length; length is %d", gen->tone_slope.len);
2802
2803
2804 /* Set only new slope shape. */
2805 expected_shape = CW_TONE_SLOPE_SHAPE_SINE;
2806 rv = cw_generator_set_tone_slope(gen, expected_shape, -1);
2807 cw_assert (rv, "failed to set new slope shape with unchanged slope length");
2808
2809 /* At this point only slope shape should be updated
2810 (compared to previous function call). */
2811 cw_assert (gen->tone_slope.shape == expected_shape,
2812 "failed to set new shape of slope; shape is %d", gen->tone_slope.shape);
2813 cw_assert (gen->tone_slope.len == expected_len,
2814 "failed to preserve slope length; length is %d", gen->tone_slope.len);
2815
2816
2817 cw_gen_delete_internal(&gen);
2818 }
2819
2820
2821
2822 /* Test C2
2823
2824 "C2: However, if selected slope shape is rectangular,
2825 function will set generator's slope length to zero, even if
2826 value of \p slope_len is '-1'." */
2827 {
2828 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2829 cw_assert (gen, "failed to initialize generator in test C2");
2830
2831
2832 /* At the beginning of test these values are
2833 generator's initial values. As test progresses,
2834 some other values will be expected after successful
2835 calls to tested function. */
2836 int expected_shape = CW_TONE_SLOPE_SHAPE_RAISED_COSINE;
2837 int expected_len = CW_AUDIO_SLOPE_LEN;
2838
2839
2840 /* At this point generator should have initial values
2841 of its parameters (yes, that's test zero again). */
2842 cw_assert (gen->tone_slope.shape == expected_shape,
2843 "new generator has unexpected initial slope shape %d", gen->tone_slope.shape);
2844 cw_assert (gen->tone_slope.len == expected_len,
2845 "new generator has unexpected initial slope length %d", gen->tone_slope.len);
2846
2847
2848 /* Set only new slope shape. */
2849 expected_shape = CW_TONE_SLOPE_SHAPE_RECTANGULAR;
2850 expected_len = 0; /* Even though we won't pass this to function, this is what we expect to get after this call. */
2851 int rv = cw_generator_set_tone_slope(gen, expected_shape, -1);
2852 cw_assert (rv, "failed to set rectangular slope shape with unchanged slope length");
2853
2854 /* At this point slope shape AND slope length should
2855 be updated (slope length is updated only because of
2856 requested rectangular slope shape). */
2857 cw_assert (gen->tone_slope.shape == expected_shape,
2858 "failed to set new shape of slope; shape is %d", gen->tone_slope.shape);
2859 cw_assert (gen->tone_slope.len == expected_len,
2860 "failed to get expected slope length; length is %d", gen->tone_slope.len);
2861
2862
2863 cw_gen_delete_internal(&gen);
2864 }
2865
2866
2867
2868 /* Test D
2869
2870 "D: Notice that the function allows non-rectangular slope
2871 shape with zero length of the slopes. The slopes will be
2872 non-rectangular, but just unusually short." */
2873 {
2874 cw_gen_t *gen = cw_gen_new_internal(audio_system, NULL);
2875 cw_assert (gen, "failed to initialize generator in test D");
2876
2877
2878 int rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_LINEAR, 0);
2879 cw_assert (rv, "failed to set linear slope with zero length");
2880 cw_assert (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_LINEAR,
2881 "failed to set linear slope shape; shape is %d", gen->tone_slope.shape);
2882 cw_assert (gen->tone_slope.len == 0,
2883 "failed to set zero slope length; length is %d", gen->tone_slope.len);
2884
2885
2886 rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_RAISED_COSINE, 0);
2887 cw_assert (rv, "failed to set raised cosine slope with zero length");
2888 cw_assert (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_RAISED_COSINE,
2889 "failed to set raised cosine slope shape; shape is %d", gen->tone_slope.shape);
2890 cw_assert (gen->tone_slope.len == 0,
2891 "failed to set zero slope length; length is %d", gen->tone_slope.len);
2892
2893
2894 rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_SINE, 0);
2895 cw_assert (rv, "failed to set sine slope with zero length");
2896 cw_assert (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_SINE,
2897 "failed to set sine slope shape; shape is %d", gen->tone_slope.shape);
2898 cw_assert (gen->tone_slope.len == 0,
2899 "failed to set zero slope length; length is %d", gen->tone_slope.len);
2900
2901
2902 rv = cw_generator_set_tone_slope(gen, CW_TONE_SLOPE_SHAPE_RECTANGULAR, 0);
2903 cw_assert (rv, "failed to set rectangular slope with zero length");
2904 cw_assert (gen->tone_slope.shape == CW_TONE_SLOPE_SHAPE_RECTANGULAR,
2905 "failed to set rectangular slope shape; shape is %d", gen->tone_slope.shape);
2906 cw_assert (gen->tone_slope.len == 0,
2907 "failed to set zero slope length; length is %d", gen->tone_slope.len);
2908
2909
2910 cw_gen_delete_internal(&gen);
2911 }
2912
2913
2914 CW_TEST_PRINT_TEST_RESULT(false, p);
2915
2916 return 0;
2917 }
2918
2919
2920
2921
2922
2923 /* Test some assertions about CW_TONE_SLOPE_SHAPE_*
2924
2925 Code in this file depends on the fact that these values are
2926 different than -1. I think that ensuring that they are in general
2927 small, non-negative values is a good idea.
2928
2929 I'm testing these values to be sure that when I get a silly idea to
2930 modify them, the test will catch this modification.
2931 */
test_cw_gen_tone_slope_shape_enums(void)2932 unsigned int test_cw_gen_tone_slope_shape_enums(void)
2933 {
2934 int p = fprintf(stdout, "libcw/gen: CW_TONE_SLOPE_SHAPE_*:");
2935
2936 cw_assert (CW_TONE_SLOPE_SHAPE_LINEAR >= 0, "CW_TONE_SLOPE_SHAPE_LINEAR is negative: %d", CW_TONE_SLOPE_SHAPE_LINEAR);
2937 cw_assert (CW_TONE_SLOPE_SHAPE_RAISED_COSINE >= 0, "CW_TONE_SLOPE_SHAPE_RAISED_COSINE is negative: %d", CW_TONE_SLOPE_SHAPE_RAISED_COSINE);
2938 cw_assert (CW_TONE_SLOPE_SHAPE_SINE >= 0, "CW_TONE_SLOPE_SHAPE_SINE is negative: %d", CW_TONE_SLOPE_SHAPE_SINE);
2939 cw_assert (CW_TONE_SLOPE_SHAPE_RECTANGULAR >= 0, "CW_TONE_SLOPE_SHAPE_RECTANGULAR is negative: %d", CW_TONE_SLOPE_SHAPE_RECTANGULAR);
2940
2941 CW_TEST_PRINT_TEST_RESULT(false, p);
2942
2943 return 0;
2944 }
2945
2946
2947
2948
2949
2950 /* Version of test_cw_gen_forever() to be used in libcw_test_internal
2951 test executable.
2952
2953 It's not a test of a "forever" function, but of "forever"
2954 functionality.
2955 */
test_cw_gen_forever_internal(void)2956 unsigned int test_cw_gen_forever_internal(void)
2957 {
2958 int seconds = 2;
2959 int p = fprintf(stdout, "libcw/gen: forever tone (%d seconds):", seconds);
2960 fflush(stdout);
2961
2962 unsigned int rv = test_cw_gen_forever_sub(2, CW_AUDIO_NULL, (const char *) NULL);
2963 cw_assert (rv == 0, "\"forever\" test failed");
2964
2965 CW_TEST_PRINT_TEST_RESULT(false, p);
2966
2967 return 0;
2968 }
2969
2970
2971
2972
2973
test_cw_gen_forever_sub(int seconds,int audio_system,const char * audio_device)2974 unsigned int test_cw_gen_forever_sub(int seconds, int audio_system, const char *audio_device)
2975 {
2976 cw_gen_t *gen = cw_gen_new_internal(audio_system, audio_device);
2977 cw_assert (gen, "ERROR: failed to create generator\n");
2978 cw_gen_start_internal(gen);
2979 sleep(1);
2980
2981 cw_tone_t tone;
2982 /* Just some acceptable values. */
2983 int len = 100; /* [us] */
2984 int freq = 500;
2985
2986 CW_TONE_INIT(&tone, freq, len, CW_SLOPE_MODE_RISING_SLOPE);
2987 cw_tq_enqueue_internal(gen->tq, &tone);
2988
2989 CW_TONE_INIT(&tone, freq, gen->quantum_len, CW_SLOPE_MODE_NO_SLOPES);
2990 tone.forever = true;
2991 int rv = cw_tq_enqueue_internal(gen->tq, &tone);
2992
2993 #ifdef __FreeBSD__ /* Tested on FreeBSD 10. */
2994 /* Separate path for FreeBSD because for some reason signals
2995 badly interfere with value returned through second arg to
2996 nanolseep(). Try to run the section in #else under FreeBSD
2997 to see what happens - value returned by nanosleep() through
2998 "rem" will be increasing. */
2999 fprintf(stderr, "enter any character to end \"forever\" tone\n");
3000 char c;
3001 scanf("%c", &c);
3002 #else
3003 struct timespec t;
3004 cw_usecs_to_timespec_internal(&t, seconds * CW_USECS_PER_SEC);
3005 cw_nanosleep_internal(&t);
3006 #endif
3007
3008 CW_TONE_INIT(&tone, freq, len, CW_SLOPE_MODE_FALLING_SLOPE);
3009 rv = cw_tq_enqueue_internal(gen->tq, &tone);
3010 cw_assert (rv, "failed to enqueue last tone");
3011
3012 cw_gen_delete_internal(&gen);
3013
3014 return 0;
3015 }
3016
3017
3018
3019
3020
3021 #endif /* #ifdef LIBCW_UNIT_TESTS */
3022