react-native-simple-note-pitch-detector 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -63,6 +63,14 @@ class PitchAnalyzer {
|
|
|
63
63
|
private var hpsProduct: FloatArray? = null
|
|
64
64
|
private var hannWindow: FloatArray? = null
|
|
65
65
|
|
|
66
|
+
// Adaptive noise gate: tracks background noise floor per-dispatcher
|
|
67
|
+
// A note must be this many dB above the noise floor to be emitted
|
|
68
|
+
private val noiseGateMarginDb = 10f
|
|
69
|
+
// Exponential moving average decay for noise floor (0.01 = slow adaptation)
|
|
70
|
+
private val noiseFloorAlpha = 0.01f
|
|
71
|
+
@Volatile private var hpsNoiseFloor = -60f
|
|
72
|
+
@Volatile private var yinNoiseFloor = -60f
|
|
73
|
+
|
|
66
74
|
// HPS searches low range only: A0 (27.5Hz) to ~G3 (196Hz)
|
|
67
75
|
private val hpsMinHz = 26f
|
|
68
76
|
private val hpsMaxHz = 200f
|
|
@@ -72,12 +80,26 @@ class PitchAnalyzer {
|
|
|
72
80
|
// MPM max: reject garbage above piano range (C8 = 4186Hz)
|
|
73
81
|
private val mpmMaxHz = 4200f
|
|
74
82
|
|
|
83
|
+
private fun updateNoiseFloor(currentFloor: Float, dB: Float): Float {
|
|
84
|
+
// Only update noise floor when signal is quiet (close to current floor)
|
|
85
|
+
// This prevents played notes from raising the floor
|
|
86
|
+
return if (dB < currentFloor + noiseGateMarginDb) {
|
|
87
|
+
currentFloor + noiseFloorAlpha * (dB - currentFloor)
|
|
88
|
+
} else {
|
|
89
|
+
currentFloor
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
75
93
|
private val hpsProcessor = object : AudioProcessor {
|
|
76
94
|
override fun process(audioEvent: AudioEvent): Boolean {
|
|
77
95
|
val buffer = audioEvent.floatBuffer
|
|
78
96
|
val dB = audioEvent.getdBSPL().toFloat()
|
|
79
97
|
|
|
80
|
-
|
|
98
|
+
// Update noise floor estimate
|
|
99
|
+
hpsNoiseFloor = updateNoiseFloor(hpsNoiseFloor, dB)
|
|
100
|
+
|
|
101
|
+
// Adaptive gate: only process if dB is above noise floor + margin
|
|
102
|
+
if (dB > hpsNoiseFloor + noiseGateMarginDb) {
|
|
81
103
|
try {
|
|
82
104
|
val pitch = detectPitchHPS(buffer)
|
|
83
105
|
if (pitch > 0f) {
|
|
@@ -187,8 +209,13 @@ class PitchAnalyzer {
|
|
|
187
209
|
|
|
188
210
|
val pitchHandler = PitchDetectionHandler { result: PitchDetectionResult, event: AudioEvent ->
|
|
189
211
|
val pitch = result.pitch
|
|
190
|
-
|
|
191
|
-
|
|
212
|
+
val dB = event.getdBSPL().toFloat()
|
|
213
|
+
|
|
214
|
+
// Update YIN noise floor
|
|
215
|
+
yinNoiseFloor = updateNoiseFloor(yinNoiseFloor, dB)
|
|
216
|
+
|
|
217
|
+
if (pitch > 0 && pitch >= mpmMinHz && pitch <= mpmMaxHz && result.isPitched
|
|
218
|
+
&& dB > yinNoiseFloor + noiseGateMarginDb) {
|
|
192
219
|
emitPitch(pitch, dB)
|
|
193
220
|
}
|
|
194
221
|
}
|
|
@@ -225,10 +252,6 @@ class PitchAnalyzer {
|
|
|
225
252
|
val octave = (roundedMidiNote / 12) - 1
|
|
226
253
|
val centsOff = (midiNote - roundedMidiNote) * 100
|
|
227
254
|
|
|
228
|
-
// Pre-filter: JS discards offset > 25% anyway, so skip detections > 40%
|
|
229
|
-
// to reduce noise in the JS majority voting window
|
|
230
|
-
if (kotlin.math.abs(centsOff) > 40f) return
|
|
231
|
-
|
|
232
255
|
onPitchDetected(PitchData(
|
|
233
256
|
note = notes[noteIndex],
|
|
234
257
|
octave = octave,
|
package/package.json
CHANGED