| 107 | } |
| 108 | |
| 109 | float FrequencyBands::calculateBandEnergy(const fft::Bins& fft, float minFreq, float maxFreq, |
| 110 | float fftMinFreq, float fftMaxFreq) { |
| 111 | const int numBins = static_cast<int>(fft.raw().size()); |
| 112 | if (numBins <= 1) { |
| 113 | return 0.0f; |
| 114 | } |
| 115 | |
| 116 | float totalEnergy = 0.0f; |
| 117 | float totalWeight = 0.0f; |
| 118 | |
| 119 | for (int i = 0; i < numBins; i++) { |
| 120 | // Compute the frequency range for this CQ bin using log-spaced |
| 121 | // boundaries that match the CQ kernel's actual frequency layout. |
| 122 | float binLow; |
| 123 | float binHigh; |
| 124 | if (i == 0) { |
| 125 | binLow = fftMinFreq; |
| 126 | } else { |
| 127 | binLow = fft.binBoundary(i - 1); |
| 128 | } |
| 129 | if (i == numBins - 1) { |
| 130 | binHigh = fftMaxFreq; |
| 131 | } else { |
| 132 | binHigh = fft.binBoundary(i); |
| 133 | } |
| 134 | |
| 135 | // Calculate fractional overlap between this bin and the target band |
| 136 | float overlapMin = fl::max(binLow, minFreq); |
| 137 | float overlapMax = fl::min(binHigh, maxFreq); |
| 138 | |
| 139 | if (overlapMax <= overlapMin) { |
| 140 | continue; // No overlap |
| 141 | } |
| 142 | |
| 143 | float binWidth = binHigh - binLow; |
| 144 | float overlapFraction = (overlapMax - overlapMin) / binWidth; |
| 145 | |
| 146 | totalEnergy += fft.raw()[i] * overlapFraction; |
| 147 | totalWeight += overlapFraction; |
| 148 | } |
| 149 | |
| 150 | // Normalize by total fractional weight to make bands comparable |
| 151 | return (totalWeight > 0.0f) ? totalEnergy / totalWeight : 0.0f; |
| 152 | } |
| 153 | |
| 154 | } // namespace detector |
| 155 | } // namespace audio |
nothing calls this directly
no test coverage detected