Clean out old obsolete demodulators.

This commit is contained in:
wb2osz 2019-11-27 22:42:33 -05:00
parent 747224ce57
commit 249f5bd471
6 changed files with 7 additions and 369 deletions

View File

@ -173,9 +173,6 @@ struct audio_s {
int upsample; /* Upsample by this factor for G3RUH. */ int upsample; /* Upsample by this factor for G3RUH. */
int interleave; /* If > 1, interleave samples among multiple decoders. */
/* Quick hack for experiment. */
int mark_freq; /* Two tones for AFSK modulation, in Hz. */ int mark_freq; /* Two tones for AFSK modulation, in Hz. */
int space_freq; /* Standard tones are 1200 and 2200 for 1200 baud. */ int space_freq; /* Standard tones are 1200 and 2200 for 1200 baud. */

View File

@ -120,7 +120,6 @@ int demod_init (struct audio_s *pa)
* This can be increased by: * This can be increased by:
* Multiple frequencies. * Multiple frequencies.
* Multiple letters (not sure if I will continue this). * Multiple letters (not sure if I will continue this).
* New interleaved decoders.
* *
* num_slicers is set to max by the "+" option. * num_slicers is set to max by the "+" option.
*/ */
@ -313,48 +312,6 @@ int demod_init (struct audio_s *pa)
save_audio_config_p->achan[chan].num_subchan = num_letters; save_audio_config_p->achan[chan].num_subchan = num_letters;
/*
* Quick hack with special case for another experiment.
* Do this in a more general way if it turns out to be useful.
*/
save_audio_config_p->achan[chan].interleave = 1;
if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EE") == 0) {
save_audio_config_p->achan[chan].interleave = 2;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEE") == 0) {
save_audio_config_p->achan[chan].interleave = 3;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEEE") == 0) {
save_audio_config_p->achan[chan].interleave = 4;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "EEEEE") == 0) {
save_audio_config_p->achan[chan].interleave = 5;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GG") == 0) {
save_audio_config_p->achan[chan].interleave = 2;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGG") == 0) {
save_audio_config_p->achan[chan].interleave = 3;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGG+") == 0) {
save_audio_config_p->achan[chan].interleave = 3;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGGG") == 0) {
save_audio_config_p->achan[chan].interleave = 4;
save_audio_config_p->achan[chan].decimate = 1;
}
else if (strcasecmp(save_audio_config_p->achan[chan].profiles, "GGGGG") == 0) {
save_audio_config_p->achan[chan].interleave = 5;
save_audio_config_p->achan[chan].decimate = 1;
}
if (save_audio_config_p->achan[chan].num_subchan != num_letters) { if (save_audio_config_p->achan[chan].num_subchan != num_letters) {
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n", dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_subchan(%d) != strlen(\"%s\")\n",
@ -383,7 +340,7 @@ int demod_init (struct audio_s *pa)
dw_printf (" %d.%d: %c %d & %d\n", chan, d, profile, mark, space); dw_printf (" %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
} }
demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / (save_audio_config_p->achan[chan].decimate * save_audio_config_p->achan[chan].interleave), demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate,
save_audio_config_p->achan[chan].baud, save_audio_config_p->achan[chan].baud,
mark, mark,
space, space,

View File

@ -159,12 +159,6 @@ void demod_9600_init (int samples_per_sec, int baud, struct demodulator_state_s
D->pll_locked_inertia = 0.89; D->pll_locked_inertia = 0.89;
D->pll_searching_inertia = 0.67; D->pll_searching_inertia = 0.67;
D->play_it_again_sample = 0; // TODO: 1.6 experiment.
// assuming lp_filter_size > lp2_filter_size
D->lp2_filter_size = samples_per_sec / baud; // samples for 1 bit
// break; // break;
// } // }
@ -216,12 +210,6 @@ void demod_9600_init (int samples_per_sec, int baud, struct demodulator_state_s
(void)gen_lowpass (fc, D->lp_filter, D->lp_filter_size, D->lp_window, 0); (void)gen_lowpass (fc, D->lp_filter, D->lp_filter_size, D->lp_window, 0);
// Go back and resample where bit is expected.
fc = (float)baud * 1 / (float)samples_per_sec;
(void)gen_lowpass (fc, D->lp2_filter, D->lp2_filter_size, D->lp_window, 0);
/* Version 1.2: Experiment with different slicing levels. */ /* Version 1.2: Experiment with different slicing levels. */
for (j = 0; j < MAX_SUBCHANS; j++) { for (j = 0; j < MAX_SUBCHANS; j++) {
@ -524,32 +512,8 @@ inline static void nudge_pll (int chan, int subchan, int slice, float demod_out_
/* Overflow. Was large positive, wrapped around, now large negative. */ /* Overflow. Was large positive, wrapped around, now large negative. */
if (D->play_it_again_sample) { // New experiment in 1.6.
// FIXME: double check position and draw picture.
int offset = ( D->lp_filter_size - D->lp2_filter_size ) / 2;
float amp = convolve (D->raw_cb + offset, D->lp2_filter, D->lp2_filter_size);
int resampled;
if (D->num_slicers > 1) {
resampled = amp - slice_point[slice] > 0;;
}
else {
resampled = amp > 0;
}
hdlc_rec_bit (chan, subchan, slice, resampled, 1, D->slicer[slice].lfsr);
}
else {
// traditional
hdlc_rec_bit (chan, subchan, slice, demod_out_f > 0, 1, D->slicer[slice].lfsr); hdlc_rec_bit (chan, subchan, slice, demod_out_f > 0, 1, D->slicer[slice].lfsr);
} }
}
/* /*
* Zero crossing? * Zero crossing?

View File

@ -197,79 +197,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
switch (profile) { switch (profile) {
case 'A':
/* Original. 52 taps, truncated bandpass, IIR lowpass */
/* 'F' is the fast version for low end processors. */
/* It is a special case that works only for a particular */
/* baud rate, tone pair, and sampling rate. */
D->use_prefilter = 0;
D->ms_filter_len_bits = 1.415; /* 52 @ 44100, 1200 */
D->ms_window = BP_WINDOW_TRUNCATED;
//D->bp_window = BP_WINDOW_TRUNCATED;
D->lpf_use_fir = 0;
D->lpf_iir = 0.195;
D->agc_fast_attack = 0.250;
D->agc_slow_decay = 0.00012;
D->hysteresis = 0.005;
D->pll_locked_inertia = 0.700;
D->pll_searching_inertia = 0.580;
break;
case 'B':
/* Original bandpass. Use FIR lowpass instead. */
D->use_prefilter = 0;
D->ms_filter_len_bits = 1.415; /* 52 @ 44100, 1200 */
D->ms_window = BP_WINDOW_TRUNCATED;
//D->bp_window = BP_WINDOW_TRUNCATED;
D->lpf_use_fir = 1;
D->lpf_baud = 1.09;
D->lp_filter_len_bits = D->ms_filter_len_bits;
D->lp_window = BP_WINDOW_TRUNCATED;
D->agc_fast_attack = 0.370;
D->agc_slow_decay = 0.00014;
D->hysteresis = 0.003;
D->pll_locked_inertia = 0.620;
D->pll_searching_inertia = 0.350;
break;
case 'C':
/* Cosine window, 76 taps for bandpass, FIR lowpass. */
D->use_prefilter = 0;
D->ms_filter_len_bits = 2.068; /* 76 @ 44100, 1200 */
D->ms_window = BP_WINDOW_COSINE;
//D->bp_window = BP_WINDOW_COSINE;
D->lpf_use_fir = 1;
D->lpf_baud = 1.09;
D->lp_filter_len_bits = D->ms_filter_len_bits;
D->lp_window = BP_WINDOW_TRUNCATED;
D->agc_fast_attack = 0.495;
D->agc_slow_decay = 0.00022;
D->hysteresis = 0.005;
D->pll_locked_inertia = 0.620;
D->pll_searching_inertia = 0.350;
break;
case 'D': case 'D':
/* Prefilter, Cosine window, FIR lowpass. Tweeked for 300 baud. */ /* Prefilter, Cosine window, FIR lowpass. Tweeked for 300 baud. */
@ -335,73 +262,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
D->pll_searching_inertia = 0.50; D->pll_searching_inertia = 0.50;
break; break;
case 'G':
/* 1200 baud - Started out same as E but add 3 way interleave. */
/* Version 1.3 - EXPERIMENTAL - Needs more fine tuning. */
//D->bp_window = BP_WINDOW_COSINE; /* The name says BP but it is used for all of them. */
D->use_prefilter = 1; /* first, a bandpass filter. */
D->prefilter_baud = 0.15;
D->pre_filter_len_bits = 128 * 1200. / (44100. / 3.);
D->pre_window = BP_WINDOW_TRUNCATED;
D->ms_filter_len_bits = 25 * 1200. / (44100. / 3.);
D->ms_window = BP_WINDOW_COSINE;
D->lpf_use_fir = 1;
D->lpf_baud = 1.16;
D->lp_filter_len_bits = 21 * 1200. / (44100. / 3.);
D->lp_window = BP_WINDOW_TRUNCATED;
D->agc_fast_attack = 0.130;
D->agc_slow_decay = 0.00013;
D->hysteresis = 0.01;
D->pll_locked_inertia = 0.73;
D->pll_searching_inertia = 0.64;
break;
case 'H':
/* Experiment in Version 1.6 */
/* 1200 baud - Started out as a copy of E but */
/* will probably have little tweaks after the */
/* major experiment. */
/* Enhancements: */
/* + Look back and sample the bit position. */
/* + Avoid smearing by long filter and low pass. */
D->use_prefilter = 1; /* first, a bandpass filter. */
D->prefilter_baud = 0.21;
D->pre_filter_len_bits = 184 * 1200. / 44100.;
D->pre_filter_len_bits = 235 * 1200. / 44100.;
D->pre_window = BP_WINDOW_TRUNCATED;
D->ms_filter_len_bits = 65 * 1200. / 44100.; // Just over 2 bit times.
D->ms_window = BP_WINDOW_COSINE;
/* New for synchronous re-demod in 1.6. */
D->play_it_again_sample = 1;
D->m2_filter_len_bits = 44 * 1200. / 44100.; // a little more than 1 bit time.
D->s2_filter_len_bits = 48 * 1200. / 44100.; // a little more than 1 bit time.
D->ms2_window = BP_WINDOW_TRUNCATED;
D->lp_delay_fract = 0.53; // FIXME: This is backwards.
D->lpf_use_fir = 1;
D->lpf_baud = 1.10;
D->lp_filter_len_bits = 64 * 1200. / 44100.;
D->lp_window = BP_WINDOW_TRUNCATED;
D->agc_fast_attack = 0.820;
D->agc_slow_decay = 0.000214;
D->hysteresis = 0.001;
D->pll_locked_inertia = 0.765;
D->pll_searching_inertia = 0.44;
break;
default: default:
text_color_set(DW_COLOR_ERROR); text_color_set(DW_COLOR_ERROR);
@ -457,8 +317,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
D->pre_filter_size = (int) round( D->pre_filter_len_bits * (float)samples_per_sec / (float)baud ); D->pre_filter_size = (int) round( D->pre_filter_len_bits * (float)samples_per_sec / (float)baud );
D->ms_filter_size = (int) round( D->ms_filter_len_bits * (float)samples_per_sec / (float)baud ); D->ms_filter_size = (int) round( D->ms_filter_len_bits * (float)samples_per_sec / (float)baud );
D->m2_filter_size = (int) round( D->m2_filter_len_bits * (float)samples_per_sec / (float)baud );
D->s2_filter_size = (int) round( D->s2_filter_len_bits * (float)samples_per_sec / (float)baud );
D->lp_filter_size = (int) round( D->lp_filter_len_bits * (float)samples_per_sec / (float)baud ); D->lp_filter_size = (int) round( D->lp_filter_len_bits * (float)samples_per_sec / (float)baud );
/* Experiment with other sizes. */ /* Experiment with other sizes. */
@ -469,12 +327,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
#ifdef TUNE_MS_FILTER_SIZE #ifdef TUNE_MS_FILTER_SIZE
D->ms_filter_size = TUNE_MS_FILTER_SIZE; D->ms_filter_size = TUNE_MS_FILTER_SIZE;
#endif #endif
#ifdef TUNE_M2_FILTER_SIZE
D->m2_filter_size = TUNE_M2_FILTER_SIZE;
#endif
#ifdef TUNE_S2_FILTER_SIZE
D->s2_filter_size = TUNE_S2_FILTER_SIZE;
#endif
#ifdef TUNE_LP_FILTER_SIZE #ifdef TUNE_LP_FILTER_SIZE
D->lp_filter_size = TUNE_LP_FILTER_SIZE; D->lp_filter_size = TUNE_LP_FILTER_SIZE;
#endif #endif
@ -503,24 +355,7 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
exit (1); exit (1);
} }
if (D->m2_filter_size * 2 > MAX_FILTER_SIZE)
{
text_color_set (DW_COLOR_ERROR);
dw_printf ("Calculated filter size of %d is too large.\n", D->m2_filter_size);
dw_printf ("Decrease the audio sample rate or increase the baud rate or\n");
dw_printf ("recompile the application with MAX_FILTER_SIZE larger than %d.\n",
MAX_FILTER_SIZE);
exit (1);
}
if (D->s2_filter_size * 2 > MAX_FILTER_SIZE)
{
text_color_set (DW_COLOR_ERROR);
dw_printf ("Calculated filter size of %d is too large.\n", D->s2_filter_size);
dw_printf ("Decrease the audio sample rate or increase the baud rate or\n");
dw_printf ("recompile the application with MAX_FILTER_SIZE larger than %d.\n",
MAX_FILTER_SIZE);
exit (1);
}
if (D->lp_filter_size > MAX_FILTER_SIZE) if (D->lp_filter_size > MAX_FILTER_SIZE)
{ {
@ -585,13 +420,6 @@ void demod_afsk_init (int samples_per_sec, int baud, int mark_freq,
gen_ms (space_freq, samples_per_sec, D->s_sin_table, D->s_cos_table, D->ms_filter_size, D->ms_window); gen_ms (space_freq, samples_per_sec, D->s_sin_table, D->s_cos_table, D->ms_filter_size, D->ms_window);
// Note that these are twice as long so we can try matching different phases.
if (D->play_it_again_sample) {
gen_ms (mark_freq, samples_per_sec, D->m2_sin_table, D->m2_cos_table, D->m2_filter_size * 2, D->ms2_window);
gen_ms (space_freq, samples_per_sec, D->s2_sin_table, D->s2_cos_table, D->s2_filter_size * 2, D->ms2_window);
}
/* /*
* Now the lowpass filter. * Now the lowpass filter.
* I thought we'd want a cutoff of about 0.5 the baud rate * I thought we'd want a cutoff of about 0.5 the baud rate
@ -764,9 +592,6 @@ void demod_afsk_process_sample (int chan, int subchan, int sam, struct demodulat
// FIXME: calculate how much we really need. // FIXME: calculate how much we really need.
int extra = 0; int extra = 0;
if (D->play_it_again_sample) {
extra = D->lp_filter_size;
}
if (D->use_prefilter) { if (D->use_prefilter) {
float cleaner; float cleaner;
@ -1015,77 +840,8 @@ inline static void nudge_pll (int chan, int subchan, int slice, int demod_data,
if (D->slicer[slice].data_clock_pll < 0 && D->slicer[slice].prev_d_c_pll > 0) { if (D->slicer[slice].data_clock_pll < 0 && D->slicer[slice].prev_d_c_pll > 0) {
/* Overflow. */ /* Overflow. */
// In version 1.6 we will try a new experiment.
// The tone filters are about 2 bit times wide so this smears the signal.
// I originally expected this to be about 1 bit time but 2 turned out
// to give the best results after extensive experimentation.
// We are looking at half of each adjacent bit, not just the one we want.
// The low pass filter also smears the signal.
//
// We will try to look back in time and re-demodulate only the time period of the bit.
//
if (D->play_it_again_sample) { // New in 1.6. Currently 'H' demod profile.
// FIXME: double check position and draw picture.
#if 0
// This provided a slight benefit.
int offset = ( D->ms_filter_size - D->m2_filter_size ) / 2 + D->lp_filter_delay;
float m_sum1 = convolve (D->ms_in_cb + offset, D->m2_sin_table, D->m2_filter_size);
float m_sum2 = convolve (D->ms_in_cb + offset, D->m2_cos_table, D->m2_filter_size);
float m_amp = sqrtf(m_sum1 * m_sum1 + m_sum2 * m_sum2);
offset = ( D->ms_filter_size - D->s2_filter_size ) / 2 + D->lp_filter_delay;
float s_sum1 = convolve (D->ms_in_cb + offset, D->s2_sin_table, D->s2_filter_size);
float s_sum2 = convolve (D->ms_in_cb + offset, D->s2_cos_table, D->s2_filter_size);
float s_amp = sqrtf(s_sum1 * s_sum1 + s_sum2 * s_sum2);
#else
// Here we try something completely new.
// Rather than taking the vector magnitude of the I+Q components,
// correlate it with only a sine wave. We don't know the phase so
// we will try matching with a bunch of different phases and take the best match.
// Trying match with cosine as well could be beneficial for lower sample rates.
int j;
float m_amp = 0;
float s_amp = 0;
int offset = ( D->ms_filter_size - D->m2_filter_size ) / 2 + D->lp_filter_delay;
for (j = 0; j <= D->m2_filter_size; j++) {
float match = fabsf(convolve (D->ms_in_cb + offset, D->m2_sin_table + j, D->m2_filter_size));
if (match > m_amp) m_amp = match;
}
offset = ( D->ms_filter_size - D->s2_filter_size ) / 2 + D->lp_filter_delay;
for (j = 0; j <= D->s2_filter_size; j++) {
float match = fabsf(convolve (D->ms_in_cb + offset, D->s2_sin_table + j, D->s2_filter_size));
if (match > s_amp) s_amp = match;
}
#endif
int resampled;
if (D->num_slicers > 1) {
resampled = m_amp > s_amp * space_gain[slice];
}
else {
resampled = m_amp > s_amp;
}
hdlc_rec_bit (chan, subchan, slice, resampled, 0, -1);
}
else {
// Traditional way, after the low pass filter.
hdlc_rec_bit (chan, subchan, slice, demod_data, 0, -1); hdlc_rec_bit (chan, subchan, slice, demod_data, 0, -1);
} }
}
// Even if we used alternative method to extract the data bit, // Even if we used alternative method to extract the data bit,
// we still use the low pass output for the PLL. // we still use the low pass output for the PLL.

View File

@ -33,8 +33,6 @@ struct demodulator_state_s
char profile; // 'A', 'B', etc. Upper case. char profile; // 'A', 'B', etc. Upper case.
// Only needed to see if we are using 'F' to take fast path. // Only needed to see if we are using 'F' to take fast path.
int play_it_again_sample; // Enable new synchronous demod in version 1.6.
#define TICKS_PER_PLL_CYCLE ( 256.0 * 256.0 * 256.0 * 256.0 ) #define TICKS_PER_PLL_CYCLE ( 256.0 * 256.0 * 256.0 * 256.0 )
int pll_step_per_sample; // PLL is advanced by this much each audio sample. int pll_step_per_sample; // PLL is advanced by this much each audio sample.
@ -46,13 +44,6 @@ struct demodulator_state_s
/* but about 2 bit times turned out to be better. */ /* but about 2 bit times turned out to be better. */
/* Currently using same size for any prefilter. */ /* Currently using same size for any prefilter. */
int m2_filter_size;
int s2_filter_size; /* Size of mark & space filters, in audio samples */
/* for the synchronous demodulator. I'm expecting */
/* smaller, perhaps just over 1 bit time here. */
int lp2_filter_size; /* FSK resampling - Size of Low Pass filter, in audio samples. */
#define MAX_FILTER_SIZE 320 /* 304 is needed for profile C, 300 baud & 44100. */ #define MAX_FILTER_SIZE 320 /* 304 is needed for profile C, 300 baud & 44100. */
@ -61,8 +52,6 @@ struct demodulator_state_s
* e.g. 1 means 1/1200 second for 1200 baud. * e.g. 1 means 1/1200 second for 1200 baud.
*/ */
float ms_filter_len_bits; float ms_filter_len_bits;
float m2_filter_len_bits;
float s2_filter_len_bits;
float lp_delay_fract; float lp_delay_fract;
/* /*
@ -72,7 +61,6 @@ struct demodulator_state_s
bp_window_t pre_window; bp_window_t pre_window;
bp_window_t ms_window; bp_window_t ms_window;
bp_window_t lp_window; bp_window_t lp_window;
bp_window_t ms2_window; /* New in 1.6. */
/* /*
@ -158,17 +146,6 @@ struct demodulator_state_s
float s_sin_table[MAX_FILTER_SIZE] __attribute__((aligned(16))); float s_sin_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
float s_cos_table[MAX_FILTER_SIZE] __attribute__((aligned(16))); float s_cos_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
/*
* Same for the synchronous re-demodulator.
*/
float m2_sin_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
float m2_cos_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
float s2_sin_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
float s2_cos_table[MAX_FILTER_SIZE] __attribute__((aligned(16)));
float lp2_filter[MAX_FILTER_SIZE] __attribute__((aligned(16)));
/* /*
* These are for PSK only. * These are for PSK only.

View File

@ -306,7 +306,6 @@ void multi_modem_process_sample (int chan, int audio_sample)
{ {
int d; int d;
int subchan; int subchan;
static int i = 0; /* for interleaving among multiple demodulators. */
// Accumulate an average DC bias level. // Accumulate an average DC bias level.
// Shouldn't happen with a soundcard but could with mistuned SDR. // Shouldn't happen with a soundcard but could with mistuned SDR.
@ -334,22 +333,10 @@ void multi_modem_process_sample (int chan, int audio_sample)
/* Formerly one loop. */ /* Formerly one loop. */
/* 1.2: We can feed one demodulator but end up with multiple outputs. */ /* 1.2: We can feed one demodulator but end up with multiple outputs. */
if (save_audio_config_p->achan[chan].interleave > 1) {
// TODO: temp debug, remove this.
assert (save_audio_config_p->achan[chan].interleave == save_audio_config_p->achan[chan].num_subchan);
demod_process_sample(chan, i, audio_sample);
i++;
if (i >= save_audio_config_p->achan[chan].interleave) i = 0;
}
else {
/* Send same thing to all. */ /* Send same thing to all. */
for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) { for (d = 0; d < save_audio_config_p->achan[chan].num_subchan; d++) {
demod_process_sample(chan, d, audio_sample); demod_process_sample(chan, d, audio_sample);
} }
}
for (subchan = 0; subchan < save_audio_config_p->achan[chan].num_subchan; subchan++) { for (subchan = 0; subchan < save_audio_config_p->achan[chan].num_subchan; subchan++) {
int slice; int slice;