1 // Copyright (c) <2012> <Leif Asbrink>
2 //
3 // Permission is hereby granted, free of charge, to any person
4 // obtaining a copy of this software and associated documentation
5 // files (the "Software"), to deal in the Software without restriction,
6 // including without limitation the rights to use, copy, modify,
7 // merge, publish, distribute, sublicense, and/or sell copies of
8 // the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
16 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
21 // OR OTHER DEALINGS IN THE SOFTWARE.
22
23
24 #include <unistd.h>
25 #include <ctype.h>
26 #include <string.h>
27
28 #include "globdef.h"
29 #include "uidef.h"
30 #include "fft1def.h"
31 #include "fft2def.h"
32 #include "fft3def.h"
33 #include "sigdef.h"
34 #include "screendef.h"
35 #include "seldef.h"
36 #include "rusage.h"
37 #include "thrdef.h"
38 #include "txdef.h"
39 #include "vernr.h"
40 #include "hwaredef.h"
41 #include "keyboard_def.h"
42
43 float tx_resamp_maxamp;
44 float tx_resamp_old_maxamp;
45 void tx_ssb_buftim(char cc);
46
tx_ssb_step2(float * totpwr)47 int tx_ssb_step2(float *totpwr)
48 {
49 int i, k;
50 float t1, t2;
51 // ************* Step 2. *************
52 // Compute the power for each bin within the passband.
53 // Apply muting in the frequency domain by setting bins with too small
54 // signal power to zero.
55 // Collect the sum of the powers from surviving bins and mute the entire
56 // block in case the total power is below threshold.
57 // Here we use the agc factor as determined from the the
58 // previous block and attenuated with the decay factor.
59 // Note that the agc factor is limited to 20 dB at this point.
60 // A big pulse will not kill the signal for a long time!!
61 t1=0;
62 k=0;
63 for(i=tx_filter_ia1; i<mic_fftsize; i++)
64 {
65 t2=micfft[micfft_px+2*i ]*micfft[micfft_px+2*i ]+
66 micfft[micfft_px+2*i+1]*micfft[micfft_px+2*i+1];
67 if(t2 > micfft_bin_minpower)
68 {
69 k++;
70 t1+=t2;
71 }
72 else
73 {
74 micfft[micfft_px+2*i ]=0;
75 micfft[micfft_px+2*i+1]=0;
76 }
77 }
78 for(i=0; i<=tx_filter_ib1; i++)
79 {
80 t2=micfft[micfft_px+2*i ]*micfft[micfft_px+2*i ]+
81 micfft[micfft_px+2*i+1]*micfft[micfft_px+2*i+1];
82 if(t2 > micfft_bin_minpower)
83 {
84 k++;
85 t1+=t2;
86 }
87 else
88 {
89 micfft[micfft_px+2*i ]=0;
90 micfft[micfft_px+2*i+1]=0;
91 }
92 }
93 if(k>0 && t1 < micfft_minpower)
94 {
95 for(i=tx_filter_ia1; i<mic_fftsize; i++)
96 {
97 micfft[micfft_px+2*i ]=0;
98 micfft[micfft_px+2*i+1]=0;
99 }
100 for(i=0; i<=tx_filter_ib1; i++)
101 {
102 micfft[micfft_px+2*i ]=0;
103 micfft[micfft_px+2*i+1]=0;
104 }
105 k=0;
106 }
107 totpwr[0]=t1;
108 return k;
109 }
110
tx_ssb_step3(float * totamp)111 void tx_ssb_step3(float *totamp)
112 {
113 int i;
114 float t1, t2, r1;
115 // ************* Step 3. *************
116 // Find out what the average amplitude would become if the old AGC
117 // factor would be applied. Change the agc factor in case the
118 // average amplitude is above the limit.
119 // Note that this step is only executed if k!=0.
120 // When k==0, the entire block is muted. The operation
121 // would be meaningless on a zero transform.
122 t1=sqrt(totamp[0]);
123 r1=pow(10.0,0.05*txssb.mic_gain);
124 t2=r1*t1*tx_agc_factor*(tx_highest_bin-tx_lowest_bin+1);
125 if(t2 > TX_AGC_THRESHOLD*(tx_highest_bin-tx_lowest_bin+1))
126 {
127 tx_agc_factor=TX_AGC_THRESHOLD/(r1*t1);
128 }
129 t2=tx_agc_factor*(tx_highest_bin-tx_lowest_bin+1)*r1;
130 t2*=pow(10.0,0.05*(txssb.mic_out_gain-60));
131 // Apply the AGC within the current fft block.
132 for(i=tx_filter_ia1; i<mic_fftsize; i++)
133 {
134 micfft[micfft_px+2*i ]*=t2;
135 micfft[micfft_px+2*i+1]*=t2;
136 }
137 for(i=0; i<=tx_filter_ib1; i++)
138 {
139 micfft[micfft_px+2*i ]*=t2;
140 micfft[micfft_px+2*i+1]*=t2;
141 }
142 totamp[0]=t1;
143 }
144
tx_ssb_step4(float ampinv,float * t1,float * prat)145 void tx_ssb_step4(float ampinv,float *t1, float *prat)
146 {
147 int i, k, panew;
148 char mute_current, mute_previous;
149 float r1, r2, t2;
150 prat[0]=0;
151 t1[0]=0;
152 if( (tx_filter_ia1&1) != 0)tx_ph1*=-1;
153 panew=(cliptimf_pa+mic_fftsize)&micfft_mask;
154 if(ampinv == 0)
155 {
156 mute_current=TRUE;
157 }
158 else
159 {
160 mute_current=FALSE;
161 }
162 cliptimf_mute[cliptimf_pa/mic_fftsize]=mute_current;
163 mute_previous=cliptimf_mute[((cliptimf_pa-mic_fftsize+micfft_bufsiz)&
164 micfft_mask)/mic_fftsize];
165 // We do nothing in case both the current transform and the
166 // previous one are muted.
167 if( (mute_current&mute_previous) == FALSE)
168 {
169 if( (mute_current|mute_previous) == FALSE)
170 {
171 // None of the transforms is muted.
172 // Do normal (continous) back transformation.
173 r1=pow(10.0,0.05*txssb.rf1_gain)/TX_AGC_THRESHOLD;
174 t2=0;
175 r1*=ampinv;
176 for(i=0; i<mic_fftsize; i+=2)
177 {
178 cliptimf[cliptimf_pa+i ]=tx_ph1*
179 (cliptimf[cliptimf_pa+i ]+r1*micfft[micfft_px+i ]);
180 cliptimf[cliptimf_pa+i+1]=tx_ph1*
181 (cliptimf[cliptimf_pa+i+1]+r1*micfft[micfft_px+i+1]);
182 t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+
183 cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1];
184 prat[0]+=t2;
185 if(t2>t1[0])t1[0]=t2;
186 if(t2 > 1)
187 {
188 t2=1/sqrt(t2);
189 cliptimf[cliptimf_pa+i ]*=t2;
190 cliptimf[cliptimf_pa+i+1]*=t2;
191 }
192 }
193 if( (tx_filter_ia1&1) != 0)r1*=-1;
194 for(i=0; i<mic_fftsize; i++)
195 {
196 cliptimf[panew+i]=r1*micfft[micfft_px+mic_fftsize+i];
197 }
198 }
199 else
200 {
201 // This is the first or the last transform.
202 // Multiply the beginning and the end with a sine squared window
203 // to make the start and end filtered with a sine to power 4
204 // window in total.
205 // The first and last transforms are likely to be incorrect
206 // because muting in the frequency domain will distort the
207 // signal if only the very strongest bins have survived
208 // the muting process. This is particularly obvious if the
209 // microphone signal is a keyed tone which is present only
210 // a short time in the last or first transform. In such a
211 // situation the signal would be extended over the entire
212 // transform in case only a single bin would survive.
213 // The added sine squared window will remove the abrupt
214 // start that the signal otherwise would have.
215 if(mute_current)
216 {
217 k=0;
218 for(i=mic_fftsize-2; i>=0; i-=2)
219 {
220 r1=micfft_winfac*micfft_win[k];
221 cliptimf[cliptimf_pa+i ]=tx_ph1*cliptimf[cliptimf_pa+i ]*r1;
222 cliptimf[cliptimf_pa+i+1]=tx_ph1*cliptimf[cliptimf_pa+i+1]*r1;
223 k++;
224 t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+
225 cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1];
226 if(t1[0] < MAX_DYNRANGE && t2 < MAX_DYNRANGE)
227 {
228 cliptimf[cliptimf_pa+i ]=0;
229 cliptimf[cliptimf_pa+i+1]=0;
230 }
231 else
232 {
233 prat[0]+=t2;
234 if(t2>t1[0])t1[0]=t2;
235 if(t2 > 1)
236 {
237 t2=1/sqrt(t2);
238 cliptimf[cliptimf_pa+i ]*=t2;
239 cliptimf[cliptimf_pa+i+1]*=t2;
240 t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+
241 cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1];
242 }
243 }
244 }
245 for(i=0; i<mic_fftsize; i++)
246 {
247 cliptimf[panew+i]=0;
248 }
249 }
250 else // if(mute_previous)
251 {
252 r1=pow(10.0,0.05*txssb.rf1_gain)/TX_AGC_THRESHOLD;
253 t2=0;
254 r1*=ampinv;
255 for(i=0; i<mic_fftsize; i+=2)
256 {
257 r2=r1*micfft_winfac*micfft_win[i>>1];
258 cliptimf[cliptimf_pa+i ]=tx_ph1*r2*micfft[micfft_px+i ];
259 cliptimf[cliptimf_pa+i+1]=tx_ph1*r2*micfft[micfft_px+i+1];
260 t2=cliptimf[cliptimf_pa+i ]*cliptimf[cliptimf_pa+i ]+
261 cliptimf[cliptimf_pa+i+1]*cliptimf[cliptimf_pa+i+1];
262 if(t1[0] < MAX_DYNRANGE && t2 < MAX_DYNRANGE)
263 {
264 cliptimf[cliptimf_pa+i ]=0;
265 cliptimf[cliptimf_pa+i+1]=0;
266 }
267 else
268 {
269 prat[0]+=t2;
270 if(t2>t1[0])t1[0]=t2;
271 if(t2 > 1)
272 {
273 t2=1/sqrt(t2);
274 cliptimf[cliptimf_pa+i ]*=t2;
275 cliptimf[cliptimf_pa+i+1]*=t2;
276 }
277 }
278 }
279 if( (tx_filter_ia1&1) != 0)r1*=-1;
280 for(i=0; i<mic_fftsize; i++)
281 {
282 cliptimf[panew+i]=r1*micfft[micfft_px+mic_fftsize+i];
283 }
284 }
285 }
286 }
287 cliptimf_pa=panew;
288 micfft_px=(micfft_px+micfft_block)&micfft_mask;
289 }
290
tx_ssb_step5(void)291 void tx_ssb_step5(void)
292 {
293 int i, j, pb, nx;
294 while( ((cliptimf_pa-cliptimf_px+micfft_bufsiz)&micfft_mask) >=
295 2*mic_fftsize)
296 {
297 pb=(cliptimf_px+2*(mic_fftsize-1))&micfft_mask;
298 nx=cliptimf_px/mic_fftsize;
299 if(cliptimf_mute[nx]==FALSE)
300 {
301 j=mic_fftsize-1;
302 for(i=0; i<mic_sizhalf; i++)
303 {
304 clipfft[clipfft_pa+2*i ]=cliptimf[cliptimf_px+2*i ]*micfft_win[i];
305 clipfft[clipfft_pa+2*i+1]=cliptimf[cliptimf_px+2*i+1]*micfft_win[i];
306 clipfft[clipfft_pa+2*j ]=cliptimf[pb ]*micfft_win[i];
307 clipfft[clipfft_pa+2*j+1]=cliptimf[pb+1]*micfft_win[i];
308 j--;
309 pb-=2;
310 }
311 fftforward(mic_fftsize, mic_fftn, &clipfft[clipfft_pa],
312 micfft_table, micfft_permute,FALSE);
313 if(tx_setup_flag == TRUE)
314 {
315 lir_sched_yield();
316 if(screen_count>=MAX_SCREENCOUNT)
317 {
318 show_txfft(&clipfft[clipfft_pa],0,1,mic_fftsize);
319 }
320 }
321 for(i=tx_filter_ib1+1; i<tx_filter_ia1; i++)
322 {
323 clipfft[clipfft_pa+2*i ]=0;
324 clipfft[clipfft_pa+2*i+1]=0;
325 }
326 clipfft_mute[clipfft_pa/alc_block]=FALSE;
327 }
328 else
329 {
330 clipfft_mute[clipfft_pa/alc_block]=TRUE;
331 }
332 cliptimf_px=(cliptimf_px+mic_fftsize)&micfft_mask;
333 clipfft_pa=(clipfft_pa+alc_block)&alc_mask;
334 }
335 }
336
tx_ssb_step6(float * prat)337 float tx_ssb_step6(float *prat)
338 {
339 int i, k, pb, mute_previous;
340 float t1, t2, pmax;
341 mute_previous=clipfft_mute[((clipfft_px-alc_block+alc_bufsiz)
342 &alc_mask)/alc_block];
343 pmax=0;
344 prat[0]=0;
345 if(clipfft_mute[clipfft_px/alc_block] == FALSE)
346 {
347 alctimf_mute[alctimf_pa/alc_fftsize]=FALSE;
348 if(mic_fftsize < alc_fftsize)
349 {
350 i=tx_filter_ia1;
351 k=tx_filter_ia2;
352 while(i<mic_fftsize)
353 {
354 clipfft[clipfft_px+2*k ]=clipfft[clipfft_px+2*i ];
355 clipfft[clipfft_px+2*k+1]=clipfft[clipfft_px+2*i+1];
356 i++;
357 k++;
358 }
359 }
360 for(i=tx_filter_ib1+1; i<tx_filter_ia2; i++)
361 {
362 clipfft[clipfft_px+2*i]=0;
363 clipfft[clipfft_px+2*i+1]=0;
364 }
365 fftback(alc_fftsize, alc_fftn, &clipfft[clipfft_px],
366 alc_table, alc_permute, FALSE);
367 if(mute_previous)
368 {
369 for(i=0; i<alc_sizhalf; i++)
370 {
371 alctimf[alctimf_pa+2*i ]=clipfft[clipfft_px+2*i ];
372
373 alctimf[alctimf_pa+2*i+1]=clipfft[clipfft_px+2*i+1];
374 t2=alctimf[alctimf_pa+2*i ]*alctimf[alctimf_pa+2*i ]+
375 alctimf[alctimf_pa+2*i+1]*alctimf[alctimf_pa+2*i+1];
376 prat[0]+=t2;
377 if(t2>pmax)pmax=t2;
378 tx_forwardpwr*=txpwr_decay;
379 if(tx_forwardpwr<t2)tx_forwardpwr=t2;
380 alctimf_pwrf[(alctimf_pa>>1)+i]=tx_forwardpwr;
381 }
382 }
383 else
384 {
385 for(i=0; i<alc_sizhalf; i++)
386 {
387 alctimf[alctimf_pa+2*i ]+=clipfft[clipfft_px+2*i ];
388 alctimf[alctimf_pa+2*i+1]+=clipfft[clipfft_px+2*i+1];
389 t2=alctimf[alctimf_pa+2*i ]*alctimf[alctimf_pa+2*i ]+
390 alctimf[alctimf_pa+2*i+1]*alctimf[alctimf_pa+2*i+1];
391 prat[0]+=t2;
392 if(t2>pmax)pmax=t2;
393 tx_forwardpwr*=txpwr_decay;
394 if(tx_forwardpwr<t2)tx_forwardpwr=t2;
395 alctimf_pwrf[(alctimf_pa>>1)+i]=tx_forwardpwr;
396 }
397 }
398 }
399 else
400 {
401 if(mute_previous)
402 {
403 tx_forwardpwr=0;
404 alctimf_mute[alctimf_pa/alc_fftsize]=TRUE;
405 }
406 else
407 {
408 alctimf_mute[alctimf_pa/alc_fftsize]=FALSE;
409 for(i=0; i<alc_sizhalf; i++)
410 {
411 t2=alctimf[alctimf_pa+2*i ]*alctimf[alctimf_pa+2*i ]+
412 alctimf[alctimf_pa+2*i+1]*alctimf[alctimf_pa+2*i+1];
413 prat[0]+=t2;
414 if(t2>pmax)pmax=t2;
415 tx_forwardpwr*=txpwr_decay;
416 if(tx_forwardpwr<t2)tx_forwardpwr=t2;
417 alctimf_pwrf[(alctimf_pa>>1)+i]=tx_forwardpwr;
418 }
419 }
420 }
421 if( alctimf_mute[alctimf_pa/alc_fftsize] == FALSE)
422 {
423 // Store an exponential power fall-off with the same time constant, 50 ms,
424 // in the reverse direction.
425 i=alc_sizhalf-1;
426 t1=0;
427 while(i >= 0)
428 {
429 t1*=txpwr_decay;
430 if(t1 < alctimf_pwrf[(alctimf_pa>>1)+i])t1=alctimf_pwrf[(alctimf_pa>>1)+i];
431 alctimf_pwrd[(alctimf_pa>>1)+i]=t1;
432 i--;
433 }
434 pb=alctimf_pa;
435 t1=alctimf_pwrd[(pb>>1)];
436 i=0;
437 while( pb != ((int)(alctimf_fx+4+alc_bufsiz)&alc_mask) && i == 0)
438 {
439 t1*=txpwr_decay;
440 pb=(pb+alc_mask)&alc_mask;
441 if(t1 > alctimf_pwrf[(pb>>1)])
442 {
443 alctimf_pwrd[(pb>>1)]=t1;
444 }
445 else
446 {
447 i=1;
448 }
449 }
450 }
451 alctimf_pa=(alctimf_pa+alc_fftsize)&alc_mask;
452 if(clipfft_mute[clipfft_px/alc_block] == FALSE)
453 {
454 for(i=0; i<alc_fftsize; i++)
455 {
456 alctimf[alctimf_pa+i]=clipfft[clipfft_px+alc_fftsize+i];
457 }
458 }
459 else
460 {
461 for(i=0; i<alc_fftsize; i++)
462 {
463 alctimf[alctimf_pa+i]=0;
464 }
465 }
466 clipfft_px=(clipfft_px+alc_block)&alc_mask;
467 return pmax;
468 }
469
tx_ssb_step7(float * prat)470 float tx_ssb_step7(float *prat)
471 {
472 int i, p0;
473 float r1, t1, t2, t3, pmax;
474 if(alctimf_mute[alctimf_pb/alc_fftsize]==FALSE)
475 {
476 p0=(alctimf_pb-2+alc_bufsiz)&alc_mask;
477 t1=alctimf[p0-2]*alctimf[p0-2]+
478 alctimf[p0-1]*alctimf[p0-1];
479 t2=alctimf[p0 ]*alctimf[p0 ]+
480 alctimf[p0+1]*alctimf[p0+1];
481 pmax=0;
482 prat[0]=0;
483 for(i=0; i<alc_sizhalf; i++)
484 {
485 r1=alctimf_pwrd[(alctimf_pb>>1)+i];
486 if(r1 > 1)
487 {
488 r1=1/sqrt(r1);
489 alctimf[alctimf_pb+2*i ]*=r1;
490 alctimf[alctimf_pb+2*i+1]*=r1;
491 }
492 t3=alctimf[alctimf_pb+2*i ]*alctimf[alctimf_pb+2*i ]+
493 alctimf[alctimf_pb+2*i+1]*alctimf[alctimf_pb+2*i+1];
494 // We do not want more than MAX_DYNRANGE dynamic range.
495 // any signal below is just rounding errors in muted periods.
496 if(t1 < MAX_DYNRANGE && t2 < MAX_DYNRANGE && t3 < MAX_DYNRANGE)
497 {
498 alctimf[p0 ]=0;
499 alctimf[p0+1]=0;
500 }
501 p0=(p0+2)&alc_mask;
502 if(t3 > pmax)pmax=t3;
503 prat[0]+=t3;
504 }
505 }
506 else
507 {
508 pmax=0;
509 prat[0]=0;
510 for(i=0; i<alc_fftsize; i++)
511 {
512 alctimf[alctimf_pb+i]=0;
513 }
514 }
515 alctimf_pb=(alctimf_pb+alc_fftsize)&alc_mask;
516 return pmax;
517 }
518
tx_ssb_step8(void)519 void tx_ssb_step8(void)
520 {
521 if(tx_output_flag == 0)
522 {
523 if( ((alctimf_pb-(int)(alctimf_fx)+alc_bufsiz)&alc_mask) >
524 tx_ssb_resamp_block_factor*SSB_DELAY_EXTRA*alc_fftsize)
525 {
526 tx_output_flag=1;
527 tx_resamp_pa=0;
528 tx_resamp_px=0;
529 }
530 }
531 if(tx_output_flag == 1)
532 {
533 resample_tx_output();
534 }
535 }
536
use_tx_resamp(float ampfac)537 void use_tx_resamp(float ampfac)
538 {
539 int i, j, k, m;
540 float t1, t2, t3, r1, r2, pilot_ampl;
541 double dt1;
542 // The latest half block of data resides in tx_resamp[alc_fftsize]
543 // to tx_resamp[2*alc_fftsize-1]
544 // Copy the previous block from resamp_tmp and multiply with
545 // the window function.
546 dt1=1/sqrt(tx_daout_sin*tx_daout_sin+tx_daout_cos*tx_daout_cos);
547 tx_daout_sin*=dt1;
548 tx_daout_cos*=dt1;
549 k=alc_sizhalf;
550 m=k-1;
551 t1=0;
552 for(i=0; i<alc_sizhalf; i++)
553 {
554 tx_resamp[2*i ]=resamp_tmp[2*i ]*alc_win[i];
555 tx_resamp[2*i+1]=resamp_tmp[2*i+1]*alc_win[i];
556 resamp_tmp[2*i ]=ampfac*tx_resamp[2*k ];
557 resamp_tmp[2*i+1]=ampfac*tx_resamp[2*k+1];
558 tx_resamp[2*k ]*=ampfac*alc_win[m];
559 tx_resamp[2*k+1]*=ampfac*alc_win[m];
560 m--;
561 k++;
562 }
563 fftforward(alc_fftsize, alc_fftn, tx_resamp, alc_table, alc_permute, FALSE);
564 // Clear the spectrum outside the desired passband.
565 // These data points should be very small.
566 k=txout_fftsize-alc_fftsize;
567 if(k > 0)
568 {
569 for(i=alc_sizhalf; i<alc_fftsize; i++)
570 {
571 tx_resamp[2*(k+i) ]=tx_resamp[2*i ];
572 tx_resamp[2*(k+i)+1]=tx_resamp[2*i+1];
573 }
574 i=tx_filter_ib3+1;
575 k=tx_filter_ia3-1;
576 t1=1;
577 t3=1./tx_filter_ib3;
578 t2=0;
579 while(k>=i && t1 >0)
580 {
581 tx_resamp[2*k]*=t1;
582 tx_resamp[2*k+1]*=t1;
583 tx_resamp[2*i]*=t1;
584 tx_resamp[2*i+1]*=t1;
585 t2+=t3;
586 t1=1-t2*t2;
587 i++;
588 k--;
589 }
590 while(k>=i)
591 {
592 tx_resamp[2*k]=0;
593 tx_resamp[2*k+1]=0;
594 tx_resamp[2*i]=0;
595 tx_resamp[2*i+1]=0;
596 i++;
597 k--;
598 }
599 }
600 if(k < 0)
601 {
602 lirerr(77676);
603 }
604 //
605 //if(screen_count>=MAX_SCREENCOUNT)
606 // {
607 // if(tx_setup_flag == TRUE)show_txfft(tx_resamp,0,2,txout_fftsize);
608 // lir_refresh_screen();
609 // }
610 // Now we have the output in the frequency domain at the size txout_fftsize
611 // with a sampling rate that fits our D/A converter. Transform it back
612 // to the time domain into txout.
613 if(tx_onoff_flag !=0)
614 {
615 fftback(txout_fftsize, txout_fftn, tx_resamp, txout_table,
616 txout_permute, FALSE);
617 for(i=0; i<txout_fftsize; i+=2)
618 {
619 tx_pilot_tone*=-1;
620 if(tx_resamp_maxamp < 0.0001 && tx_resamp_old_maxamp < 0.0001)
621 {
622 pilot_ampl=0;
623 }
624 else
625 {
626 pilot_ampl=tx_pilot_tone;
627 }
628 dt1=tx_daout_cos;
629 tx_daout_cos=dt1*tx_daout_phstep_cos+tx_daout_sin*tx_daout_phstep_sin;
630 tx_daout_sin=tx_daout_sin*tx_daout_phstep_cos-dt1*tx_daout_phstep_sin;
631 r1=tx_resamp[i ]+txout_tmp[i ];
632 r2=tx_resamp[i+1]+txout_tmp[i+1];
633 t1=tx_daout_cos*tx_output_amplitude;
634 t2=-tx_daout_sin*tx_output_amplitude;
635 txout[i ]=r1*t1+r2*t2+pilot_ampl;
636 txout[i+1]=-r1*t2+r2*t1-pilot_ampl;
637 }
638 for(i=0; i<txout_fftsize; i++)
639 {
640 txout_tmp[i]=tx_resamp[txout_fftsize+i];
641 }
642 }
643 else
644 {
645 for(i=0; i<txout_fftsize; i++)
646 {
647 txout_tmp[i]=0;
648 txout[i]=0;
649 }
650 }
651 // Compute the total time from tx input to tx output and
652 // express it as samples of the tx input clock and store in tx_wsamps.
653 tx_wsamps=lir_tx_input_samples();
654 tx_wsamps+=(mictimf_pa-mictimf_px+mictimf_bufsiz)&mictimf_mask;
655 // The microphone input is real data at the soundcard speed.
656 // The complex output of micfft is at half the speed
657 // and transforms overlap by 50%.
658 tx_wsamps*=2;
659 tx_wsamps+=((micfft_pa-micfft_px+micfft_bufsiz)&micfft_mask)/2;
660 tx_wsamps+=(cliptimf_pa-cliptimf_px+micfft_bufsiz)&micfft_mask;
661 j=((clipfft_pa-clipfft_px+alc_bufsiz)&alc_mask)/2;
662 j+=(alctimf_pa-((int)(alctimf_fx))+4+alc_bufsiz)&alc_mask;
663 tx_wsamps+=j/tx_pre_resample;
664 // The maximum amplitude should ideally be 1.0 but since
665 // a litte power outside the passband was removed in the last
666 // backwards transform, a small amount of re-peaking could occur
667 // Set the maximum level to TX_DA_MARGIN of full scale to make sure
668 // D/A converters will not overflow.
669 tx_send_to_da();
670 }
671
resample_tx_output(void)672 void resample_tx_output(void)
673 {
674 int i1, i2, i3, i4, mask2;
675 float t1, t2, t3, t4, t5, t6, t7, r1, r2;
676 float a1, a2, rdiff;
677 // The microphone is best sampled at a low sampling speed since
678 // we do not want much bandwidth nor dynamic range.
679 // For the output the requirements depend on the circumstances.
680 // In case the transmitter is used in a wideband up-conversion
681 // system, the output sampling rate may be very high and the
682 // requirements on the signal purity might be very high.
683 // We do the resampling in two steps. First do a fractional
684 // resampling to a speed near the speed of the microphone
685 // signal (but perhaps a power of two below the desired output
686 // speed as indicated by tx_output_upsample.)
687 // Subsequently, use an FFT to sample up the signal to the
688 // desired frequency while filtering out the false signals
689 // that non-linearities in the fractional resampling have
690 // introduced.
691 mask2=alc_mask-1;
692 begin:;
693 r1=tx_resamp_pa/tx_resample_ratio;
694 resamp:;
695 r2=(tx_resamp_pa+2)/tx_resample_ratio;
696 i2=alctimf_fx+r1+1;
697 i3=alctimf_fx+r2+1;
698 i2&=mask2;
699 i3&=mask2;
700 if(abs(i3-i2) > 2)
701 {
702 i2=alctimf_fx+(r1+r2)/2;
703 i3=i2+2;
704 i2&=mask2;
705 i3&=mask2;
706 }
707 else
708 {
709 if(i3==i2)
710 {
711 i2=alctimf_fx+r1;
712 i2&=mask2;
713 if(i3==i2)
714 {
715 i3=i2+2;
716 i3&=mask2;
717 }
718 }
719 }
720 i4=(i3+2)&(mask2);
721 i1=(i2+mask2)&(mask2);
722 if( ((alctimf_pb-i4+alc_bufsiz)&alc_mask) > 4)
723 {
724 if(alctimf_mute[i2/alc_fftsize]==FALSE ||
725 alctimf_mute[i3/alc_fftsize]==FALSE)
726 {
727 rdiff=r1+alctimf_fx-i2;
728 if(rdiff > alc_bufsiz/2)
729 {
730 rdiff-=alc_bufsiz;
731 }
732 rdiff/=2;
733 // Use Lagrange's interpolation formula to fit a third degree
734 // polynomial to 4 points:
735 // a1=-rdiff * (rdiff-1)*(rdiff-2)*alctimf[i1]/6
736 // +(rdiff+1)*(rdiff-1)*(rdiff-2)*alctimf[i2]/2
737 // -(rdiff+1)* rdiff *(rdiff-2)*alctimf[i3]/2
738 // +(rdiff+1)* rdiff *(rdiff-1)*alctimf[i4]/6;
739 // Rewrite slightly to save a few multiplications - do not
740 // think the compiler is smart enough to do it for us.
741 t1=rdiff-1;
742 t2=rdiff-2;
743 t3=rdiff+1;
744 t4=t1*t2;
745 t5=t3*rdiff;
746 t6=rdiff*t4;
747 t4=t3*t4;
748 t7=t5*t2;
749 t5=t5*t1;
750 a1=((t5*alctimf[i4 ]-t6*alctimf[i1 ])/3+t4*alctimf[i2 ]-t7*alctimf[i3 ])/2;
751 a2=((t5*alctimf[i4+1]-t6*alctimf[i1+1])/3+t4*alctimf[i2+1]-t7*alctimf[i3+1])/2;
752 // The curve fitting is (of course) just an approximation.
753 // Make sure we do not go outside our range!
754 t2=a1*a1+a2*a2;
755 if(t2 > tx_resamp_maxamp)tx_resamp_maxamp=t2;
756
757 if(t2 > tx_resamp_ampfac1)tx_resamp_ampfac1=t2;
758 tx_resamp[tx_resamp_pa+alc_fftsize ]=a1;
759 tx_resamp[tx_resamp_pa+alc_fftsize+1]=a2;
760 }
761 else
762 {
763 tx_resamp[tx_resamp_pa+alc_fftsize ]=0;
764 tx_resamp[tx_resamp_pa+alc_fftsize+1]=0;
765 }
766 r1=r2;
767 tx_resamp_pa+=2;
768 if(tx_resamp_pa >= tx_ssb_resamp_block_factor*alc_fftsize)
769 {
770 alctimf_fx+=r2;
771 if(alctimf_fx>alc_bufsiz)alctimf_fx-=alc_bufsiz;
772 t1=tx_resamp_ampfac1;
773 if(t1 < tx_resamp_ampfac2)t1=tx_resamp_ampfac2;
774 use_tx_resamp(sqrt(1/t1));
775 tx_resamp_old_maxamp=tx_resamp_maxamp;
776 tx_resamp_maxamp=0;
777 tx_resamp_ampfac2=tx_resamp_ampfac1;
778 tx_resamp_ampfac1=1;
779 tx_resamp_pa=0;
780 goto begin;
781 }
782 goto resamp;
783 }
784 }
785
786
787
tx_bar(int xt,int yt,int val1,int val2)788 void tx_bar(int xt,int yt,int val1, int val2)
789 {
790 int x, y;
791 x=xt*text_width;
792 y=yt*text_height+1;
793 if(val1 == val2)
794 {
795 if(val1 >= 0)return;
796 lir_fillbox(x,y,TX_BAR_SIZE,text_height-2,7);
797 return;
798 }
799 if(val2 > val1)
800 {
801 lir_fillbox(x+val1,y,val2-val1,text_height-2,12);
802 }
803 else
804 {
805 lir_fillbox(x+val2,y,val1-val2,text_height-2,7);
806 }
807 }
808
809
show_txfft(float * z,float lim,int type,int siz)810 void show_txfft(float *z, float lim, int type, int siz)
811 {
812 int i, ia, ib, k, m;
813 int pixels_per_bin, bins_per_pixel;
814 float t1,t2;
815 char color;
816 short int *trc;
817 if(type >= MAX_DISPLAY_TYPES)
818 {
819 lirerr(762319);
820 return;
821 }
822 trc=&txtrace[type*tx_show_siz];
823 ia=0;
824 t2=0;
825 pixels_per_bin=(screen_width-1)/siz;
826 bins_per_pixel=1;
827 while(pixels_per_bin == 0)
828 {
829 siz/=2;
830 pixels_per_bin=(screen_width-1)/siz;
831 bins_per_pixel*=2;
832 }
833 ib=pixels_per_bin;
834 lir_sched_yield();
835 for(i=1; i<siz; i++)
836 {
837 lir_line(ia,trc[i-1],ib,trc[i],0);
838 ia=ib;
839 ib+=pixels_per_bin;
840 }
841 lir_sched_yield();
842 ia=0;
843 ib=pixels_per_bin;
844 m=0;
845 for(i=0; i<siz; i++)
846 {
847 t1=0;
848 for(k=0; k<bins_per_pixel; k++)
849 {
850 t1=z[2*m]*z[2*m]+z[2*m+1]*z[2*m+1];
851 m++;
852 }
853 t1/=bins_per_pixel;
854 k=-0.07*log10(txtrace_gain*(t1+0.0000000000001))*screen_height;
855 if(k>txtrace_height)k=txtrace_height;
856 if(k<0)k=0;
857 trc[i]=k+screen_height-txtrace_height-1;
858 if(i>0)
859 {
860 if(type==0)
861 {
862 if(t2 > lim)
863 {
864 color=15;
865 }
866 else
867 {
868 color=12;
869 }
870 }
871 else
872 {
873 color=display_color[type];
874 }
875 lir_line(ia,trc[i-1],ib,trc[i],color);
876 ia=ib;
877 ib+=pixels_per_bin;
878 }
879 t2=t1;
880 }
881 lir_sched_yield();
882 }
883
spproc_setup(void)884 void spproc_setup(void)
885 {
886 char s[80];
887 int i, k;
888 int setup_mode;
889 int ad_pix1;
890 int ad_pix2;
891 int mute_pix1;
892 int mute_pix2;
893 int micagc_pix1;
894 int micagc_pix2;
895 int rf1agc_pix1;
896 int rf1agc_pix2;
897 int rf1clip_pix1;
898 int rf1clip_pix2;
899 int alc_pix1;
900 int alc_pix2;
901 float t1, t2, r2;
902 float prat, pmax;
903 int old_display_ptr;
904 int old_admax[DISPLAY_HOLD_SIZE];
905 float old_rf1agc[DISPLAY_HOLD_SIZE];
906 float old_rf1clip[DISPLAY_HOLD_SIZE];
907 float old_prat1[DISPLAY_HOLD_SIZE];
908 float old_pmax1[DISPLAY_HOLD_SIZE];
909 float old_prat2[DISPLAY_HOLD_SIZE];
910 float old_pmax2[DISPLAY_HOLD_SIZE];
911 float old_prat3[DISPLAY_HOLD_SIZE];
912 float old_pmax3[DISPLAY_HOLD_SIZE];
913 int default_spproc_no;
914 rx_mode=MODE_SSB;
915 set_hardware_tx_frequency();
916 default_spproc_no=tg.spproc_no;
917 tx_setup_flag=TRUE;
918 setup_mode=TX_SETUP_AD;
919 if(read_txpar_file()==FALSE)
920 {
921 set_default_spproc_parms();
922 }
923 restart:;
924 screen_count=0;
925 if(txssb.minfreq < SSB_MINFQ_LOW)txssb.minfreq=SSB_MINFQ_LOW;
926 if(txssb.minfreq > SSB_MINFQ_HIGH)txssb.minfreq=SSB_MINFQ_HIGH;
927 if(txssb.maxfreq < SSB_MAXFQ_LOW)txssb.maxfreq=SSB_MAXFQ_LOW;
928 if(txssb.maxfreq > SSB_MAXFQ_HIGH)txssb.maxfreq=SSB_MAXFQ_HIGH;
929 if(txssb.slope > SSB_MAXSLOPE)txssb.slope=SSB_MAXSLOPE;
930 if(txssb.slope < SSB_MINSLOPE)txssb.slope=SSB_MINSLOPE;
931 if(txssb.bass > SSB_MAXBASS)txssb.bass=SSB_MAXBASS;
932 if(txssb.bass < SSB_MINBASS)txssb.bass=SSB_MINBASS;
933 if(txssb.treble > SSB_MAXTREBLE)txssb.treble=SSB_MAXTREBLE;
934 if(txssb.treble < SSB_MINTREBLE)txssb.treble=SSB_MINTREBLE;
935 if(txssb.mic_f_threshold < 0)txssb.mic_f_threshold=0;
936 if(txssb.mic_f_threshold > SSB_MAX_MICF)txssb.mic_f_threshold=SSB_MAX_MICF;
937 if(txssb.mic_t_threshold < 0)txssb.mic_t_threshold=0;
938 if(txssb.mic_t_threshold > SSB_MAX_MICT)txssb.mic_t_threshold=SSB_MAX_MICT;
939 if(txssb.mic_gain < 0)txssb.mic_gain=0;
940 if(txssb.mic_gain > SSB_MAX_MICGAIN)txssb.mic_gain=SSB_MAX_MICGAIN;
941 if(txssb.mic_agc_time < 0)txssb.mic_agc_time=0;
942 if(txssb.mic_agc_time > SSB_MAX_MICAGC_TIME)
943 txssb.mic_agc_time=SSB_MAX_MICAGC_TIME;
944 if(txssb.mic_out_gain < 0)txssb.mic_out_gain=0;
945 if(txssb.mic_out_gain > SSB_MAX_MICOUT_GAIN)
946 txssb.mic_out_gain=SSB_MAX_MICOUT_GAIN;
947 if(txssb.rf1_gain < SSB_MIN_RF1_GAIN)txssb.rf1_gain=SSB_MIN_RF1_GAIN;
948 if(txssb.rf1_gain > SSB_MAX_RF1_GAIN)txssb.rf1_gain=SSB_MAX_RF1_GAIN;
949 init_txmem_spproc();
950 tx_show_siz=micsize;
951 if(tx_show_siz < alc_fftsize)tx_show_siz=alc_fftsize;
952 if(tx_show_siz < txout_fftsize)tx_show_siz=txout_fftsize;
953 txtrace=malloc(MAX_DISPLAY_TYPES*tx_show_siz*sizeof(short int));
954 if(txtrace == NULL)
955 {
956 lirerr(778543);
957 return;
958 }
959 lir_mutex_init();
960 for(i=0; i<MAX_DISPLAY_TYPES*tx_show_siz; i++)txtrace[i]=screen_height-1;
961 txtrace_gain=0.1;
962 txtrace_height=screen_height-text_height*(TXPAR_INPUT_LINE+1);
963 lir_sleep(50000);
964 linrad_thread_create(THREAD_TX_INPUT);
965 old_display_ptr=0;
966 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
967 {
968 old_admax[i]=0;
969 old_rf1agc[i]=0;
970 old_rf1clip[i]=0;
971 old_prat1[i]=90;
972 old_pmax1[i]=0;
973 old_prat2[i]=90;
974 old_pmax2[i]=0;
975 old_prat3[i]=90;
976 old_pmax3[i]=0;
977 }
978 clear_screen();
979 tx_ad_maxamp=0;
980 ad_pix1=0;
981 ad_pix2=0;
982 micagc_pix1=0;
983 micagc_pix2=0;
984 rf1agc_pix1=0;
985 rf1agc_pix2=0;
986 mute_pix1=0;
987 mute_pix2=0;
988 rf1clip_pix1=0;
989 rf1clip_pix2=0;
990 alc_pix1=0;
991 alc_pix2=0;
992 settextcolor(14);
993 make_txproc_filename();
994 sprintf(s,"Press 'S' to save %s, 'R' to read. '+' or '-' to change file no.",
995 txproc_filename);
996 lir_text(0,TX_BAR_AD_LINE-2,s);
997 lir_text(0,TX_BAR_AD_LINE-1,"Arrow up/down to change spectrum scale.");
998 lir_text(0,TX_BAR_AD_LINE,"'M' =");
999 lir_text(0,TX_BAR_MUTE_LINE,"'Q' =");
1000 lir_text(0,TX_BAR_MICAGC_LINE,"'A' =");
1001 lir_text(0,TX_BAR_RF1AGC_LINE,"'D' =");
1002 lir_text(0,TX_BAR_RF1CLIP_LINE,"'C' =");
1003 settextcolor(7);
1004 lir_text(6,TX_BAR_AD_LINE,"Soundcard");
1005 lir_text(6,TX_BAR_MUTE_LINE,"Mute");
1006 tx_bar(16,TX_BAR_AD_LINE,-1,-1);
1007 tx_bar(16,TX_BAR_MUTE_LINE,-1,-1);
1008 lir_text(6,TX_BAR_MICAGC_LINE,"MIC AGC");
1009 tx_bar(16,TX_BAR_MICAGC_LINE,-1,-1);
1010 lir_text(6,TX_BAR_RF1AGC_LINE,"RF1 AGC");
1011 tx_bar(16,TX_BAR_RF1AGC_LINE,-1,-1);
1012 lir_text(6,TX_BAR_RF1CLIP_LINE,"RF clip");
1013 tx_bar(16,TX_BAR_RF1CLIP_LINE,-1,-1);
1014 lir_text(6,TX_BAR_ALC_LINE,"ALC");
1015 tx_bar(16,TX_BAR_ALC_LINE,-1,-1);
1016 switch (setup_mode)
1017 {
1018 case TX_SETUP_AD:
1019 lir_text(0,0,
1020 "Verify AF clip level, (some device drivers give too few bits)");
1021 lir_text(0,1,"Use mixer program to set volume for the AF to never reach");
1022 lir_text(0,2,"its maximum during normal operation.");
1023 lir_text(0,3,
1024 "Press 'L' or 'H' to change cut-off frequencies,'F','B' or 'T'");
1025 lir_text(0,4,"for slope, bass or treble to change frequency response.");
1026 sprintf(s,
1027 "Low %.0f Hz High %.0f Hz Slope %d dB/kHz Bass %d dB Treble %d dB",
1028 tx_lowest_bin*txad_hz_per_bin, tx_highest_bin*txad_hz_per_bin,
1029 txssb.slope, txssb.bass, txssb.treble);
1030 lir_text(0,5,s);
1031 break;
1032
1033 case TX_SETUP_MUTE:
1034 lir_text(0,0,"Press 'F' to set frequency domain threshold or");
1035 lir_text(0,1,"Press 'T' to set time domain threshold for signal");
1036
1037 lir_text(0,2,"to become muted when only background noise is present.");
1038 sprintf(s,"Thresholds: F=%d dB T=%d dB",
1039 txssb.mic_f_threshold, txssb.mic_t_threshold);
1040 lir_text(0,3,s);
1041 break;
1042
1043 case TX_SETUP_MICAGC:
1044 lir_text(0,0,"Press 'V' to set mic volume for suitable AGC action");
1045 lir_text(0,1,"or 'T' to set decay time constant");
1046 sprintf(s,"Vol=%d dB T=%.2f sek",txssb.mic_gain, 0.01*txssb.mic_agc_time);
1047 lir_text(0,2,s);
1048 break;
1049
1050 case TX_SETUP_RF1AGC:
1051 lir_text(0,0,"Press 'B' to set gain for some AGC action");
1052 sprintf(s,"Gain=%d dB",txssb.mic_out_gain);
1053 lir_text(0,2,s);
1054 break;
1055
1056 case TX_SETUP_RF1CLIP:
1057 lir_text(0,0,"Press 'B' to set RF1 gain for desired clip level.");
1058 lir_text(0,1,"Bar range is 0 to 30 dB");
1059 sprintf(s,"RF1 gain=%d dB",txssb.rf1_gain);
1060 lir_text(0,2,s);
1061 break;
1062 }
1063 if(!kill_all_flag)lir_await_event(EVENT_TX_INPUT);
1064 for(i=0; i<10; i++)
1065 {
1066 micfft_px=micfft_pa;
1067 lir_sched_yield();
1068 while(micfft_px == micfft_pa && !kill_all_flag)
1069 {
1070 lir_await_event(EVENT_TX_INPUT);
1071 t1=0;
1072 for(k=0;k<100;k++)t1+=sin(0.0001*k);
1073 lir_sched_yield();
1074 }
1075 }
1076 micfft_px=micfft_pa;
1077 while(!kill_all_flag)
1078 {
1079 if(screen_count>=MAX_SCREENCOUNT)screen_count=0;
1080 screen_count++;
1081 old_display_ptr++;
1082 if(old_display_ptr>=DISPLAY_HOLD_SIZE)old_display_ptr=0;
1083 // Show the microphone input level.
1084 ad_pix2=tx_ad_maxamp;
1085 if(ui.tx_ad_bytes != 2)
1086 {
1087 ad_pix2/=0x10000;
1088 }
1089 old_admax[old_display_ptr]=ad_pix2;
1090 t1=0;
1091 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1092 {
1093 if(t1<old_admax[i])t1=old_admax[i];
1094 }
1095 t1=20*log10(t1/0x8000);
1096 sprintf(s,"%.1fdB ",t1);
1097 lir_text(18+TX_BAR_SIZE/text_width, TX_BAR_AD_LINE, s);
1098 ad_pix2=(ad_pix2*TX_BAR_SIZE)/0x8000;
1099 tx_bar(16,TX_BAR_AD_LINE,ad_pix1,ad_pix2);
1100 ad_pix1=ad_pix2;
1101 tx_ad_maxamp=0.95*tx_ad_maxamp;
1102 // **************************************************************
1103 // The setup routine contains the same processing steps as the
1104 // transmit routine, but it has varoius display functions added
1105 // into it. The processing steps are numbered and described below.
1106 // **************************************************************
1107 //
1108 // ************* Step 1. *************
1109 // Wait for a new block of data from the mic input routine.
1110 // Note that the data arrives as fourier transforms (micfft) and
1111 // that the mic input routine tx_input() already has applied
1112 // the filtering of the microphone signal.
1113 lir_refresh_screen();
1114 //tx_ssb_buftim('a');
1115 lir_await_event(EVENT_TX_INPUT);
1116 tx_agc_factor=tx_agc_decay*tx_agc_factor+(1-tx_agc_decay);
1117 micfft_bin_minpower=micfft_bin_minpower_ref*tx_agc_factor*tx_agc_factor;
1118 micfft_minpower=micfft_minpower_ref;//*tx_agc_factor*tx_agc_factor;
1119 if(screen_count>=MAX_SCREENCOUNT)
1120 {
1121 show_txfft(&micfft[micfft_px],micfft_bin_minpower,0,mic_fftsize);
1122 }
1123 k=tx_ssb_step2(&t1);
1124 if(k==0)
1125 {
1126 sprintf(s,"MUTED");
1127 }
1128 else
1129 {
1130 sprintf(s," ");
1131 tx_ssb_step3(&t1);
1132 }
1133 mute_pix2=(k*TX_BAR_SIZE)/(tx_highest_bin-tx_lowest_bin+1);
1134 tx_bar(16,TX_BAR_MUTE_LINE,mute_pix1,mute_pix2);
1135 mute_pix1=mute_pix2;
1136 settextcolor(15);
1137 lir_text(18+TX_BAR_SIZE/text_width,TX_BAR_MUTE_LINE,s);
1138 settextcolor(7);
1139 // In case AGC has reduced the gain by more than 20 dB, set the
1140 // AGC factor to -20 dB immediately because voice should never
1141 // be as loud. This is to avoid the agc release time constant
1142 // for impulse sounds caused by hitting the microphone etc.
1143 t1=20*log10(tx_agc_factor);
1144 sprintf(s,"%.1fdB ",t1);
1145 if(tx_agc_factor < 0.1)tx_agc_factor=0.1;
1146 lir_text(18+TX_BAR_SIZE/text_width, TX_BAR_MICAGC_LINE, s);
1147 micagc_pix2=-log10(tx_agc_factor)*TX_BAR_SIZE;
1148 tx_bar(16,TX_BAR_MICAGC_LINE,micagc_pix1,micagc_pix2);
1149 micagc_pix1=micagc_pix2;
1150 // ************* Step 4. *************
1151 // Go back to the time domain and store the signal in cliptimf
1152 // Remember that we use sin squared windows and that
1153 // the transforms overlap with 50%.
1154 //
1155 // Ideally, the peak amplitude should be 1.0, the audio AGC
1156 // should be active and keep the power level nearly constant.
1157 // For a voice signal the waveform will differ from time to time
1158 // and therefore the peak to average power ratio will vary.
1159 // Compute the peak amplitude for the current transform
1160 // and save it for the next time we arrive here.
1161 // Use the peak amplitude for an AGC in the time domain (complex-valued).
1162 // The Hilbert space AGC is a constant that may vary from one
1163 // FFT block to the next one. It is equivalent with an AM modulator
1164 // with a bandwidth corresponding to a single bin in the FFT so this
1165 // AM modulation will not increase the bandwidth notably, but it
1166 // will bring the RF amplitude near unity always.
1167 //
1168 // Finally, apply an amplitude limiter to the complex time domain signal.
1169 // It will work as an RF limiter on the SSB signal and cause a lot of
1170 // signal outside the passband.
1171 if(k!=0)
1172 {
1173 fftback(mic_fftsize, mic_fftn, &micfft[micfft_px],
1174 micfft_table, micfft_permute,FALSE);
1175 lir_sched_yield();
1176 r2=0;
1177 for(i=0; i<mic_fftsize; i++)
1178 {
1179 t2=micfft[micfft_px+2*i ]*micfft[micfft_px+2*i ]+
1180 micfft[+2*i+1]*micfft[micfft_px+2*i+1];
1181 if(t2>r2)r2=t2;
1182 }
1183 if(r2 > 0.01*MAX_DYNRANGE)
1184 {
1185 t1=sqrt(r2);
1186 r2=1/t1;
1187 old_rf1agc[old_display_ptr]=t1;
1188 if(t1>10)t1=10;
1189 rf1agc_pix2=log10(t1)*TX_BAR_SIZE;
1190 if(r2>10/tx_agc_factor)r2=10/tx_agc_factor;
1191 if(rf1agc_pix2 < 0)rf1agc_pix2=0;
1192 }
1193 else
1194 {
1195 r2=0;
1196 rf1agc_pix2=0;
1197 old_rf1agc[old_display_ptr]=0;
1198 }
1199 }
1200 else
1201 {
1202 r2=0;
1203 rf1agc_pix2=0;
1204 old_rf1agc[old_display_ptr]=0;
1205 }
1206 t1=0;
1207 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1208 {
1209 if(t1<old_rf1agc[i])t1=old_rf1agc[i];
1210 }
1211 if(t1 > 0)t1=20*log10(t1);
1212 sprintf(s,"%.1fdB ",t1);
1213 lir_text(18+TX_BAR_SIZE/text_width, TX_BAR_RF1AGC_LINE, s);
1214 tx_bar(16,TX_BAR_RF1AGC_LINE,rf1agc_pix1,rf1agc_pix2);
1215 rf1agc_pix1=rf1agc_pix2;
1216 //tx_ssb_buftim('b');
1217 tx_ssb_step4(r2,&pmax,&prat);
1218 //tx_ssb_buftim('c');
1219 prat/=mic_sizhalf;
1220 old_prat1[old_display_ptr]=prat;
1221 old_pmax1[old_display_ptr]=pmax;
1222 prat=0;
1223 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1224 {
1225 prat+=old_prat1[i];
1226 }
1227 prat/=DISPLAY_HOLD_SIZE;
1228 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1229 {
1230 if(pmax<old_pmax1[i])pmax=old_pmax1[i];
1231 }
1232 if(prat>0.000000001 && pmax > prat)
1233 {
1234 prat=10*log10(pmax/prat);
1235 }
1236 else
1237 {
1238 prat=99;
1239 }
1240 sprintf(s,"[%.1f] ",prat);
1241 lir_text(28+TX_BAR_SIZE/text_width, TX_BAR_MICAGC_LINE, s);
1242 old_rf1clip[old_display_ptr]=pmax;
1243 if(pmax > 1000)pmax=1000;
1244 if(pmax > 1)
1245 {
1246 rf1clip_pix2=log10(pmax)*TX_BAR_SIZE/3;
1247 }
1248 else
1249 {
1250 rf1clip_pix2=0;
1251 }
1252 t1=0;
1253 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1254 {
1255 if(t1<old_rf1clip[i])t1=old_rf1clip[i];
1256 }
1257 if(t1 > 1)
1258 {
1259 t1=10*log10(t1);
1260 }
1261 else
1262 {
1263 t1=0;
1264 }
1265 sprintf(s,"%.1fdB ",t1);
1266 lir_text(18+TX_BAR_SIZE/text_width, TX_BAR_RF1CLIP_LINE, s);
1267 tx_bar(16,TX_BAR_RF1CLIP_LINE,rf1clip_pix1,rf1clip_pix2);
1268 rf1clip_pix1=rf1clip_pix2;
1269 // ************* Step 5. *************
1270 // At this point we have applied an RF clipper by limiting power on a
1271 // complex-valued time domain function. As a consequence we have
1272 // produced intermodulation products outside the desired passband.
1273 // Go to the frequency domain and remove undesired frequencies.
1274 tx_ssb_step5();
1275 // ************* Step 6. *************
1276 // Go back to the time domain and store the signal in alctimf.
1277 // Remember that we use sin squared windows and that
1278 // the transforms overlap with 50%.
1279 // Compute power and store the peak power with
1280 // an exponential decay corresponding to a time constant
1281 // of 50 milliseconds.
1282 // We expand the fft size from mic_fftsize to tx_fftsiz2 because
1283 // the fractional resampling that will follow this step needs
1284 // the signal to be oversampled by a factor of four to avoid
1285 // attenuation at high frequencies. The polynomial fitting
1286 // works as a low pass filter and we do not want any attenuation
1287 // at the high side of our passband.
1288 //tx_ssb_buftim('d');
1289 if(lir_tx_output_samples() < snd[TXDA].tot_frames-2*snd[TXDA].block_frames)
1290 {
1291 while(clipfft_px != clipfft_pa)
1292 {
1293 pmax=tx_ssb_step6(&prat);
1294 lir_sched_yield();
1295 prat/=alc_sizhalf;
1296 old_prat2[old_display_ptr]=prat;
1297 old_pmax2[old_display_ptr]=pmax;
1298 prat=0;
1299 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1300 {
1301 prat+=old_prat2[i];
1302 }
1303 prat/=DISPLAY_HOLD_SIZE;
1304 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1305 {
1306 if(pmax<old_pmax2[i])pmax=old_pmax2[i];
1307 }
1308 if(prat>0.000000001 && pmax > prat)
1309 {
1310 prat=10*log10(pmax/prat);
1311 }
1312 else
1313 {
1314 prat=99;
1315 }
1316 sprintf(s,"[%.1f] ",prat);
1317 lir_text(28+TX_BAR_SIZE/text_width, TX_BAR_RF1CLIP_LINE, s);
1318 if(pmax > 1)
1319 {
1320 pmax=2*log10(pmax);
1321 if(pmax>1)pmax=1;
1322 alc_pix2=pmax*TX_BAR_SIZE;
1323 }
1324 else
1325 {
1326 alc_pix2=0;
1327 }
1328 tx_bar(16,TX_BAR_ALC_LINE,alc_pix1,alc_pix2);
1329 alc_pix1=alc_pix2;
1330 }
1331 // ************* Step 7. *************
1332 // Use the slowly decaying bi-directional peak power as an ALC
1333 // but make sure we allow at least two data blocks un-processed
1334 // to allow the backwards fall-off to become re-calculated.
1335 // Using the slowly varying function for an ALC (= AM modulation)
1336 // will not increase the bandwidth by more than the bandwidth
1337 // of the modulation signal (50 ms or 20 Hz)
1338 while( ((alctimf_pa-alctimf_pb+alc_bufsiz)&alc_mask) >= 3*alc_fftsize)
1339 {
1340 pmax=tx_ssb_step7(&prat);
1341 prat/=alc_sizhalf;
1342 old_prat3[old_display_ptr]=prat;
1343 old_pmax3[old_display_ptr]=pmax;
1344 prat=0;
1345 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1346 {
1347 prat+=old_prat3[i];
1348 }
1349 prat/=DISPLAY_HOLD_SIZE;
1350 for(i=0; i<DISPLAY_HOLD_SIZE; i++)
1351 {
1352 if(pmax<old_pmax3[i])pmax=old_pmax3[i];
1353 }
1354 if(prat>0.000000001 && pmax > prat)
1355 {
1356 prat=10*log10(pmax/prat);
1357 }
1358 else
1359 {
1360 prat=99;
1361 }
1362 sprintf(s,"[%.1f] ",prat);
1363 lir_text(28+TX_BAR_SIZE/text_width, TX_BAR_ALC_LINE, s);
1364 }
1365 // ************* Step 8. *************
1366 // In case we have enough signal in the buffer, start the output.
1367 tx_ssb_step8();
1368 }
1369 test_keyboard();
1370 if(lir_inkey != 0)
1371 {
1372 process_current_lir_inkey();
1373 if(lir_inkey=='X')goto end_tx_setup;
1374 if(lir_inkey==ARROW_UP_KEY)
1375 {
1376 txtrace_gain*=1.33;
1377 goto continue_setup;
1378 }
1379 if(lir_inkey==ARROW_DOWN_KEY)
1380 {
1381 txtrace_gain/=1.25;
1382 goto continue_setup;
1383 }
1384 close_tx_sndout();
1385 linrad_thread_stop_and_join(THREAD_TX_INPUT);
1386 close_tx_sndin();
1387 if(txmem_handle != NULL)free(txmem_handle);
1388 txmem_handle=NULL;
1389 lir_await_event(EVENT_TX_INPUT);
1390 lir_mutex_destroy();
1391 if(lir_inkey=='S')
1392 {
1393 clear_screen();
1394 save_tx_parms(TRUE);
1395 }
1396 if(lir_inkey=='R')
1397 {
1398 clear_screen();
1399 read_txpar_file();
1400 }
1401 switch (setup_mode)
1402 {
1403 case TX_SETUP_AD:
1404 if(lir_inkey=='L')
1405 {
1406 lir_text(0,TXPAR_INPUT_LINE,"Low:");
1407 txssb.minfreq=lir_get_integer(5,TXPAR_INPUT_LINE,4,1,SSB_MINFQ_HIGH);
1408 }
1409 if(lir_inkey=='H')
1410 {
1411 lir_text(0,TXPAR_INPUT_LINE,"High:");
1412 txssb.maxfreq=lir_get_integer(6,TXPAR_INPUT_LINE,5,
1413 SSB_MAXFQ_LOW,ui.tx_ad_speed/2);
1414 }
1415 if(lir_inkey=='F')
1416 {
1417 lir_text(0,TXPAR_INPUT_LINE,"Slope:");
1418 txssb.slope=lir_get_integer(7,TXPAR_INPUT_LINE,4,SSB_MINSLOPE,
1419 SSB_MAXSLOPE);
1420 }
1421 if(lir_inkey=='B')
1422 {
1423 lir_text(0,TXPAR_INPUT_LINE,"Bass:");
1424 txssb.bass=lir_get_integer(6,
1425 TXPAR_INPUT_LINE,4,SSB_MINBASS,SSB_MAXBASS);
1426 }
1427 if(lir_inkey=='T')
1428 {
1429 lir_text(0,TXPAR_INPUT_LINE,"Treble:");
1430 txssb.treble=lir_get_integer(8,
1431 TXPAR_INPUT_LINE,4,SSB_MINTREBLE,SSB_MAXTREBLE);
1432 }
1433 break;
1434
1435 case TX_SETUP_MUTE:
1436 if(lir_inkey=='F')
1437 {
1438 lir_text(0,TXPAR_INPUT_LINE,"Freq domain:");
1439 txssb.mic_f_threshold=lir_get_integer(13,
1440 TXPAR_INPUT_LINE,3,0,SSB_MAX_MICF);
1441 }
1442 if(lir_inkey=='T')
1443 {
1444 lir_text(0,TXPAR_INPUT_LINE,"Time domain:");
1445 txssb.mic_t_threshold=lir_get_integer(13,
1446 TXPAR_INPUT_LINE,3,0,SSB_MAX_MICT);
1447 }
1448 break;
1449
1450 case TX_SETUP_MICAGC:
1451 if(lir_inkey=='V')
1452 {
1453 lir_text(0,TXPAR_INPUT_LINE,"Volume:");
1454 txssb.mic_gain=lir_get_integer(8,
1455 TXPAR_INPUT_LINE,3,0,SSB_MAX_MICGAIN);
1456 }
1457 if(lir_inkey=='T')
1458 {
1459 lir_text(0,TXPAR_INPUT_LINE,"Time constant:");
1460 t1=lir_get_float(15,TXPAR_INPUT_LINE,6,0,SSB_MAX_MICAGC_TIME);
1461 txssb.mic_agc_time=100*t1;
1462 }
1463 break;
1464
1465
1466
1467 case TX_SETUP_RF1AGC:
1468 if(lir_inkey=='B')
1469 {
1470 lir_text(0,TXPAR_INPUT_LINE,"Gain:");
1471 txssb.mic_out_gain=lir_get_integer(15,
1472 TXPAR_INPUT_LINE,2,0,SSB_MAX_MICOUT_GAIN);
1473 }
1474 break;
1475
1476 case TX_SETUP_RF1CLIP:
1477 if(lir_inkey=='B')
1478 {
1479 lir_text(0,TXPAR_INPUT_LINE,"Clipper gain:");
1480 txssb.rf1_gain=lir_get_integer(15,
1481 TXPAR_INPUT_LINE,3,SSB_MIN_RF1_GAIN,SSB_MAX_RF1_GAIN);
1482 }
1483 break;
1484 }
1485 if(lir_inkey=='A')setup_mode=TX_SETUP_MICAGC;
1486 if(lir_inkey=='M')setup_mode=TX_SETUP_AD;
1487 if(lir_inkey=='Q')setup_mode=TX_SETUP_MUTE;
1488 if(lir_inkey=='D')setup_mode=TX_SETUP_RF1AGC;
1489 if(lir_inkey=='C')setup_mode=TX_SETUP_RF1CLIP;
1490 if(lir_inkey=='+')
1491 {
1492 tg.spproc_no++;
1493 if(tg.spproc_no > MAX_SSBPROC_FILES)tg.spproc_no=MAX_SSBPROC_FILES;
1494 }
1495 if(lir_inkey=='-')
1496 {
1497 tg.spproc_no--;
1498 if(tg.spproc_no < 0)tg.spproc_no=0;
1499 }
1500 goto restart;
1501 }
1502 continue_setup:;
1503 }
1504 end_tx_setup:;
1505 close_tx_sndout();
1506 linrad_thread_stop_and_join(THREAD_TX_INPUT);
1507 close_tx_sndin();
1508 if(txmem_handle != NULL)free(txmem_handle);
1509 txmem_handle=NULL;
1510 lir_close_event(EVENT_TX_INPUT);
1511 lir_mutex_destroy();
1512 tg.spproc_no=default_spproc_no;
1513 }
1514
1515