react-native-tuner-engine 1.0.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 (224) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +188 -0
  3. package/TunerEngine.podspec +32 -0
  4. package/android/build.gradle +86 -0
  5. package/android/src/main/AndroidManifest.xml +3 -0
  6. package/android/src/main/cpp/CMakeLists.txt +31 -0
  7. package/android/src/main/cpp/OboeAudioSource.cpp +101 -0
  8. package/android/src/main/cpp/OboeAudioSource.h +41 -0
  9. package/android/src/main/cpp/TunerEngineJni.cpp +220 -0
  10. package/android/src/main/java/com/tunerengine/TunerEngineModule.kt +183 -0
  11. package/android/src/main/java/com/tunerengine/TunerEnginePackage.kt +31 -0
  12. package/cpp/CMakeLists.txt +25 -0
  13. package/cpp/build/CMakeCache.txt +347 -0
  14. package/cpp/build/CMakeFiles/4.3.2/CMakeCXXCompiler.cmake +102 -0
  15. package/cpp/build/CMakeFiles/4.3.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
  16. package/cpp/build/CMakeFiles/4.3.2/CMakeSystem.cmake +15 -0
  17. package/cpp/build/CMakeFiles/4.3.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +949 -0
  18. package/cpp/build/CMakeFiles/4.3.2/CompilerIdCXX/a.out +0 -0
  19. package/cpp/build/CMakeFiles/4.3.2/CompilerIdCXX/apple-sdk.cpp +1 -0
  20. package/cpp/build/CMakeFiles/CMakeConfigureLog.yaml +1619 -0
  21. package/cpp/build/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
  22. package/cpp/build/CMakeFiles/InstallScripts.json +7 -0
  23. package/cpp/build/CMakeFiles/Makefile.cmake +118 -0
  24. package/cpp/build/CMakeFiles/Makefile2 +122 -0
  25. package/cpp/build/CMakeFiles/TargetDirectories.txt +3 -0
  26. package/cpp/build/CMakeFiles/cmake.check_cache +1 -0
  27. package/cpp/build/CMakeFiles/progress.marks +1 -0
  28. package/cpp/build/CMakeFiles/tuner_engine_core.dir/DependInfo.cmake +36 -0
  29. package/cpp/build/CMakeFiles/tuner_engine_core.dir/build.make +322 -0
  30. package/cpp/build/CMakeFiles/tuner_engine_core.dir/cmake_clean.cmake +37 -0
  31. package/cpp/build/CMakeFiles/tuner_engine_core.dir/cmake_clean_target.cmake +3 -0
  32. package/cpp/build/CMakeFiles/tuner_engine_core.dir/compiler_depend.make +2 -0
  33. package/cpp/build/CMakeFiles/tuner_engine_core.dir/compiler_depend.ts +2 -0
  34. package/cpp/build/CMakeFiles/tuner_engine_core.dir/depend.make +2 -0
  35. package/cpp/build/CMakeFiles/tuner_engine_core.dir/flags.make +12 -0
  36. package/cpp/build/CMakeFiles/tuner_engine_core.dir/link.txt +2 -0
  37. package/cpp/build/CMakeFiles/tuner_engine_core.dir/progress.make +16 -0
  38. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/AudioFrameDispatcher.cpp.o +0 -0
  39. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/AudioFrameDispatcher.cpp.o.d +814 -0
  40. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/BiquadHpf.cpp.o +0 -0
  41. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/BiquadHpf.cpp.o.d +206 -0
  42. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/CepstrumPitchDetector.cpp.o +0 -0
  43. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/CepstrumPitchDetector.cpp.o.d +797 -0
  44. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/EnsembleSelector.cpp.o +0 -0
  45. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/EnsembleSelector.cpp.o.d +755 -0
  46. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/NoteMapper.cpp.o +0 -0
  47. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/NoteMapper.cpp.o.d +669 -0
  48. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/OnsetDetector.cpp.o +0 -0
  49. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/OnsetDetector.cpp.o.d +648 -0
  50. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/Pipeline.cpp.o +0 -0
  51. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/Pipeline.cpp.o.d +765 -0
  52. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/PostProcessor.cpp.o +0 -0
  53. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/PostProcessor.cpp.o.d +648 -0
  54. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/PyinPitchDetector.cpp.o +0 -0
  55. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/PyinPitchDetector.cpp.o.d +755 -0
  56. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/SnrEstimator.cpp.o +0 -0
  57. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/SnrEstimator.cpp.o.d +648 -0
  58. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/StringMatcher.cpp.o +0 -0
  59. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/StringMatcher.cpp.o.d +665 -0
  60. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/TunerEngine.cpp.o +0 -0
  61. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/TunerEngine.cpp.o.d +811 -0
  62. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/Window.cpp.o +0 -0
  63. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/Window.cpp.o.d +754 -0
  64. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/YinPitchDetector.cpp.o +0 -0
  65. package/cpp/build/CMakeFiles/tuner_engine_core.dir/src/YinPitchDetector.cpp.o.d +755 -0
  66. package/cpp/build/Makefile +532 -0
  67. package/cpp/build/cmake_install.cmake +61 -0
  68. package/cpp/build/libtuner_engine_core.a +0 -0
  69. package/cpp/include/AudioFrameDispatcher.hpp +87 -0
  70. package/cpp/include/BiquadHpf.hpp +22 -0
  71. package/cpp/include/CepstrumPitchDetector.hpp +33 -0
  72. package/cpp/include/EnsembleSelector.hpp +25 -0
  73. package/cpp/include/Fft.hpp +44 -0
  74. package/cpp/include/IPitchDetector.hpp +21 -0
  75. package/cpp/include/InstrumentPresets.hpp +33 -0
  76. package/cpp/include/NoteMapper.hpp +15 -0
  77. package/cpp/include/OnsetDetector.hpp +37 -0
  78. package/cpp/include/Pipeline.hpp +55 -0
  79. package/cpp/include/PitchResult.hpp +24 -0
  80. package/cpp/include/PostProcessor.hpp +51 -0
  81. package/cpp/include/PyinPitchDetector.hpp +35 -0
  82. package/cpp/include/RingBuffer.hpp +72 -0
  83. package/cpp/include/SnrEstimator.hpp +21 -0
  84. package/cpp/include/StringMatcher.hpp +27 -0
  85. package/cpp/include/TunerEngine.hpp +32 -0
  86. package/cpp/include/TuningPresets.hpp +103 -0
  87. package/cpp/include/Window.hpp +13 -0
  88. package/cpp/include/YinPitchDetector.hpp +37 -0
  89. package/cpp/src/AudioFrameDispatcher.cpp +180 -0
  90. package/cpp/src/BiquadHpf.cpp +35 -0
  91. package/cpp/src/CepstrumPitchDetector.cpp +116 -0
  92. package/cpp/src/EnsembleSelector.cpp +91 -0
  93. package/cpp/src/NoteMapper.cpp +47 -0
  94. package/cpp/src/OnsetDetector.cpp +39 -0
  95. package/cpp/src/Pipeline.cpp +133 -0
  96. package/cpp/src/PostProcessor.cpp +111 -0
  97. package/cpp/src/PyinPitchDetector.cpp +134 -0
  98. package/cpp/src/SnrEstimator.cpp +33 -0
  99. package/cpp/src/StringMatcher.cpp +37 -0
  100. package/cpp/src/TunerEngine.cpp +67 -0
  101. package/cpp/src/Window.cpp +21 -0
  102. package/cpp/src/YinPitchDetector.cpp +118 -0
  103. package/cpp/tests/CMakeLists.txt +23 -0
  104. package/cpp/tests/bench.cpp +160 -0
  105. package/cpp/tests/build/CMakeCache.txt +356 -0
  106. package/cpp/tests/build/CMakeFiles/4.3.2/CMakeCXXCompiler.cmake +102 -0
  107. package/cpp/tests/build/CMakeFiles/4.3.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
  108. package/cpp/tests/build/CMakeFiles/4.3.2/CMakeSystem.cmake +15 -0
  109. package/cpp/tests/build/CMakeFiles/4.3.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +949 -0
  110. package/cpp/tests/build/CMakeFiles/4.3.2/CompilerIdCXX/a.out +0 -0
  111. package/cpp/tests/build/CMakeFiles/4.3.2/CompilerIdCXX/apple-sdk.cpp +1 -0
  112. package/cpp/tests/build/CMakeFiles/CMakeConfigureLog.yaml +1619 -0
  113. package/cpp/tests/build/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
  114. package/cpp/tests/build/CMakeFiles/InstallScripts.json +8 -0
  115. package/cpp/tests/build/CMakeFiles/Makefile.cmake +122 -0
  116. package/cpp/tests/build/CMakeFiles/Makefile2 +211 -0
  117. package/cpp/tests/build/CMakeFiles/TargetDirectories.txt +9 -0
  118. package/cpp/tests/build/CMakeFiles/cmake.check_cache +1 -0
  119. package/cpp/tests/build/CMakeFiles/progress.marks +1 -0
  120. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/DependInfo.cmake +23 -0
  121. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/bench.cpp.o +0 -0
  122. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/bench.cpp.o.d +813 -0
  123. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/build.make +114 -0
  124. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/cmake_clean.cmake +11 -0
  125. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/compiler_depend.make +2 -0
  126. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/compiler_depend.ts +2 -0
  127. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/depend.make +2 -0
  128. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/flags.make +12 -0
  129. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/link.txt +1 -0
  130. package/cpp/tests/build/CMakeFiles/tuner_engine_bench.dir/progress.make +3 -0
  131. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/DependInfo.cmake +23 -0
  132. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/build.make +114 -0
  133. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/cmake_clean.cmake +11 -0
  134. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/compiler_depend.make +2 -0
  135. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/compiler_depend.ts +2 -0
  136. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/depend.make +2 -0
  137. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/flags.make +12 -0
  138. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/link.txt +1 -0
  139. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/main.cpp.o +0 -0
  140. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/main.cpp.o.d +823 -0
  141. package/cpp/tests/build/CMakeFiles/tuner_engine_tests.dir/progress.make +3 -0
  142. package/cpp/tests/build/CTestTestfile.cmake +9 -0
  143. package/cpp/tests/build/Makefile +247 -0
  144. package/cpp/tests/build/cmake_install.cmake +66 -0
  145. package/cpp/tests/build/tuner_engine_bench +0 -0
  146. package/cpp/tests/build/tuner_engine_core/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
  147. package/cpp/tests/build/tuner_engine_core/CMakeFiles/progress.marks +1 -0
  148. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/DependInfo.cmake +36 -0
  149. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/build.make +322 -0
  150. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/cmake_clean.cmake +37 -0
  151. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/cmake_clean_target.cmake +3 -0
  152. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/compiler_depend.make +2 -0
  153. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/compiler_depend.ts +2 -0
  154. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/depend.make +2 -0
  155. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/flags.make +12 -0
  156. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/link.txt +2 -0
  157. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/progress.make +16 -0
  158. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/AudioFrameDispatcher.cpp.o +0 -0
  159. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/AudioFrameDispatcher.cpp.o.d +814 -0
  160. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/BiquadHpf.cpp.o +0 -0
  161. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/BiquadHpf.cpp.o.d +206 -0
  162. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/CepstrumPitchDetector.cpp.o +0 -0
  163. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/CepstrumPitchDetector.cpp.o.d +797 -0
  164. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/EnsembleSelector.cpp.o +0 -0
  165. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/EnsembleSelector.cpp.o.d +755 -0
  166. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/NoteMapper.cpp.o +0 -0
  167. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/NoteMapper.cpp.o.d +669 -0
  168. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/OnsetDetector.cpp.o +0 -0
  169. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/OnsetDetector.cpp.o.d +648 -0
  170. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/Pipeline.cpp.o +0 -0
  171. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/Pipeline.cpp.o.d +765 -0
  172. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/PostProcessor.cpp.o +0 -0
  173. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/PostProcessor.cpp.o.d +648 -0
  174. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/PyinPitchDetector.cpp.o +0 -0
  175. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/PyinPitchDetector.cpp.o.d +755 -0
  176. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/SnrEstimator.cpp.o +0 -0
  177. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/SnrEstimator.cpp.o.d +648 -0
  178. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/StringMatcher.cpp.o +0 -0
  179. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/StringMatcher.cpp.o.d +665 -0
  180. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/TunerEngine.cpp.o +0 -0
  181. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/TunerEngine.cpp.o.d +811 -0
  182. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/Window.cpp.o +0 -0
  183. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/Window.cpp.o.d +754 -0
  184. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/YinPitchDetector.cpp.o +0 -0
  185. package/cpp/tests/build/tuner_engine_core/CMakeFiles/tuner_engine_core.dir/src/YinPitchDetector.cpp.o.d +755 -0
  186. package/cpp/tests/build/tuner_engine_core/Makefile +544 -0
  187. package/cpp/tests/build/tuner_engine_core/cmake_install.cmake +45 -0
  188. package/cpp/tests/build/tuner_engine_core/libtuner_engine_core.a +0 -0
  189. package/cpp/tests/build/tuner_engine_tests +0 -0
  190. package/cpp/tests/main.cpp +624 -0
  191. package/ios/IosAudioSource.h +23 -0
  192. package/ios/IosAudioSource.mm +174 -0
  193. package/ios/TunerBridge.h +24 -0
  194. package/ios/TunerBridge.mm +136 -0
  195. package/ios/TunerEngine.h +6 -0
  196. package/ios/TunerEngine.mm +144 -0
  197. package/lib/module/NativeTunerEngine.js +5 -0
  198. package/lib/module/NativeTunerEngine.js.map +1 -0
  199. package/lib/module/TunerEngine.js +43 -0
  200. package/lib/module/TunerEngine.js.map +1 -0
  201. package/lib/module/index.js +5 -0
  202. package/lib/module/index.js.map +1 -0
  203. package/lib/module/package.json +1 -0
  204. package/lib/module/types.js +2 -0
  205. package/lib/module/types.js.map +1 -0
  206. package/lib/module/useTuner.js +55 -0
  207. package/lib/module/useTuner.js.map +1 -0
  208. package/lib/typescript/package.json +1 -0
  209. package/lib/typescript/src/NativeTunerEngine.d.ts +17 -0
  210. package/lib/typescript/src/NativeTunerEngine.d.ts.map +1 -0
  211. package/lib/typescript/src/TunerEngine.d.ts +18 -0
  212. package/lib/typescript/src/TunerEngine.d.ts.map +1 -0
  213. package/lib/typescript/src/index.d.ts +4 -0
  214. package/lib/typescript/src/index.d.ts.map +1 -0
  215. package/lib/typescript/src/types.d.ts +86 -0
  216. package/lib/typescript/src/types.d.ts.map +1 -0
  217. package/lib/typescript/src/useTuner.d.ts +15 -0
  218. package/lib/typescript/src/useTuner.d.ts.map +1 -0
  219. package/package.json +141 -0
  220. package/src/NativeTunerEngine.ts +17 -0
  221. package/src/TunerEngine.ts +62 -0
  222. package/src/index.tsx +11 -0
  223. package/src/types.ts +109 -0
  224. package/src/useTuner.ts +67 -0
