5
5
#include < dsp/multirate/polyphase_bank.h>
6
6
#include < dsp/math/step.h>
7
7
8
+ #define LINE_SIZE 945
9
+
10
+ #define SYNC_LEN 70
11
+ #define SYNC_SIDE_LEN 17
12
+ #define SYNC_L_START (LINE_SIZE - SYNC_SIDE_LEN)
13
+ #define SYNC_R_START (SYNC_LEN/2 )
14
+ #define SYNC_R_END (SYNC_R_START + (SYNC_LEN/2 ) + SYNC_SIDE_LEN)
15
+ #define SYNC_HALF_LEN ((SYNC_LEN/2 ) + SYNC_SIDE_LEN)
16
+
17
+ #define EQUAL_LEN 35
18
+
19
+ #define HBLANK_START SYNC_LEN
20
+ #define HBLANK_END 155
21
+ #define HBLANK_LEN (HBLANK_END - HBLANK_START + 1 )
22
+
23
+ #define SYNC_LEVEL (-0.428 )
24
+
25
+ #define MAX_LOCK 1000
26
+
8
27
class LineSync : public dsp ::Processor<float , float > {
9
28
using base_type = dsp::Processor<float , float >;
10
29
public:
@@ -27,41 +46,17 @@ class LineSync : public dsp::Processor<float, float> {
27
46
_interpPhaseCount = interpPhaseCount;
28
47
_interpTapCount = interpTapCount;
29
48
30
- pcl.init (_muGain, _omegaGain, 0.0 , 0.0 , 1.0 , _omega, _omega * (1.0 - omegaRelLimit), _omega * (1.0 + omegaRelLimit));
31
49
generateInterpTaps ();
32
50
buffer = dsp::buffer::alloc<float >(STREAM_BUFFER_SIZE + _interpTapCount);
33
51
bufStart = &buffer[_interpTapCount - 1 ];
52
+
53
+ // TODO: Needs tuning, so do the gains
54
+ maxPeriod = (int32_t )(1.0001 * (float )(1 << 30 ));
55
+ minPeriod = (int32_t )(0.9999 * (float )(1 << 30 ));
34
56
35
57
base_type::init (in);
36
58
}
37
59
38
- void setOmegaGain (double omegaGain) {
39
- assert (base_type::_block_init);
40
- std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
41
- _omegaGain = omegaGain;
42
- pcl.setCoefficients (_muGain, _omegaGain);
43
- }
44
-
45
- void setMuGain (double muGain) {
46
- assert (base_type::_block_init);
47
- std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
48
- _muGain = muGain;
49
- pcl.setCoefficients (_muGain, _omegaGain);
50
- }
51
-
52
- void setOmegaRelLimit (double omegaRelLimit) {
53
- assert (base_type::_block_init);
54
- std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
55
- _omegaRelLimit = omegaRelLimit;
56
- pcl.setFreqLimits (_omega * (1.0 - _omegaRelLimit), _omega * (1.0 + _omegaRelLimit));
57
- }
58
-
59
- void setSyncLevel (float level) {
60
- assert (base_type::_block_init);
61
- std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
62
- syncLevel = level;
63
- }
64
-
65
60
void setInterpParams (int interpPhaseCount, int interpTapCount) {
66
61
assert (base_type::_block_init);
67
62
std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
@@ -81,8 +76,7 @@ class LineSync : public dsp::Processor<float, float> {
81
76
std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
82
77
base_type::tempStop ();
83
78
offset = 0 ;
84
- pcl.phase = 0 .0f ;
85
- pcl.freq = _omega;
79
+ phase = 0 ;
86
80
base_type::tempStart ();
87
81
}
88
82
@@ -93,78 +87,136 @@ class LineSync : public dsp::Processor<float, float> {
93
87
// Copy data to work buffer
94
88
memcpy (bufStart, base_type::_in->readBuf , count * sizeof (float ));
95
89
96
- if (test2) {
97
- test2 = false ;
98
- offset += 5 ;
99
- }
100
-
101
- // Process all samples
90
+ // Process samples while they are available
102
91
while (offset < count) {
103
- // Calculate new output value
104
- int phase = std::clamp<int >(floorf (pcl.phase * (float )_interpPhaseCount), 0 , _interpPhaseCount - 1 );
105
- float outVal;
106
- volk_32f_x2_dot_prod_32f (&outVal, &buffer[offset], interpBank.phases [phase], _interpTapCount);
107
- base_type::out.writeBuf [outCount++] = outVal;
108
-
109
- // If the end of the line is reached, process it and determin error
110
- float error = 0 ;
111
- if (outCount >= 720 ) {
112
- // Compute averages.
92
+ // While the offset is negative, out put zeros
93
+ while (offset < 0 && pixel < LINE_SIZE) {
94
+ // Output a zero
95
+ base_type::out.writeBuf [pixel++] = 0 .0f ;
96
+
97
+ // Increment the phase
98
+ phase += period;
99
+ offset += (phase >> 30 );
100
+ phase &= 0x3FFFFFFF ;
101
+ }
102
+
103
+ // Process as much of a line as possible
104
+ while (offset < count && pixel < LINE_SIZE) {
105
+ // Compute the output sample
106
+ volk_32f_x2_dot_prod_32f (&base_type::out.writeBuf [pixel++], &buffer[offset], interpBank.phases [(phase >> 23 ) & 0x7F ], _interpTapCount);
107
+
108
+ // Increment the phase
109
+ phase += period;
110
+ offset += (phase >> 30 );
111
+ phase &= 0x3FFFFFFF ;
112
+ }
113
+
114
+ // If the line is done, process it
115
+ if (pixel == LINE_SIZE) {
116
+ // Compute averages. (TODO: Try faster method)
113
117
float left = 0 .0f , right = 0 .0f ;
114
- for (int i = (720 -17 ); i < 720 ; i++) {
118
+ int lc = 0 , rc = 0 ;
119
+ for (int i = SYNC_L_START; i < LINE_SIZE; i++) {
115
120
left += base_type::out.writeBuf [i];
121
+ lc++;
116
122
}
117
- for (int i = 0 ; i < 27 ; i++) {
123
+ for (int i = 0 ; i < SYNC_R_START ; i++) {
118
124
left += base_type::out.writeBuf [i];
125
+ lc++;
119
126
}
120
- for (int i = 27 ; i < ( 54 + 17 ) ; i++) {
127
+ for (int i = SYNC_R_START ; i < SYNC_R_END ; i++) {
121
128
right += base_type::out.writeBuf [i];
129
+ rc++;
130
+ }
131
+
132
+ // Compute the error
133
+ float error = (left - right) * (1 .0f /((float )SYNC_HALF_LEN));
134
+
135
+ // Compute the change in phase and frequency due to the error
136
+ float periodDelta = error * _omegaGain;
137
+ float phaseDelta = error * _muGain;
138
+
139
+ // Normalize the phase delta (TODO: Make faster)
140
+ while (phaseDelta <= -1 .0f ) {
141
+ phaseDelta += 1 .0f ;
142
+ offset--;
143
+ }
144
+ while (phaseDelta >= 1 .0f ) {
145
+ phaseDelta -= 1 .0f ;
146
+ offset++;
122
147
}
123
- left *= (1 .0f /44 .0f );
124
- right *= (1 .0f /44 .0f );
125
148
126
- // If the sync is present, compute error
127
- if ((left < syncLevel && right < syncLevel) && !forceLock) {
128
- error = (left + syncBias - right);
129
- locked = true ;
149
+ // Update the period (TODO: Clamp error*omegaGain to prevent weird shit with corrupt samples)
150
+ period += (int32_t )(periodDelta * (float )(1 << 30 ));
151
+ period = std::clamp<uint32_t >(period, minPeriod, maxPeriod);
152
+
153
+ // Update the phase
154
+ phase += (int32_t )(phaseDelta * (float )(1 << 30 ));
155
+
156
+ // Normalize the phase
157
+ uint32_t overflow = phase >> 30 ;
158
+ if (overflow) {
159
+ if (error < 0 ) {
160
+ offset -= 4 - overflow;
161
+ }
162
+ else {
163
+ offset += overflow;
164
+ }
130
165
}
131
- else {
132
- locked = false ;
166
+ phase &= 0x3FFFFFFF ;
167
+
168
+ // Find the lowest value
169
+ float lowest = INFINITY;
170
+ int lowestId = -1 ;
171
+ for (int i = 0 ; i < LINE_SIZE; i++) {
172
+ float val = base_type::out.writeBuf [i];
173
+ if (val < lowest) {
174
+ lowest = val;
175
+ lowestId = i;
176
+ }
133
177
}
134
178
135
- if (++counter >= 100 ) {
136
- counter = 0 ;
137
- // flog::warn("Left: {}, Right: {}, Error: {}, Freq: {}, Phase: {}", left, right, error, pcl.freq, pcl.phase);
179
+ // Check the the line is in lock
180
+ bool lineLocked = (lowestId < SYNC_R_END || lowestId >= SYNC_L_START);
181
+
182
+ // Update the lock status based on the line lock
183
+ if (!lineLocked && locked) {
184
+ locked--;
185
+ }
186
+ else if (lineLocked && locked < MAX_LOCK) {
187
+ locked++;
188
+ }
189
+
190
+ // If not locked, attempt to lock by forcing the sync to happen at the right spot
191
+ // TODO: This triggers waaaay too easily at low SNR
192
+ if (!locked && fastLock) {
193
+ offset += lowestId - SYNC_R_START;
194
+ locked = MAX_LOCK / 2 ;
138
195
}
139
196
140
197
// Output line
141
- if (!base_type::out.swap (outCount )) { break ; }
142
- outCount = 0 ;
198
+ if (!base_type::out.swap (LINE_SIZE )) { break ; }
199
+ pixel = 0 ;
143
200
}
144
-
145
- // Advance symbol offset and phase
146
- pcl.advance (error);
147
- float delta = floorf (pcl.phase );
148
- offset += delta;
149
- pcl.phase -= delta;
150
201
}
202
+
203
+ // Get the offset ready for the next buffer
151
204
offset -= count;
152
205
153
206
// Update delay buffer
154
207
memmove (buffer, &buffer[count], (_interpTapCount - 1 ) * sizeof (float ));
155
208
156
209
// Swap if some data was generated
157
210
base_type::_in->flush ();
158
- return outCount ;
211
+ return 0 ;
159
212
}
160
213
161
- bool locked = false ;
162
- bool test2 = false ;
214
+ float syncBias = 0 ;
163
215
164
- float syncBias = 0 .0f ;
165
- bool forceLock = false ;
216
+ uint32_t period = (0x800072F3 >> 1 );// (1 << 31) + 1;
166
217
167
- int counter = 0 ;
218
+ int locked = 0 ;
219
+ bool fastLock = true ;
168
220
169
221
protected:
170
222
void generateInterpTaps () {
@@ -175,19 +227,21 @@ class LineSync : public dsp::Processor<float, float> {
175
227
}
176
228
177
229
dsp::multirate::PolyphaseBank<float > interpBank;
178
- dsp::loop::PhaseControlLoop<double , false > pcl;
179
230
180
231
double _omega;
181
232
double _omegaGain;
182
233
double _muGain;
183
234
double _omegaRelLimit;
184
235
int _interpPhaseCount;
185
236
int _interpTapCount;
186
-
187
- int offset = 0 ;
188
- int outCount = 0 ;
189
237
float * buffer;
190
238
float * bufStart;
191
-
239
+
240
+ uint32_t phase = 0 ;
241
+ uint32_t maxPeriod;
242
+ uint32_t minPeriod;
192
243
float syncLevel = -0 .03f ;
244
+
245
+ int offset = 0 ;
246
+ int pixel = 0 ;
193
247
};
0 commit comments