summaryrefslogtreecommitdiffstats
path: root/dogwhistle.c
blob: 894d7e3a9a69eafaa4deab05cfe30cb0c8648195 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/* See LICENSE file for copyright and license details. */
#include "common.h"
#include <alsa/asoundlib.h>
#include <math.h>

/* TODO add support for 12, 14, 18 and 20, 22 kHz in addition to 16 kHz as well as custom frequencies */
/* TODO add support for selecting output device and backend */
/* TODO add support for selecting volume */
/* TODO add support for pausing and exiting */
/* TODO prefer loudspeakers over headphones */
/* TODO use bus to listen for incoming phone calls and pause when arriving */

#define UTYPE   uint32_t
#define SMAX    INT32_MAX
#define FORMAT  SND_PCM_FORMAT_U32

#define SAMPLE_RATE  52000   /* Hz */
#define LATENCY      100000  /* µs */

USAGE("");


int
main(int argc, char *argv[])
{
	UTYPE *buffer;
	snd_pcm_uframes_t i, buflen, wavelen;
	snd_pcm_sframes_t n;
	snd_pcm_t *sound_handle = NULL;
	double freq = 16000;
	double volume = (double)0.1f, imul, omul;
	int r;

	NOFLAGS(argc);

	/* Set up audio */
	r = snd_pcm_open(&sound_handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
	if (r < 0)
		eprintf("snd_pcm_open: %s\n", snd_strerror(r));
	if (!sound_handle)
		eprintf("snd_pcm_open:");

	/* Configure audio */
	r = snd_pcm_set_params(sound_handle, FORMAT, SND_PCM_ACCESS_RW_INTERLEAVED, 1 /* channels */,
	                       SAMPLE_RATE, 1 /* allow resampling? */, LATENCY);
	if (r < 0)
		eprintf("snd_pcm_set_params: %s\n", snd_strerror(r));

	/* Generate tone */
	buflen = wavelen = (snd_pcm_uframes_t)((double)SAMPLE_RATE / freq);
	if ((snd_pcm_uframes_t)freq > 1)
		buflen *= (snd_pcm_uframes_t)freq;
	buffer = emallocn((size_t)buflen, sizeof(*buffer), 0);
	omul = volume * SMAX * 2;
#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunsuffixed-float-constants"
#endif
	imul = 2 * M_PI * freq / (double)SAMPLE_RATE;
#ifdef __GNUC__
# pragma GCC diagnostic pop
#endif
	for (i = 0; i < wavelen; i++)
		buffer[i] = (UTYPE)(sin(imul * (double)i) * omul + SMAX);
	for (i = wavelen; i < buflen; i += wavelen)
		memcpy(&buffer[i], &buffer[0], wavelen * sizeof(UTYPE));

	/* Play tone */
	for (;;) {
		n = snd_pcm_writei(sound_handle, buffer, buflen);
		if (n < 0)
			n = snd_pcm_recover(sound_handle, (int)n, 0 /* do not print error reason? */);
		if (n < 0)
			eprintf("snd_pcm_writei: %s\n", snd_strerror((int)n));
		if (n > 0 && (snd_pcm_uframes_t)n < buflen)
			eprintf("short write from snd_pcm_writei\n");
	}

	snd_pcm_close(sound_handle);
	return 0;
}