| 25 | Transient::~Transient() FL_NOEXCEPT = default; |
| 26 | |
| 27 | void Transient::update(shared_ptr<Context> context) { |
| 28 | mRetainedFFT = context->getFFT16(); |
| 29 | const fft::Bins& fft = *mRetainedFFT; |
| 30 | u32 timestamp = context->getTimestamp(); |
| 31 | |
| 32 | // Calculate high-frequency energy (transients have strong high-freq components) |
| 33 | mCurrentEnergy = calculateHighFreqEnergy(fft); |
| 34 | |
| 35 | // Calculate energy flux (rate of change) |
| 36 | float flux = calculateEnergyFlux(mCurrentEnergy); |
| 37 | |
| 38 | // Detect transient |
| 39 | mTransientDetected = detectTransient(flux, timestamp); |
| 40 | |
| 41 | if (mTransientDetected) { |
| 42 | updateAttackTime(flux); |
| 43 | mLastTransientTime = timestamp; |
| 44 | } |
| 45 | |
| 46 | // Update previous energy for next frame |
| 47 | mPreviousEnergy = mCurrentEnergy; |
| 48 | |
| 49 | // Filter energy through HampelFilter to reject outliers before history |
| 50 | float filteredEnergy = mEnergyOutlierFilter.update(mCurrentEnergy); |
| 51 | |
| 52 | // Update energy history with outlier-rejected values |
| 53 | if (mEnergyHistory.size() >= ENERGY_HISTORY_SIZE) { |
| 54 | mEnergyHistory.pop_front(); |
| 55 | } |
| 56 | mEnergyHistory.push_back(filteredEnergy); |
| 57 | } |
| 58 | |
| 59 | void Transient::fireCallbacks() { |
| 60 | if (mTransientDetected) { |
nothing calls this directly
no test coverage detected