1 /*!
2  * Fixed-point tone generator.
3  *
4  * The code here implements a simple fixed-point tone generator that uses
5  * integer arithmetic to generate a sinusoid at a fixed sample rate of
6  * 16kHz.
7  *
8  * To set the initial state of the state machine, you specify a frequency
9  * and duration using tone_reset.  The corresponding C file embeds a
10  * sinusoid look-up table.  The total number of samples is computed for
11  * the given time and used to initialise 'remain', 'time' is initialised
12  * to 0, and 'step' gives the amount to increment 'time' by each iteration.
13  *
14  * The samples are retrieved by repeatedly calling tone_next.  This
15  * advances 'time' and decrements 'remain'.  The tone is complete when
16  * 'remain' is zero.
17  *
18  * Author Stuart Longland <me@vk4msl.id.au>
19  * Copyright (C) 2015 FreeDV project.
20  *
21  * This program is free software; you can redistribute it and/or modify it
22  * under the terms of the GNU Lesser General Public License version 2.1,
23  * as published by the Free Software Foundation.  This program is
24  * distributed in the hope that it will be useful, but WITHOUT ANY
25  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
26  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
27  * for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public
30  * License along with this program; if not, see
31  * <http://www.gnu.org/licenses/>.
32  */
33 
34 #include "tone.h"
35 
36 /*! Fixed-point shift factor */
37 #define TONE_SHIFT	(12)
38 
39 /*! Static compiled quarter-sinusoid. */
40 static const int16_t partial_sine[] = {
41    830,   2488,   4140,   5781,   7407,   9014,  10598,  12155,
42  13681,  15171,  16623,  18031,  19394,  20707,  21967,  23170,
43  24314,  25395,  26411,  27360,  28238,  29043,  29774,  30429,
44  31006,  31503,  31919,  32253,  32504,  32672,  32756
45 };
46 
47 /*! Length of quarter-sinusoid in samples */
48 #define TONE_PART_SINE_LEN	(sizeof(partial_sine)\
49 			/sizeof(partial_sine[0]))
50 
51 /*! Total length of sinusoid */
52 #define TONE_SINE_LEN	((TONE_PART_SINE_LEN*4)+4)
53 
54 /*!
55  * Generate a sine from the quarter-waveform.
56  */
tone_sine(uint8_t sample)57 static int16_t tone_sine(uint8_t sample)
58 {
59 	/* Key points */
60 	if ((sample % (TONE_SINE_LEN/2)) == 0)
61 		/* Zero crossings */
62 		return 0;
63 	if (sample == TONE_SINE_LEN/4)
64 		/* Maximum */
65 		return INT16_MAX;
66 	if (sample == (3*TONE_SINE_LEN)/4)
67 		/* Minimum */
68 		return INT16_MIN;
69 
70 	if (sample < TONE_SINE_LEN/4)
71 		/* First quarter of sine wave */
72 		return partial_sine[sample-1];
73 
74 	if (sample < (TONE_SINE_LEN/2))
75 		/* Second quarter */
76 		return partial_sine[(TONE_SINE_LEN/2)-sample-1];
77 	if (sample < ((3*TONE_SINE_LEN)/4))
78 		/* Third quarter */
79 		return -partial_sine[(sample-3) % TONE_PART_SINE_LEN];
80 	if (sample < TONE_SINE_LEN)
81 		/* Final quarter */
82 		return -partial_sine[TONE_SINE_LEN-sample-1];
83 	/* We should not get here */
84 	return 0;
85 }
86 
87 /*!
88  * Re-set the tone generator.
89  *
90  * @param	tone_gen	Tone generator to reset.
91  * @param	freq		Frequency in Hz, 0 = silence.
92  * @param	duration	Duration in milliseconds.  0 to stop.
93  */
tone_reset(struct tone_gen_t * const tone_gen,uint16_t freq,uint16_t duration)94 void tone_reset(
95 	struct tone_gen_t* const tone_gen,
96 	uint16_t freq, uint16_t duration)
97 {
98 	if (freq)
99 		/* Compute the time step */
100 		tone_gen->step = (((2*freq*TONE_SINE_LEN) << TONE_SHIFT)
101 				/ ((2*TONE_FS) + 1) + 1);
102 	else
103 		/* DC tone == silence */
104 		tone_gen->step = 0;
105 
106 	/* Compute remaining samples */
107 	tone_gen->remain = (uint16_t)(
108 			((uint32_t)(TONE_FS * duration)) / 1000);
109 
110 	/* Initialise the sample counter */
111 	tone_gen->sample = 0;
112 }
113 
114 /*!
115  * Retrieve the next sample from the tone generator.
116  * @param	tone_gen	Tone generator to update.
117  */
tone_next(struct tone_gen_t * const tone_gen)118 int16_t tone_next(
119 	struct tone_gen_t* const tone_gen)
120 {
121 	if (!tone_gen)
122 		return 0;
123 	if (!tone_gen->remain)
124 		return 0;
125 	if (!tone_gen->step) {
126 		/* Special case, emit silence */
127 		tone_gen->remain--;
128 		return 0;
129 	}
130 
131 	/* Compute sample index */
132 	uint16_t sample_int = ((tone_gen->sample) >> TONE_SHIFT)
133 				% TONE_SINE_LEN;
134 
135 	/* Advance tone generator state */
136 	tone_gen->sample += tone_gen->step;
137 	tone_gen->remain--;
138 
139 	return tone_sine(sample_int);
140 }
141 
142 /*!
143  * Retrieve the current time in milliseconds.
144  */
tone_msec(const struct tone_gen_t * const tone_gen)145 uint32_t tone_msec(const struct tone_gen_t* const tone_gen)
146 {
147 	uint64_t ms = tone_gen->sample;
148 	ms *= 1000;
149 	ms /= TONE_FS;
150 	return ms >> TONE_SHIFT;
151 }
152