MCPcopy Create free account
hub / github.com/aethersdr/AetherSDR / process

Method process

src/core/ClientPhaseRotator.cpp:105–150  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

103}
104
105void ClientPhaseRotator::process(float* interleaved, int frames, int channels) noexcept
106{
107 if (!isEnabled() || frames <= 0 || channels < 1 || channels > 2) return;
108 recacheIfDirty();
109 if (m_cachedStages <= 0) return;
110
111 // Block-level peak tracking, signed — record max positive sample and
112 // most negative sample at both input and output. Asymmetry meter
113 // visualises peakPos vs |peakNeg|; phase rotation should make those
114 // values converge.
115 float inPos = 0.0f, inNeg = 0.0f, outPos = 0.0f, outNeg = 0.0f;
116
117 for (int i = 0; i < frames; ++i) {
118 for (int ch = 0; ch < channels; ++ch) {
119 const float x = interleaved[i * channels + ch];
120 if (x > inPos) inPos = x;
121 if (x < inNeg) inNeg = x;
122
123 float v = x;
124 for (int s = 0; s < m_cachedStages; ++s) {
125 auto& f = m_sections[s];
126 // Direct Form I all-pass:
127 // y[n] = a2*x[n] + a1*x[n-1] + x[n-2] - a1*y[n-1] - a2*y[n-2]
128 const float y = f.a2 * v
129 + f.a1 * f.x1[ch]
130 + f.x2[ch]
131 - f.a1 * f.y1[ch]
132 - f.a2 * f.y2[ch];
133 f.x2[ch] = f.x1[ch];
134 f.x1[ch] = v;
135 f.y2[ch] = f.y1[ch];
136 f.y1[ch] = y;
137 v = y;
138 }
139 interleaved[i * channels + ch] = v;
140
141 if (v > outPos) outPos = v;
142 if (v < outNeg) outNeg = v;
143 }
144 }
145
146 m_meters.inPosDb.store(linToDb(inPos), std::memory_order_relaxed);
147 m_meters.inNegDb.store(linToDb(-inNeg), std::memory_order_relaxed);
148 m_meters.outPosDb.store(linToDb(outPos), std::memory_order_relaxed);
149 m_meters.outNegDb.store(linToDb(-outNeg), std::memory_order_relaxed);
150}
151
152} // namespace AetherSDR

Callers

nothing calls this directly

Calls 2

isEnabledFunction · 0.85
linToDbFunction · 0.70

Tested by

no test coverage detected