react-native-simple-note-pitch-detector 0.5.0 → 0.6.0
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.
- package/android/.gradle/9.0-milestone-1/checksums/checksums.lock +0 -0
- package/android/.gradle/9.0-milestone-1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/9.0-milestone-1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/9.0-milestone-1/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/config.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/AndroidProjectSystem.xml +6 -0
- package/android/.idea/caches/deviceStreaming.xml +1318 -0
- package/android/.idea/gradle.xml +12 -0
- package/android/.idea/migrations.xml +10 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/runConfigurations.xml +17 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/local.properties +8 -0
- package/android/src/main/java/expo/modules/simplenotepitchdetector/PitchAnalyzer.kt +34 -2
- package/android/src/main/java/expo/modules/simplenotepitchdetector/ReactNativeSimpleNotePitchDetectorModule.kt +24 -0
- package/build/ReactNativeSimpleNotePitchDetectorModule.web.d.ts +6 -1
- package/build/ReactNativeSimpleNotePitchDetectorModule.web.d.ts.map +1 -1
- package/build/ReactNativeSimpleNotePitchDetectorModule.web.js +6 -1
- package/build/ReactNativeSimpleNotePitchDetectorModule.web.js.map +1 -1
- package/build/index.d.ts +55 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +63 -0
- package/build/index.js.map +1 -1
- package/ios/ReactNativeSimpleNotePitchDetectorModule.swift +91 -11
- package/package.json +1 -1
- package/src/ReactNativeSimpleNotePitchDetectorModule.web.ts +6 -1
- package/src/index.ts +67 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="GradleSettings">
|
|
4
|
+
<option name="linkedExternalProjectsSettings">
|
|
5
|
+
<GradleProjectSettings>
|
|
6
|
+
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
|
7
|
+
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
8
|
+
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
|
9
|
+
</GradleProjectSettings>
|
|
10
|
+
</option>
|
|
11
|
+
</component>
|
|
12
|
+
</project>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
4
|
+
<component name="ProjectRootManager">
|
|
5
|
+
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
6
|
+
</component>
|
|
7
|
+
<component name="ProjectType">
|
|
8
|
+
<option name="id" value="Android" />
|
|
9
|
+
</component>
|
|
10
|
+
</project>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="RunConfigurationProducerService">
|
|
4
|
+
<option name="ignoredProducers">
|
|
5
|
+
<set>
|
|
6
|
+
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
|
7
|
+
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
|
8
|
+
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
|
9
|
+
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
|
10
|
+
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
|
11
|
+
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
|
12
|
+
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
|
13
|
+
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
|
14
|
+
</set>
|
|
15
|
+
</option>
|
|
16
|
+
</component>
|
|
17
|
+
</project>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## This file must *NOT* be checked into Version Control Systems,
|
|
2
|
+
# as it contains information specific to your local configuration.
|
|
3
|
+
#
|
|
4
|
+
# Location of the SDK. This is only used by Gradle.
|
|
5
|
+
# For customization when using a Version Control System, please read the
|
|
6
|
+
# header note.
|
|
7
|
+
#Mon Feb 02 16:28:55 PST 2026
|
|
8
|
+
sdk.dir=/Users/derekdawson/Library/Android/sdk
|
|
@@ -26,6 +26,13 @@ class PitchAnalyzer {
|
|
|
26
26
|
private lateinit var onPitchDetected: (PitchData) -> Unit
|
|
27
27
|
private var isRecording = false
|
|
28
28
|
private var levelThreshold = -30f
|
|
29
|
+
// Configurable buffer size - can be changed from JS
|
|
30
|
+
// Larger buffer = better low frequency detection, more latency
|
|
31
|
+
// Smaller buffer = better high frequency detection, less latency
|
|
32
|
+
private var bufferSize = 2048
|
|
33
|
+
// Configurable algorithm - can be changed from JS
|
|
34
|
+
private var algorithm = PitchEstimationAlgorithm.FFT_YIN
|
|
35
|
+
private var algorithmName = "fft_yin"
|
|
29
36
|
|
|
30
37
|
private var dispatcher: AudioDispatcher? = null
|
|
31
38
|
private var processor: AudioProcessor? = null
|
|
@@ -42,8 +49,8 @@ class PitchAnalyzer {
|
|
|
42
49
|
|
|
43
50
|
private fun prepare() {
|
|
44
51
|
processor =
|
|
45
|
-
PitchProcessor(
|
|
46
|
-
dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050,
|
|
52
|
+
PitchProcessor(algorithm, 22050f, bufferSize, handler)
|
|
53
|
+
dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050, bufferSize, 0)
|
|
47
54
|
dispatcher?.addAudioProcessor(processor)
|
|
48
55
|
}
|
|
49
56
|
|
|
@@ -86,6 +93,31 @@ class PitchAnalyzer {
|
|
|
86
93
|
this.levelThreshold = threshold
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
fun setBufferSize(size: Int) {
|
|
97
|
+
this.bufferSize = size
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
fun getBufferSize(): Int {
|
|
101
|
+
return this.bufferSize
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
fun setAlgorithm(name: String) {
|
|
105
|
+
this.algorithmName = name.lowercase()
|
|
106
|
+
this.algorithm = when (this.algorithmName) {
|
|
107
|
+
"yin" -> PitchEstimationAlgorithm.YIN
|
|
108
|
+
"fft_yin" -> PitchEstimationAlgorithm.FFT_YIN
|
|
109
|
+
"mpm" -> PitchEstimationAlgorithm.MPM
|
|
110
|
+
"fft_pitch" -> PitchEstimationAlgorithm.FFT_PITCH
|
|
111
|
+
"dynamic_wavelet" -> PitchEstimationAlgorithm.DYNAMIC_WAVELET
|
|
112
|
+
"amdf" -> PitchEstimationAlgorithm.AMDF
|
|
113
|
+
else -> PitchEstimationAlgorithm.FFT_YIN // Default
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
fun getAlgorithm(): String {
|
|
118
|
+
return this.algorithmName
|
|
119
|
+
}
|
|
120
|
+
|
|
89
121
|
fun start() {
|
|
90
122
|
prepare()
|
|
91
123
|
runner = Thread(dispatcher)
|
|
@@ -43,5 +43,29 @@ class ReactNativeSimpleNotePitchDetectorModule : Module() {
|
|
|
43
43
|
Function("setLevelThreshold") { threshold: Double ->
|
|
44
44
|
pitchAnalyzer.setLevelThreshold(threshold.toFloat())
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
// Allow JS to configure the buffer size
|
|
48
|
+
// Must be called before start() to take effect
|
|
49
|
+
// Common values: 1024 (better for high frequencies), 2048 (balanced), 4096 (better for low frequencies)
|
|
50
|
+
Function("setBufferSize") { size: Int ->
|
|
51
|
+
pitchAnalyzer.setBufferSize(size)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Get current buffer size
|
|
55
|
+
Function("getBufferSize") {
|
|
56
|
+
pitchAnalyzer.getBufferSize()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Allow JS to configure the estimation algorithm
|
|
60
|
+
// Android options: "yin", "fft_yin", "mpm", "fft_pitch", "dynamic_wavelet", "amdf"
|
|
61
|
+
// Must be called before start() to take effect
|
|
62
|
+
Function("setAlgorithm") { algorithm: String ->
|
|
63
|
+
pitchAnalyzer.setAlgorithm(algorithm)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Get current algorithm name
|
|
67
|
+
Function("getAlgorithm") {
|
|
68
|
+
pitchAnalyzer.getAlgorithm()
|
|
69
|
+
}
|
|
46
70
|
}
|
|
47
71
|
}
|
|
@@ -2,8 +2,13 @@ import { ChangeEventPayload } from "./ReactNativeSimpleNotePitchDetector.types";
|
|
|
2
2
|
declare const _default: {
|
|
3
3
|
start: () => void;
|
|
4
4
|
stop: () => void;
|
|
5
|
-
isRecording: () =>
|
|
5
|
+
isRecording: () => boolean;
|
|
6
6
|
onChangePitch: (_: ChangeEventPayload) => void;
|
|
7
|
+
setLevelThreshold: (_: number) => void;
|
|
8
|
+
setBufferSize: (_: number) => void;
|
|
9
|
+
getBufferSize: () => number;
|
|
10
|
+
setAlgorithm: (_: string) => void;
|
|
11
|
+
getAlgorithm: () => string;
|
|
7
12
|
};
|
|
8
13
|
export default _default;
|
|
9
14
|
//# sourceMappingURL=ReactNativeSimpleNotePitchDetectorModule.web.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactNativeSimpleNotePitchDetectorModule.web.d.ts","sourceRoot":"","sources":["../src/ReactNativeSimpleNotePitchDetectorModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;;;;;uBAM3D,kBAAkB;;
|
|
1
|
+
{"version":3,"file":"ReactNativeSimpleNotePitchDetectorModule.web.d.ts","sourceRoot":"","sources":["../src/ReactNativeSimpleNotePitchDetectorModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;;;;;uBAM3D,kBAAkB;2BACd,MAAM;uBACV,MAAM;;sBAEP,MAAM;;;AAR1B,wBAUE"}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
export default {
|
|
2
2
|
start: () => { },
|
|
3
3
|
stop: () => { },
|
|
4
|
-
isRecording: () =>
|
|
4
|
+
isRecording: () => false,
|
|
5
5
|
onChangePitch: (_) => { },
|
|
6
|
+
setLevelThreshold: (_) => { },
|
|
7
|
+
setBufferSize: (_) => { },
|
|
8
|
+
getBufferSize: () => 8192,
|
|
9
|
+
setAlgorithm: (_) => { },
|
|
10
|
+
getAlgorithm: () => "yin",
|
|
6
11
|
};
|
|
7
12
|
//# sourceMappingURL=ReactNativeSimpleNotePitchDetectorModule.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReactNativeSimpleNotePitchDetectorModule.web.js","sourceRoot":"","sources":["../src/ReactNativeSimpleNotePitchDetectorModule.web.ts"],"names":[],"mappings":"AAEA,eAAe;IACb,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,WAAW,EAAE,GAAG,EAAE,GAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ReactNativeSimpleNotePitchDetectorModule.web.js","sourceRoot":"","sources":["../src/ReactNativeSimpleNotePitchDetectorModule.web.ts"],"names":[],"mappings":"AAEA,eAAe;IACb,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;IACd,WAAW,EAAE,GAAG,EAAE,CAAC,KAAK;IACxB,aAAa,EAAE,CAAC,CAAqB,EAAE,EAAE,GAAE,CAAC;IAC5C,iBAAiB,EAAE,CAAC,CAAS,EAAE,EAAE,GAAE,CAAC;IACpC,aAAa,EAAE,CAAC,CAAS,EAAE,EAAE,GAAE,CAAC;IAChC,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI;IACzB,YAAY,EAAE,CAAC,CAAS,EAAE,EAAE,GAAE,CAAC;IAC/B,YAAY,EAAE,GAAG,EAAE,CAAC,KAAK;CAC1B,CAAC","sourcesContent":["import { ChangeEventPayload } from \"./ReactNativeSimpleNotePitchDetector.types\";\n\nexport default {\n start: () => {},\n stop: () => {},\n isRecording: () => false,\n onChangePitch: (_: ChangeEventPayload) => {},\n setLevelThreshold: (_: number) => {},\n setBufferSize: (_: number) => {},\n getBufferSize: () => 8192,\n setAlgorithm: (_: string) => {},\n getAlgorithm: () => \"yin\",\n};\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -11,6 +11,61 @@ export declare function isRecording(): any;
|
|
|
11
11
|
* @param threshold - Level threshold in dB (e.g., -30, -35, -40)
|
|
12
12
|
*/
|
|
13
13
|
export declare function setLevelThreshold(threshold: number): any;
|
|
14
|
+
/**
|
|
15
|
+
* Set the buffer size for pitch detection.
|
|
16
|
+
* Must be called before start() or will restart the engine if already running.
|
|
17
|
+
*
|
|
18
|
+
* Buffer size affects the trade-off between frequency range and responsiveness:
|
|
19
|
+
* - Smaller buffer (2048-4096): Better for high frequencies, faster response, but less accurate for low notes
|
|
20
|
+
* - Larger buffer (8192-16384): Better for low frequencies, more accurate, but slightly more latency
|
|
21
|
+
*
|
|
22
|
+
* iOS defaults to 8192, Android defaults to 2048.
|
|
23
|
+
*
|
|
24
|
+
* Recommended values:
|
|
25
|
+
* - 4096: Good balance for most use cases
|
|
26
|
+
* - 8192: Better for bass instruments or full piano range (iOS default)
|
|
27
|
+
* - 2048: Better for high-pitched instruments, faster response (Android default)
|
|
28
|
+
*
|
|
29
|
+
* @param size - Buffer size (must be power of 2: 1024, 2048, 4096, 8192, 16384)
|
|
30
|
+
*/
|
|
31
|
+
export declare function setBufferSize(size: number): any;
|
|
32
|
+
/**
|
|
33
|
+
* Get the current buffer size.
|
|
34
|
+
* @returns Current buffer size
|
|
35
|
+
*/
|
|
36
|
+
export declare function getBufferSize(): number;
|
|
37
|
+
/**
|
|
38
|
+
* Set the pitch estimation algorithm.
|
|
39
|
+
* Must be called before start() or will restart the engine if already running.
|
|
40
|
+
*
|
|
41
|
+
* Available algorithms differ by platform:
|
|
42
|
+
*
|
|
43
|
+
* **iOS (Beethoven library):**
|
|
44
|
+
* - "yin" (default) - YIN algorithm, good for monophonic instruments
|
|
45
|
+
* - "hps" - Harmonic Product Spectrum
|
|
46
|
+
* - "barycentric" - Barycentric interpolation
|
|
47
|
+
* - "quadradic" - Quadratic interpolation
|
|
48
|
+
* - "jains" - Jain's method
|
|
49
|
+
* - "quinnsFirst" - Quinn's first estimator
|
|
50
|
+
* - "quinnsSecond" - Quinn's second estimator
|
|
51
|
+
* - "maxValue" - Maximum value method
|
|
52
|
+
*
|
|
53
|
+
* **Android (TarsosDSP library):**
|
|
54
|
+
* - "fft_yin" (default) - FFT-based YIN, faster than pure YIN
|
|
55
|
+
* - "yin" - Pure YIN algorithm
|
|
56
|
+
* - "mpm" - McLeod Pitch Method, good for speech and music
|
|
57
|
+
* - "fft_pitch" - FFT bin with most energy
|
|
58
|
+
* - "dynamic_wavelet" - Dynamic wavelet algorithm
|
|
59
|
+
* - "amdf" - Average Magnitude Difference Function
|
|
60
|
+
*
|
|
61
|
+
* @param algorithm - Algorithm name (case-insensitive)
|
|
62
|
+
*/
|
|
63
|
+
export declare function setAlgorithm(algorithm: string): any;
|
|
64
|
+
/**
|
|
65
|
+
* Get the current algorithm name.
|
|
66
|
+
* @returns Current algorithm name
|
|
67
|
+
*/
|
|
68
|
+
export declare function getAlgorithm(): string;
|
|
14
69
|
export declare function onChangeNote(listener: (event: ChangeEventPayload) => void): Subscription;
|
|
15
70
|
export { ReactNativeSimpleNotePitchDetectorViewProps, ChangeEventPayload };
|
|
16
71
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EACb,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,kBAAkB,EAClB,2CAA2C,EAC5C,MAAM,4CAA4C,CAAC;AAEpD,wBAAgB,KAAK,QAEpB;AAED,wBAAgB,IAAI,QAEnB;AAED,wBAAgB,WAAW,QAE1B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,OAElD;AAOD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAC5C,YAAY,CAEd;AAED,OAAO,EAAE,2CAA2C,EAAE,kBAAkB,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,YAAY,EACb,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,kBAAkB,EAClB,2CAA2C,EAC5C,MAAM,4CAA4C,CAAC;AAEpD,wBAAgB,KAAK,QAEpB;AAED,wBAAgB,IAAI,QAEnB;AAED,wBAAgB,WAAW,QAE1B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,OAElD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,OAEzC;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,OAE7C;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAOD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAC5C,YAAY,CAEd;AAED,OAAO,EAAE,2CAA2C,EAAE,kBAAkB,EAAE,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -19,6 +19,69 @@ export function isRecording() {
|
|
|
19
19
|
export function setLevelThreshold(threshold) {
|
|
20
20
|
return ReactNativeSimpleNotePitchDetectorModule.setLevelThreshold(threshold);
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Set the buffer size for pitch detection.
|
|
24
|
+
* Must be called before start() or will restart the engine if already running.
|
|
25
|
+
*
|
|
26
|
+
* Buffer size affects the trade-off between frequency range and responsiveness:
|
|
27
|
+
* - Smaller buffer (2048-4096): Better for high frequencies, faster response, but less accurate for low notes
|
|
28
|
+
* - Larger buffer (8192-16384): Better for low frequencies, more accurate, but slightly more latency
|
|
29
|
+
*
|
|
30
|
+
* iOS defaults to 8192, Android defaults to 2048.
|
|
31
|
+
*
|
|
32
|
+
* Recommended values:
|
|
33
|
+
* - 4096: Good balance for most use cases
|
|
34
|
+
* - 8192: Better for bass instruments or full piano range (iOS default)
|
|
35
|
+
* - 2048: Better for high-pitched instruments, faster response (Android default)
|
|
36
|
+
*
|
|
37
|
+
* @param size - Buffer size (must be power of 2: 1024, 2048, 4096, 8192, 16384)
|
|
38
|
+
*/
|
|
39
|
+
export function setBufferSize(size) {
|
|
40
|
+
return ReactNativeSimpleNotePitchDetectorModule.setBufferSize(size);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the current buffer size.
|
|
44
|
+
* @returns Current buffer size
|
|
45
|
+
*/
|
|
46
|
+
export function getBufferSize() {
|
|
47
|
+
return ReactNativeSimpleNotePitchDetectorModule.getBufferSize();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Set the pitch estimation algorithm.
|
|
51
|
+
* Must be called before start() or will restart the engine if already running.
|
|
52
|
+
*
|
|
53
|
+
* Available algorithms differ by platform:
|
|
54
|
+
*
|
|
55
|
+
* **iOS (Beethoven library):**
|
|
56
|
+
* - "yin" (default) - YIN algorithm, good for monophonic instruments
|
|
57
|
+
* - "hps" - Harmonic Product Spectrum
|
|
58
|
+
* - "barycentric" - Barycentric interpolation
|
|
59
|
+
* - "quadradic" - Quadratic interpolation
|
|
60
|
+
* - "jains" - Jain's method
|
|
61
|
+
* - "quinnsFirst" - Quinn's first estimator
|
|
62
|
+
* - "quinnsSecond" - Quinn's second estimator
|
|
63
|
+
* - "maxValue" - Maximum value method
|
|
64
|
+
*
|
|
65
|
+
* **Android (TarsosDSP library):**
|
|
66
|
+
* - "fft_yin" (default) - FFT-based YIN, faster than pure YIN
|
|
67
|
+
* - "yin" - Pure YIN algorithm
|
|
68
|
+
* - "mpm" - McLeod Pitch Method, good for speech and music
|
|
69
|
+
* - "fft_pitch" - FFT bin with most energy
|
|
70
|
+
* - "dynamic_wavelet" - Dynamic wavelet algorithm
|
|
71
|
+
* - "amdf" - Average Magnitude Difference Function
|
|
72
|
+
*
|
|
73
|
+
* @param algorithm - Algorithm name (case-insensitive)
|
|
74
|
+
*/
|
|
75
|
+
export function setAlgorithm(algorithm) {
|
|
76
|
+
return ReactNativeSimpleNotePitchDetectorModule.setAlgorithm(algorithm);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get the current algorithm name.
|
|
80
|
+
* @returns Current algorithm name
|
|
81
|
+
*/
|
|
82
|
+
export function getAlgorithm() {
|
|
83
|
+
return ReactNativeSimpleNotePitchDetectorModule.getAlgorithm();
|
|
84
|
+
}
|
|
22
85
|
const emitter = new EventEmitter(ReactNativeSimpleNotePitchDetectorModule ??
|
|
23
86
|
NativeModulesProxy.ReactNativeSimpleNotePitchDetector);
|
|
24
87
|
export function onChangeNote(listener) {
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,GAEb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,wCAAwC,MAAM,4CAA4C,CAAC;AAMlG,MAAM,UAAU,KAAK;IACnB,OAAO,wCAAwC,CAAC,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,wCAAwC,CAAC,IAAI,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,wCAAwC,CAAC,WAAW,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,wCAAwC,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,wCAAwC;IACtC,kBAAkB,CAAC,kCAAkC,CACxD,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,QAA6C;IAE7C,OAAO,OAAO,CAAC,WAAW,CAAqB,cAAc,EAAE,QAAQ,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["import {\n NativeModulesProxy,\n EventEmitter,\n Subscription,\n} from \"expo-modules-core\";\n\nimport ReactNativeSimpleNotePitchDetectorModule from \"./ReactNativeSimpleNotePitchDetectorModule\";\nimport {\n ChangeEventPayload,\n ReactNativeSimpleNotePitchDetectorViewProps,\n} from \"./ReactNativeSimpleNotePitchDetector.types\";\n\nexport function start() {\n return ReactNativeSimpleNotePitchDetectorModule.start();\n}\n\nexport function stop() {\n return ReactNativeSimpleNotePitchDetectorModule.stop();\n}\n\nexport function isRecording() {\n return ReactNativeSimpleNotePitchDetectorModule.isRecording();\n}\n\n/**\n * Set the minimum audio level threshold for pitch detection.\n * Values are in dB (e.g., -30 means sounds quieter than -30dB are ignored).\n * Lower values = more sensitive (picks up quieter sounds).\n * Default is -30.\n * @param threshold - Level threshold in dB (e.g., -30, -35, -40)\n */\nexport function setLevelThreshold(threshold: number) {\n return ReactNativeSimpleNotePitchDetectorModule.setLevelThreshold(threshold);\n}\n\nconst emitter = new EventEmitter(\n ReactNativeSimpleNotePitchDetectorModule ??\n NativeModulesProxy.ReactNativeSimpleNotePitchDetector\n);\n\nexport function onChangeNote(\n listener: (event: ChangeEventPayload) => void\n): Subscription {\n return emitter.addListener<ChangeEventPayload>(\"onChangeNote\", listener);\n}\n\nexport { ReactNativeSimpleNotePitchDetectorViewProps, ChangeEventPayload };\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,GAEb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,wCAAwC,MAAM,4CAA4C,CAAC;AAMlG,MAAM,UAAU,KAAK;IACnB,OAAO,wCAAwC,CAAC,KAAK,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,wCAAwC,CAAC,IAAI,EAAE,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,wCAAwC,CAAC,WAAW,EAAE,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IACjD,OAAO,wCAAwC,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,wCAAwC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,wCAAwC,CAAC,aAAa,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,wCAAwC,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,wCAAwC,CAAC,YAAY,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,YAAY,CAC9B,wCAAwC;IACtC,kBAAkB,CAAC,kCAAkC,CACxD,CAAC;AAEF,MAAM,UAAU,YAAY,CAC1B,QAA6C;IAE7C,OAAO,OAAO,CAAC,WAAW,CAAqB,cAAc,EAAE,QAAQ,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["import {\n NativeModulesProxy,\n EventEmitter,\n Subscription,\n} from \"expo-modules-core\";\n\nimport ReactNativeSimpleNotePitchDetectorModule from \"./ReactNativeSimpleNotePitchDetectorModule\";\nimport {\n ChangeEventPayload,\n ReactNativeSimpleNotePitchDetectorViewProps,\n} from \"./ReactNativeSimpleNotePitchDetector.types\";\n\nexport function start() {\n return ReactNativeSimpleNotePitchDetectorModule.start();\n}\n\nexport function stop() {\n return ReactNativeSimpleNotePitchDetectorModule.stop();\n}\n\nexport function isRecording() {\n return ReactNativeSimpleNotePitchDetectorModule.isRecording();\n}\n\n/**\n * Set the minimum audio level threshold for pitch detection.\n * Values are in dB (e.g., -30 means sounds quieter than -30dB are ignored).\n * Lower values = more sensitive (picks up quieter sounds).\n * Default is -30.\n * @param threshold - Level threshold in dB (e.g., -30, -35, -40)\n */\nexport function setLevelThreshold(threshold: number) {\n return ReactNativeSimpleNotePitchDetectorModule.setLevelThreshold(threshold);\n}\n\n/**\n * Set the buffer size for pitch detection.\n * Must be called before start() or will restart the engine if already running.\n *\n * Buffer size affects the trade-off between frequency range and responsiveness:\n * - Smaller buffer (2048-4096): Better for high frequencies, faster response, but less accurate for low notes\n * - Larger buffer (8192-16384): Better for low frequencies, more accurate, but slightly more latency\n *\n * iOS defaults to 8192, Android defaults to 2048.\n *\n * Recommended values:\n * - 4096: Good balance for most use cases\n * - 8192: Better for bass instruments or full piano range (iOS default)\n * - 2048: Better for high-pitched instruments, faster response (Android default)\n *\n * @param size - Buffer size (must be power of 2: 1024, 2048, 4096, 8192, 16384)\n */\nexport function setBufferSize(size: number) {\n return ReactNativeSimpleNotePitchDetectorModule.setBufferSize(size);\n}\n\n/**\n * Get the current buffer size.\n * @returns Current buffer size\n */\nexport function getBufferSize(): number {\n return ReactNativeSimpleNotePitchDetectorModule.getBufferSize();\n}\n\n/**\n * Set the pitch estimation algorithm.\n * Must be called before start() or will restart the engine if already running.\n *\n * Available algorithms differ by platform:\n *\n * **iOS (Beethoven library):**\n * - \"yin\" (default) - YIN algorithm, good for monophonic instruments\n * - \"hps\" - Harmonic Product Spectrum\n * - \"barycentric\" - Barycentric interpolation\n * - \"quadradic\" - Quadratic interpolation\n * - \"jains\" - Jain's method\n * - \"quinnsFirst\" - Quinn's first estimator\n * - \"quinnsSecond\" - Quinn's second estimator\n * - \"maxValue\" - Maximum value method\n *\n * **Android (TarsosDSP library):**\n * - \"fft_yin\" (default) - FFT-based YIN, faster than pure YIN\n * - \"yin\" - Pure YIN algorithm\n * - \"mpm\" - McLeod Pitch Method, good for speech and music\n * - \"fft_pitch\" - FFT bin with most energy\n * - \"dynamic_wavelet\" - Dynamic wavelet algorithm\n * - \"amdf\" - Average Magnitude Difference Function\n *\n * @param algorithm - Algorithm name (case-insensitive)\n */\nexport function setAlgorithm(algorithm: string) {\n return ReactNativeSimpleNotePitchDetectorModule.setAlgorithm(algorithm);\n}\n\n/**\n * Get the current algorithm name.\n * @returns Current algorithm name\n */\nexport function getAlgorithm(): string {\n return ReactNativeSimpleNotePitchDetectorModule.getAlgorithm();\n}\n\nconst emitter = new EventEmitter(\n ReactNativeSimpleNotePitchDetectorModule ??\n NativeModulesProxy.ReactNativeSimpleNotePitchDetector\n);\n\nexport function onChangeNote(\n listener: (event: ChangeEventPayload) => void\n): Subscription {\n return emitter.addListener<ChangeEventPayload>(\"onChangeNote\", listener);\n}\n\nexport { ReactNativeSimpleNotePitchDetectorViewProps, ChangeEventPayload };\n"]}
|
|
@@ -5,6 +5,13 @@ import Pitchy
|
|
|
5
5
|
|
|
6
6
|
public class ReactNativeSimpleNotePitchDetectorModule: Module {
|
|
7
7
|
|
|
8
|
+
// Configurable buffer size - can be changed from JS
|
|
9
|
+
// Larger buffer = better low frequency detection, more latency
|
|
10
|
+
// Smaller buffer = better high frequency detection, less latency
|
|
11
|
+
private var bufferSize: UInt32 = 8192
|
|
12
|
+
private var estimationStrategy: EstimationStrategy = .yin
|
|
13
|
+
private var _pitchEngine: PitchEngine?
|
|
14
|
+
|
|
8
15
|
public func definition() -> ModuleDefinition {
|
|
9
16
|
|
|
10
17
|
Name("ReactNativeSimpleNotePitchDetector")
|
|
@@ -12,32 +19,105 @@ public class ReactNativeSimpleNotePitchDetectorModule: Module {
|
|
|
12
19
|
Events("onChangeNote")
|
|
13
20
|
|
|
14
21
|
Function("start") {
|
|
15
|
-
pitchEngine.start()
|
|
22
|
+
self.pitchEngine.start()
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
Function("stop") {
|
|
19
|
-
pitchEngine.stop()
|
|
26
|
+
self.pitchEngine.stop()
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
Function("isRecording") {
|
|
23
|
-
return pitchEngine.active
|
|
30
|
+
return self.pitchEngine.active
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
// Allow JS to configure the level threshold
|
|
27
34
|
Function("setLevelThreshold") { (threshold: Double) in
|
|
28
35
|
self.pitchEngine.levelThreshold = Float(threshold)
|
|
29
36
|
}
|
|
37
|
+
|
|
38
|
+
// Allow JS to configure the buffer size
|
|
39
|
+
// Must be called before start() or after stop() to take effect
|
|
40
|
+
// Common values: 4096 (better for high frequencies), 8192 (balanced), 16384 (better for low frequencies)
|
|
41
|
+
Function("setBufferSize") { (size: Int) in
|
|
42
|
+
let wasActive = self._pitchEngine?.active ?? false
|
|
43
|
+
if wasActive {
|
|
44
|
+
self._pitchEngine?.stop()
|
|
45
|
+
}
|
|
46
|
+
self.bufferSize = UInt32(size)
|
|
47
|
+
self._pitchEngine = nil // Force recreation with new buffer size
|
|
48
|
+
if wasActive {
|
|
49
|
+
self.pitchEngine.start()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Get current buffer size
|
|
54
|
+
Function("getBufferSize") {
|
|
55
|
+
return Int(self.bufferSize)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Allow JS to configure the estimation algorithm
|
|
59
|
+
// iOS options: "yin", "hps", "barycentric", "quadradic", "jains", "quinnsFirst", "quinnsSecond", "maxValue"
|
|
60
|
+
// Must be called before start() or will restart the engine
|
|
61
|
+
Function("setAlgorithm") { (algorithm: String) in
|
|
62
|
+
let wasActive = self._pitchEngine?.active ?? false
|
|
63
|
+
if wasActive {
|
|
64
|
+
self._pitchEngine?.stop()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
switch algorithm.lowercased() {
|
|
68
|
+
case "yin":
|
|
69
|
+
self.estimationStrategy = .yin
|
|
70
|
+
case "hps":
|
|
71
|
+
self.estimationStrategy = .hps
|
|
72
|
+
case "barycentric":
|
|
73
|
+
self.estimationStrategy = .barycentric
|
|
74
|
+
case "quadradic":
|
|
75
|
+
self.estimationStrategy = .quadradic
|
|
76
|
+
case "jains":
|
|
77
|
+
self.estimationStrategy = .jains
|
|
78
|
+
case "quinnsfirst":
|
|
79
|
+
self.estimationStrategy = .quinnsFirst
|
|
80
|
+
case "quinnssecond":
|
|
81
|
+
self.estimationStrategy = .quinnsSecond
|
|
82
|
+
case "maxvalue":
|
|
83
|
+
self.estimationStrategy = .maxValue
|
|
84
|
+
default:
|
|
85
|
+
// Default to YIN if unknown
|
|
86
|
+
self.estimationStrategy = .yin
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
self._pitchEngine = nil // Force recreation with new algorithm
|
|
90
|
+
if wasActive {
|
|
91
|
+
self.pitchEngine.start()
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Get current algorithm name
|
|
96
|
+
Function("getAlgorithm") {
|
|
97
|
+
switch self.estimationStrategy {
|
|
98
|
+
case .yin: return "yin"
|
|
99
|
+
case .hps: return "hps"
|
|
100
|
+
case .barycentric: return "barycentric"
|
|
101
|
+
case .quadradic: return "quadradic"
|
|
102
|
+
case .jains: return "jains"
|
|
103
|
+
case .quinnsFirst: return "quinnsFirst"
|
|
104
|
+
case .quinnsSecond: return "quinnsSecond"
|
|
105
|
+
case .maxValue: return "maxValue"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
30
108
|
}
|
|
31
109
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
let
|
|
110
|
+
var pitchEngine: PitchEngine {
|
|
111
|
+
if let engine = _pitchEngine {
|
|
112
|
+
return engine
|
|
113
|
+
}
|
|
114
|
+
let config = Config(bufferSize: bufferSize, estimationStrategy: estimationStrategy)
|
|
115
|
+
let engine = PitchEngine(config: config, delegate: self)
|
|
37
116
|
// Default threshold - can be adjusted from JS via setLevelThreshold()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
117
|
+
engine.levelThreshold = -30
|
|
118
|
+
_pitchEngine = engine
|
|
119
|
+
return engine
|
|
120
|
+
}
|
|
41
121
|
}
|
|
42
122
|
|
|
43
123
|
extension ReactNativeSimpleNotePitchDetectorModule: PitchEngineDelegate {
|
package/package.json
CHANGED
|
@@ -3,6 +3,11 @@ import { ChangeEventPayload } from "./ReactNativeSimpleNotePitchDetector.types";
|
|
|
3
3
|
export default {
|
|
4
4
|
start: () => {},
|
|
5
5
|
stop: () => {},
|
|
6
|
-
isRecording: () =>
|
|
6
|
+
isRecording: () => false,
|
|
7
7
|
onChangePitch: (_: ChangeEventPayload) => {},
|
|
8
|
+
setLevelThreshold: (_: number) => {},
|
|
9
|
+
setBufferSize: (_: number) => {},
|
|
10
|
+
getBufferSize: () => 8192,
|
|
11
|
+
setAlgorithm: (_: string) => {},
|
|
12
|
+
getAlgorithm: () => "yin",
|
|
8
13
|
};
|
package/src/index.ts
CHANGED
|
@@ -33,6 +33,73 @@ export function setLevelThreshold(threshold: number) {
|
|
|
33
33
|
return ReactNativeSimpleNotePitchDetectorModule.setLevelThreshold(threshold);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Set the buffer size for pitch detection.
|
|
38
|
+
* Must be called before start() or will restart the engine if already running.
|
|
39
|
+
*
|
|
40
|
+
* Buffer size affects the trade-off between frequency range and responsiveness:
|
|
41
|
+
* - Smaller buffer (2048-4096): Better for high frequencies, faster response, but less accurate for low notes
|
|
42
|
+
* - Larger buffer (8192-16384): Better for low frequencies, more accurate, but slightly more latency
|
|
43
|
+
*
|
|
44
|
+
* iOS defaults to 8192, Android defaults to 2048.
|
|
45
|
+
*
|
|
46
|
+
* Recommended values:
|
|
47
|
+
* - 4096: Good balance for most use cases
|
|
48
|
+
* - 8192: Better for bass instruments or full piano range (iOS default)
|
|
49
|
+
* - 2048: Better for high-pitched instruments, faster response (Android default)
|
|
50
|
+
*
|
|
51
|
+
* @param size - Buffer size (must be power of 2: 1024, 2048, 4096, 8192, 16384)
|
|
52
|
+
*/
|
|
53
|
+
export function setBufferSize(size: number) {
|
|
54
|
+
return ReactNativeSimpleNotePitchDetectorModule.setBufferSize(size);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get the current buffer size.
|
|
59
|
+
* @returns Current buffer size
|
|
60
|
+
*/
|
|
61
|
+
export function getBufferSize(): number {
|
|
62
|
+
return ReactNativeSimpleNotePitchDetectorModule.getBufferSize();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Set the pitch estimation algorithm.
|
|
67
|
+
* Must be called before start() or will restart the engine if already running.
|
|
68
|
+
*
|
|
69
|
+
* Available algorithms differ by platform:
|
|
70
|
+
*
|
|
71
|
+
* **iOS (Beethoven library):**
|
|
72
|
+
* - "yin" (default) - YIN algorithm, good for monophonic instruments
|
|
73
|
+
* - "hps" - Harmonic Product Spectrum
|
|
74
|
+
* - "barycentric" - Barycentric interpolation
|
|
75
|
+
* - "quadradic" - Quadratic interpolation
|
|
76
|
+
* - "jains" - Jain's method
|
|
77
|
+
* - "quinnsFirst" - Quinn's first estimator
|
|
78
|
+
* - "quinnsSecond" - Quinn's second estimator
|
|
79
|
+
* - "maxValue" - Maximum value method
|
|
80
|
+
*
|
|
81
|
+
* **Android (TarsosDSP library):**
|
|
82
|
+
* - "fft_yin" (default) - FFT-based YIN, faster than pure YIN
|
|
83
|
+
* - "yin" - Pure YIN algorithm
|
|
84
|
+
* - "mpm" - McLeod Pitch Method, good for speech and music
|
|
85
|
+
* - "fft_pitch" - FFT bin with most energy
|
|
86
|
+
* - "dynamic_wavelet" - Dynamic wavelet algorithm
|
|
87
|
+
* - "amdf" - Average Magnitude Difference Function
|
|
88
|
+
*
|
|
89
|
+
* @param algorithm - Algorithm name (case-insensitive)
|
|
90
|
+
*/
|
|
91
|
+
export function setAlgorithm(algorithm: string) {
|
|
92
|
+
return ReactNativeSimpleNotePitchDetectorModule.setAlgorithm(algorithm);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the current algorithm name.
|
|
97
|
+
* @returns Current algorithm name
|
|
98
|
+
*/
|
|
99
|
+
export function getAlgorithm(): string {
|
|
100
|
+
return ReactNativeSimpleNotePitchDetectorModule.getAlgorithm();
|
|
101
|
+
}
|
|
102
|
+
|
|
36
103
|
const emitter = new EventEmitter(
|
|
37
104
|
ReactNativeSimpleNotePitchDetectorModule ??
|
|
38
105
|
NativeModulesProxy.ReactNativeSimpleNotePitchDetector
|