| 1 | // Copyright (C) 2024 The Qt Company Ltd. |
|---|---|
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
| 3 | |
| 4 | #include "qsinewavevalidator_p.h" |
| 5 | |
| 6 | #include <QtCore/qmath.h> |
| 7 | #include <QtCore/QDebug> |
| 8 | |
| 9 | QSineWaveValidator::QSineWaveValidator(float notchFrequency, float sampleRate) |
| 10 | { |
| 11 | using namespace std; |
| 12 | float pi = static_cast<float>(M_PI); |
| 13 | float f0 = notchFrequency; |
| 14 | float Fs = sampleRate; |
| 15 | float Q = 1 / sqrt(x: 2.f); // higher Q gives narrow bandwidth, but requires a larger number of |
| 16 | // frames during the transient |
| 17 | |
| 18 | // compare https://webaudio.github.io/Audio-EQ-Cookbook/Audio-EQ-Cookbook.txt |
| 19 | float w0 = 2 * pi * f0 / Fs; |
| 20 | float alpha = sin(x: w0) / (2 * Q); |
| 21 | |
| 22 | b0 = 1; |
| 23 | b1 = -2 * cos(x: w0); |
| 24 | b2 = 1; |
| 25 | a0 = 1 + alpha; |
| 26 | a1 = -2 * cos(x: w0); |
| 27 | a2 = 1 - alpha; |
| 28 | } |
| 29 | |
| 30 | void QSineWaveValidator::feedSample(float sample) |
| 31 | { |
| 32 | if (pendingFramesBeforeAnalysis == framesBeforeAnalysis) { |
| 33 | x.fill(u: sample); |
| 34 | y.fill(u: b0 / a0 * sample); |
| 35 | } |
| 36 | |
| 37 | x[2] = x[1]; |
| 38 | x[1] = x[0]; |
| 39 | x[0] = sample; |
| 40 | |
| 41 | y[2] = y[1]; |
| 42 | y[1] = y[0]; |
| 43 | y[0] = (b0 / a0) * x[0] + (b1 / a0) * x[1] + (b2 / a0) * x[2] - (a1 / a0) * y[1] |
| 44 | - (a2 / a0) * y[2]; |
| 45 | |
| 46 | accumPeak = std::max(a: std::abs(x: sample), b: accumPeak); |
| 47 | |
| 48 | if (pendingFramesBeforeAnalysis) { |
| 49 | pendingFramesBeforeAnalysis -= 1; |
| 50 | return; |
| 51 | } |
| 52 | |
| 53 | accumNotchPeak = std::max(a: std::abs(x: y[0]), b: accumNotchPeak); |
| 54 | } |
| 55 | |
| 56 | float QSineWaveValidator::notchPeak() const |
| 57 | { |
| 58 | if (pendingFramesBeforeAnalysis) |
| 59 | qWarning() << "notchPeak during initial frames. Result will not be accurate"; |
| 60 | return accumNotchPeak; |
| 61 | } |
| 62 |
