| 46 | Note::~Note() FL_NOEXCEPT = default; |
| 47 | |
| 48 | void Note::update(shared_ptr<Context> context) { |
| 49 | // Update pitch detector if we own it |
| 50 | if (mOwnsPitchDetector && mPitchDetector) { |
| 51 | mPitchDetector->update(context); |
| 52 | } |
| 53 | |
| 54 | // Get pitch detection results |
| 55 | if (!mPitchDetector) { |
| 56 | return; // No pitch detector available |
| 57 | } |
| 58 | |
| 59 | float pitch = mPitchDetector->getPitch(); |
| 60 | float confidence = mPitchDetector->getConfidence(); |
| 61 | bool voiced = mPitchDetector->isVoiced(); |
| 62 | u32 timestamp = context->getTimestamp(); |
| 63 | float energy = context->getRMS(); |
| 64 | |
| 65 | mCurrentPitch = pitch; |
| 66 | mLastUpdateTime = timestamp; |
| 67 | |
| 68 | // State machine: note-on, note-off, note-change detection |
| 69 | if (!mNoteActive) { |
| 70 | // No note currently active - check for note-on |
| 71 | if (shouldTriggerNoteOn(confidence, pitch)) { |
| 72 | u8 newNote = frequencyToMidiNote(pitch); |
| 73 | u8 velocity = calculateVelocity(energy, confidence); |
| 74 | |
| 75 | mCurrentNote = newNote; |
| 76 | mLastVelocity = velocity; |
| 77 | mNoteActive = true; |
| 78 | mNoteOnTime = timestamp; |
| 79 | mNoteOnEnergy = energy; |
| 80 | mPitchBend = calculatePitchBend(pitch, newNote); |
| 81 | |
| 82 | mFireNoteOn = true; |
| 83 | mPendingOnNote = newNote; |
| 84 | mPendingOnVelocity = velocity; |
| 85 | } |
| 86 | } else { |
| 87 | // Note currently active - check for note-off or note-change |
| 88 | if (shouldTriggerNoteOff(confidence, voiced)) { |
| 89 | // Check minimum note duration to prevent flicker |
| 90 | u32 noteDuration = timestamp - mNoteOnTime; |
| 91 | if (noteDuration >= mMinNoteDuration) { |
| 92 | mFireNoteOff = true; |
| 93 | mPendingOffNote = mCurrentNote; |
| 94 | |
| 95 | mCurrentNote = NO_NOTE; |
| 96 | mLastVelocity = 0; |
| 97 | mNoteActive = false; |
| 98 | mPitchBend = 0.0f; |
| 99 | } |
| 100 | } else if (voiced && confidence >= mNoteOnThreshold) { |
| 101 | // Note still active - check for note change |
| 102 | u8 newNote = frequencyToMidiNote(pitch); |
| 103 | mPitchBend = calculatePitchBend(pitch, mCurrentNote); |
| 104 | |
| 105 | if (shouldTriggerNoteChange(newNote, mCurrentNote)) { |
nothing calls this directly
no test coverage detected