fb04db7c2414f95265db2c687faf43a8cb8c3924
[debian/gnuradio] / gr-atsc / src / lib / atsci_equalizer.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include <atsci_equalizer.h>
24 #include <algorithm>
25 #include <iostream>
26 #include <atsc_types.h>
27
28 using std::cerr;
29 using std::endl;
30 using std::min;
31
32
33 // total number of symbols (including field sync) / field
34 static const int SYMBOLS_PER_FIELD =
35   (ATSC_DSEGS_PER_FIELD + 1) * ATSC_DATA_SEGMENT_LENGTH;
36
37
38 atsci_equalizer::atsci_equalizer ()
39 {
40   d_locked_p = false;
41   d_offset_from_last_field_sync = 0;
42   d_current_field = 0;
43 }
44
45 atsci_equalizer::~atsci_equalizer ()
46 {
47 }
48
49 void
50 atsci_equalizer::reset ()
51 {
52   d_locked_p = false;
53   d_offset_from_last_field_sync = 0;
54   d_current_field = 0;
55 }
56 \f
57 /*
58  * Errrr.... Define to 1 if compiler handles tail recursion without pushing
59  * unnecessary stack frames, else define to 0 for lame compilers.
60  */
61 #define WINNING_COMPILER        0
62
63
64 /*
65  * divide and conquer...
66  *
67  * Note that this could be refactored to take advantage of the
68  * symbol_num that is contained in the input_tags.  Then we wouldn't
69  * have to be counting here.
70  *
71  * Today's strategy: get it working.
72  */
73
74 void 
75 atsci_equalizer::filter (const float         *input_samples,
76                         const atsc::syminfo *input_tags,
77                         float               *output_samples,
78                         int                  nsamples)
79 {
80  lame_compiler_kludge:
81
82   if (!d_locked_p){
83
84     // look for a field sync
85
86     int i;
87     for (i = 0; i < nsamples; i++){
88       if (atsc::tag_is_start_field_sync (input_tags[i]))
89         break;
90     }
91
92     // whether we found one or not, everything up to it should
93     // be run through the normal path
94
95     if (i != 0)
96       filter_normal (input_samples, output_samples, i);
97
98     if (i == nsamples)          // no field sync found, still not locked.
99       return;
100
101     // OK, we've just transitioned to the locked state.
102
103     d_locked_p = true;
104     d_offset_from_last_field_sync = 0;
105
106     // handle locked case recursively
107
108     if (WINNING_COMPILER)
109       filter (&input_samples[i], &input_tags[i],
110               &output_samples[i], nsamples - i);
111     else {
112       input_samples += i;
113       input_tags += i;
114       output_samples += i;
115       nsamples -= i;
116       goto lame_compiler_kludge;
117     }
118
119     return;
120   }
121
122   // We're in the locked state.
123   //
124   // Figure out where we are with respect to a data segment boundary
125   // and do the right thing.  Note that in the interested of performance,
126   // we don't scan all the tags looking for trouble.  We only check
127   // them where we expect them to be non-NORMAL.  Worst case, it'll take
128   // us a field to notice that something went wrong...
129
130   if (d_offset_from_last_field_sync % SYMBOLS_PER_FIELD == 0){  // we should be looking
131                                                                 //   at a field sync
132     if (atsc::tag_is_start_field_sync_1 (input_tags[0]))
133       d_current_field = 0;
134
135     else if (atsc::tag_is_start_field_sync_2 (input_tags[0]))
136       d_current_field = 1;
137
138     else {      // we're lost... no field sync where we expected it
139
140       cerr << "!!! atsci_equalizer: expected field sync, didn't find one\n";
141         
142       d_locked_p = false;
143       d_offset_from_last_field_sync = 0;        
144
145       if (WINNING_COMPILER)
146         filter (input_samples, input_tags, output_samples, nsamples);
147       else
148         goto lame_compiler_kludge;
149       
150       return;
151     }
152
153     // OK, everything's cool.  We're looking at a field sync.
154
155     int n = min (ATSC_DATA_SEGMENT_LENGTH, nsamples);
156
157     filter_field_sync (input_samples, output_samples, n, 0, d_current_field);
158
159     d_offset_from_last_field_sync = n;
160     nsamples -= n;
161
162     if (nsamples > 0){
163       if (WINNING_COMPILER)
164         filter (&input_samples[n], &input_tags[n],
165                 &output_samples[n], nsamples);
166       else {
167         input_samples += n;
168         input_tags += n;
169         output_samples += n;
170         goto lame_compiler_kludge;
171       }
172     }
173     return;
174   }
175
176   if (d_offset_from_last_field_sync < ATSC_DATA_SEGMENT_LENGTH){ // we're in the middle of a field sync
177     int n = min (ATSC_DATA_SEGMENT_LENGTH - d_offset_from_last_field_sync, nsamples);
178
179     filter_field_sync (input_samples, output_samples, n,
180                        d_offset_from_last_field_sync, d_current_field);
181
182     d_offset_from_last_field_sync += n;
183     nsamples -= n;
184
185     if (nsamples > 0){
186       if (WINNING_COMPILER)
187         filter (&input_samples[n], &input_tags[n],
188                 &output_samples[n], nsamples);
189       else {
190         input_samples += n;
191         input_tags += n;
192         output_samples += n;
193         goto lame_compiler_kludge;
194       }
195     }
196     return;
197   }
198
199   // OK, we're not in a field sync.  We're either in a data segment sync or in the clear...
200
201   int seg_offset = d_offset_from_last_field_sync % ATSC_DATA_SEGMENT_LENGTH;
202
203   assert (seg_offset >= 0);
204
205   if (seg_offset < 4){  // somewhere in a data seg sync.
206     int n = min (4 - seg_offset, nsamples);
207
208     filter_data_seg_sync (input_samples, output_samples, n, seg_offset);
209     
210     d_offset_from_last_field_sync += n;
211     nsamples -= n;
212
213     if (nsamples > 0){
214       if (WINNING_COMPILER)
215         filter (&input_samples[n], &input_tags[n],
216                 &output_samples[n], nsamples);
217       else {
218         input_samples += n;
219         input_tags += n;
220         output_samples += n;
221         goto lame_compiler_kludge;
222       }
223     }
224     return;
225   }
226
227   // otherwise... we're in the normal zone
228
229   int n = min (ATSC_DATA_SEGMENT_LENGTH - seg_offset, nsamples);
230   
231   filter_normal (input_samples, output_samples, n);
232
233   d_offset_from_last_field_sync += n;
234   nsamples -= n;
235
236   if (nsamples <= 0)
237     return;
238   
239   if (WINNING_COMPILER)
240     filter (&input_samples[n], &input_tags[n],
241             &output_samples[n], nsamples);
242   else {
243     input_samples += n;
244     input_tags += n;
245     output_samples += n;
246     goto lame_compiler_kludge;
247   }
248 }