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.
Files changed (30) hide show
  1. package/android/.gradle/9.0-milestone-1/checksums/checksums.lock +0 -0
  2. package/android/.gradle/9.0-milestone-1/fileChanges/last-build.bin +0 -0
  3. package/android/.gradle/9.0-milestone-1/fileHashes/fileHashes.lock +0 -0
  4. package/android/.gradle/9.0-milestone-1/gc.properties +0 -0
  5. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  6. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  7. package/android/.gradle/config.properties +2 -0
  8. package/android/.gradle/vcs-1/gc.properties +0 -0
  9. package/android/.idea/AndroidProjectSystem.xml +6 -0
  10. package/android/.idea/caches/deviceStreaming.xml +1318 -0
  11. package/android/.idea/gradle.xml +12 -0
  12. package/android/.idea/migrations.xml +10 -0
  13. package/android/.idea/misc.xml +10 -0
  14. package/android/.idea/runConfigurations.xml +17 -0
  15. package/android/.idea/vcs.xml +6 -0
  16. package/android/local.properties +8 -0
  17. package/android/src/main/java/expo/modules/simplenotepitchdetector/PitchAnalyzer.kt +34 -2
  18. package/android/src/main/java/expo/modules/simplenotepitchdetector/ReactNativeSimpleNotePitchDetectorModule.kt +24 -0
  19. package/build/ReactNativeSimpleNotePitchDetectorModule.web.d.ts +6 -1
  20. package/build/ReactNativeSimpleNotePitchDetectorModule.web.d.ts.map +1 -1
  21. package/build/ReactNativeSimpleNotePitchDetectorModule.web.js +6 -1
  22. package/build/ReactNativeSimpleNotePitchDetectorModule.web.js.map +1 -1
  23. package/build/index.d.ts +55 -0
  24. package/build/index.d.ts.map +1 -1
  25. package/build/index.js +63 -0
  26. package/build/index.js.map +1 -1
  27. package/ios/ReactNativeSimpleNotePitchDetectorModule.swift +91 -11
  28. package/package.json +1 -1
  29. package/src/ReactNativeSimpleNotePitchDetectorModule.web.ts +6 -1
  30. 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="ProjectMigrations">
4
+ <option name="MigrateToGradleLocalJavaHome">
5
+ <set>
6
+ <option value="$PROJECT_DIR$" />
7
+ </set>
8
+ </option>
9
+ </component>
10
+ </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,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
5
+ </component>
6
+ </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(PitchEstimationAlgorithm.FFT_YIN, 22050f, 1024, handler)
46
- dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(22050, 1024, 0)
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: () => void;
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;;AAJvC,wBAKE"}
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;IACrB,aAAa,EAAE,CAAC,CAAqB,EAAE,EAAE,GAAE,CAAC;CAC7C,CAAC","sourcesContent":["import { ChangeEventPayload } from \"./ReactNativeSimpleNotePitchDetector.types\";\n\nexport default {\n start: () => {},\n stop: () => {},\n isRecording: () => {},\n onChangePitch: (_: ChangeEventPayload) => {},\n};\n"]}
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
@@ -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) {
@@ -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
- lazy var pitchEngine: PitchEngine = { [weak self] in
33
- // Larger buffer (8192) = more accurate pitch detection, slightly more latency
34
- // Using .yin which is generally best for monophonic instruments
35
- let config = Config(bufferSize: 8192, estimationStrategy: .yin)
36
- let pitchEngine = PitchEngine(config: config, delegate: self)
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
- pitchEngine.levelThreshold = -30
39
- return pitchEngine
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-simple-note-pitch-detector",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "a simple react native library to detect the pitch of the input recording",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -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