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 <string.h>
26 #include <fcntl.h>
27 
28 
29 #include "globdef.h"
30 #include "uidef.h"
31 #include "fft1def.h"
32 #include "fft2def.h"
33 #include "fft3def.h"
34 #include "screendef.h"
35 #include "sigdef.h"
36 #include "seldef.h"
37 #include "rusage.h"
38 #include "thrdef.h"
39 #include "txdef.h"
40 #include "options.h"
41 #include "conf.h"
42 
43 #if BUFBARS == TRUE
44 #define RX_INDICATOR_MAXNUM 8
45 extern int rx_indicator_maxpos[RX_INDICATOR_MAXNUM];
46 extern int rx_indicator_minpos[RX_INDICATOR_MAXNUM];
47 void show_bufbar(int i, int k);
48 #endif
49 
50 float iir3_gain[9]={6.0,
51                     31.55634919,
52                     188.6646578,
53                     1274.138623,
54                     9304.588559,
55                     70996.86308,
56                     554452.4788,
57                     4382011.796,
58                     34842632.96};
59 
60 float iir3_c0[9]={0.0,
61                   0.1978251873,
62                   0.4535459334,
63                   0.6748018873,
64                   0.8216600080,
65                   0.9064815219,
66                   0.9520967536,
67                   0.9757549044,
68                   0.9878031267};
69 
70 float iir3_c1[9]={ -0.3333333333,
71                    -0.9103690003,
72                    -1.7151178300,
73                    -2.2889939150,
74                    -2.6262484669,
75                    -2.8084292678,
76                    -2.9030250284,
77                    -2.9512131915,
78                    -2.9755315293};
79 
80 float iir3_c2[9]={ 0.0,
81                    1.4590290622,
82                    2.2191686183,
83                    2.6079132760,
84                    2.8037286680,
85                    2.9018350649,
86                    2.9509138462,
87                    2.9754564614,
88                    2.9877281729};
89 
90 
blocking_rxout(void)91 void blocking_rxout(void)
92 {
93 #if RUSAGE_OLD == TRUE
94 int local_workload_counter;
95 #endif
96 int k, initial_n, sleep_cnt;
97 int local_workload_reset;
98 char s[80];
99 char cc;
100 float sleep_time, short_sleep_time;
101 float t1;
102 #if OSNUM == OSNUM_LINUX
103 clear_thread_times(THREAD_BLOCKING_RXOUT);
104 #endif
105 #if RUSAGE_OLD == TRUE
106 local_workload_counter=workload_counter;
107 #endif
108 local_workload_reset=workload_reset_flag;
109 sleep_time=2000000./snd[RXDA].interrupt_rate;
110 if(sleep_time < 1010)sleep_time=1010;
111 if(sleep_time > 100000)sleep_time=100000;
112 short_sleep_time=0.2*sleep_time;
113 if(short_sleep_time > 10000)short_sleep_time=10000;
114 if(short_sleep_time < 1010)short_sleep_time=1010;
115 if(rx_daout_bytes == 1)
116   {
117   cc=0x80;
118   }
119 else
120   {
121   cc=0;
122   }
123 lir_await_event(EVENT_BLOCKING_RXOUT);
124 daout_px=(daout_px-snd[RXDA].block_bytes+daout_size)&daout_bufmask;
125 memset(&daout[daout_px],cc,snd[RXDA].block_bytes);
126 // It may take a long time to return from the first write.
127 // 4Front OSS may require 0.1 second to set up the output
128 // Write data that will fill the soundcard with data for about
129 // 20 milliseconds (or more).
130 lir_rx_dawrite();
131 t1=0.5+.02*genparm[DA_OUTPUT_SPEED]/snd[RXDA].block_frames;
132 k=t1-1;
133 while(k>0)
134   {
135   daout_px=(daout_px-snd[RXDA].block_bytes+daout_size)&daout_bufmask;
136   lir_rx_dawrite();
137   k--;
138   }
139 update_snd(RXDA);
140 thread_status_flag[THREAD_BLOCKING_RXOUT]=THRFLAG_ACTIVE;
141 sleep_cnt=0;
142 initial_n=2;
143 while(!kill_all_flag &&
144          thread_command_flag[THREAD_BLOCKING_RXOUT]==THRFLAG_ACTIVE)
145   {
146 // *******************************************************
147 #if RUSAGE_OLD == TRUE
148   if(local_workload_counter != workload_counter)
149     {
150     local_workload_counter=workload_counter;
151     update_snd(RXDA);
152     if(snd[RXDA].valid_bytes > snd[RXDA].block_bytes)
153       {
154       make_thread_times(THREAD_BLOCKING_RXOUT);
155       update_snd(RXDA);
156       }
157     }
158 #endif
159   if(local_workload_reset!=workload_reset_flag)
160     {
161     update_snd(RXDA);
162     snd[RXDA].min_valid_frames=snd[RXDA].tot_frames;
163     local_workload_reset=workload_reset_flag;
164     }
165   if( ((daout_pa-daout_px+daout_size)&daout_bufmask) >
166                                        initial_n*snd[RXDA].block_bytes)
167     {
168     sleep_cnt=0;
169     if(audio_dump_flag==0 && rx_audio_out != -1)
170       {
171       while(initial_n > 1)
172         {
173         lir_rx_dawrite();
174         initial_n--;
175         }
176       lir_sched_yield();
177       if( ((daout_pa-daout_px+daout_size)&daout_bufmask) >
178                                                 snd[RXDA].block_bytes)
179         {
180         lir_rx_dawrite();
181         lir_sched_yield();
182         if( ((daout_pa-daout_px+daout_size)&daout_bufmask) >
183                                                 snd[RXDA].block_bytes)
184           {
185           lir_rx_dawrite();
186           }
187         }
188       }
189     else
190       {
191       daout_px=(daout_px+snd[RXDA].block_bytes)&daout_bufmask;
192       }
193     }
194   else
195     {
196     if(audio_dump_flag == 1 || rx_audio_out == -1)
197       {
198       lir_sleep(sleep_time);
199       }
200     else
201       {
202       update_snd(RXDA);
203       if(snd[RXDA].valid_bytes > 8*snd[RXDA].block_bytes)
204         {
205         lir_sleep(sleep_time);
206         goto loop_end;;
207         }
208       if(snd[RXDA].valid_bytes < snd[RXDA].block_bytes/4)
209         {
210         if(count_rx_underrun_flag)
211           {
212           no_of_rx_underrun_errors++;
213           sprintf(s,"RX%s%d",underrun_error_msg,no_of_rx_underrun_errors);
214           wg_error(s,WGERR_RXOUT);
215           }
216 // clear the buffer
217         daout_px=(daout_px-snd[RXDA].block_bytes+daout_size)&daout_bufmask;
218         memset(&daout[daout_px],cc,snd[RXDA].block_bytes);
219         lir_rx_dawrite();
220         lir_sleep(short_sleep_time);
221         }
222       else
223         {
224         sleep_cnt++;
225         if(sleep_cnt > 2)lir_sleep(short_sleep_time);
226         }
227       }
228     }
229 loop_end:;
230   }
231 thread_status_flag[THREAD_BLOCKING_RXOUT]=THRFLAG_RETURNED;
232 while(!kill_all_flag &&
233             thread_command_flag[THREAD_BLOCKING_RXOUT] != THRFLAG_NOT_ACTIVE)
234   {
235   lir_sleep(1000);
236   }
237 }
238 
239 #define MAXMAIL 5
240 
rx_output(void)241 void rx_output(void)
242 {
243 #if RUSAGE_OLD == TRUE
244 int local_workload_counter;
245 #endif
246 char delay_margin_flag;
247 char cc, blocking;
248 float dasync_time_interval;
249 int da_start_bytes;
250 int dasync_errors;
251 int daout_py;
252 int i, k;
253 int speed_cnt_maxval;
254 char s[80];
255 double dt1;
256 int local_channels, local_bytes;
257 int local_workload_reset;
258 int speed_cnt;
259 float local_fft3_blocktime;
260 float t1, t2;
261 float sleep_time;
262 double total_time2;
263 double daspeed_time;
264 #if OSNUM == OSNUM_LINUX
265 clear_thread_times(THREAD_RX_OUTPUT);
266 #endif
267 #if RUSAGE_OLD == TRUE
268 local_workload_counter=workload_counter;
269 #endif
270 blocking=TRUE;
271 if( (ui.use_alsa&PORTAUDIO_RX_OUT) != 0)
272   {
273   blocking=FALSE;
274   }
275 thread_status_flag[THREAD_RX_OUTPUT]=THRFLAG_ACTIVE;
276 local_channels=rx_daout_channels;
277 local_bytes=rx_daout_bytes;
278 local_fft3_blocktime=fft3_blocktime;
279 daout_pa=0;
280 daout_px=0;
281 count_rx_underrun_flag=FALSE;
282 sys_func(THRFLAG_OPEN_RX_SNDOUT);
283 if(rx_audio_out == -1)blocking=FALSE;
284 if(kill_all_flag)goto da_output_error;
285 if(blocking && audio_dump_flag == 0 && rx_audio_out >= 0)
286   {
287   lir_rx_dawrite();
288   daout_pa=0;
289   daout_px=0;
290   }
291 dasync_errors=0;
292 baseb_output_block=128;
293 da_start_bytes=-1;
294 thread_command_flag[THREAD_BLOCKING_RXOUT]=THRFLAG_NOT_ACTIVE;
295 if(blocking)
296   {
297   lir_init_event(EVENT_BLOCKING_RXOUT);
298   lir_sched_yield();
299   linrad_thread_create(THREAD_BLOCKING_RXOUT);
300   }
301 while(!kill_all_flag &&
302           thread_command_flag[THREAD_RX_OUTPUT]==THRFLAG_ACTIVE)
303   {
304   lir_sleep(3000);
305   }
306 speed_cnt_maxval=0.2*snd[RXDA].interrupt_rate;
307 goto stop_output;
308 resume:;
309 if(blocking)
310   {
311   lir_init_event(EVENT_BLOCKING_RXOUT);
312   lir_sched_yield();
313   linrad_thread_create(THREAD_BLOCKING_RXOUT);
314   }
315 if(lir_rxout_status != LIR_OK)
316   {
317   wg_error("Output soundcard disabled",WGERR_SOUNDCARD);
318   }
319 thread_status_flag[THREAD_RX_OUTPUT]=THRFLAG_ACTIVE;
320 count_rx_underrun_flag=FALSE;
321 lir_sched_yield();
322 sleep_time=1000000./snd[RXDA].interrupt_rate;
323 if(sleep_time < 1010)sleep_time=1010;
324 if(sleep_time > 100000)sleep_time=100000;
325 dasync_time_interval=(float)(7*fft3_size)/timf3_sampling_speed;
326 if(dasync_time_interval < (float)(7*fft1_size)/timf1_sampling_speed)
327                  dasync_time_interval = (float)(7*fft1_size)/timf1_sampling_speed;
328 if(genparm[SECOND_FFT_ENABLE]!=0)
329   {
330   if(dasync_time_interval < (float)(7*fft2_size)/timf1_sampling_speed)
331                   dasync_time_interval = (float)(7*fft2_size)/timf1_sampling_speed;
332   }
333 if(dasync_time_interval < 0.5)dasync_time_interval=0.5;
334 local_workload_reset=workload_reset_flag;
335 speed_cnt=snd[RXDA].interrupt_rate;
336 baseb_output_block=snd[RXDA].block_bytes/(2*da_resample_ratio);
337 if(baseb_output_block < 16)baseb_output_block=16;
338 baseb_min_block=1+1/da_resample_ratio;
339 if(baseb_min_block < baseb_output_block/16)
340   {
341   baseb_min_block=baseb_output_block/16;
342   }
343 k=0;
344 dasync_time=current_time();
345 daspeed_time=dasync_time;
346 await_narrowband_processing:;
347 if(kill_all_flag) goto da_output_error;
348 if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
349 lir_sleep(2000);
350 update_snd(RXDA);
351 make_timing_info();
352 if(kill_all_flag) goto da_output_error;
353 if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
354 t1=total_wttim-da_wait_time;
355 if(t1 < 0)
356   {
357   goto await_narrowband_processing;
358   }
359 if(k == 0 && blocking)
360   {
361   lir_set_event(EVENT_BLOCKING_RXOUT);
362   lir_sched_yield();
363   update_snd(RXDA);
364   make_timing_info();
365   }
366 k++;
367 if(t1*baseband_sampling_speed > 3*baseb_output_block)
368   {
369   i=t1*baseband_sampling_speed;
370   if(i > baseb_wts)i=baseb_wts;
371   baseb_py=(baseb_py+i+baseband_size)&baseband_mask;
372   baseb_wts-=i;
373   }
374 lir_sched_yield();
375 update_snd(RXDA);
376 make_timing_info();
377 if(kill_all_flag) goto da_output_error;
378 if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
379 t1=total_wttim-da_wait_time;
380 if(t1*baseband_sampling_speed > 3*baseb_output_block )//|| k<2)
381   {
382   if(recent_time-dasync_time > 2)
383     {
384     lirerr(1199);
385     goto da_output_error;
386     }
387   goto await_narrowband_processing;
388   }
389 if(blocking && thread_status_flag[THREAD_BLOCKING_RXOUT] != THRFLAG_ACTIVE)
390   {
391   goto await_narrowband_processing;
392   }
393 baseb_fx=(baseb_py-2+baseband_size)&baseband_mask;
394 if(da_start_bytes == -1)
395   {
396   dasync_counter=0;
397   dasync_sum=0;
398   dasync_avg1=-1.5;
399   dasync_avg2=-1.5;
400   dasync_avg3=-1.5;
401   dasync_time=current_time();
402   dasync_avgtime=dasync_time;
403   daspeed_time=dasync_time+1;
404   }
405 daout_pa=0;
406 daout_px=0;
407 daout_py=0;
408 snd[RXDA].min_valid_frames=snd[RXDA].tot_frames;
409 min_daout_samps=baseband_size;
410 delay_margin_flag=TRUE;
411 lir_sleep(1000);
412 make_timing_info();
413 update_snd(RXDA);
414 if(kill_all_flag) goto da_output_error;
415 if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
416 t1=total_wttim-da_wait_time;
417 if(t1*baseband_sampling_speed > 3*baseb_output_block )//|| k<2)
418   {
419   goto await_narrowband_processing;
420   }
421 while(!kill_all_flag &&
422                    thread_command_flag[THREAD_RX_OUTPUT] == THRFLAG_ACTIVE)
423   {
424 #if RUSAGE_OLD == TRUE
425   if(local_workload_counter != workload_counter)
426     {
427     local_workload_counter=workload_counter;
428     make_thread_times(THREAD_RX_OUTPUT);
429     }
430 #endif
431 // We use speed_cnt to avoid using a lot of CPU time on this code section.
432   if(audio_dump_flag==0)speed_cnt--;
433   if(speed_cnt==0)
434     {
435     if(delay_margin_flag)
436       {
437       snd[RXDA].min_valid_frames=snd[RXDA].tot_frames;
438       min_daout_samps=baseband_size;
439       delay_margin_flag=FALSE;
440       }
441     if(local_workload_reset!=workload_reset_flag)
442       {
443       snd[RXDA].min_valid_frames=snd[RXDA].tot_frames;
444       local_workload_reset=workload_reset_flag;
445       }
446     speed_cnt=speed_cnt_maxval;
447     total_time2=recent_time;
448     if(recent_time-daspeed_time > 0)
449       {
450 // Compute the D/A speed and once every second.
451       if(audio_dump_flag==0)
452         {
453         daspeed_time=recent_time+1;
454         lir_sched_yield();
455         if(da_start_bytes == -1)
456           {
457           da_start_time=total_time2;
458           da_block_counter=0;
459           da_start_bytes=snd[RXDA].empty_bytes;
460           snd[RXDA].min_valid_frames=snd[RXDA].tot_frames;
461           count_rx_underrun_flag=TRUE;
462           }
463         else
464           {
465           measured_da_speed=(da_block_counter*snd[RXDA].block_bytes+
466                                   snd[RXDA].empty_bytes-da_start_bytes)/
467                           (snd[RXDA].framesize*(total_time2-da_start_time));
468           }
469         }
470 // Keep track of the error in the frequency ratio between input and output.
471 // Average the total processing delay and adjust resampling rate to
472 // keep it constant.
473 #define DASYNC_MAXCOUNT 15 //Number of seconds used to form average
474       dt1=current_time();
475       if(  diskread_flag == 0 &&
476            new_baseb_flag == 0 &&
477            dt1-dasync_avgtime > dasync_time_interval &&
478            rx_audio_out != -1)
479         {
480         dasync_avgtime=dt1;
481         lir_sched_yield();
482         make_timing_info();
483         if(kill_all_flag) goto da_output_error;
484         if(timinfo_flag != 0)
485           {
486           sprintf(s,"sync:%f ",total_wttim-dasync_avg3);
487           lir_text(26,screen_last_line-8,s);
488           }
489         if(dasync_avg3 >= 0 && fabs(total_wttim-dasync_avg3)>0.5)
490           {
491           dasync_errors++;
492           sprintf(s,"DA SYNC ERRORS %d",dasync_errors);
493           wg_error(s,WGERR_DASYNC);
494           baseb_reset_counter++;
495           da_start_bytes=-1;
496           dasync_counter=0;
497           }
498         dasync_counter++;
499         dasync_sum+=total_wttim;
500         if(dasync_counter >= DASYNC_MAXCOUNT)
501           {
502           dasync_avg1=dasync_sum/dasync_counter;
503           dasync_counter=0;
504           dasync_sum=0;
505           t2=dt1-dasync_time;
506           dasync_time=dt1;
507           if(dasync_avg2 > 0)
508             {
509 // The drift between input and output after t2 seconds is
510 // the difference between the two averages.
511 // Convert to frequency ratio, but use half the error only
512 // to avoid oscillations.
513 // Correct for the deviation from the first average, but only 20%
514 // so we drift slowy towards it if we are off.
515 // also add 5% of the time deviation from the ideal time.
516             t1= (t2+0.5*(dasync_avg2-dasync_avg1)+
517                                    0.2*(dasync_avg3-dasync_avg1))/t2;
518 //            dasync_avg3=0.9*dasync_avg3+0.1*da_wait_time;
519             new_da_resample_ratio=da_resample_ratio*t1;
520             dasync_avg2=dasync_avg1;
521             }
522           else
523             {
524             if(dasync_avg3 <0)
525               {
526               dasync_avg3=dasync_avg1;
527               }
528             else
529               {
530               dasync_avg2=dasync_avg1;
531               }
532             }
533           }
534         }
535       if(thread_command_flag[THREAD_RX_OUTPUT] !=
536                                             THRFLAG_ACTIVE)goto stop_output;
537       }
538     }
539 // ***********************************************************
540   lir_sched_yield();
541   if( ((baseb_pa-baseb_py+baseband_size)&baseband_mask) > baseb_output_block )
542     {
543     if( ((daout_px-snd[RXDA].block_bytes-daout_pa+daout_size)&daout_bufmask) > (daout_size>>1) )
544       {
545       make_audio_signal();
546       }
547     else
548       {
549       if(audio_dump_flag==0)lir_sleep(sleep_time);
550       }
551     }
552   lir_sched_yield();
553   if( ((baseb_pa-baseb_py+baseband_size)&baseband_mask) <= baseb_output_block )
554     {
555     lir_await_event(EVENT_BASEB);
556     }
557   if( (ui.network_flag&NET_RXOUT_BASEBRAW) != 0)
558     {
559 #if NET_BASEBRAW_MODE == WFM_FM_FIRST_LOWPASS || \
560     NET_BASEBRAW_MODE == WFM_FM_FIRST_LOWPASS_UPSAMP || \
561     NET_BASEBRAW_MODE == WFM_STEREO_LOW || \
562     NET_BASEBRAW_MODE == WFM_STEREO_HIGH
563     int *ntbuf;
564     while(baseb_pn != baseb_pa &&
565      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
566       {
567       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
568       ntbuf[0]=floor(1000000000.*baseb_fm_demod_low[baseb_pn]);
569       baseb_pn=(baseb_pn+1)&baseband_mask;
570       basebrawnet_pa=(basebrawnet_pa+4)&basebrawnet_mask;
571       }
572 #endif
573 #if NET_BASEBRAW_MODE == WFM_FM_FULL_BANDWIDTH
574     int *ntbuf;
575     while(baseb_pn != baseb_pa &&
576      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
577       {
578       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
579       ntbuf[0]=floor(300000000.*baseb_fm_demod[baseb_pn]);
580       baseb_pn=(baseb_pn+1)&baseband_mask;
581       basebrawnet_pa=(basebrawnet_pa+4)&basebrawnet_mask;
582       }
583 #endif
584 #if NET_BASEBRAW_MODE == WFM_AM_FIRST_LOWPASS
585     int *ntbuf;
586     while(baseb_pn != baseb_pa &&
587      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
588       {
589       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
590       ntbuf[0]=floor(0.2*sqrt(baseb_carrier_ampl[baseb_pn]));
591       baseb_pn=(baseb_pn+1)&baseband_mask;
592       basebrawnet_pa=(basebrawnet_pa+4)&basebrawnet_mask;
593       }
594 #endif
595 #if NET_BASEBRAW_MODE == WFM_FM_FIRST_LOWPASS_RESAMP
596     int *ntbuf;
597     while(fm1_px != fm1_pa &&
598      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
599       {
600       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
601       ntbuf[0]=floor(fm1_all[fm1_px]);
602 //        baseb_pn=(baseb_pn+1)&baseband_mask;
603       fm1_px=(fm1_px+1)&fm1_mask;
604       basebrawnet_pa=(basebrawnet_pa+4)&basebrawnet_mask;
605       }
606 #endif
607 #if NET_BASEBRAW_MODE == BASEBAND_IQ
608     int *ntbuf;
609     if(ui.rx_rf_channels == 1)
610       {
611       while(baseb_pn != baseb_pa &&
612         ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
613         {
614         ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
615         ntbuf[0]=floor(0.05*baseb_raw[2*baseb_pn  ]);
616         ntbuf[1]=floor(0.05*baseb_raw[2*baseb_pn+1]);
617         baseb_pn=(baseb_pn+1)&baseband_mask;
618         basebrawnet_pa=(basebrawnet_pa+8)&basebrawnet_mask;
619         }
620       }
621     else
622       {
623       while(baseb_pn != baseb_pa &&
624         ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
625         {
626         ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
627         ntbuf[0]=floor(0.05*baseb_raw[2*baseb_pn  ]);
628         ntbuf[1]=floor(0.05*baseb_raw[2*baseb_pn+1]);
629         ntbuf[2]=floor(0.05*baseb_raw_orthog[2*baseb_pn  ]);
630         ntbuf[3]=floor(0.05*baseb_raw_orthog[2*baseb_pn+1]);
631         baseb_pn=(baseb_pn+1)&baseband_mask;
632         basebrawnet_pa=(basebrawnet_pa+16)&basebrawnet_mask;
633         }
634       }
635 #endif
636 #if NET_BASEBRAW_MODE == WFM_SYNTHETIZED_FROM_FIRST_LOWPASS || \
637     NET_BASEBRAW_MODE == WFM_SUBTRACT_FROM_FIRST_LOWPASS
638     int *ntbuf;
639     while(baseb_pn != baseb_pa &&
640      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
641       {
642       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
643       for(i=0; i<basebraw_ad_channels; i++)
644         {
645         ntbuf[i]=floor(0.05*baseb_carrier[basebraw_ad_channels*baseb_pn+i]);
646         }
647       baseb_pn=(baseb_pn+1)&baseband_mask;
648       basebrawnet_pa=(basebrawnet_pa+4*basebraw_ad_channels)&basebrawnet_mask;
649       }
650 #endif
651 #if NET_BASEBRAW_MODE == WFM_AM_FULL_BANDWIDTH
652     int *ntbuf;
653     while(baseb_pn != baseb_pa &&
654      ((basebrawnet_px-basebrawnet_pa+basebrawnet_mask)&basebrawnet_mask) >16)
655       {
656       ntbuf=(int*)&basebraw_netsend_buffer[basebrawnet_pa];
657       ntbuf[0]=0.1*floor(sqrt(baseb_totpwr[baseb_pn]));
658       baseb_pn=(baseb_pn+1)&baseband_mask;
659       basebrawnet_pa=(basebrawnet_pa+4)&basebrawnet_mask;
660       }
661 #endif
662     }
663   if(kill_all_flag) goto da_output_error;
664   if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
665   if(audio_dump_flag == 1 || rx_audio_out == -1)
666     {
667     while( ((daout_pa-daout_px+daout_size)&daout_bufmask) >
668                                                  snd[RXDA].block_bytes)
669       {
670       daout_px=(daout_px+snd[RXDA].block_bytes)&daout_bufmask;
671       if(kill_all_flag) goto da_output_error;
672       if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
673       }
674     lir_sched_yield();
675     if(kill_all_flag) goto da_output_error;
676     if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
677     }
678   while(daout_px != daout_py)
679     {
680     if(wav_write_flag != 0)
681       {
682       if(fwrite(&daout[daout_py],snd[RXDA].block_bytes,1,wav_file)!=1)
683                                                         wavsave_start_stop(0);
684       }
685     da_block_counter+=1;
686     daout_py=(daout_py+snd[RXDA].block_bytes)&daout_bufmask;
687     if(kill_all_flag) goto da_output_error;
688     if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)goto stop_output;
689     }
690 #if BUFBARS == TRUE
691   if(baseband_handle != NULL && timinfo_flag!=0)
692     {
693     i=(daout_pa+2-daout_px+daout_bufmask+1)&daout_bufmask;
694     i/=daout_indicator_block;
695     show_bufbar(7,i);
696     }
697 #endif
698   }
699 stop_output:;
700 if(blocking)
701   {
702   lir_set_event(EVENT_BLOCKING_RXOUT);
703   linrad_thread_stop_and_join(THREAD_BLOCKING_RXOUT);
704   lir_close_event(EVENT_BLOCKING_RXOUT);
705   }
706 //stop_output_2:;
707 daout_px=0;
708 daout_pa=0;
709 daout_py=0;
710 if(thread_command_flag[THREAD_RX_OUTPUT] == THRFLAG_IDLE)
711   {
712   if(rx_audio_out >= 0)lir_empty_da_device_buffer();
713   thread_status_flag[THREAD_RX_OUTPUT] = THRFLAG_IDLE;
714   lir_sleep(10000);
715   while(thread_command_flag[THREAD_RX_OUTPUT] == THRFLAG_IDLE)
716     {
717     lir_sleep(5000);
718     if(kill_all_flag) goto da_output_error;
719     }
720   daout_px=0;
721   daout_pa=0;
722   while(thread_command_flag[THREAD_RX_OUTPUT] == THRFLAG_SEMCLEAR)
723     {
724     thread_status_flag[THREAD_RX_OUTPUT] = THRFLAG_SEMCLEAR;
725     lir_await_event(EVENT_RX_START_DA);
726     if(kill_all_flag) goto da_output_error;
727     }
728   if(thread_command_flag[THREAD_RX_OUTPUT] == THRFLAG_ACTIVE)
729     {
730     if( rx_audio_out != -1 && (local_channels != rx_daout_channels ||
731                                local_bytes != rx_daout_bytes ||
732                                local_fft3_blocktime != fft3_blocktime))
733       {
734       sys_func(THRFLAG_CLOSE_RX_SNDOUT);
735       lir_sched_yield();
736       if(rx_daout_bytes == 1)
737         {
738         cc=0x80;
739         }
740       else
741         {
742         cc=0;
743         }
744       daout_px=0;
745       daout_pa=0;
746       memset(&daout[daout_px],cc,snd[RXDA].block_bytes);
747       sys_func(THRFLAG_OPEN_RX_SNDOUT);
748       if(kill_all_flag || lir_rxout_status != LIR_OK) goto da_output_error;
749       lir_empty_da_device_buffer();
750       da_start_bytes=-1;
751       local_channels=rx_daout_channels;
752       local_bytes=rx_daout_bytes;
753       local_fft3_blocktime=fft3_blocktime;
754       }
755     if(kill_all_flag) goto da_output_error;
756     goto resume;
757     }
758   }
759 da_output_error:;
760 count_rx_underrun_flag=FALSE;
761 if(blocking && thread_command_flag[THREAD_BLOCKING_RXOUT] != THRFLAG_NOT_ACTIVE)
762   {
763   linrad_thread_stop_and_join(THREAD_BLOCKING_RXOUT);
764   }
765 if(rx_audio_out >= 0)
766   {
767 /*
768   if( (ui.use_alsa&(PORTAUDIO_TX_IN+PORTAUDIO_RX_OUT)) == 0)
769     {
770     while( rx_audio_out == tx_audio_in)lir_sleep(10000);
771     }
772 // Perhaps when using OSS in RDWR mode???
773 */
774   sys_func(THRFLAG_CLOSE_RX_SNDOUT);
775   }
776 thread_status_flag[THREAD_RX_OUTPUT]=THRFLAG_RETURNED;
777 while(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_NOT_ACTIVE &&
778       thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_KILL)
779   {
780   lir_sleep(1000);
781   }
782 }
783 
make_audio_signal(void)784 void make_audio_signal(void)
785 {
786 int i,i1,i2,i3,i4,mm,nn;
787 float t1,t2,t3,t4,t5,t6,t7;
788 float a1, a2, b1, b2, u1, u2;
789 double dt1;
790 short int *intvar;
791 short int *ntbuf;
792 float r1,r2,r3,r4;
793 float rdiff, final_gain1, final_gain2;
794 float baseb_r1, baseb_r2;
795 int loop_counter;
796 i=1;
797 if(bg_filter_points > 5 && 2*bg_filter_points < bg_xpoints)
798   {
799   if(bg.squelch_level !=0)
800     {
801     if(recent_time-squelch_turnon_time > bg.squelch_time+0.1)
802       {
803       i=0;
804       }
805     }
806   }
807 squelch_on=i;
808 // Resample the baseband signal so we get the correct sampling speed
809 // for the D/A converter.
810 // For each interval in baseb_out there is a non integer number of points
811 // in da_output.
812 dt1=1/sqrt(rx_daout_sin*rx_daout_sin+rx_daout_cos*rx_daout_cos);
813 rx_daout_sin*=dt1;
814 rx_daout_cos*=dt1;
815 final_gain1=final_gain2=0;
816 mm=snd[RXDA].framesize;
817 nn=2*baseb_channels;
818 baseb_r1=daout_pa/(mm*da_resample_ratio);
819 loop_counter=0;
820 resamp:;
821 baseb_r2=(daout_pa+mm)/(mm*da_resample_ratio);
822 i2=baseb_fx+baseb_r1+.5;
823 if(baseb_r2>baseb_r1)
824   {
825   i3=baseb_fx+baseb_r2+.5;
826   }
827 else
828   {
829   i3=baseb_fx+baseb_r2+.5+daout_size/da_resample_ratio;
830   }
831 i2&=baseband_mask;
832 i3&=baseband_mask;
833 if(abs(i3-i2) > 1)
834   {
835   i2=baseb_fx+(baseb_r1+baseb_r2)/2;
836   i3=i2+1;
837   i2&=baseband_mask;
838   i3&=baseband_mask;
839   }
840 else
841   {
842   if(i3==i2)
843     {
844     i2=baseb_fx+baseb_r1;
845     i2&=baseband_mask;
846     if(i3==i2)
847       {
848       i3=i2+1;
849       i3&=baseband_mask;
850       }
851     }
852   }
853 i4=(i3+1)&baseband_mask;
854 baseb_py=i4;
855 i1=(i2+baseband_mask)&baseband_mask;
856 baseb_wts=baseb_pa-baseb_r2-baseb_fx;
857 if(baseb_wts<0)baseb_wts+=baseband_size;
858 loop_counter++;
859 if(loop_counter > 2*baseb_output_block)lir_sched_yield();
860 if( ((daout_pa-daout_px+daout_size)&daout_bufmask) > (daout_size>>1) ||
861      ((baseb_pa-baseb_py+baseband_size)&baseband_mask) < baseb_min_block)
862   {
863   return;
864   }
865 rdiff=baseb_r1+baseb_fx-i2;
866 if(rdiff > baseband_size/2)
867   {
868   rdiff-=baseband_size;
869   }
870 // Use Lagrange's interpolation formula to fit a third degree
871 // polynomial to 4 points:
872 //  a1=-rdiff *   (rdiff-1)*(rdiff-2)*baseb_out[nn*i1]/6
873 //     +(rdiff+1)*(rdiff-1)*(rdiff-2)*baseb_out[nn*i2]/2
874 //     -(rdiff+1)* rdiff   *(rdiff-2)*baseb_out[nn*i3]/2
875 //     +(rdiff+1)* rdiff   *(rdiff-1)*baseb_out[nn*i4]/6;
876 // Rewrite slightly to save a few multiplications - do not
877 // think the compiler is smart enough to do it for us.
878 t1=rdiff-1;
879 t2=rdiff-2;
880 t3=rdiff+1;
881 t4=t1*t2;
882 t5=t3*rdiff;
883 t6=rdiff*t4;
884 t4=t3*t4;
885 t7=t5*t2;
886 t5=t5*t1;
887 final_gain1=daout_gain;
888 final_gain2=daout_gain;
889 if(bg.agc_flag == 1)
890   {
891   if( daout_gain*baseb_agc_level[i2] > bg_agc_amplimit)
892     {
893     final_gain1=bg_agc_amplimit/baseb_agc_level[i2];
894     final_gain2=final_gain1;
895     }
896   }
897 if(bg.agc_flag == 2)
898   {
899   if( daout_gain*baseb_agc_level[2*i2] > bg_agc_amplimit)
900     {
901     final_gain1=bg_agc_amplimit/baseb_agc_level[2*i2];
902     }
903   if( daout_gain*baseb_agc_level[2*i2+1] > bg_agc_amplimit)
904     {
905     final_gain2=bg_agc_amplimit/baseb_agc_level[2*i2+1];
906     }
907   }
908 if(squelch_on == 0)
909   {
910   final_gain1=0;
911   final_gain2=0;
912   }
913 
914 a1=final_gain1*(((t5*baseb_out[nn*i4  ]-t6*baseb_out[nn*i1  ])/3
915                     +t4*baseb_out[nn*i2  ]-t7*baseb_out[nn*i3  ])/2);
916 a2=final_gain1*(((t5*baseb_out[nn*i4+1]-t6*baseb_out[nn*i1+1])/3
917                     +t4*baseb_out[nn*i2+1]-t7*baseb_out[nn*i3+1])/2);
918 if(enable_resamp_iir5)
919   {
920   xva1[0]=xva1[1];
921   xva1[1]=xva1[2];
922   xva1[2]=xva1[3];
923   xva1[3]=xva1[4];
924   xva1[4]=xva1[5];
925   xva1[5]=a1/iir_a.gain;
926   yva1[0]=yva1[1];
927   yva1[1]=yva1[2];
928   yva1[2]=yva1[3];
929   yva1[3]=yva1[4];
930   yva1[4]=yva1[5];
931   yva1[5]=xva1[0]+xva1[5]+5*(xva1[1]+xva1[4])+10*(xva1[2]+xva1[3])+
932           iir_a.c0*yva1[0]+iir_a.c1*yva1[1]+iir_a.c2*yva1[2]+
933           iir_a.c3 * yva1[3]+iir_a.c4*yva1[4];
934   a1=yva1[5];
935   xva2[0]=xva2[1];
936   xva2[1]=xva2[2];
937   xva2[2]=xva2[3];
938   xva2[3]=xva2[4];
939   xva2[4]=xva2[5];
940   xva2[5]=a2/iir_a.gain;
941   yva2[0]=yva2[1];
942   yva2[1]=yva2[2];
943   yva2[2]=yva2[3];
944   yva2[3]=yva2[4];
945   yva2[4]=yva2[5];
946   yva2[5]=xva2[0]+xva2[5]+5*(xva2[1] + xva2[4])+10*(xva2[2]+xva2[3])+
947           iir_a.c0*yva2[0]+iir_a.c1*yva2[1]+iir_a.c2*yva2[2]+
948           iir_a.c3*yva2[3]+iir_a.c4*yva2[4];
949   a2=yva2[5];
950   }
951 old_out1=out1;
952 old_out2=out2;
953 if(baseb_channels == 1)
954   {
955   if( (ui.network_flag&NET_RXOUT_BASEB) != 0)
956     {
957     ntbuf=(short int*)&baseb_netsend_buffer[basebnet_pa];
958     if(rx_daout_bytes == 1)
959       {
960       ntbuf[0]=floor(256*a2);
961       ntbuf[1]=floor(256*a1);
962       }
963     else
964       {
965       ntbuf[0]=floor(a2);
966       ntbuf[1]=floor(a1);
967       }
968     basebnet_pa=(basebnet_pa+4)&basebnet_mask;
969     }
970   if(rx_mode == MODE_FM)
971     {
972     out1=a1;
973     out2=a2;
974 // ************************************
975     t1=(out1-old_out1)/daout_upsamp;
976     t2=old_out1;
977     t3=(out2-old_out2)/daout_upsamp;
978     t4=old_out2;
979     for(i=0; i<daout_upsamp; i++)
980       {
981       xv1[0]=xv1[1];
982       xv1[1]=xv1[2];
983       xv1[2]=xv1[3];
984       xv1[3]=t2/iir3_gain[daout_upsamp_n];
985       yv1[0]=yv1[1];
986       yv1[1]=yv1[2];
987       yv1[2]=yv1[3];
988       yv1[3]=xv1[0]+xv1[3]+3*(xv1[1]+xv1[2])+
989               iir3_c0[daout_upsamp_n]*yv1[0]+
990               iir3_c1[daout_upsamp_n]*yv1[1]+
991               iir3_c2[daout_upsamp_n]*yv1[2];
992       a1 = yv1[3];
993       xv2[0]=xv2[1];
994       xv2[1]=xv2[2];
995       xv2[2]=xv2[3];
996       xv2[3]=t4/iir3_gain[daout_upsamp_n];
997       yv2[0]=yv2[1];
998       yv2[1]=yv2[2];
999       yv2[2]=yv2[3];
1000       yv2[3]=xv2[0]+xv2[3]+3*(xv2[1]+xv2[2])+
1001                     iir3_c0[daout_upsamp_n]*yv2[0]+
1002                     iir3_c1[daout_upsamp_n]*yv2[1]+
1003                     iir3_c2[daout_upsamp_n]*yv2[2];
1004       a2 = yv2[3];
1005       if(a1 < -bg_amplimit)a1=-bg_amplimit;
1006       if(a1 > bg_amplimit)a1=bg_amplimit;
1007       if(bg_maxamp < fabs(a1))bg_maxamp=fabs(a1);
1008       if(a2 < -bg_amplimit)a2=-bg_amplimit;
1009       if(a2 > bg_amplimit)a2=bg_amplimit;
1010       if(bg_maxamp < fabs(a2))bg_maxamp=fabs(a2);
1011       if(rx_daout_bytes == 1)
1012         {
1013         daout[daout_pa]=0x80+a1;
1014         if(rx_daout_channels == 2)daout[daout_pa+1]=0x80+a2;
1015         }
1016       else
1017         {
1018         intvar=(short int*)(&daout[daout_pa]);
1019         intvar[0]=a1;
1020         if(rx_daout_channels == 2)intvar[1]=a2;
1021         }
1022       daout_pa=(daout_pa+mm)&daout_bufmask;
1023       t2+=t1;
1024       t4+=t3;
1025       }
1026     }
1027   else
1028     {
1029     if(bg_expand != 2)
1030       {
1031       t1=sqrt(a1*a1+a2*a2);
1032       if(t1 > 0.5)
1033         {
1034         if(t1<bg_amplimit)t2=t1; else t2=bg_amplimit;
1035         if(bg_expand == 1)t2=bg_expand_a*(exp(bg_expand_b*t2)-1);
1036         t2/=t1;
1037         out1=t2*a1;
1038         out2=t2*a2;
1039         }
1040       else
1041         {
1042         out1=0;
1043         out2=0;
1044         }
1045       }
1046     else
1047       {
1048       out1=a1;
1049       out2=a2;
1050       }
1051     t1=(out1-old_out1)/daout_upsamp;
1052     t2=old_out1;
1053     t3=(out2-old_out2)/daout_upsamp;
1054     t4=old_out2;
1055     for(i=0; i<daout_upsamp; i++)
1056       {
1057       dt1=rx_daout_cos;
1058       rx_daout_cos=rx_daout_cos*rx_daout_phstep_cos+
1059                    rx_daout_sin*rx_daout_phstep_sin;
1060       rx_daout_sin=rx_daout_sin*rx_daout_phstep_cos-
1061                             dt1*rx_daout_phstep_sin;
1062       xv1[0]=xv1[1];
1063       xv1[1]=xv1[2];
1064       xv1[2]=xv1[3];
1065       xv1[3]=t2/iir3_gain[daout_upsamp_n];
1066       yv1[0]=yv1[1];
1067       yv1[1]=yv1[2];
1068       yv1[2]=yv1[3];
1069       yv1[3]=xv1[0]+xv1[3]+3*(xv1[1]+xv1[2])+
1070               iir3_c0[daout_upsamp_n]*yv1[0]+
1071               iir3_c1[daout_upsamp_n]*yv1[1]+
1072               iir3_c2[daout_upsamp_n]*yv1[2];
1073       a1 = yv1[3];
1074       xv2[0]=xv2[1];
1075       xv2[1]=xv2[2];
1076       xv2[2]=xv2[3];
1077       xv2[3]=t4/iir3_gain[daout_upsamp_n];
1078       yv2[0]=yv2[1];
1079       yv2[1]=yv2[2];
1080       yv2[2]=yv2[3];
1081       yv2[3]=xv2[0]+xv2[3]+3*(xv2[1]+xv2[2])+
1082                     iir3_c0[daout_upsamp_n]*yv2[0]+
1083                     iir3_c1[daout_upsamp_n]*yv2[1]+
1084                     iir3_c2[daout_upsamp_n]*yv2[2];
1085       a2 = yv2[3];
1086       u1= a1*rx_daout_cos+a2*rx_daout_sin;
1087       if(u1 > bg_amplimit)u1=bg_amplimit;
1088       if(u1 < -bg_amplimit)u1=-bg_amplimit;
1089       if(bg_maxamp < fabs(u1))bg_maxamp=fabs(u1);
1090       if(da_ch2_sign == 0)
1091         {
1092         u2=-a1*rx_daout_sin+a2*rx_daout_cos;
1093         if(u2 > bg_amplimit)u2=bg_amplimit;
1094         if(u2 < -bg_amplimit)u2=-bg_amplimit;
1095         if(bg_maxamp < fabs(u2))bg_maxamp=fabs(u2);
1096         if(rx_daout_bytes == 1)
1097           {
1098           daout[daout_pa  ]=0x80+u1;
1099           daout[daout_pa+1]=0x80+u2;
1100           }
1101         else
1102           {
1103           intvar=(short int*)(&daout[daout_pa]);
1104           intvar[0]=u1;
1105           intvar[1]=u2;
1106           }
1107         }
1108       else
1109         {
1110         if(rx_daout_bytes == 1)
1111           {
1112           daout[daout_pa]=0x80+u1;
1113           if(rx_daout_channels == 2)daout[daout_pa+1]=0x80+u1*da_ch2_sign;
1114           }
1115         else
1116           {
1117           intvar=(short int*)(&daout[daout_pa]);
1118           intvar[0]=u1;
1119           if(rx_daout_channels == 2)intvar[1]=u1*da_ch2_sign;
1120           }
1121         }
1122       daout_pa=(daout_pa+mm)&daout_bufmask;
1123       t2+=t1;
1124       t4+=t3;
1125       }
1126     }
1127   }
1128 else
1129   {
1130   old_out3=out3;
1131   old_out4=out4;
1132   b1=final_gain2*(((t5*baseb_out[nn*i4+2]-t6*baseb_out[nn*i1+2])/3
1133                     +t4*baseb_out[nn*i2+2]-t7*baseb_out[nn*i3+2])/2);
1134   b2=final_gain2*(((t5*baseb_out[nn*i4+3]-t6*baseb_out[nn*i1+3])/3
1135                     +t4*baseb_out[nn*i2+3]-t7*baseb_out[nn*i3+3])/2);
1136   if(enable_resamp_iir5)
1137     {
1138     xvb1[0]=xvb1[1];
1139     xvb1[1]=xvb1[2];
1140     xvb1[2]=xvb1[3];
1141     xvb1[3]=xvb1[4];
1142     xvb1[4]=xvb1[5];
1143     xvb1[5]=b1/iir_a.gain;
1144     yvb1[0]=yvb1[1];
1145     yvb1[1]=yvb1[2];
1146     yvb1[2]=yvb1[3];
1147     yvb1[3]=yvb1[4];
1148     yvb1[4]=yvb1[5];
1149     yvb1[5]=xvb1[0]+xvb1[5]+5*(xvb1[1]+xvb1[4])+10*(xvb1[2]+xvb1[3])+
1150             iir_a.c0*yvb1[0]+iir_a.c1*yvb1[1]+iir_a.c2*yvb1[2]+
1151             iir_a.c3 * yvb1[3]+iir_a.c4*yvb1[4];
1152     b1=yvb1[5];
1153     xvb2[0]=xvb2[1];
1154     xvb2[1]=xvb2[2];
1155     xvb2[2]=xvb2[3];
1156     xvb2[3]=xvb2[4];
1157     xvb2[4]=xvb2[5];
1158     xvb2[5]=b2/iir_a.gain;
1159     yvb2[0]=yvb2[1];
1160     yvb2[1]=yvb2[2];
1161     yvb2[2]=yvb2[3];
1162     yvb2[3]=yvb2[4];
1163     yvb2[4]=yvb2[5];
1164     yvb2[5]=xvb2[0]+xvb2[5]+5*(xvb2[1] + xvb2[4])+10*(xvb2[2]+xvb2[3])+
1165             iir_a.c0*yvb2[0]+iir_a.c1*yvb2[1]+iir_a.c2*yvb2[2]+
1166             iir_a.c3*yvb2[3]+iir_a.c4*yvb2[4];
1167     b2=yvb2[5];
1168     }
1169   if( (ui.network_flag&NET_RXOUT_BASEB) != 0)
1170     {
1171     ntbuf=(short int*)&baseb_netsend_buffer[basebnet_pa];
1172     if(rx_daout_bytes == 1)
1173       {
1174       ntbuf[0]=floor(256*a2);
1175       ntbuf[1]=floor(256*a1);
1176       ntbuf[2]=floor(256*b2);
1177       ntbuf[3]=floor(256*b1);
1178       }
1179     else
1180       {
1181       ntbuf[0]=floor(a2);
1182       ntbuf[1]=floor(a1);
1183       ntbuf[2]=floor(b2);
1184       ntbuf[3]=floor(b1);
1185       }
1186     basebnet_pa=(basebnet_pa+8)&basebnet_mask;
1187     }
1188   if( (bg_expand != 2 && bg.agc_flag != 2 ) || bg_twopol != 0)
1189     {
1190     t1=a1*a1+a2*a2;
1191     t2=b1*b1+b2*b2;
1192     if(t1 < t2)t1=t2;
1193     t1=sqrt(t1);
1194     if(t1 > 0.5)
1195       {
1196       if(t1<bg_amplimit)t2=t1; else t2=bg_amplimit;
1197       if(bg_expand == 1)t2=bg_expand_a*(exp(bg_expand_b*t2)-1);
1198       if(bg_maxamp < t2)bg_maxamp=t2;
1199       t2/=t1;
1200       out1=t2*a1;
1201       out2=t2*a2;
1202       out3=t2*b1;
1203       out4=t2*b2;
1204       }
1205     else
1206       {
1207       out1=0;
1208       out2=0;
1209       out3=0;
1210       out4=0;
1211       }
1212     }
1213   else
1214     {
1215     out1=a1;
1216     out2=a2;
1217     out3=b1;
1218     out4=b2;
1219     }
1220 // ************************************
1221   t1=(out1-old_out1)/daout_upsamp;
1222   t2=old_out1;
1223   t3=(out2-old_out2)/daout_upsamp;
1224   t4=old_out2;
1225   r1=(out3-old_out3)/daout_upsamp;
1226   r2=old_out3;
1227   r3=(out4-old_out4)/daout_upsamp;
1228   r4=old_out4;
1229   for(i=0; i<daout_upsamp; i++)
1230     {
1231     dt1=rx_daout_cos;
1232     rx_daout_cos=rx_daout_cos*rx_daout_phstep_cos+
1233                  rx_daout_sin*rx_daout_phstep_sin;
1234     rx_daout_sin=rx_daout_sin*rx_daout_phstep_cos-
1235                         dt1*rx_daout_phstep_sin;
1236     xv1[0]=xv1[1];
1237     xv1[1]=xv1[2];
1238     xv1[2]=xv1[3];
1239     xv1[3]=t2/iir3_gain[daout_upsamp_n];
1240     yv1[0]=yv1[1];
1241     yv1[1]=yv1[2];
1242     yv1[2]=yv1[3];
1243     yv1[3]=xv1[0]+xv1[3]+3*(xv1[1]+xv1[2])+
1244                      iir3_c0[daout_upsamp_n]*yv1[0]+
1245                      iir3_c1[daout_upsamp_n]*yv1[1]+
1246                      iir3_c2[daout_upsamp_n]*yv1[2];
1247     a1 = yv1[3];
1248     xv2[0]=xv2[1];
1249     xv2[1]=xv2[2];
1250     xv2[2]=xv2[3];
1251     xv2[3]=t4/iir3_gain[daout_upsamp_n];
1252     yv2[0]=yv2[1];
1253     yv2[1]=yv2[2];
1254     yv2[2]=yv2[3];
1255     yv2[3]=xv2[0]+xv2[3]+3*(xv2[1]+xv2[2])+
1256                      iir3_c0[daout_upsamp_n]*yv2[0]+
1257                      iir3_c1[daout_upsamp_n]*yv2[1]+
1258                      iir3_c2[daout_upsamp_n]*yv2[2];
1259     a2 = yv2[3];
1260     xv3[0]=xv3[1];
1261     xv3[1]=xv3[2];
1262     xv3[2]=xv3[3];
1263     xv3[3]=r2/iir3_gain[daout_upsamp_n];
1264     yv3[0]=yv3[1];
1265     yv3[1]=yv3[2];
1266     yv3[2]=yv3[3];
1267     yv3[3]=xv3[0]+xv3[3]+3*(xv3[1]+xv3[2])+
1268                      iir3_c0[daout_upsamp_n]*yv3[0]+
1269                      iir3_c1[daout_upsamp_n]*yv3[1]+
1270                      iir3_c2[daout_upsamp_n]*yv3[2];
1271     b1 = yv3[3];
1272     xv4[0]=xv4[1];
1273     xv4[1]=xv4[2];
1274     xv4[2]=xv4[3];
1275     xv4[3]=r4/iir3_gain[daout_upsamp_n];
1276     yv4[0]=yv4[1];
1277     yv4[1]=yv4[2];
1278     yv4[2]=yv4[3];
1279     yv4[3]=xv4[0]+xv4[3]+3*(xv4[1]+xv4[2])+
1280                      iir3_c0[daout_upsamp_n]*yv4[0]+
1281                      iir3_c1[daout_upsamp_n]*yv4[1]+
1282                      iir3_c2[daout_upsamp_n]*yv4[2];
1283     b2 = yv4[3];
1284     u1= a1*rx_daout_cos+a2*rx_daout_sin;
1285     if(u1 > bg_amplimit)u1=bg_amplimit;
1286     if(u1 < -bg_amplimit)u1=-bg_amplimit;
1287   //  if(bg_maxamp < fabs(u1))bg_maxamp=fabs(u1);
1288     u2= b1*rx_daout_cos+b2*rx_daout_sin;
1289     if(u2 > bg_amplimit)u2=bg_amplimit;
1290     if(u2 < -bg_amplimit)u2=-bg_amplimit;
1291  //   if(bg_maxamp < fabs(u2))bg_maxamp=fabs(u2);
1292     if(rx_daout_bytes == 1)
1293       {
1294       daout[daout_pa]=0x80+u1;
1295       if(rx_daout_channels == 2)daout[daout_pa+1]=0x80+u2;
1296       }
1297     else
1298       {
1299       intvar=(short int*)(&daout[daout_pa]);
1300       intvar[0]=u1;
1301       if(rx_daout_channels == 2)intvar[1]=u2;
1302       }
1303 if(rx_daout_channels==1)lirerr(213567);
1304     daout_pa=(daout_pa+mm)&daout_bufmask;
1305     t2+=t1;
1306     t4+=t3;
1307     r2+=r1;
1308     r4+=r3;
1309     }
1310   }
1311 baseb_r1=baseb_r2;
1312 
1313 if(daout_pa > daout_bufmask)lirerr(994578);
1314 if(daout_pa == 0)
1315   {
1316   baseb_fx+=baseb_r2;
1317   baseb_r1=0;
1318   da_resample_ratio=new_da_resample_ratio;
1319   if(baseb_fx>baseband_size)baseb_fx-=baseband_size;
1320   if(use_bfo != 0)
1321     {
1322     t1=(2*PI_L*bg.bfo_freq)/genparm[DA_OUTPUT_SPEED];
1323     rx_daout_phstep_cos=cos(t1);
1324     rx_daout_phstep_sin=sin(t1);
1325     }
1326   }
1327 if(thread_command_flag[THREAD_RX_OUTPUT] != THRFLAG_ACTIVE)return;
1328 goto resamp;
1329 }
1330