@@ -0,0 +1,22 @@
1
+ #pragma once
2
+
3
+ // 2nd-order high-pass filter, Direct Form II Transposed.
4
+ // Coefficients from Audio EQ Cookbook (Bristow-Johnson).
5
+ // State (w1_, w2_) persists across frames for continuity.
6
+ class BiquadHpf {
7
+ public:
8
+ // cutoffHz: -3 dB frequency; q: 0.707 = Butterworth (maximally flat)
9
+ BiquadHpf(float sampleRate, float cutoffHz, float q = 0.7071f);
10
+
11
+ // Filter frame in-place.
12
+ void process(float* frame, int n);
13
+
14
+ // Reset inter-frame state (call when stream restarts).
15
+ void reset();
16
+
17
+ private:
18
+ float b0_, b1_, b2_;
19
+ float a1_, a2_;
20
+ float w1_ = 0.0f;
21
+ float w2_ = 0.0f;
22
+ };
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include "IPitchDetector.hpp"
4
+ #include <complex>
5
+ #include <vector>
6
+
7
+ // Real-cepstrum pitch detector.
8
+ // HPF-filtered frame → Hann window → FFT → log-power spectrum → IFFT → quefrency peak.
9
+ // Particularly robust for signals with strong harmonics where the fundamental is weak.
10
+ class CepstrumPitchDetector : public IPitchDetector {
11
+ public:
12
+ CepstrumPitchDetector(float sampleRate, int frameSize);
13
+
14
+ DetectorResult detect(const float* frame, int n, float sampleRate) override;
15
+
16
+ void reset() override {}
17
+ void setFrequencyRange(float minHz, float maxHz) override;
18
+ void setThreshold(float threshold) override;
19
+
20
+ private:
21
+ float sampleRate_;
22
+ int frameSize_;
23
+
24
+ float minHz_ = 60.0f;
25
+ float maxHz_ = 1200.0f;
26
+ float threshold_ = 0.10f; // minimum peak prominence to be considered voiced
27
+
28
+ std::vector<float> hann_;
29
+ std::vector<std::complex<float>> fftBuf_;
30
+ std::vector<float> logPow_;
31
+
32
+ float peakProminence(int tauMin, int tauMax, int peakTau) const;
33
+ };
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #include "IPitchDetector.hpp"
4
+ #include <memory>
5
+ #include <vector>
6
+
7
+ // Runs every sub-detector on the same frame and selects the best result.
8
+ // Detectors that agree within one semitone reinforce each other (confidence bonus).
9
+ // A lone detector with no agreement receives a confidence penalty.
10
+ class EnsembleSelector : public IPitchDetector {
11
+ public:
12
+ explicit EnsembleSelector(std::vector<std::unique_ptr<IPitchDetector>> detectors);
13
+
14
+ DetectorResult detect(const float* frame, int n, float sampleRate) override;
15
+
16
+ void reset() override;
17
+ void setFrequencyRange(float minHz, float maxHz) override;
18
+ void setThreshold(float threshold) override;
19
+
20
+ private:
21
+ std::vector<std::unique_ptr<IPitchDetector>> detectors_;
22
+ std::vector<DetectorResult> resultsBuf_;
23
+
24
+ static bool withinSemitones(float f1, float f2, float tolerance = 1.0f);
25
+ };
@@ -0,0 +1,44 @@
1
+ #pragma once
2
+
3
+ #include <cmath>
4
+ #include <complex>
5
+ #include <vector>
6
+
7
+ namespace tuner {
8
+
9
+ // In-place radix-2 Cooley-Tukey DFT. n = x.size() must be a power of 2.
10
+ inline void fft(std::vector<std::complex<float>>& x) {
11
+ const int n = static_cast<int>(x.size());
12
+
13
+ for (int i = 1, j = 0; i < n; ++i) {
14
+ int bit = n >> 1;
15
+ for (; j & bit; bit >>= 1) j ^= bit;
16
+ j ^= bit;
17
+ if (i < j) std::swap(x[i], x[j]);
18
+ }
19
+
20
+ for (int len = 2; len <= n; len <<= 1) {
21
+ const float angle = -2.0f * 3.14159265358979323846f / static_cast<float>(len);
22
+ const std::complex<float> wlen(std::cos(angle), std::sin(angle));
23
+ for (int i = 0; i < n; i += len) {
24
+ std::complex<float> w(1.0f, 0.0f);
25
+ for (int j = 0; j < len / 2; ++j) {
26
+ const std::complex<float> u = x[i + j];
27
+ const std::complex<float> v = x[i + j + len / 2] * w;
28
+ x[i + j] = u + v;
29
+ x[i + j + len / 2] = u - v;
30
+ w *= wlen;
31
+ }
32
+ }
33
+ }
34
+ }
35
+
36
+ // In-place inverse DFT.
37
+ inline void ifft(std::vector<std::complex<float>>& x) {
38
+ for (auto& c : x) c = std::conj(c);
39
+ fft(x);
40
+ const float inv = 1.0f / static_cast<float>(x.size());
41
+ for (auto& c : x) c = std::conj(c) * inv;
42
+ }
43
+
44
+ } // namespace tuner
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ struct DetectorResult {
4
+ bool voiced = false;
5
+ float frequency = 0.0f;
6
+ float confidence = 0.0f;
7
+ };
8
+
9
+ class IPitchDetector {
10
+ public:
11
+ virtual ~IPitchDetector() = default;
12
+
13
+ // Detect pitch from a pre-filtered, windowed frame of length n at the given sample rate.
14
+ virtual DetectorResult detect(const float* frame, int n, float sampleRate) = 0;
15
+
16
+ // Reset any inter-frame state (Viterbi, smoothing, etc.).
17
+ virtual void reset() {}
18
+
19
+ virtual void setFrequencyRange(float minHz, float maxHz) = 0;
20
+ virtual void setThreshold(float threshold) = 0;
21
+ };
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ struct FrequencyRange {
6
+ float minHz;
7
+ float maxHz;
8
+ };
9
+
10
+ // Returns the recommended pitch-detection frequency range for a given instrument name.
11
+ // Falls back to chromatic (60–1200 Hz) for unknown names.
12
+ inline FrequencyRange instrumentPreset(const std::string& name) {
13
+ if (name == "guitar") return { 75.0f, 1320.0f };
14
+ if (name == "bass") return { 38.0f, 330.0f };
15
+ if (name == "ukulele") return { 250.0f, 880.0f };
16
+ if (name == "violin") return { 190.0f, 3200.0f };
17
+ if (name == "cello") return { 60.0f, 1050.0f };
18
+ if (name == "viola") return { 125.0f, 1320.0f };
19
+ if (name == "mandolin") return { 190.0f, 2100.0f };
20
+ if (name == "banjo") return { 190.0f, 1320.0f };
21
+ return { 60.0f, 1200.0f }; // chromatic default
22
+ }
23
+
24
+ // Returns the recommended DSP frame size for a given instrument.
25
+ // Low-pitched instruments (bass, cello) need larger frames to resolve
26
+ // their fundamental frequencies via autocorrelation (YIN lag = frameSize/2).
27
+ // frame=2048 @ 48 kHz → min detectable ≈ 46.9 Hz
28
+ // frame=4096 @ 48 kHz → min detectable ≈ 23.4 Hz
29
+ inline int instrumentRecommendedFrameSize(const std::string& name) {
30
+ if (name == "bass") return 4096;
31
+ if (name == "cello") return 4096;
32
+ return 2048; // guitar, violin, viola, ukulele, mandolin, banjo, chromatic
33
+ }
@@ -0,0 +1,15 @@
1
+ #pragma once
2
+
3
+ #include "PitchResult.hpp"
4
+
5
+ class NoteMapper {
6
+ public:
7
+ explicit NoteMapper(float a4 = 440.0f);
8
+
9
+ PitchResult map(float frequency, float confidence, float rmsDb) const;
10
+
11
+ void setA4(float value);
12
+
13
+ private:
14
+ float a4_;
15
+ };
@@ -0,0 +1,37 @@
1
+ #pragma once
2
+
3
+ // Lightweight onset detector based on energy rise.
4
+ //
5
+ // Computes the difference between the current frame's RMS and a slow-decay
6
+ // envelope. When the rise exceeds a threshold, an onset is signalled.
7
+ //
8
+ // Cost: one subtraction + one comparison per frame when enabled.
9
+ // When disabled (`enabled_ == false`), detect() returns false immediately — zero work.
10
+ class OnsetDetector {
11
+ public:
12
+ struct Config {
13
+ float thresholdDb = 6.0f; // minimum dB rise to trigger an onset
14
+ float envelopeAlpha = 0.15f; // envelope decay speed (lower = slower)
15
+ int cooldownFrames = 8; // minimum frames between consecutive onsets
16
+ };
17
+
18
+ OnsetDetector() = default;
19
+ explicit OnsetDetector(Config cfg);
20
+
21
+ // Returns true if an onset is detected for the current frame.
22
+ // rmsDb: current frame's RMS in dBFS (already computed by Pipeline — free).
23
+ bool detect(float rmsDb);
24
+
25
+ void setEnabled(bool enabled) { enabled_ = enabled; }
26
+ bool isEnabled() const { return enabled_; }
27
+
28
+ void setConfig(Config cfg);
29
+ void reset();
30
+
31
+ private:
32
+ Config cfg_{};
33
+ bool enabled_ = false; // disabled by default — zero cost
34
+
35
+ float envelopeDb_ = -100.0f;
36
+ int cooldown_ = 0;
37
+ };
@@ -0,0 +1,55 @@
1
+ #pragma once
2
+
3
+ #include "BiquadHpf.hpp"
4
+ #include "IPitchDetector.hpp"
5
+ #include "InstrumentPresets.hpp"
6
+ #include "NoteMapper.hpp"
7
+ #include "OnsetDetector.hpp"
8
+ #include "PitchResult.hpp"
9
+ #include "PostProcessor.hpp"
10
+ #include "SnrEstimator.hpp"
11
+ #include "StringMatcher.hpp"
12
+ #include "Window.hpp"
13
+
14
+ #include <memory>
15
+ #include <vector>
16
+
17
+ // Ordered DSP chain: HPF → Hann window → IPitchDetector → SNR weighting → PostProcessor → NoteMapper → StringMatcher.
18
+ class Pipeline {
19
+ public:
20
+ Pipeline(int frameSize, float sampleRate, std::unique_ptr<IPitchDetector> detector);
21
+
22
+ PitchResult process(const float* input, int frameCount);
23
+
24
+ void setA4(float hz);
25
+ void setNoiseGateDb(float db);
26
+ void setConfidenceThreshold(float threshold);
27
+ void setFrequencyRange(float minHz, float maxHz);
28
+ void setInstrument(const std::string& name);
29
+ void setTuning(const std::string& name); // e.g. "guitar_standard", "" to disable
30
+ void setPostProcessorConfig(PostProcessor::Config cfg);
31
+ void setHpfCutoff(float hz);
32
+ void setOnsetDetectionEnabled(bool enabled);
33
+ void setOnsetConfig(OnsetDetector::Config cfg);
34
+
35
+ private:
36
+ int frameSize_;
37
+ float sampleRate_;
38
+
39
+ float noiseGateDb_ = -55.0f;
40
+ float confidenceThreshold_ = 0.60f; // lower than raw YIN default; SNR will tighten it
41
+
42
+ BiquadHpf hpf_;
43
+ HannWindow window_;
44
+ std::unique_ptr<IPitchDetector> detector_;
45
+ SnrEstimator snr_;
46
+ OnsetDetector onsetDetector_;
47
+ PostProcessor postProcessor_;
48
+ NoteMapper noteMapper_;
49
+ StringMatcher stringMatcher_;
50
+
51
+ std::vector<float> workBuffer_; // HPF + windowing happen here (copy of input)
52
+
53
+ float calculateRmsDb(const float* input, int n) const;
54
+ float calculateRmsLinear(const float* input, int n) const;
55
+ };
@@ -0,0 +1,24 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ struct PitchResult
6
+ {
7
+ bool hasPitch = false;
8
+
9
+ float frequency = 0.0f;
10
+ float confidence = 0.0f;
11
+ float rmsDb = -120.0f;
12
+
13
+ int midiNote = 0;
14
+ std::string noteName;
15
+ int octave = 0;
16
+
17
+ float targetFrequency = 0.0f;
18
+ float cents = 0.0f;
19
+
20
+ // Set when a TuningProfile is active (via Pipeline::setTuning).
21
+ // Empty string means no tuning is configured.
22
+ std::string nearestString; // e.g. "E2", "A2"
23
+ float stringDeviation = 0.0f; // cents from that string's target, signed
24
+ };
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+
3
+ // Stabilises pitch output via:
4
+ // 1. Median-5 filter on frequency (kills transient spikes)
5
+ // 2. EMA smoothing on the median frequency
6
+ // 3. Note-change hysteresis (debounce rapid note switches)
7
+ class PostProcessor {
8
+ public:
9
+ struct Config {
10
+ float emaAlpha = 0.35f; // smoothing speed (higher = faster response)
11
+ int hysteresisFrames = 3; // consecutive frames needed to confirm a new note
12
+ };
13
+
14
+ PostProcessor();
15
+ explicit PostProcessor(Config cfg);
16
+
17
+ struct Result {
18
+ float frequency = 0.0f;
19
+ int midiNote = -1; // -1 = no stable note yet
20
+ float cents = 0.0f; // cents deviation from locked note
21
+ bool isStable = false;
22
+ };
23
+
24
+ // Call once per detected frame. frequency = 0 means "no pitch".
25
+ Result process(float frequency, float confidence);
26
+
27
+ void reset();
28
+ void setConfig(Config cfg);
29
+
30
+ private:
31
+ Config cfg_;
32
+
33
+ // Median-5 circular buffer
34
+ static constexpr int kMedianLen = 5;
35
+ float medianBuf_[kMedianLen] = {};
36
+ int medianIdx_ = 0;
37
+ int medianFill_ = 0;
38
+
39
+ float median5() const;
40
+
41
+ // EMA state
42
+ float smoothedFreq_ = 0.0f;
43
+
44
+ // Hysteresis state
45
+ int lockedMidi_ = -1;
46
+ int candidateMidi_ = -1;
47
+ int candidateCount_ = 0;
48
+
49
+ static int freqToMidi(float hz);
50
+ static float freqToCentsFromMidi(float hz, int midi);
51
+ };
@@ -0,0 +1,35 @@
1
+ #pragma once
2
+
3
+ #include "IPitchDetector.hpp"
4
+ #include <vector>
5
+
6
+ // Probabilistic YIN (PYIN) — unlike plain YIN, it collects every CMND local minimum
7
+ // below threshold and picks the most probable one rather than the first.
8
+ // This eliminates the octave errors that occur when the first minimum corresponds
9
+ // to a harmonic period rather than the fundamental.
10
+ class PyinPitchDetector : public IPitchDetector {
11
+ public:
12
+ PyinPitchDetector(float sampleRate, int frameSize);
13
+
14
+ DetectorResult detect(const float* frame, int n, float sampleRate) override;
15
+
16
+ void reset() override {}
17
+ void setFrequencyRange(float minHz, float maxHz) override;
18
+ void setThreshold(float threshold) override;
19
+
20
+ private:
21
+ float sampleRate_;
22
+ int frameSize_;
23
+
24
+ float minHz_ = 60.0f;
25
+ float maxHz_ = 1200.0f;
26
+ float threshold_ = 0.25f; // wider than YIN — captures all plausible candidates
27
+
28
+ std::vector<float> diff_;
29
+ std::vector<float> cmnd_;
30
+
31
+ struct Candidate { int tau; float prob; };
32
+ std::vector<Candidate> candidates_; // pre-allocated, reused each frame
33
+
34
+ float parabolicInterpolation(int tau) const;
35
+ };
@@ -0,0 +1,72 @@
1
+ #pragma once
2
+
3
+ #include <atomic>
4
+ #include <algorithm>
5
+
6
+ // Lock-free single-producer single-consumer ring buffer for float samples.
7
+ // Capacity must be a power of 2. push() is safe from the producer/audio thread;
8
+ // pop() and available() are safe from the consumer/worker thread.
9
+ // Uses monotonically-growing unsigned indices for correct wrap-around arithmetic.
10
+ template<unsigned Capacity>
11
+ class FloatRingBuffer {
12
+ static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be power of 2");
13
+ static constexpr unsigned kMask = Capacity - 1;
14
+
15
+ public:
16
+ FloatRingBuffer() : writeIdx_(0u), readIdx_(0u) {}
17
+
18
+ // Push up to n samples from src. Returns actual count written (may be < n if full).
19
+ // Safe to call from the audio/producer thread.
20
+ int push(const float* src, int n) {
21
+ const unsigned w = writeIdx_.load(std::memory_order_relaxed);
22
+ const unsigned r = readIdx_.load(std::memory_order_acquire);
23
+ const unsigned space = Capacity - (w - r);
24
+ const unsigned count = static_cast<unsigned>(std::min<int>(n, static_cast<int>(space)));
25
+ if (count == 0) return 0;
26
+
27
+ const unsigned startSlot = w & kMask;
28
+ const unsigned first = std::min(count, Capacity - startSlot);
29
+ const unsigned second = count - first;
30
+
31
+ std::copy(src, src + first, data_ + startSlot);
32
+ if (second > 0) {
33
+ std::copy(src + first, src + first + second, data_);
34
+ }
35
+
36
+ writeIdx_.store(w + count, std::memory_order_release);
37
+ return static_cast<int>(count);
38
+ }
39
+
40
+ // Pop exactly n samples into dst. Returns n on success, 0 if not enough data.
41
+ // Safe to call from the consumer/worker thread.
42
+ int pop(float* dst, int n) {
43
+ const unsigned r = readIdx_.load(std::memory_order_relaxed);
44
+ const unsigned w = writeIdx_.load(std::memory_order_acquire);
45
+ const unsigned avail = w - r;
46
+ if (avail < static_cast<unsigned>(n)) return 0;
47
+
48
+ const unsigned startSlot = r & kMask;
49
+ const unsigned first = std::min<unsigned>(static_cast<unsigned>(n), Capacity - startSlot);
50
+ const unsigned second = static_cast<unsigned>(n) - first;
51
+
52
+ std::copy(data_ + startSlot, data_ + startSlot + first, dst);
53
+ if (second > 0) {
54
+ std::copy(data_, data_ + second, dst + first);
55
+ }
56
+
57
+ readIdx_.store(r + static_cast<unsigned>(n), std::memory_order_release);
58
+ return n;
59
+ }
60
+
61
+ // Samples currently available to read. Safe from any thread.
62
+ int available() const {
63
+ const unsigned w = writeIdx_.load(std::memory_order_acquire);
64
+ const unsigned r = readIdx_.load(std::memory_order_relaxed);
65
+ return static_cast<int>(w - r);
66
+ }
67
+
68
+ private:
69
+ float data_[Capacity];
70
+ std::atomic<unsigned> writeIdx_;
71
+ std::atomic<unsigned> readIdx_;
72
+ };
@@ -0,0 +1,21 @@
1
+ #pragma once
2
+
3
+ // Estimates signal-to-noise ratio by tracking a slow noise-floor EMA.
4
+ // The floor decays toward the current RMS level; it only rises when the
5
+ // signal drops below it (i.e. it tracks the quiet passages).
6
+ class SnrEstimator {
7
+ public:
8
+ explicit SnrEstimator(float floorInitDb = -70.0f);
9
+
10
+ // Update with current linear RMS and return SNR in dB.
11
+ float update(float rmsLinear);
12
+
13
+ // Map SNR to a confidence weight in [0, 1].
14
+ static float snrToWeight(float snrDb);
15
+
16
+ void reset();
17
+
18
+ private:
19
+ float noiseFloorLinear_;
20
+ static constexpr float kAttackAlpha = 0.0100f; // how fast floor follows signal downward
21
+ };
@@ -0,0 +1,27 @@
1
+ #pragma once
2
+
3
+ #include "TuningPresets.hpp"
4
+
5
+ #include <optional>
6
+
7
+ struct StringMatch {
8
+ const char* name; // "E2", "A2", "D3" ...
9
+ int stringNumber; // 1-based (thickest = 1)
10
+ float targetHz; // exact equal-temperament frequency
11
+ float deviationCents; // signed: negative = flat, positive = sharp
12
+ };
13
+
14
+ // Maps a detected frequency to the nearest string in the active TuningProfile.
15
+ class StringMatcher {
16
+ public:
17
+ void setTuning(const TuningProfile* profile);
18
+ bool hasTuning() const;
19
+
20
+ // Returns the nearest string within maxDeviationCents (default 100 ¢ = 1 semitone).
21
+ // Returns std::nullopt if no tuning is set or no string is close enough.
22
+ std::optional<StringMatch> match(float frequency,
23
+ float maxDeviationCents = 100.0f) const;
24
+
25
+ private:
26
+ const TuningProfile* profile_ = nullptr;
27
+ };
@@ -0,0 +1,32 @@
1
+ #pragma once
2
+
3
+ #include "Pipeline.hpp"
4
+ #include "OnsetDetector.hpp"
5
+ #include "PostProcessor.hpp"
6
+ #include "PitchResult.hpp"
7
+
8
+ #include <memory>
9
+ #include <string>
10
+
11
+ // Facade that owns a Pipeline. The external API is identical to the pre-M2 TunerEngine
12
+ // so AudioFrameDispatcher and all existing tests require no changes.
13
+ class TunerEngine {
14
+ public:
15
+ TunerEngine(float sampleRate, int frameSize);
16
+
17
+ PitchResult process(const float* input, int frameCount);
18
+
19
+ void setA4(float a4);
20
+ void setNoiseGateDb(float db);
21
+ void setConfidenceThreshold(float value);
22
+ void setFrequencyRange(float minFrequency, float maxFrequency);
23
+ void setInstrument(const std::string& name);
24
+ void setTuning(const std::string& name);
25
+ void setPostProcessorConfig(PostProcessor::Config cfg);
26
+ void setHpfCutoff(float hz);
27
+ void setOnsetDetectionEnabled(bool enabled);
28
+ void setOnsetConfig(OnsetDetector::Config cfg);
29
+
30
+ private:
31
+ std::unique_ptr<Pipeline> pipeline_;
32
+ };
@@ -0,0 +1,103 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ struct StringTarget {
6
+ const char* name; // e.g. "E2", "A2", "D3"
7
+ int stringNumber; // 1-based, thickest/lowest string = 1
8
+ float frequency; // Hz, equal temperament A4=440
9
+ };
10
+
11
+ struct TuningProfile {
12
+ const char* name;
13
+ StringTarget strings[8]; // max 8 strings
14
+ int stringCount;
15
+ };
16
+
17
+ // Standard tunings — frequencies in Hz (equal temperament, A4=440)
18
+ namespace tuning_presets {
19
+
20
+ inline constexpr TuningProfile guitar_standard = {
21
+ "guitar_standard",
22
+ {{"E2",1,82.41f},{"A2",2,110.00f},{"D3",3,146.83f},
23
+ {"G3",4,196.00f},{"B3",5,246.94f},{"E4",6,329.63f}},
24
+ 6
25
+ };
26
+
27
+ inline constexpr TuningProfile guitar_drop_d = {
28
+ "guitar_drop_d",
29
+ {{"D2",1,73.42f},{"A2",2,110.00f},{"D3",3,146.83f},
30
+ {"G3",4,196.00f},{"B3",5,246.94f},{"E4",6,329.63f}},
31
+ 6
32
+ };
33
+
34
+ inline constexpr TuningProfile guitar_open_g = {
35
+ "guitar_open_g",
36
+ {{"D2",1,73.42f},{"G2",2,98.00f},{"D3",3,146.83f},
37
+ {"G3",4,196.00f},{"B3",5,246.94f},{"D4",6,293.66f}},
38
+ 6
39
+ };
40
+
41
+ inline constexpr TuningProfile bass_standard = {
42
+ "bass_standard",
43
+ {{"E1",1,41.20f},{"A1",2,55.00f},{"D2",3,73.42f},{"G2",4,98.00f}},
44
+ 4
45
+ };
46
+
47
+ inline constexpr TuningProfile bass_drop_d = {
48
+ "bass_drop_d",
49
+ {{"D1",1,36.71f},{"A1",2,55.00f},{"D2",3,73.42f},{"G2",4,98.00f}},
50
+ 4
51
+ };
52
+
53
+ inline constexpr TuningProfile violin_standard = {
54
+ "violin_standard",
55
+ {{"G3",1,196.00f},{"D4",2,293.66f},{"A4",3,440.00f},{"E5",4,659.26f}},
56
+ 4
57
+ };
58
+
59
+ inline constexpr TuningProfile viola_standard = {
60
+ "viola_standard",
61
+ {{"C3",1,130.81f},{"G3",2,196.00f},{"D4",3,293.66f},{"A4",4,440.00f}},
62
+ 4
63
+ };
64
+
65
+ inline constexpr TuningProfile cello_standard = {
66
+ "cello_standard",
67
+ {{"C2",1,65.41f},{"G2",2,98.00f},{"D3",3,146.83f},{"A3",4,220.00f}},
68
+ 4
69
+ };
70
+
71
+ inline constexpr TuningProfile ukulele_standard = {
72
+ "ukulele_standard",
73
+ {{"G4",1,392.00f},{"C4",2,261.63f},{"E4",3,329.63f},{"A4",4,440.00f}},
74
+ 4
75
+ };
76
+
77
+ } // namespace tuning_presets
78
+
79
+ // Returns a pointer to a built-in TuningProfile by name, or nullptr for unknown names.
80
+ inline const TuningProfile* tuningPreset(const std::string& name) {
81
+ if (name == "guitar_standard") return &tuning_presets::guitar_standard;
82
+ if (name == "guitar_drop_d") return &tuning_presets::guitar_drop_d;
83
+ if (name == "guitar_open_g") return &tuning_presets::guitar_open_g;
84
+ if (name == "bass_standard") return &tuning_presets::bass_standard;
85
+ if (name == "bass_drop_d") return &tuning_presets::bass_drop_d;
86
+ if (name == "violin_standard") return &tuning_presets::violin_standard;
87
+ if (name == "viola_standard") return &tuning_presets::viola_standard;
88
+ if (name == "cello_standard") return &tuning_presets::cello_standard;
89
+ if (name == "ukulele_standard")return &tuning_presets::ukulele_standard;
90
+ return nullptr;
91
+ }
92
+
93
+ // Returns the default tuning name for a given instrument name (mirrors InstrumentPresets).
94
+ // Returns "" if the instrument has no default tuning (chromatic, mandolin, banjo).
95
+ inline std::string defaultTuningForInstrument(const std::string& instrument) {
96
+ if (instrument == "guitar") return "guitar_standard";
97
+ if (instrument == "bass") return "bass_standard";
98
+ if (instrument == "violin") return "violin_standard";
99
+ if (instrument == "viola") return "viola_standard";
100
+ if (instrument == "cello") return "cello_standard";
101
+ if (instrument == "ukulele") return "ukulele_standard";
102
+ return "";
103
+ }
@@ -0,0 +1,13 @@
1
+ #pragma once
2
+
3
+ #include <vector>
4
+
5
+ // Precomputed Hann window. apply() multiplies a frame in-place.
6
+ class HannWindow {
7
+ public:
8
+ explicit HannWindow(int size);
9
+ void apply(float* frame, int n) const;
10
+
11
+ private:
12
+ std::vector<float> coeffs_;
13
+ };