| 199 | } |
| 200 | |
| 201 | void SpectralMonitorNode::spectralMag(std::vector<float> & result) |
| 202 | { |
| 203 | std::vector<float> window; |
| 204 | |
| 205 | { |
| 206 | std::lock_guard<std::recursive_mutex> lock(internalNode->magMutex); |
| 207 | window.swap(internalNode->buffer); |
| 208 | internalNode->setWindowSize(internalNode->windowSize->valueUint32()); |
| 209 | } |
| 210 | |
| 211 | // http://www.ni.com/white-paper/4844/en/ |
| 212 | ApplyWindowFunctionInplace(WindowFunction::blackman, window.data(), static_cast<int>(window.size())); |
| 213 | internalNode->fft->forward(window); |
| 214 | |
| 215 | // similar to cinder audio2 Scope object, although Scope smooths spectral samples frame by frame |
| 216 | // remove nyquist component - the first imaginary component |
| 217 | window[1] = 0.0f; |
| 218 | |
| 219 | // compute normalized magnitude spectrum |
| 220 | /// @TODO @tofix - break this into vector Cartesian -> polar and then vector lowpass. skip lowpass if smoothing factor is very small |
| 221 | const float kMagScale = 1.0f; /// detail->windowSize; |
| 222 | for (int i = 0; i < window.size(); i += 2) |
| 223 | { |
| 224 | float re = window[i]; |
| 225 | float im = window[i + 1]; |
| 226 | window[i / 2] = sqrt(re * re + im * im) * kMagScale; |
| 227 | } |
| 228 | |
| 229 | result.swap(window); |
| 230 | } |
| 231 | |
| 232 | void SpectralMonitorNode::windowSize(unsigned int ws) |
| 233 | { |
nothing calls this directly
no test coverage detected