1 // ----------------------------------------------------------------------------
2 // tune.cxx  -- create a single sinewave output with controlled start/end shape
3 //
4 // Copyright (C) 2006-2007
5 //		Dave Freese, W1HKJ
6 //
7 // This file is part of fldigi.
8 //
9 // Fldigi is free software: you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 3 of the License, or
12 // (at your option) any later version.
13 //
14 // Fldigi is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with fldigi.  If not, see <http://www.gnu.org/licenses/>.
21 // ----------------------------------------------------------------------------
22 
23 #include <math.h>
24 #include "sound.h"
25 #include "confdialog.h"
26 
27 #include "test_signal.h"
28 
29 namespace xmttune {
30 
31 // use same wave shaping for tune key down / key up as for the CW tx_process
32 // produces a 4 msec leading / trailing edge
33 #define KNUM 32
34 // keydown wave shape
35 
36 double kdshape[KNUM] = {
37 	0.00240750255310301, 0.00960708477768751,
38 	0.02152941088003600, 0.03805966253618680,
39 	0.05903864465505320, 0.08426431851158830,
40 	0.11349374748686800, 0.14644543667658500,
41 	0.18280204383628200, 0.22221343555548300,
42 	0.26430005922814900, 0.30865659834558700,
43 	0.35485587590940700, 0.40245296837259500,
44 	0.45098949048925500, 0.49999800980765500,
45 	0.54900654829266300, 0.59754312772456200,
46 	0.64514031509964400, 0.69133972425796200,
47 	0.73569643038517400, 0.77778325487450100,
48 	0.81719487928327800, 0.85355174876454100,
49 	0.88650372738152000, 0.91573347010241700,
50 	0.94095947900139100, 0.96193881423287900,
51 	0.97846943367117300, 0.99039213868324900,
52 	0.99759210729604500, 0.99999999999295900
53 };
54 
55 // keyup wave shape
56 double kushape[KNUM] = {
57 	0.99999999999295900, 0.99759210729604500,
58 	0.99039213868324900, 0.97846943367117300,
59 	0.96193881423287900, 0.94095947900139100,
60 	0.91573347010241700, 0.88650372738152000,
61 	0.85355174876454100, 0.81719487928327800,
62 	0.77778325487450100, 0.73569643038517400,
63 	0.69133972425796200, 0.64514031509964400,
64 	0.59754312772456200, 0.54900654829266300,
65 	0.49999800980765500, 0.45098949048925500,
66 	0.40245296837259500, 0.35485587590940700,
67 	0.30865659834558700, 0.26430005922814900,
68 	0.22221343555548300, 0.18280204383628200,
69 	0.14644543667658500, 0.11349374748686800,
70 	0.08426431851158830, 0.05903864465505320,
71 	0.03805966253618680, 0.02152941088003600,
72 	0.00960708477768751, 0.00240750255310301
73 };
74 
75 #define BUFLEN 512
76 double phaseacc = 0.0;
77 double phaseincr = 0.0;
78 double pttacc = 0.0;
79 double outbuf[BUFLEN];
80 double pttbuf[BUFLEN];
81 
82 //===========================================================================
83 
nco()84 inline double nco()
85 {
86 	phaseacc += phaseincr;
87 	if (phaseacc > TWOPI) phaseacc -= TWOPI;
88 	return cos(phaseacc);
89 }
90 
pttnco()91 inline double pttnco()
92 {
93 	pttacc += TWOPI * 1000 / active_modem->get_samplerate();
94 	if (pttacc > TWOPI) pttacc -= TWOPI;
95 	return sin(pttacc);
96 }
97 
98 
99 //=====================================================================
100 
101 
102 //=====================================================================
103 
keydown(double freq,SoundBase * scard)104 void keydown(double freq, SoundBase *scard)
105 {
106 	int i;
107 	phaseincr = 2.0 * M_PI * freq / active_modem->get_samplerate();
108 	for (i = 0; i < KNUM; i++){
109 		outbuf[i] = nco() * kdshape[i];
110 		pttbuf[i] = pttnco();
111 	}
112 	for (; i < BUFLEN; i++) {
113 		outbuf[i] = nco();
114 		pttbuf[i] = pttnco();
115 	}
116 	if ((active_modem == cw_modem) && progdefaults.QSK) {
117 		active_modem->ModulateStereo(
118 			outbuf, pttbuf,
119 			BUFLEN, false);
120 	} else {
121 		active_modem->ModulateXmtr(outbuf, BUFLEN);
122 	}
123 }
124 
125 //=====================================================================
126 
keyup(double freq,SoundBase * scard)127 void keyup(double freq, SoundBase *scard)
128 {
129 	int i;
130 	phaseincr = 2.0 * M_PI * freq / active_modem->get_samplerate();
131 	for (i = 0; i < KNUM; i++) {
132 		outbuf[i] = nco() * kushape[i];
133 		pttbuf[i] = pttnco();
134 	}
135 	for (; i < BUFLEN; i++) {
136 		outbuf[i] = 0.0;
137 		pttbuf[i] = pttnco();
138 	}
139 	if ((active_modem == cw_modem) && progdefaults.QSK) {
140 		active_modem->ModulateStereo(
141 			outbuf, pttbuf,
142 			BUFLEN, false);
143 	} else {
144 		active_modem->ModulateXmtr(outbuf, BUFLEN);
145 	}
146 }
147 
148 //=====================================================================
149 
tune(double freq,SoundBase * scard)150 void tune(double freq, SoundBase *scard)
151 {
152 	int i;
153 
154 	if (test_signal_window && test_signal_window->visible() && btnOffsetOn->value())
155 		freq += ctrl_freq_offset->value();
156 
157 	phaseincr = 2.0 * M_PI * freq / active_modem->get_samplerate();
158 
159 	for (i = 0; i < BUFLEN; i++) {
160 		outbuf[i] = nco();
161 		pttbuf[i] = pttnco();
162 	}
163 	if ((active_modem == cw_modem) && progdefaults.QSK) {
164 		active_modem->ModulateStereo(
165 			outbuf, pttbuf,
166 			BUFLEN, false);
167 	} else {
168 		active_modem->ModulateXmtr(outbuf, BUFLEN);
169 	}
170 }
171 
172 };  // namespace tune
173