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