55#include < dsp/multirate/polyphase_bank.h>
66#include < dsp/math/step.h>
77
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+
827class LineSync : public dsp ::Processor<float , float > {
928 using base_type = dsp::Processor<float , float >;
1029public:
@@ -27,41 +46,17 @@ class LineSync : public dsp::Processor<float, float> {
2746 _interpPhaseCount = interpPhaseCount;
2847 _interpTapCount = interpTapCount;
2948
30- pcl.init (_muGain, _omegaGain, 0.0 , 0.0 , 1.0 , _omega, _omega * (1.0 - omegaRelLimit), _omega * (1.0 + omegaRelLimit));
3149 generateInterpTaps ();
3250 buffer = dsp::buffer::alloc<float >(STREAM_BUFFER_SIZE + _interpTapCount);
3351 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 ));
3456
3557 base_type::init (in);
3658 }
3759
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-
6560 void setInterpParams (int interpPhaseCount, int interpTapCount) {
6661 assert (base_type::_block_init);
6762 std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
@@ -81,8 +76,7 @@ class LineSync : public dsp::Processor<float, float> {
8176 std::lock_guard<std::recursive_mutex> lck (base_type::ctrlMtx);
8277 base_type::tempStop ();
8378 offset = 0 ;
84- pcl.phase = 0 .0f ;
85- pcl.freq = _omega;
79+ phase = 0 ;
8680 base_type::tempStart ();
8781 }
8882
@@ -93,78 +87,136 @@ class LineSync : public dsp::Processor<float, float> {
9387 // Copy data to work buffer
9488 memcpy (bufStart, base_type::_in->readBuf , count * sizeof (float ));
9589
96- if (test2) {
97- test2 = false ;
98- offset += 5 ;
99- }
100-
101- // Process all samples
90+ // Process samples while they are available
10291 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)
113117 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++) {
115120 left += base_type::out.writeBuf [i];
121+ lc++;
116122 }
117- for (int i = 0 ; i < 27 ; i++) {
123+ for (int i = 0 ; i < SYNC_R_START ; i++) {
118124 left += base_type::out.writeBuf [i];
125+ lc++;
119126 }
120- for (int i = 27 ; i < ( 54 + 17 ) ; i++) {
127+ for (int i = SYNC_R_START ; i < SYNC_R_END ; i++) {
121128 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++;
122147 }
123- left *= (1 .0f /44 .0f );
124- right *= (1 .0f /44 .0f );
125148
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+ }
130165 }
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+ }
133177 }
134178
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 ;
138195 }
139196
140197 // 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 ;
143200 }
144-
145- // Advance symbol offset and phase
146- pcl.advance (error);
147- float delta = floorf (pcl.phase );
148- offset += delta;
149- pcl.phase -= delta;
150201 }
202+
203+ // Get the offset ready for the next buffer
151204 offset -= count;
152205
153206 // Update delay buffer
154207 memmove (buffer, &buffer[count], (_interpTapCount - 1 ) * sizeof (float ));
155208
156209 // Swap if some data was generated
157210 base_type::_in->flush ();
158- return outCount ;
211+ return 0 ;
159212 }
160213
161- bool locked = false ;
162- bool test2 = false ;
214+ float syncBias = 0 ;
163215
164- float syncBias = 0 .0f ;
165- bool forceLock = false ;
216+ uint32_t period = (0x800072F3 >> 1 );// (1 << 31) + 1;
166217
167- int counter = 0 ;
218+ int locked = 0 ;
219+ bool fastLock = true ;
168220
169221protected:
170222 void generateInterpTaps () {
@@ -175,19 +227,21 @@ class LineSync : public dsp::Processor<float, float> {
175227 }
176228
177229 dsp::multirate::PolyphaseBank<float > interpBank;
178- dsp::loop::PhaseControlLoop<double , false > pcl;
179230
180231 double _omega;
181232 double _omegaGain;
182233 double _muGain;
183234 double _omegaRelLimit;
184235 int _interpPhaseCount;
185236 int _interpTapCount;
186-
187- int offset = 0 ;
188- int outCount = 0 ;
189237 float * buffer;
190238 float * bufStart;
191-
239+
240+ uint32_t phase = 0 ;
241+ uint32_t maxPeriod;
242+ uint32_t minPeriod;
192243 float syncLevel = -0 .03f ;
244+
245+ int offset = 0 ;
246+ int pixel = 0 ;
193247};
0 commit comments