1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
/* -*- c++ -*- */
/*
* Copyright 2002 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include <GrAtscViterbiDecoder.h>
#include <iostream>
// typedefs for fundamental i/o types
typedef atsc_soft_data_segment iType;
typedef atsc_mpeg_packet_rs_encoded oType;
static const int NUMBER_OF_OUTPUTS = 1; // # of output streams (almost always one)
GrAtscViterbiDecoder::GrAtscViterbiDecoder ()
: VrHistoryProc<iType,oType> (NUMBER_OF_OUTPUTS), last_start(-1)
{
// 1 + number of extra input elements at which we look. This is
// used by the superclass's forecast routine to get us the correct
// range on our inputs.
//
// We need our input to be aligned on a 12-segment boundary,
// to ensure satisfaction, ask for 11 more
history = 1 + (atsci_viterbi_decoder::NCODERS - 1);
// any other init here.
// Let the bottom end know we must produce output in multiples of 12 segments.
setOutputSize (atsci_viterbi_decoder::NCODERS);
}
GrAtscViterbiDecoder::~GrAtscViterbiDecoder ()
{
// Anything that isn't automatically cleaned up...
}
/*
* This is the real work horse. In general this interface can handle
* multiple streams of input and output, but we almost always
* use a single input and output stream.
*/
int
GrAtscViterbiDecoder::work (VrSampleRange output, void *ao[],
VrSampleRange inputs[], void *ai[])
{
// If we have state that persists across invocations (e.g., we have
// instance variables that we modify), we must use the sync method
// to indicate to the scheduler that our output must be computed in
// order. This doesn't keep other things from being run in
// parallel, it just means that at any given time, there is only a
// single thread working this code, and that the scheduler will
// ensure that we are asked to produce output that is contiguous and
// that will be presented to us in order of increasing time.
// We have state, the current state of the decoder, hence
// we must use sync.
sync (output.index);
// construct some nicer i/o pointers to work with.
iType *in = ((iType **) ai)[0];
oType *out = ((oType **) ao)[0];
assert (output.size % atsci_viterbi_decoder::NCODERS == 0);
// find the first mod 12 boundary to begin decoding
int start;
for (start = 0; start < atsci_viterbi_decoder::NCODERS; start++){
assert (in[start].pli.regular_seg_p ());
if ((in[start].pli.segno () % atsci_viterbi_decoder::NCODERS) == 0)
break;
}
if (start == atsci_viterbi_decoder::NCODERS){
// we didn't find a mod 12 boundary. There's some kind of problem
// upstream of us (not yet sync'd??)
cerr << "!!!GrAtscViterbiDecoder: no mod-12 boundary found\7\n";
start = 0;
}
else if (start != last_start){
cerr << "GrAtscViterbiDecoder: new starting offset = " << start
<< " output.index = " << output.index << endl;
last_start = start;
}
// We must produce output.size units of output.
for (unsigned int i = 0; i < output.size; i += atsci_viterbi_decoder::NCODERS){
// primitive does 12 segments at a time.
// pipeline info is handled in the primitive.
decoder.decode (&out[i], &in[i + start]);
}
#if 0
// FIXME paranoid check...
for (unsigned int i = 0; i < output.size; i++){
plinfo::sanity_check (out[i].pli);
assert (out[i].pli.regular_seg_p ());
}
#endif
#if 0
cerr << "@@@ GrAtscViterbiDecoder: output.index = " << output.index
<< " output.size = " << output.size
<< " sum = " << output.index + output.size << endl;
#endif
// Return the number of units we produced.
// Note that for all intents and purposes, it is an error to
// produce less than you are asked for.
return output.size;
}
|