├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ ├── ci.yml │ ├── codeql-analysis.yml │ ├── documentation.yml │ └── release.yml ├── .gitignore ├── .jest ├── __mocks__ │ └── PitchDetectorModule.ts └── jest.setup.ts ├── .madgerc ├── .npmignore ├── .nvmrc ├── .scannerwork └── .sonar_lock ├── .watchmanconfig ├── .yarnrc ├── LICENSE ├── README.md ├── android ├── build.gradle ├── gradle.properties └── src │ ├── libs │ └── tarsos-dsp.jar │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── pitchdetector │ ├── PitchDetectorModule.kt │ ├── PitchDetectorPackage.kt │ ├── processors │ └── BaseProcessor.kt │ └── utils │ └── Algorithms.kt ├── babel.config.js ├── example ├── .bundle │ └── config ├── .node-version ├── .watchmanconfig ├── Gemfile ├── Gemfile.lock ├── android │ ├── app │ │ ├── build.gradle │ │ ├── debug.keystore │ │ ├── proguard-rules.pro │ │ └── src │ │ │ ├── debug │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── pitchdetectorexample │ │ │ │ └── ReactNativeFlipper.java │ │ │ ├── main │ │ │ ├── AndroidManifest.xml │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── pitchdetectorexample │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ └── res │ │ │ │ ├── drawable │ │ │ │ └── rn_edit_text_material.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ │ └── values │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── release │ │ │ └── java │ │ │ └── com │ │ │ └── pitchdetectorexample │ │ │ └── ReactNativeFlipper.java │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle ├── app.json ├── babel.config.js ├── index.js ├── ios │ ├── .xcode.env │ ├── File.swift │ ├── PitchDetectorExample-Bridging-Header.h │ ├── PitchDetectorExample.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── PitchDetectorExample.xcscheme │ ├── PitchDetectorExample.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── PitchDetectorExample │ │ ├── AppDelegate.h │ │ ├── AppDelegate.mm │ │ ├── Images.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── LaunchScreen.storyboard │ │ └── main.m │ ├── PitchDetectorExampleTests │ │ ├── Info.plist │ │ └── PitchDetectorExampleTests.m │ ├── Podfile │ └── Podfile.lock ├── metro.config.js ├── package.json ├── patches │ └── react-native+0.71.5.patch ├── react-native.config.js ├── src │ ├── App.tsx │ └── types │ │ └── index.ts └── yarn.lock ├── ios ├── PitchDetector-Bridging-Header.h ├── PitchDetector.xcodeproj │ └── project.pbxproj └── PitchDetector │ ├── PitchDetectorModule.swift │ ├── PitchDetectorModuleBridge.m │ ├── Processors │ └── BaseProcessor.swift │ └── Utils │ ├── AlgorithmsUtils.swift │ ├── EventEmitterUtils.swift │ └── PromiseUtils.swift ├── jest.config.ts ├── lefthook.yml ├── package.json ├── react-native-pitch-detector.podspec ├── scripts └── bootstrap.js ├── sonar-project.properties ├── src ├── index.ts ├── internal │ ├── erros │ │ ├── __tests__ │ │ │ └── errors.spec.ts │ │ └── index.ts │ ├── permissions │ │ ├── __tests__ │ │ │ └── permissions.spec.ts │ │ ├── factory │ │ │ └── index.ts │ │ └── index.ts │ ├── pitch-detector │ │ ├── __tests__ │ │ │ └── pitch-detector.spec.ts │ │ └── index.ts │ └── utils │ │ ├── __tests__ │ │ └── utils.spec.ts │ │ └── index.ts └── types │ └── index.ts ├── tsconfig.build.json ├── tsconfig.json ├── website ├── .gitignore ├── README.md ├── babel.config.js ├── docs │ ├── before-you-start.md │ ├── code-of-conduct.md │ ├── contributing.md │ ├── installation.md │ ├── license.md │ ├── playground.md │ └── usage.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── components │ │ └── HomepageFeatures │ │ │ ├── index.tsx │ │ │ └── styles.module.css │ ├── css │ │ └── custom.css │ └── pages │ │ ├── index.module.css │ │ └── index.tsx ├── static │ ├── .nojekyll │ └── img │ │ ├── favicon.ico │ │ ├── react-native-pitch-detector.svg │ │ ├── recording.jpeg │ │ └── stopped.jpeg ├── tsconfig.json └── yarn.lock └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | indent_style = space 10 | indent_size = 2 11 | 12 | end_of_line = lf 13 | charset = utf-8 14 | trim_trailing_whitespace = true 15 | insert_final_newline = true 16 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [1fabiopereira]# Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Check Code Quality 2 | 3 | on: 4 | pull_request: 5 | branches: [main, master, develop] 6 | push: 7 | branches: [main, master] 8 | 9 | jobs: 10 | lint-and-tests: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Git checkout 15 | uses: actions/checkout@v3 16 | with: 17 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 18 | 19 | - name: Use Node.js Version 20.11.x 20 | uses: actions/setup-node@v3 21 | with: 22 | node-version: 20.11.x 23 | 24 | - name: Install dependencies 25 | run: yarn install --frozen-lockfile 26 | 27 | - name: Type check 28 | run: yarn typecheck 29 | 30 | - name: Lint 31 | run: yarn lint 32 | 33 | - name: Check circular dependencies 34 | run: yarn circular 35 | 36 | - name: Run Jest Unit Tests 37 | run: yarn test 38 | 39 | - name: Typescript build 40 | run: yarn prepack 41 | 42 | - name: SonarCloud Scan Typescript 43 | uses: SonarSource/sonarcloud-github-action@master 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 47 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: ["main", "master"] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: ["main", "master"] 20 | schedule: 21 | - cron: "21 4 * * 2" 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: ["javascript", "TypeScript"] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v2 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 62 | 63 | # If the Autobuild fails above, remove it and uncomment the following three lines. 64 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 65 | 66 | # - run: | 67 | # echo "Run, Build Application using script" 68 | # ./location_of_script_within_repo/buildscript.sh 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v2 72 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Generate Documentation 2 | 3 | on: 4 | push: 5 | branches: [main, master] 6 | 7 | jobs: 8 | checks: 9 | if: github.event_name != 'push' 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Git checkout 14 | uses: actions/checkout@v3 15 | 16 | - name: Use Node.js Version 20.11.x 17 | uses: actions/setup-node@v3 18 | with: 19 | node-version: 20.11.x 20 | 21 | - name: Test Build 22 | run: | 23 | cd website/ 24 | npm i 25 | npm run build 26 | 27 | gh-release: 28 | if: github.event_name != 'pull_request' 29 | runs-on: ubuntu-latest 30 | 31 | steps: 32 | - name: Git checkout 33 | uses: actions/checkout@v23 34 | 35 | - name: 'Use Node.js Version 20.11.x' 36 | uses: actions/setup-node@v3 37 | with: 38 | node-version: 20.11.x 39 | 40 | - name: Add key to allow access to repository 41 | env: 42 | SSH_AUTH_SOCK: /tmp/ssh_agent.sock 43 | run: | 44 | mkdir -p ~/.ssh 45 | ssh-keyscan github.com >> ~/.ssh/known_hosts 46 | echo "${{ secrets.GH_PAGES_DEPLOY }}" > ~/.ssh/id_rsa 47 | chmod 600 ~/.ssh/id_rsa 48 | cat <> ~/.ssh/config 49 | Host github.com 50 | HostName github.com 51 | IdentityFile ~/.ssh/id_rsa 52 | EOT 53 | 54 | - name: Release to GitHub Pages 55 | env: 56 | USE_SSH: true 57 | GIT_USER: git 58 | run: | 59 | git config --global user.email ${{ secrets.EMAIL }} 60 | git config --global user.name ${{ secrets.USERNAME }} 61 | cd website/ 62 | npm i 63 | npm run build 64 | npx docusaurus deploy -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release NPM package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy-package: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # Checkout the exact commit tagged on the release. 13 | - name: Checkout repo 14 | uses: actions/checkout@v2 15 | with: 16 | ref: ${{ github.event.release.target_commitish }} 17 | 18 | # This is the action in this repo! 👇 19 | # Note we set an `id` called `release`. We'll use that later... 20 | - name: Validate and extract release information 21 | id: release 22 | uses: manovotny/github-releases-for-automated-package-publishing-action@v1.0.0 23 | 24 | # When setting the node version for publishing a release, it's also impotant 25 | # to set `always-auth` and `registry-url` too. I've encountered vauge errors 26 | # and publishing doesn't work unless they are supplied. 27 | # 28 | # This example is using NPM's registry. If you were publishing to GitHub's 29 | # Package registry, you'd use `https://npm.pkg.github.com` instead. 30 | - name: Use Node.js Version 16.x 31 | uses: actions/setup-node@v2 32 | with: 33 | always-auth: true 34 | node-version: 16.14.x 35 | registry-url: 'https://registry.npmjs.org' 36 | 37 | # Perform installs dependencies 38 | - name: Install dependencies 39 | run: yarn install --frozen-lockfile 40 | 41 | # Perform type check 42 | - name: Type check 43 | run: yarn typecheck 44 | 45 | # Perform lint 46 | - name: Lint 47 | run: yarn lint 48 | 49 | # Perform check for circular dependencies 50 | - name: Check circular dependencies 51 | run: yarn circular 52 | 53 | # Run Jest Unit Tests 54 | - name: Run Jest Unit Tests 55 | run: yarn test 56 | 57 | # Perform build project 58 | - name: Build 59 | run: yarn prepack 60 | 61 | # The last two steps will publish the package. Note that we're using 62 | # information from the `release` step above (I told you we'd use it 63 | # later). Notice the `if` statements on both steps... 64 | # 65 | # If there *is* a tag (ie. `beta`, `canary`, etc.), we publish a 66 | # "pre-release" or "tagged" version of a package (ie. 1.2.3-beta.1). 67 | # 68 | # If there *is not* a tag (ie. `beta`, `canary`, etc.), we publish a 69 | # version of a package (ie. 1.2.3). 70 | # 71 | # This example is using yarn to publish, but you could just as easily 72 | # use npm, if you prefer. It's also publishing to the NPM registry, 73 | # thus, it's using `NPM_TOKEN`, but you could just as easily use 74 | # `GITHUB_TOKEN` if you were publishing to the GitHub Package registry. 75 | 76 | # This will publish a "pre-release" or "tagged" version of a package. 77 | - name: Publish tagged version 78 | if: steps.release.outputs.tag != '' 79 | run: yarn publish --new-version ${{ steps.release.outputs.version }} --tag ${{ steps.release.outputs.tag }} 80 | env: 81 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 82 | 83 | # This will publish a version of a package. 84 | - name: Publish version 85 | if: steps.release.outputs.tag == '' 86 | run: yarn publish --new-version ${{ steps.release.outputs.version }} 87 | env: 88 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # XDE 6 | .expo/ 7 | 8 | # VSCode 9 | .vscode/ 10 | jsconfig.json 11 | 12 | # Xcode 13 | # 14 | build/ 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata 24 | *.xccheckout 25 | *.moved-aside 26 | DerivedData 27 | *.hmap 28 | *.ipa 29 | *.xcuserstate 30 | project.xcworkspace 31 | 32 | # Android/IJ 33 | # 34 | .classpath 35 | .cxx 36 | .gradle 37 | .idea 38 | .project 39 | .settings 40 | local.properties 41 | android.iml 42 | 43 | # Cocoapods 44 | # 45 | example/ios/Pods 46 | 47 | # Ruby 48 | example/vendor/ 49 | 50 | # node.js 51 | # 52 | node_modules/ 53 | npm-debug.log 54 | yarn-debug.log 55 | yarn-error.log 56 | 57 | # BUCK 58 | buck-out/ 59 | \.buckd/ 60 | android/app/libs 61 | android/keystores/debug.keystore 62 | 63 | # Expo 64 | .expo/ 65 | 66 | # Turborepo 67 | .turbo/ 68 | 69 | # generated by bob 70 | lib/ 71 | 72 | # Jest 73 | coverage/ 74 | -------------------------------------------------------------------------------- /.jest/__mocks__/PitchDetectorModule.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | start: jest.fn(), 3 | stop: jest.fn(), 4 | isRecording: jest.fn(), 5 | } -------------------------------------------------------------------------------- /.jest/jest.setup.ts: -------------------------------------------------------------------------------- 1 | import PitchDetectorModule from './__mocks__/PitchDetectorModule' 2 | 3 | jest.mock('react-native-permissions', () => require('react-native-permissions/mock')); 4 | 5 | const mocks = { PitchDetectorModule } 6 | Object.keys(mocks).forEach((module => jest.doMock(module, () => mocks[module], { virtual: true }))) 7 | 8 | jest.mock('react-native', () => ({ 9 | Platform: { 10 | OS: 'android', 11 | select: jest.fn((data: { android: any, ios: any }) => data.android) 12 | }, 13 | NativeEventEmitter: jest.fn().mockImplementation(() => ({ 14 | addListener: jest.fn(), 15 | emit: jest.fn(), 16 | listenerCount: jest.fn(), 17 | removeAllListeners: jest.fn(), 18 | removeEventListener: jest.fn(), 19 | removeSubscription: jest.fn(), 20 | })), 21 | NativeModules: mocks, 22 | })) 23 | -------------------------------------------------------------------------------- /.madgerc: -------------------------------------------------------------------------------- 1 | { 2 | "fontSize": "10px", 3 | "graphVizOptions": { 4 | "G": { 5 | "rankdir": "LR" 6 | } 7 | }, 8 | "tsConfig": "./tsconfig.json" 9 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # root 2 | .github/ 3 | .husky/ 4 | coverage/ 5 | example/ 6 | scripts/ 7 | src/__tests__/ 8 | 9 | # lib 10 | lib/typescript/example/ 11 | lib/typescript/website/ 12 | lib/typescript/src/__tests__/ 13 | lib/typescript/src/__mocks__/ 14 | lib/typescript/src/__fixtures__/ 15 | 16 | # android 17 | android/.gradle/ 18 | android/.idea/ 19 | android/build/ 20 | android/gradle 21 | android/gradlew 22 | android/gradlew.bat 23 | android/local.properties 24 | 25 | # ios 26 | ios/build 27 | 28 | # docs 29 | website/ -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.18.1 2 | -------------------------------------------------------------------------------- /.scannerwork/.sonar_lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/.scannerwork/.sonar_lock -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | # Override Yarn command so we can automatically setup the repo on running `yarn` 2 | 3 | yarn-path "scripts/bootstrap.js" 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Fábio Pereira 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

3 | React Native Pitch Detector Logo
4 | React Native Pitch Detector 5 |

6 | 7 | 8 |

9 | 10 | NPM downloads 11 | 12 | 13 | NPM version 14 | 15 | 16 | 17 | Sonar Cloud 18 | 19 | Package License 20 | 21 |

22 | 23 |

High performance real time pitch detection.

24 | 25 | ## [Documentation](https://1fabiopereira.github.io/react-native-pitch-detector/) 26 | - ### [Getting Started](https://1fabiopereira.github.io/react-native-pitch-detector/docs/before-you-start) 27 | - [Before you start](https://1fabiopereira.github.io/react-native-pitch-detector/docs/before-you-start) 28 | 29 | - [Installation](https://1fabiopereira.github.io/react-native-pitch-detector/docs/installation) 30 | 31 | - [Usage](https://1fabiopereira.github.io/react-native-pitch-detector/docs/usage) 32 | 33 | - [Playground](https://1fabiopereira.github.io/react-native-pitch-detector/docs/playground) 34 | 35 | - ### [Meta](https://1fabiopereira.github.io/react-native-pitch-detector/docs/contributing) 36 | - [Contributing](https://1fabiopereira.github.io/react-native-pitch-detector/docs/contributing) 37 | 38 | - [Code of Conduct](https://1fabiopereira.github.io/react-native-pitch-detector/docs/code-of-conduct) 39 | 40 | - [License](https://1fabiopereira.github.io/react-native-pitch-detector/docs/license) 41 | 42 | 43 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | // Buildscript is evaluated before everything else so we can't use getExtOrDefault 3 | def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["PitchDetector_kotlinVersion"] 4 | 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath "com.android.tools.build:gradle:7.2.2" 12 | // noinspection DifferentKotlinGradleVersion 13 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 14 | } 15 | } 16 | 17 | def isNewArchitectureEnabled() { 18 | return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true" 19 | } 20 | 21 | apply plugin: "com.android.library" 22 | apply plugin: "kotlin-android" 23 | 24 | 25 | def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') } 26 | 27 | if (isNewArchitectureEnabled()) { 28 | apply plugin: "com.facebook.react" 29 | } 30 | 31 | def getExtOrDefault(name) { 32 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["PitchDetector_" + name] 33 | } 34 | 35 | def getExtOrIntegerDefault(name) { 36 | return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["PitchDetector_" + name]).toInteger() 37 | } 38 | 39 | android { 40 | compileSdkVersion getExtOrIntegerDefault("compileSdkVersion") 41 | 42 | compileOptions { 43 | sourceCompatibility JavaVersion.VERSION_11 44 | targetCompatibility JavaVersion.VERSION_11 45 | } 46 | 47 | defaultConfig { 48 | minSdkVersion getExtOrIntegerDefault("minSdkVersion") 49 | targetSdkVersion getExtOrIntegerDefault("targetSdkVersion") 50 | buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() 51 | } 52 | 53 | buildTypes { 54 | release { 55 | minifyEnabled false 56 | } 57 | } 58 | 59 | lintOptions { 60 | disable "GradleCompatible" 61 | } 62 | } 63 | 64 | repositories { 65 | google() 66 | mavenCentral() 67 | } 68 | 69 | def kotlin_version = getExtOrDefault("kotlinVersion") 70 | 71 | dependencies { 72 | implementation fileTree(dir: "./src/libs", include: ["*.jar"]) 73 | //noinspection GradleDependency 74 | 75 | // For < 0.71, this will be from the local maven repo 76 | // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin 77 | // implementation ("com.facebook.react:react-android:$version") 78 | //noinspection GradleDynamicVersion 79 | implementation ("com.facebook.react:react-native:+") 80 | 81 | //noinspection GradleDependency 82 | implementation ("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version") 83 | } 84 | 85 | if (isNewArchitectureEnabled()) { 86 | react { 87 | jsRootDir = file("../src/") 88 | libraryName = "PitchDetector" 89 | codegenJavaPackageName = "com.pitchdetector" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | PitchDetector_kotlinVersion=1.7.0 2 | PitchDetector_minSdkVersion=21 3 | PitchDetector_targetSdkVersion=31 4 | PitchDetector_compileSdkVersion=31 5 | PitchDetector_ndkversion=21.4.7075529 6 | -------------------------------------------------------------------------------- /android/src/libs/tarsos-dsp.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/android/src/libs/tarsos-dsp.jar -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /android/src/main/java/com/pitchdetector/PitchDetectorModule.kt: -------------------------------------------------------------------------------- 1 | package com.pitchdetector 2 | 3 | import com.facebook.react.bridge.Promise 4 | import com.facebook.react.bridge.ReactApplicationContext 5 | import com.facebook.react.bridge.ReactContextBaseJavaModule 6 | import com.facebook.react.bridge.ReactMethod 7 | import com.facebook.react.bridge.ReadableMap 8 | import com.facebook.react.bridge.WritableMap 9 | import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter 10 | import com.pitchdetector.processors.BaseProcessor 11 | 12 | class PitchDetectorModule(private val reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { 13 | private val processor = BaseProcessor() 14 | private var recording = false 15 | 16 | override fun getName(): String { 17 | return NAME 18 | } 19 | 20 | @ReactMethod 21 | fun start(config: ReadableMap, promise: Promise) { 22 | if (!this.recording) { 23 | try { 24 | val emitter = reactContext.getJSModule(RCTDeviceEventEmitter::class.java) 25 | processor.start(config, emitter) 26 | this.recording = true 27 | promise.resolve(null) 28 | } catch (e: Exception) { 29 | this.recording = false 30 | promise.reject(e) 31 | } 32 | } 33 | } 34 | 35 | @ReactMethod 36 | fun stop(promise: Promise) { 37 | if (this.recording) { 38 | try { 39 | processor.stop() 40 | this.recording = false 41 | promise.resolve(null) 42 | } catch (e: Exception) { 43 | this.recording = false 44 | promise.reject(e) 45 | } 46 | } 47 | } 48 | 49 | @ReactMethod 50 | fun isRecording(promise: Promise) { 51 | try { 52 | promise.resolve(this.recording) 53 | } catch (e: Exception) { 54 | promise.reject(e) 55 | } 56 | } 57 | 58 | @ReactMethod 59 | fun addListener(eventName: String?) { 60 | // Keep: Required for RN built in Event Emitter Calls. 61 | } 62 | 63 | @ReactMethod 64 | fun removeListeners(count: Int?) { 65 | // Keep: Required for RN built in Event Emitter Calls. 66 | } 67 | 68 | companion object { 69 | const val NAME = "PitchDetectorModule" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /android/src/main/java/com/pitchdetector/PitchDetectorPackage.kt: -------------------------------------------------------------------------------- 1 | package com.pitchdetector 2 | 3 | import com.facebook.react.ReactPackage 4 | import com.facebook.react.bridge.NativeModule 5 | import com.facebook.react.bridge.ReactApplicationContext 6 | import com.facebook.react.uimanager.ViewManager 7 | 8 | 9 | class PitchDetectorPackage : ReactPackage { 10 | override fun createNativeModules(reactContext: ReactApplicationContext): List { 11 | return listOf(PitchDetectorModule(reactContext)) 12 | } 13 | 14 | override fun createViewManagers(reactContext: ReactApplicationContext): List> { 15 | return emptyList() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /android/src/main/java/com/pitchdetector/processors/BaseProcessor.kt: -------------------------------------------------------------------------------- 1 | package com.pitchdetector.processors 2 | 3 | import android.util.Log 4 | import be.tarsos.dsp.AudioDispatcher 5 | import be.tarsos.dsp.AudioProcessor 6 | import be.tarsos.dsp.io.android.AudioDispatcherFactory 7 | import be.tarsos.dsp.pitch.PitchDetectionHandler 8 | import be.tarsos.dsp.pitch.PitchProcessor 9 | import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm 10 | import com.facebook.react.bridge.ReadableMap 11 | 12 | import com.facebook.react.bridge.WritableMap 13 | import com.facebook.react.bridge.WritableNativeMap 14 | import com.facebook.react.modules.core.DeviceEventManagerModule 15 | import com.facebook.react.modules.core.DeviceEventManagerModule.RCTDeviceEventEmitter 16 | import com.pitchdetector.utils.Algorithms 17 | 18 | import kotlin.math.log2 19 | import kotlin.math.round 20 | 21 | open class BaseProcessor() { 22 | private val tones = arrayOf("C","C#","D","D#","E","F","F#","G","G#","A","A#","B") 23 | 24 | private var dispatcher: AudioDispatcher? = null 25 | private var processor: AudioProcessor? = null 26 | 27 | private var runner: Thread? = null 28 | private var emitter: RCTDeviceEventEmitter? = null 29 | 30 | private val handler = PitchDetectionHandler { res, e -> 31 | val pitchInHz = res.pitch 32 | process(pitchInHz) 33 | } 34 | 35 | private fun process(pitchInHz: Float) { 36 | val index = round(12 * (log2(pitchInHz / 440) / log2(2f)) + 69) % 12 37 | 38 | if (!index.isNaN() && pitchInHz > 0) { 39 | val tone = tones[index.toInt()] 40 | val data: WritableMap = WritableNativeMap() 41 | 42 | data.putDouble("frequency", pitchInHz.toDouble()) 43 | data.putString("tone", tone) 44 | 45 | emitter?.emit("data", data) 46 | } 47 | } 48 | 49 | private fun prepare(config: ReadableMap) { 50 | val sampleRate = config.getDouble("sampleRate").toFloat() 51 | val bufferSize = config.getInt("bufferSize") 52 | val bufferOverLap = config.getInt("bufferOverLap") 53 | val algorithm = Algorithms.parse(config.getString("algorithm")) 54 | 55 | Log.i("PITCH DETECTOR", "STARTED WITH: algorithm: $algorithm, sampleRate: $sampleRate, bufferSize: $bufferSize, bufferOverLap: $bufferOverLap") 56 | 57 | processor = PitchProcessor(algorithm, sampleRate, bufferSize, handler) 58 | dispatcher = AudioDispatcherFactory.fromDefaultMicrophone(sampleRate.toInt(), bufferSize, bufferOverLap); 59 | dispatcher?.addAudioProcessor(processor) 60 | } 61 | 62 | fun start(config: ReadableMap, emitter: RCTDeviceEventEmitter) { 63 | this.emitter = emitter 64 | 65 | prepare(config) 66 | 67 | runner = Thread(dispatcher) 68 | runner?.start() 69 | } 70 | 71 | fun stop() { 72 | dispatcher?.stop() 73 | runner?.interrupt() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /android/src/main/java/com/pitchdetector/utils/Algorithms.kt: -------------------------------------------------------------------------------- 1 | package com.pitchdetector.utils 2 | 3 | import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm 4 | import be.tarsos.dsp.pitch.PitchProcessor.PitchEstimationAlgorithm.* 5 | 6 | object Algorithms { 7 | fun parse(algorithm: String?): PitchEstimationAlgorithm { 8 | return when(algorithm) { 9 | "AMDF" -> AMDF 10 | "DYNAMIC_WAVELET" -> DYNAMIC_WAVELET 11 | "FFT_PITCH" -> FFT_PITCH 12 | "FFT_YIN" -> FFT_YIN 13 | "MPM" -> MPM 14 | "YIN" -> YIN 15 | else -> { 16 | YIN 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:metro-react-native-babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /example/.bundle/config: -------------------------------------------------------------------------------- 1 | BUNDLE_PATH: "vendor/bundle" 2 | BUNDLE_FORCE_RUBY_PLATFORM: 1 3 | -------------------------------------------------------------------------------- /example/.node-version: -------------------------------------------------------------------------------- 1 | 18 2 | -------------------------------------------------------------------------------- /example/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 4 | ruby '>= 2.6.10' 5 | 6 | gem 'cocoapods', '>= 1.11.3' 7 | -------------------------------------------------------------------------------- /example/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.6) 5 | rexml 6 | activesupport (7.0.4.3) 7 | concurrent-ruby (~> 1.0, >= 1.0.2) 8 | i18n (>= 1.6, < 2) 9 | minitest (>= 5.1) 10 | tzinfo (~> 2.0) 11 | addressable (2.8.2) 12 | public_suffix (>= 2.0.2, < 6.0) 13 | algoliasearch (1.27.5) 14 | httpclient (~> 2.8, >= 2.8.3) 15 | json (>= 1.5.1) 16 | atomos (0.1.3) 17 | claide (1.1.0) 18 | cocoapods (1.12.0) 19 | addressable (~> 2.8) 20 | claide (>= 1.0.2, < 2.0) 21 | cocoapods-core (= 1.12.0) 22 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 23 | cocoapods-downloader (>= 1.6.0, < 2.0) 24 | cocoapods-plugins (>= 1.0.0, < 2.0) 25 | cocoapods-search (>= 1.0.0, < 2.0) 26 | cocoapods-trunk (>= 1.6.0, < 2.0) 27 | cocoapods-try (>= 1.1.0, < 2.0) 28 | colored2 (~> 3.1) 29 | escape (~> 0.0.4) 30 | fourflusher (>= 2.3.0, < 3.0) 31 | gh_inspector (~> 1.0) 32 | molinillo (~> 0.8.0) 33 | nap (~> 1.0) 34 | ruby-macho (>= 2.3.0, < 3.0) 35 | xcodeproj (>= 1.21.0, < 2.0) 36 | cocoapods-core (1.12.0) 37 | activesupport (>= 5.0, < 8) 38 | addressable (~> 2.8) 39 | algoliasearch (~> 1.0) 40 | concurrent-ruby (~> 1.1) 41 | fuzzy_match (~> 2.0.4) 42 | nap (~> 1.0) 43 | netrc (~> 0.11) 44 | public_suffix (~> 4.0) 45 | typhoeus (~> 1.0) 46 | cocoapods-deintegrate (1.0.5) 47 | cocoapods-downloader (1.6.3) 48 | cocoapods-plugins (1.0.0) 49 | nap 50 | cocoapods-search (1.0.1) 51 | cocoapods-trunk (1.6.0) 52 | nap (>= 0.8, < 2.0) 53 | netrc (~> 0.11) 54 | cocoapods-try (1.2.0) 55 | colored2 (3.1.2) 56 | concurrent-ruby (1.2.2) 57 | escape (0.0.4) 58 | ethon (0.16.0) 59 | ffi (>= 1.15.0) 60 | ffi (1.15.5) 61 | fourflusher (2.3.1) 62 | fuzzy_match (2.0.4) 63 | gh_inspector (1.1.3) 64 | httpclient (2.8.3) 65 | i18n (1.12.0) 66 | concurrent-ruby (~> 1.0) 67 | json (2.6.3) 68 | minitest (5.18.0) 69 | molinillo (0.8.0) 70 | nanaimo (0.3.0) 71 | nap (1.1.0) 72 | netrc (0.11.0) 73 | public_suffix (4.0.7) 74 | rexml (3.2.5) 75 | ruby-macho (2.5.1) 76 | typhoeus (1.4.0) 77 | ethon (>= 0.9.0) 78 | tzinfo (2.0.6) 79 | concurrent-ruby (~> 1.0) 80 | xcodeproj (1.22.0) 81 | CFPropertyList (>= 2.3.3, < 4.0) 82 | atomos (~> 0.1.3) 83 | claide (>= 1.0.2, < 2.0) 84 | colored2 (~> 3.1) 85 | nanaimo (~> 0.3.0) 86 | rexml (~> 3.2.4) 87 | 88 | PLATFORMS 89 | ruby 90 | 91 | DEPENDENCIES 92 | cocoapods (>= 1.11.3) 93 | 94 | RUBY VERSION 95 | ruby 2.7.6p219 96 | 97 | BUNDLED WITH 98 | 2.1.4 99 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: "com.android.application" 2 | apply plugin: "com.facebook.react" 3 | 4 | import com.android.build.OutputFile 5 | 6 | /** 7 | * This is the configuration block to customize your React Native Android app. 8 | * By default you don't need to apply any configuration, just uncomment the lines you need. 9 | */ 10 | react { 11 | /* Folders */ 12 | // The root of your project, i.e. where "package.json" lives. Default is '..' 13 | // root = file("../") 14 | // The folder where the react-native NPM package is. Default is ../node_modules/react-native 15 | // reactNativeDir = file("../node_modules/react-native") 16 | // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen 17 | // codegenDir = file("../node_modules/react-native-codegen") 18 | // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js 19 | // cliFile = file("../node_modules/react-native/cli.js") 20 | 21 | /* Variants */ 22 | // The list of variants to that are debuggable. For those we're going to 23 | // skip the bundling of the JS bundle and the assets. By default is just 'debug'. 24 | // If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants. 25 | // debuggableVariants = ["liteDebug", "prodDebug"] 26 | 27 | /* Bundling */ 28 | // A list containing the node command and its flags. Default is just 'node'. 29 | // nodeExecutableAndArgs = ["node"] 30 | // 31 | // The command to run when bundling. By default is 'bundle' 32 | // bundleCommand = "ram-bundle" 33 | // 34 | // The path to the CLI configuration file. Default is empty. 35 | // bundleConfig = file(../rn-cli.config.js) 36 | // 37 | // The name of the generated asset file containing your JS bundle 38 | // bundleAssetName = "MyApplication.android.bundle" 39 | // 40 | // The entry file for bundle generation. Default is 'index.android.js' or 'index.js' 41 | // entryFile = file("../js/MyApplication.android.js") 42 | // 43 | // A list of extra flags to pass to the 'bundle' commands. 44 | // See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle 45 | // extraPackagerArgs = [] 46 | 47 | /* Hermes Commands */ 48 | // The hermes compiler command to run. By default it is 'hermesc' 49 | // hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc" 50 | // 51 | // The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map" 52 | // hermesFlags = ["-O", "-output-source-map"] 53 | } 54 | 55 | /** 56 | * Set this to true to create four separate APKs instead of one, 57 | * one for each native architecture. This is useful if you don't 58 | * use App Bundles (https://developer.android.com/guide/app-bundle/) 59 | * and want to have separate APKs to upload to the Play Store. 60 | */ 61 | def enableSeparateBuildPerCPUArchitecture = false 62 | 63 | /** 64 | * Set this to true to Run Proguard on Release builds to minify the Java bytecode. 65 | */ 66 | def enableProguardInReleaseBuilds = false 67 | 68 | /** 69 | * The preferred build flavor of JavaScriptCore (JSC) 70 | * 71 | * For example, to use the international variant, you can use: 72 | * `def jscFlavor = 'org.webkit:android-jsc-intl:+'` 73 | * 74 | * The international variant includes ICU i18n library and necessary data 75 | * allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that 76 | * give correct results when using with locales other than en-US. Note that 77 | * this variant is about 6MiB larger per architecture than default. 78 | */ 79 | def jscFlavor = 'org.webkit:android-jsc:+' 80 | 81 | /** 82 | * Private function to get the list of Native Architectures you want to build. 83 | * This reads the value from reactNativeArchitectures in your gradle.properties 84 | * file and works together with the --active-arch-only flag of react-native run-android. 85 | */ 86 | def reactNativeArchitectures() { 87 | def value = project.getProperties().get("reactNativeArchitectures") 88 | return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] 89 | } 90 | 91 | android { 92 | ndkVersion rootProject.ext.ndkVersion 93 | compileSdkVersion rootProject.ext.compileSdkVersion 94 | 95 | compileOptions { 96 | sourceCompatibility JavaVersion.VERSION_11 97 | targetCompatibility JavaVersion.VERSION_11 98 | } 99 | 100 | namespace "com.pitchdetectorexample" 101 | defaultConfig { 102 | applicationId "com.pitchdetectorexample" 103 | minSdkVersion rootProject.ext.minSdkVersion 104 | targetSdkVersion rootProject.ext.targetSdkVersion 105 | versionCode 1 106 | versionName "1.0" 107 | } 108 | 109 | splits { 110 | abi { 111 | reset() 112 | enable enableSeparateBuildPerCPUArchitecture 113 | universalApk false // If true, also generate a universal APK 114 | include (*reactNativeArchitectures()) 115 | } 116 | } 117 | signingConfigs { 118 | debug { 119 | storeFile file('debug.keystore') 120 | storePassword 'android' 121 | keyAlias 'androiddebugkey' 122 | keyPassword 'android' 123 | } 124 | } 125 | buildTypes { 126 | debug { 127 | signingConfig signingConfigs.debug 128 | } 129 | release { 130 | // Caution! In production, you need to generate your own keystore file. 131 | // see https://reactnative.dev/docs/signed-apk-android. 132 | signingConfig signingConfigs.debug 133 | minifyEnabled enableProguardInReleaseBuilds 134 | proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" 135 | } 136 | } 137 | 138 | // applicationVariants are e.g. debug, release 139 | applicationVariants.all { variant -> 140 | variant.outputs.each { output -> 141 | // For each separate APK per architecture, set a unique version code as described here: 142 | // https://developer.android.com/studio/build/configure-apk-splits.html 143 | // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. 144 | def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] 145 | def abi = output.getFilter(OutputFile.ABI) 146 | if (abi != null) { // null for the universal-debug, universal-release variants 147 | output.versionCodeOverride = 148 | defaultConfig.versionCode * 1000 + versionCodes.get(abi) 149 | } 150 | 151 | } 152 | } 153 | } 154 | 155 | dependencies { 156 | // The version of react-native is set by the React Native Gradle Plugin 157 | implementation("com.facebook.react:react-android") 158 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") 159 | 160 | debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") 161 | debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { 162 | exclude group:'com.squareup.okhttp3', module:'okhttp' 163 | } 164 | 165 | debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") 166 | if (hermesEnabled.toBoolean()) { 167 | implementation("com.facebook.react:hermes-android") 168 | } else { 169 | implementation jscFlavor 170 | } 171 | } 172 | 173 | apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) 174 | -------------------------------------------------------------------------------- /example/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/debug.keystore -------------------------------------------------------------------------------- /example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/android/app/src/debug/java/com/pitchdetectorexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.pitchdetectorexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.flipper.android.AndroidFlipperClient; 11 | import com.facebook.flipper.android.utils.FlipperUtils; 12 | import com.facebook.flipper.core.FlipperClient; 13 | import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; 14 | import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; 15 | import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; 16 | import com.facebook.flipper.plugins.inspector.DescriptorMapping; 17 | import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; 18 | import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; 19 | import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; 20 | import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; 21 | import com.facebook.react.ReactInstanceEventListener; 22 | import com.facebook.react.ReactInstanceManager; 23 | import com.facebook.react.bridge.ReactContext; 24 | import com.facebook.react.modules.network.NetworkingModule; 25 | import okhttp3.OkHttpClient; 26 | 27 | /** 28 | * Class responsible of loading Flipper inside your React Native application. This is the debug 29 | * flavor of it. Here you can add your own plugins and customize the Flipper setup. 30 | */ 31 | public class ReactNativeFlipper { 32 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 33 | if (FlipperUtils.shouldEnableFlipper(context)) { 34 | final FlipperClient client = AndroidFlipperClient.getInstance(context); 35 | 36 | client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); 37 | client.addPlugin(new DatabasesFlipperPlugin(context)); 38 | client.addPlugin(new SharedPreferencesFlipperPlugin(context)); 39 | client.addPlugin(CrashReporterPlugin.getInstance()); 40 | 41 | NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); 42 | NetworkingModule.setCustomClientBuilder( 43 | new NetworkingModule.CustomClientBuilder() { 44 | @Override 45 | public void apply(OkHttpClient.Builder builder) { 46 | builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); 47 | } 48 | }); 49 | client.addPlugin(networkFlipperPlugin); 50 | client.start(); 51 | 52 | // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized 53 | // Hence we run if after all native modules have been initialized 54 | ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); 55 | if (reactContext == null) { 56 | reactInstanceManager.addReactInstanceEventListener( 57 | new ReactInstanceEventListener() { 58 | @Override 59 | public void onReactContextInitialized(ReactContext reactContext) { 60 | reactInstanceManager.removeReactInstanceEventListener(this); 61 | reactContext.runOnNativeModulesQueueThread( 62 | new Runnable() { 63 | @Override 64 | public void run() { 65 | client.addPlugin(new FrescoFlipperPlugin()); 66 | } 67 | }); 68 | } 69 | }); 70 | } else { 71 | client.addPlugin(new FrescoFlipperPlugin()); 72 | } 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/pitchdetectorexample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.pitchdetectorexample; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 6 | import com.facebook.react.defaults.DefaultReactActivityDelegate; 7 | 8 | public class MainActivity extends ReactActivity { 9 | 10 | /** 11 | * Returns the name of the main component registered from JavaScript. This is used to schedule 12 | * rendering of the component. 13 | */ 14 | @Override 15 | protected String getMainComponentName() { 16 | return "PitchDetectorExample"; 17 | } 18 | 19 | /** 20 | * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link 21 | * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React 22 | * (aka React 18) with two boolean flags. 23 | */ 24 | @Override 25 | protected ReactActivityDelegate createReactActivityDelegate() { 26 | return new DefaultReactActivityDelegate( 27 | this, 28 | getMainComponentName(), 29 | // If you opted-in for the New Architecture, we enable the Fabric Renderer. 30 | DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled 31 | // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). 32 | DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/pitchdetectorexample/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.pitchdetectorexample; 2 | 3 | import android.app.Application; 4 | import com.facebook.react.PackageList; 5 | import com.facebook.react.ReactApplication; 6 | import com.facebook.react.ReactNativeHost; 7 | import com.facebook.react.ReactPackage; 8 | import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; 9 | import com.facebook.react.defaults.DefaultReactNativeHost; 10 | import com.facebook.soloader.SoLoader; 11 | import java.util.List; 12 | 13 | public class MainApplication extends Application implements ReactApplication { 14 | 15 | private final ReactNativeHost mReactNativeHost = 16 | new DefaultReactNativeHost(this) { 17 | @Override 18 | public boolean getUseDeveloperSupport() { 19 | return BuildConfig.DEBUG; 20 | } 21 | 22 | @Override 23 | protected List getPackages() { 24 | @SuppressWarnings("UnnecessaryLocalVariable") 25 | List packages = new PackageList(this).getPackages(); 26 | // Packages that cannot be autolinked yet can be added manually here, for example: 27 | // packages.add(new MyReactNativePackage()); 28 | return packages; 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | 36 | @Override 37 | protected boolean isNewArchEnabled() { 38 | return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; 39 | } 40 | 41 | @Override 42 | protected Boolean isHermesEnabled() { 43 | return BuildConfig.IS_HERMES_ENABLED; 44 | } 45 | }; 46 | 47 | @Override 48 | public ReactNativeHost getReactNativeHost() { 49 | return mReactNativeHost; 50 | } 51 | 52 | @Override 53 | public void onCreate() { 54 | super.onCreate(); 55 | SoLoader.init(this, /* native exopackage */ false); 56 | if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { 57 | // If you opted-in for the New Architecture, we load the native entry point for this app. 58 | DefaultNewArchitectureEntryPoint.load(); 59 | } 60 | ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/rn_edit_text_material.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 21 | 22 | 23 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | PitchDetectorExample 3 | 4 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/release/java/com/pitchdetectorexample/ReactNativeFlipper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Meta Platforms, Inc. and affiliates. 3 | * 4 | *

This source code is licensed under the MIT license found in the LICENSE file in the root 5 | * directory of this source tree. 6 | */ 7 | package com.pitchdetectorexample; 8 | 9 | import android.content.Context; 10 | import com.facebook.react.ReactInstanceManager; 11 | 12 | /** 13 | * Class responsible of loading Flipper inside your React Native application. This is the release 14 | * flavor of it so it's empty as we don't want to load Flipper. 15 | */ 16 | public class ReactNativeFlipper { 17 | public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { 18 | // Do nothing as we don't want to initialize Flipper on Release. 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "33.0.0" 6 | minSdkVersion = 21 7 | compileSdkVersion = 33 8 | targetSdkVersion = 33 9 | 10 | // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. 11 | ndkVersion = "23.1.7779620" 12 | } 13 | 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | 19 | dependencies { 20 | classpath('com.android.tools.build:gradle:7.2.2') 21 | classpath("com.facebook.react:react-native-gradle-plugin") 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m 13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | 25 | # Automatically convert third-party libraries to use AndroidX 26 | android.enableJetifier=true 27 | 28 | # Version of flipper SDK to use with React Native 29 | FLIPPER_VERSION=0.125.0 30 | 31 | # Use this property to specify which architecture you want to build. 32 | # You can also override it from the CLI using 33 | # ./gradlew -PreactNativeArchitectures=x86_64 34 | reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64 35 | 36 | # Use this property to enable support to the new architecture. 37 | # This will allow you to use TurboModules and the Fabric render in 38 | # your application. You should enable this flag either if you want 39 | # to write custom TurboModules/Fabric components OR use libraries that 40 | # are providing them. 41 | newArchEnabled=false 42 | 43 | # Use this property to enable or disable the Hermes JS engine. 44 | # If set to false, you will be using JSC instead. 45 | hermesEnabled=true 46 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'PitchDetectorExample' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | 4 | include ':app' 5 | includeBuild('../node_modules/react-native-gradle-plugin') 6 | -------------------------------------------------------------------------------- /example/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PitchDetectorExample", 3 | "displayName": "PitchDetectorExample" 4 | } -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | presets: ['module:metro-react-native-babel-preset'], 6 | plugins: [ 7 | [ 8 | 'module-resolver', 9 | { 10 | extensions: ['.tsx', '.ts', '.js', '.json'], 11 | alias: { 12 | [pak.name]: path.join(__dirname, '..', pak.source), 13 | }, 14 | }, 15 | ], 16 | ], 17 | }; 18 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | import { AppRegistry } from 'react-native'; 2 | import App from './src/App'; 3 | import { name as appName } from './app.json'; 4 | 5 | AppRegistry.registerComponent(appName, () => App); 6 | -------------------------------------------------------------------------------- /example/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | 6 | # NODE_BINARY variable contains the PATH to the node executable. 7 | # 8 | # Customize the NODE_BINARY variable here. 9 | # For example, to use nvm with brew, add the following line 10 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 11 | export NODE_BINARY=$(command -v node) 12 | -------------------------------------------------------------------------------- /example/ios/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // PitchDetectorExample 4 | // 5 | 6 | import Foundation 7 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample.xcodeproj/xcshareddata/xcschemes/PitchDetectorExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 55 | 61 | 62 | 63 | 64 | 70 | 72 | 78 | 79 | 80 | 81 | 83 | 84 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/AppDelegate.mm: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | 5 | @implementation AppDelegate 6 | 7 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 8 | { 9 | self.moduleName = @"PitchDetectorExample"; 10 | // You can add your custom initial props in the dictionary below. 11 | // They will be passed down to the ViewController used by React Native. 12 | self.initialProps = @{}; 13 | 14 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 15 | } 16 | 17 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 18 | { 19 | #if DEBUG 20 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; 21 | #else 22 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 23 | #endif 24 | } 25 | 26 | /// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. 27 | /// 28 | /// @see: https://reactjs.org/blog/2022/03/29/react-v18.html 29 | /// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). 30 | /// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. 31 | - (BOOL)concurrentRootEnabled 32 | { 33 | return true; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | PitchDetectorExample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSRequiresIPhoneOS 26 | 27 | NSAppTransportSecurity 28 | 29 | NSExceptionDomains 30 | 31 | localhost 32 | 33 | NSExceptionAllowsInsecureHTTPLoads 34 | 35 | 36 | 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | NSMicrophoneUsageDescription 47 | Perform pitch detection 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UIViewControllerBasedStatusBarAppearance 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExample/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | @autoreleasepool { 8 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/ios/PitchDetectorExampleTests/PitchDetectorExampleTests.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import 5 | #import 6 | 7 | #define TIMEOUT_SECONDS 600 8 | #define TEXT_TO_LOOK_FOR @"Welcome to React" 9 | 10 | @interface PitchDetectorExampleTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation PitchDetectorExampleTests 15 | 16 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test 17 | { 18 | if (test(view)) { 19 | return YES; 20 | } 21 | for (UIView *subview in [view subviews]) { 22 | if ([self findSubviewInView:subview matching:test]) { 23 | return YES; 24 | } 25 | } 26 | return NO; 27 | } 28 | 29 | - (void)testRendersWelcomeScreen 30 | { 31 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 32 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 33 | BOOL foundElement = NO; 34 | 35 | __block NSString *redboxError = nil; 36 | #ifdef DEBUG 37 | RCTSetLogFunction( 38 | ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 39 | if (level >= RCTLogLevelError) { 40 | redboxError = message; 41 | } 42 | }); 43 | #endif 44 | 45 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 46 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 47 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 48 | 49 | foundElement = [self findSubviewInView:vc.view 50 | matching:^BOOL(UIView *view) { 51 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 52 | return YES; 53 | } 54 | return NO; 55 | }]; 56 | } 57 | 58 | #ifdef DEBUG 59 | RCTSetLogFunction(RCTDefaultLogFunction); 60 | #endif 61 | 62 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 63 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /example/ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | 4 | platform :ios, min_ios_version_supported 5 | prepare_react_native_project! 6 | 7 | # If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set. 8 | # because `react-native-flipper` depends on (FlipperKit,...) that will be excluded 9 | # 10 | # To fix this you can also exclude `react-native-flipper` using a `react-native.config.js` 11 | # ```js 12 | # module.exports = { 13 | # dependencies: { 14 | # ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}), 15 | # ``` 16 | flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled 17 | 18 | linkage = ENV['USE_FRAMEWORKS'] 19 | if linkage != nil 20 | Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green 21 | use_frameworks! :linkage => linkage.to_sym 22 | end 23 | 24 | target 'PitchDetectorExample' do 25 | config = use_native_modules! 26 | 27 | # Flags change depending on the env values. 28 | flags = get_default_flags() 29 | 30 | use_react_native!( 31 | :path => config[:reactNativePath], 32 | # Hermes is now enabled by default. Disable by setting this flag to false. 33 | # Upcoming versions of React Native may rely on get_default_flags(), but 34 | # we make it explicit here to aid in the React Native upgrade process. 35 | :hermes_enabled => flags[:hermes_enabled], 36 | :fabric_enabled => flags[:fabric_enabled], 37 | # Enables Flipper. 38 | # 39 | # Note that if you have use_frameworks! enabled, Flipper will not work and 40 | # you should disable the next line. 41 | :flipper_configuration => flipper_config, 42 | # An absolute path to your application root. 43 | :app_path => "#{Pod::Config.instance.installation_root}/.." 44 | ) 45 | 46 | target 'PitchDetectorExampleTests' do 47 | inherit! :complete 48 | # Pods for testing 49 | end 50 | 51 | post_install do |installer| 52 | react_native_post_install( 53 | installer, 54 | # Set `mac_catalyst_enabled` to `true` in order to apply patches 55 | # necessary for Mac Catalyst builds 56 | :mac_catalyst_enabled => false 57 | ) 58 | __apply_Xcode_12_5_M1_post_install_workaround(installer) 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Beethoven (5.0.0): 3 | - Pitchy (~> 3.0) 4 | - boost (1.76.0) 5 | - CocoaAsyncSocket (7.6.5) 6 | - DoubleConversion (1.1.6) 7 | - FBLazyVector (0.71.5) 8 | - FBReactNativeSpec (0.71.5): 9 | - RCT-Folly (= 2021.07.22.00) 10 | - RCTRequired (= 0.71.5) 11 | - RCTTypeSafety (= 0.71.5) 12 | - React-Core (= 0.71.5) 13 | - React-jsi (= 0.71.5) 14 | - ReactCommon/turbomodule/core (= 0.71.5) 15 | - Flipper (0.125.0): 16 | - Flipper-Folly (~> 2.6) 17 | - Flipper-RSocket (~> 1.4) 18 | - Flipper-Boost-iOSX (1.76.0.1.11) 19 | - Flipper-DoubleConversion (3.2.0.1) 20 | - Flipper-Fmt (7.1.7) 21 | - Flipper-Folly (2.6.10): 22 | - Flipper-Boost-iOSX 23 | - Flipper-DoubleConversion 24 | - Flipper-Fmt (= 7.1.7) 25 | - Flipper-Glog 26 | - libevent (~> 2.1.12) 27 | - OpenSSL-Universal (= 1.1.1100) 28 | - Flipper-Glog (0.5.0.5) 29 | - Flipper-PeerTalk (0.0.4) 30 | - Flipper-RSocket (1.4.3): 31 | - Flipper-Folly (~> 2.6) 32 | - FlipperKit (0.125.0): 33 | - FlipperKit/Core (= 0.125.0) 34 | - FlipperKit/Core (0.125.0): 35 | - Flipper (~> 0.125.0) 36 | - FlipperKit/CppBridge 37 | - FlipperKit/FBCxxFollyDynamicConvert 38 | - FlipperKit/FBDefines 39 | - FlipperKit/FKPortForwarding 40 | - SocketRocket (~> 0.6.0) 41 | - FlipperKit/CppBridge (0.125.0): 42 | - Flipper (~> 0.125.0) 43 | - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): 44 | - Flipper-Folly (~> 2.6) 45 | - FlipperKit/FBDefines (0.125.0) 46 | - FlipperKit/FKPortForwarding (0.125.0): 47 | - CocoaAsyncSocket (~> 7.6) 48 | - Flipper-PeerTalk (~> 0.0.4) 49 | - FlipperKit/FlipperKitHighlightOverlay (0.125.0) 50 | - FlipperKit/FlipperKitLayoutHelpers (0.125.0): 51 | - FlipperKit/Core 52 | - FlipperKit/FlipperKitHighlightOverlay 53 | - FlipperKit/FlipperKitLayoutTextSearchable 54 | - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): 55 | - FlipperKit/Core 56 | - FlipperKit/FlipperKitHighlightOverlay 57 | - FlipperKit/FlipperKitLayoutHelpers 58 | - YogaKit (~> 1.18) 59 | - FlipperKit/FlipperKitLayoutPlugin (0.125.0): 60 | - FlipperKit/Core 61 | - FlipperKit/FlipperKitHighlightOverlay 62 | - FlipperKit/FlipperKitLayoutHelpers 63 | - FlipperKit/FlipperKitLayoutIOSDescriptors 64 | - FlipperKit/FlipperKitLayoutTextSearchable 65 | - YogaKit (~> 1.18) 66 | - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) 67 | - FlipperKit/FlipperKitNetworkPlugin (0.125.0): 68 | - FlipperKit/Core 69 | - FlipperKit/FlipperKitReactPlugin (0.125.0): 70 | - FlipperKit/Core 71 | - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): 72 | - FlipperKit/Core 73 | - FlipperKit/SKIOSNetworkPlugin (0.125.0): 74 | - FlipperKit/Core 75 | - FlipperKit/FlipperKitNetworkPlugin 76 | - fmt (6.2.1) 77 | - glog (0.3.5) 78 | - hermes-engine (0.71.5): 79 | - hermes-engine/Pre-built (= 0.71.5) 80 | - hermes-engine/Pre-built (0.71.5) 81 | - libevent (2.1.12) 82 | - OpenSSL-Universal (1.1.1100) 83 | - Pitchy (3.0.0) 84 | - RCT-Folly (2021.07.22.00): 85 | - boost 86 | - DoubleConversion 87 | - fmt (~> 6.2.1) 88 | - glog 89 | - RCT-Folly/Default (= 2021.07.22.00) 90 | - RCT-Folly/Default (2021.07.22.00): 91 | - boost 92 | - DoubleConversion 93 | - fmt (~> 6.2.1) 94 | - glog 95 | - RCT-Folly/Futures (2021.07.22.00): 96 | - boost 97 | - DoubleConversion 98 | - fmt (~> 6.2.1) 99 | - glog 100 | - libevent 101 | - RCTRequired (0.71.5) 102 | - RCTTypeSafety (0.71.5): 103 | - FBLazyVector (= 0.71.5) 104 | - RCTRequired (= 0.71.5) 105 | - React-Core (= 0.71.5) 106 | - React (0.71.5): 107 | - React-Core (= 0.71.5) 108 | - React-Core/DevSupport (= 0.71.5) 109 | - React-Core/RCTWebSocket (= 0.71.5) 110 | - React-RCTActionSheet (= 0.71.5) 111 | - React-RCTAnimation (= 0.71.5) 112 | - React-RCTBlob (= 0.71.5) 113 | - React-RCTImage (= 0.71.5) 114 | - React-RCTLinking (= 0.71.5) 115 | - React-RCTNetwork (= 0.71.5) 116 | - React-RCTSettings (= 0.71.5) 117 | - React-RCTText (= 0.71.5) 118 | - React-RCTVibration (= 0.71.5) 119 | - React-callinvoker (0.71.5) 120 | - React-Codegen (0.71.5): 121 | - FBReactNativeSpec 122 | - hermes-engine 123 | - RCT-Folly 124 | - RCTRequired 125 | - RCTTypeSafety 126 | - React-Core 127 | - React-jsi 128 | - React-jsiexecutor 129 | - ReactCommon/turbomodule/bridging 130 | - ReactCommon/turbomodule/core 131 | - React-Core (0.71.5): 132 | - glog 133 | - hermes-engine 134 | - RCT-Folly (= 2021.07.22.00) 135 | - React-Core/Default (= 0.71.5) 136 | - React-cxxreact (= 0.71.5) 137 | - React-hermes 138 | - React-jsi (= 0.71.5) 139 | - React-jsiexecutor (= 0.71.5) 140 | - React-perflogger (= 0.71.5) 141 | - Yoga 142 | - React-Core/CoreModulesHeaders (0.71.5): 143 | - glog 144 | - hermes-engine 145 | - RCT-Folly (= 2021.07.22.00) 146 | - React-Core/Default 147 | - React-cxxreact (= 0.71.5) 148 | - React-hermes 149 | - React-jsi (= 0.71.5) 150 | - React-jsiexecutor (= 0.71.5) 151 | - React-perflogger (= 0.71.5) 152 | - Yoga 153 | - React-Core/Default (0.71.5): 154 | - glog 155 | - hermes-engine 156 | - RCT-Folly (= 2021.07.22.00) 157 | - React-cxxreact (= 0.71.5) 158 | - React-hermes 159 | - React-jsi (= 0.71.5) 160 | - React-jsiexecutor (= 0.71.5) 161 | - React-perflogger (= 0.71.5) 162 | - Yoga 163 | - React-Core/DevSupport (0.71.5): 164 | - glog 165 | - hermes-engine 166 | - RCT-Folly (= 2021.07.22.00) 167 | - React-Core/Default (= 0.71.5) 168 | - React-Core/RCTWebSocket (= 0.71.5) 169 | - React-cxxreact (= 0.71.5) 170 | - React-hermes 171 | - React-jsi (= 0.71.5) 172 | - React-jsiexecutor (= 0.71.5) 173 | - React-jsinspector (= 0.71.5) 174 | - React-perflogger (= 0.71.5) 175 | - Yoga 176 | - React-Core/RCTActionSheetHeaders (0.71.5): 177 | - glog 178 | - hermes-engine 179 | - RCT-Folly (= 2021.07.22.00) 180 | - React-Core/Default 181 | - React-cxxreact (= 0.71.5) 182 | - React-hermes 183 | - React-jsi (= 0.71.5) 184 | - React-jsiexecutor (= 0.71.5) 185 | - React-perflogger (= 0.71.5) 186 | - Yoga 187 | - React-Core/RCTAnimationHeaders (0.71.5): 188 | - glog 189 | - hermes-engine 190 | - RCT-Folly (= 2021.07.22.00) 191 | - React-Core/Default 192 | - React-cxxreact (= 0.71.5) 193 | - React-hermes 194 | - React-jsi (= 0.71.5) 195 | - React-jsiexecutor (= 0.71.5) 196 | - React-perflogger (= 0.71.5) 197 | - Yoga 198 | - React-Core/RCTBlobHeaders (0.71.5): 199 | - glog 200 | - hermes-engine 201 | - RCT-Folly (= 2021.07.22.00) 202 | - React-Core/Default 203 | - React-cxxreact (= 0.71.5) 204 | - React-hermes 205 | - React-jsi (= 0.71.5) 206 | - React-jsiexecutor (= 0.71.5) 207 | - React-perflogger (= 0.71.5) 208 | - Yoga 209 | - React-Core/RCTImageHeaders (0.71.5): 210 | - glog 211 | - hermes-engine 212 | - RCT-Folly (= 2021.07.22.00) 213 | - React-Core/Default 214 | - React-cxxreact (= 0.71.5) 215 | - React-hermes 216 | - React-jsi (= 0.71.5) 217 | - React-jsiexecutor (= 0.71.5) 218 | - React-perflogger (= 0.71.5) 219 | - Yoga 220 | - React-Core/RCTLinkingHeaders (0.71.5): 221 | - glog 222 | - hermes-engine 223 | - RCT-Folly (= 2021.07.22.00) 224 | - React-Core/Default 225 | - React-cxxreact (= 0.71.5) 226 | - React-hermes 227 | - React-jsi (= 0.71.5) 228 | - React-jsiexecutor (= 0.71.5) 229 | - React-perflogger (= 0.71.5) 230 | - Yoga 231 | - React-Core/RCTNetworkHeaders (0.71.5): 232 | - glog 233 | - hermes-engine 234 | - RCT-Folly (= 2021.07.22.00) 235 | - React-Core/Default 236 | - React-cxxreact (= 0.71.5) 237 | - React-hermes 238 | - React-jsi (= 0.71.5) 239 | - React-jsiexecutor (= 0.71.5) 240 | - React-perflogger (= 0.71.5) 241 | - Yoga 242 | - React-Core/RCTSettingsHeaders (0.71.5): 243 | - glog 244 | - hermes-engine 245 | - RCT-Folly (= 2021.07.22.00) 246 | - React-Core/Default 247 | - React-cxxreact (= 0.71.5) 248 | - React-hermes 249 | - React-jsi (= 0.71.5) 250 | - React-jsiexecutor (= 0.71.5) 251 | - React-perflogger (= 0.71.5) 252 | - Yoga 253 | - React-Core/RCTTextHeaders (0.71.5): 254 | - glog 255 | - hermes-engine 256 | - RCT-Folly (= 2021.07.22.00) 257 | - React-Core/Default 258 | - React-cxxreact (= 0.71.5) 259 | - React-hermes 260 | - React-jsi (= 0.71.5) 261 | - React-jsiexecutor (= 0.71.5) 262 | - React-perflogger (= 0.71.5) 263 | - Yoga 264 | - React-Core/RCTVibrationHeaders (0.71.5): 265 | - glog 266 | - hermes-engine 267 | - RCT-Folly (= 2021.07.22.00) 268 | - React-Core/Default 269 | - React-cxxreact (= 0.71.5) 270 | - React-hermes 271 | - React-jsi (= 0.71.5) 272 | - React-jsiexecutor (= 0.71.5) 273 | - React-perflogger (= 0.71.5) 274 | - Yoga 275 | - React-Core/RCTWebSocket (0.71.5): 276 | - glog 277 | - hermes-engine 278 | - RCT-Folly (= 2021.07.22.00) 279 | - React-Core/Default (= 0.71.5) 280 | - React-cxxreact (= 0.71.5) 281 | - React-hermes 282 | - React-jsi (= 0.71.5) 283 | - React-jsiexecutor (= 0.71.5) 284 | - React-perflogger (= 0.71.5) 285 | - Yoga 286 | - React-CoreModules (0.71.5): 287 | - RCT-Folly (= 2021.07.22.00) 288 | - RCTTypeSafety (= 0.71.5) 289 | - React-Codegen (= 0.71.5) 290 | - React-Core/CoreModulesHeaders (= 0.71.5) 291 | - React-jsi (= 0.71.5) 292 | - React-RCTBlob 293 | - React-RCTImage (= 0.71.5) 294 | - ReactCommon/turbomodule/core (= 0.71.5) 295 | - React-cxxreact (0.71.5): 296 | - boost (= 1.76.0) 297 | - DoubleConversion 298 | - glog 299 | - hermes-engine 300 | - RCT-Folly (= 2021.07.22.00) 301 | - React-callinvoker (= 0.71.5) 302 | - React-jsi (= 0.71.5) 303 | - React-jsinspector (= 0.71.5) 304 | - React-logger (= 0.71.5) 305 | - React-perflogger (= 0.71.5) 306 | - React-runtimeexecutor (= 0.71.5) 307 | - React-hermes (0.71.5): 308 | - DoubleConversion 309 | - glog 310 | - hermes-engine 311 | - RCT-Folly (= 2021.07.22.00) 312 | - RCT-Folly/Futures (= 2021.07.22.00) 313 | - React-cxxreact (= 0.71.5) 314 | - React-jsi 315 | - React-jsiexecutor (= 0.71.5) 316 | - React-jsinspector (= 0.71.5) 317 | - React-perflogger (= 0.71.5) 318 | - React-jsi (0.71.5): 319 | - boost (= 1.76.0) 320 | - DoubleConversion 321 | - glog 322 | - hermes-engine 323 | - RCT-Folly (= 2021.07.22.00) 324 | - React-jsiexecutor (0.71.5): 325 | - DoubleConversion 326 | - glog 327 | - hermes-engine 328 | - RCT-Folly (= 2021.07.22.00) 329 | - React-cxxreact (= 0.71.5) 330 | - React-jsi (= 0.71.5) 331 | - React-perflogger (= 0.71.5) 332 | - React-jsinspector (0.71.5) 333 | - React-logger (0.71.5): 334 | - glog 335 | - react-native-pitch-detector (0.1.0): 336 | - Beethoven 337 | - React-Core 338 | - React-perflogger (0.71.5) 339 | - React-RCTActionSheet (0.71.5): 340 | - React-Core/RCTActionSheetHeaders (= 0.71.5) 341 | - React-RCTAnimation (0.71.5): 342 | - RCT-Folly (= 2021.07.22.00) 343 | - RCTTypeSafety (= 0.71.5) 344 | - React-Codegen (= 0.71.5) 345 | - React-Core/RCTAnimationHeaders (= 0.71.5) 346 | - React-jsi (= 0.71.5) 347 | - ReactCommon/turbomodule/core (= 0.71.5) 348 | - React-RCTAppDelegate (0.71.5): 349 | - RCT-Folly 350 | - RCTRequired 351 | - RCTTypeSafety 352 | - React-Core 353 | - ReactCommon/turbomodule/core 354 | - React-RCTBlob (0.71.5): 355 | - hermes-engine 356 | - RCT-Folly (= 2021.07.22.00) 357 | - React-Codegen (= 0.71.5) 358 | - React-Core/RCTBlobHeaders (= 0.71.5) 359 | - React-Core/RCTWebSocket (= 0.71.5) 360 | - React-jsi (= 0.71.5) 361 | - React-RCTNetwork (= 0.71.5) 362 | - ReactCommon/turbomodule/core (= 0.71.5) 363 | - React-RCTImage (0.71.5): 364 | - RCT-Folly (= 2021.07.22.00) 365 | - RCTTypeSafety (= 0.71.5) 366 | - React-Codegen (= 0.71.5) 367 | - React-Core/RCTImageHeaders (= 0.71.5) 368 | - React-jsi (= 0.71.5) 369 | - React-RCTNetwork (= 0.71.5) 370 | - ReactCommon/turbomodule/core (= 0.71.5) 371 | - React-RCTLinking (0.71.5): 372 | - React-Codegen (= 0.71.5) 373 | - React-Core/RCTLinkingHeaders (= 0.71.5) 374 | - React-jsi (= 0.71.5) 375 | - ReactCommon/turbomodule/core (= 0.71.5) 376 | - React-RCTNetwork (0.71.5): 377 | - RCT-Folly (= 2021.07.22.00) 378 | - RCTTypeSafety (= 0.71.5) 379 | - React-Codegen (= 0.71.5) 380 | - React-Core/RCTNetworkHeaders (= 0.71.5) 381 | - React-jsi (= 0.71.5) 382 | - ReactCommon/turbomodule/core (= 0.71.5) 383 | - React-RCTSettings (0.71.5): 384 | - RCT-Folly (= 2021.07.22.00) 385 | - RCTTypeSafety (= 0.71.5) 386 | - React-Codegen (= 0.71.5) 387 | - React-Core/RCTSettingsHeaders (= 0.71.5) 388 | - React-jsi (= 0.71.5) 389 | - ReactCommon/turbomodule/core (= 0.71.5) 390 | - React-RCTText (0.71.5): 391 | - React-Core/RCTTextHeaders (= 0.71.5) 392 | - React-RCTVibration (0.71.5): 393 | - RCT-Folly (= 2021.07.22.00) 394 | - React-Codegen (= 0.71.5) 395 | - React-Core/RCTVibrationHeaders (= 0.71.5) 396 | - React-jsi (= 0.71.5) 397 | - ReactCommon/turbomodule/core (= 0.71.5) 398 | - React-runtimeexecutor (0.71.5): 399 | - React-jsi (= 0.71.5) 400 | - ReactCommon/turbomodule/bridging (0.71.5): 401 | - DoubleConversion 402 | - glog 403 | - hermes-engine 404 | - RCT-Folly (= 2021.07.22.00) 405 | - React-callinvoker (= 0.71.5) 406 | - React-Core (= 0.71.5) 407 | - React-cxxreact (= 0.71.5) 408 | - React-jsi (= 0.71.5) 409 | - React-logger (= 0.71.5) 410 | - React-perflogger (= 0.71.5) 411 | - ReactCommon/turbomodule/core (0.71.5): 412 | - DoubleConversion 413 | - glog 414 | - hermes-engine 415 | - RCT-Folly (= 2021.07.22.00) 416 | - React-callinvoker (= 0.71.5) 417 | - React-Core (= 0.71.5) 418 | - React-cxxreact (= 0.71.5) 419 | - React-jsi (= 0.71.5) 420 | - React-logger (= 0.71.5) 421 | - React-perflogger (= 0.71.5) 422 | - RNPermissions (3.8.0): 423 | - React-Core 424 | - SocketRocket (0.6.0) 425 | - Yoga (1.14.0) 426 | - YogaKit (1.18.1): 427 | - Yoga (~> 1.14) 428 | 429 | DEPENDENCIES: 430 | - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) 431 | - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) 432 | - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) 433 | - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) 434 | - Flipper (= 0.125.0) 435 | - Flipper-Boost-iOSX (= 1.76.0.1.11) 436 | - Flipper-DoubleConversion (= 3.2.0.1) 437 | - Flipper-Fmt (= 7.1.7) 438 | - Flipper-Folly (= 2.6.10) 439 | - Flipper-Glog (= 0.5.0.5) 440 | - Flipper-PeerTalk (= 0.0.4) 441 | - Flipper-RSocket (= 1.4.3) 442 | - FlipperKit (= 0.125.0) 443 | - FlipperKit/Core (= 0.125.0) 444 | - FlipperKit/CppBridge (= 0.125.0) 445 | - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) 446 | - FlipperKit/FBDefines (= 0.125.0) 447 | - FlipperKit/FKPortForwarding (= 0.125.0) 448 | - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) 449 | - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) 450 | - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) 451 | - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) 452 | - FlipperKit/FlipperKitReactPlugin (= 0.125.0) 453 | - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) 454 | - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) 455 | - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) 456 | - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) 457 | - libevent (~> 2.1.12) 458 | - OpenSSL-Universal (= 1.1.1100) 459 | - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) 460 | - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) 461 | - RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`) 462 | - React (from `../node_modules/react-native/`) 463 | - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) 464 | - React-Codegen (from `build/generated/ios`) 465 | - React-Core (from `../node_modules/react-native/`) 466 | - React-Core/DevSupport (from `../node_modules/react-native/`) 467 | - React-Core/RCTWebSocket (from `../node_modules/react-native/`) 468 | - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) 469 | - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) 470 | - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) 471 | - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) 472 | - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) 473 | - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) 474 | - React-logger (from `../node_modules/react-native/ReactCommon/logger`) 475 | - react-native-pitch-detector (from `../..`) 476 | - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) 477 | - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) 478 | - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) 479 | - React-RCTAppDelegate (from `../node_modules/react-native/Libraries/AppDelegate`) 480 | - React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`) 481 | - React-RCTImage (from `../node_modules/react-native/Libraries/Image`) 482 | - React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`) 483 | - React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`) 484 | - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) 485 | - React-RCTText (from `../node_modules/react-native/Libraries/Text`) 486 | - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) 487 | - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) 488 | - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) 489 | - RNPermissions (from `../node_modules/react-native-permissions`) 490 | - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) 491 | 492 | SPEC REPOS: 493 | trunk: 494 | - Beethoven 495 | - CocoaAsyncSocket 496 | - Flipper 497 | - Flipper-Boost-iOSX 498 | - Flipper-DoubleConversion 499 | - Flipper-Fmt 500 | - Flipper-Folly 501 | - Flipper-Glog 502 | - Flipper-PeerTalk 503 | - Flipper-RSocket 504 | - FlipperKit 505 | - fmt 506 | - libevent 507 | - OpenSSL-Universal 508 | - Pitchy 509 | - SocketRocket 510 | - YogaKit 511 | 512 | EXTERNAL SOURCES: 513 | boost: 514 | :podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec" 515 | DoubleConversion: 516 | :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" 517 | FBLazyVector: 518 | :path: "../node_modules/react-native/Libraries/FBLazyVector" 519 | FBReactNativeSpec: 520 | :path: "../node_modules/react-native/React/FBReactNativeSpec" 521 | glog: 522 | :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" 523 | hermes-engine: 524 | :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" 525 | RCT-Folly: 526 | :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" 527 | RCTRequired: 528 | :path: "../node_modules/react-native/Libraries/RCTRequired" 529 | RCTTypeSafety: 530 | :path: "../node_modules/react-native/Libraries/TypeSafety" 531 | React: 532 | :path: "../node_modules/react-native/" 533 | React-callinvoker: 534 | :path: "../node_modules/react-native/ReactCommon/callinvoker" 535 | React-Codegen: 536 | :path: build/generated/ios 537 | React-Core: 538 | :path: "../node_modules/react-native/" 539 | React-CoreModules: 540 | :path: "../node_modules/react-native/React/CoreModules" 541 | React-cxxreact: 542 | :path: "../node_modules/react-native/ReactCommon/cxxreact" 543 | React-hermes: 544 | :path: "../node_modules/react-native/ReactCommon/hermes" 545 | React-jsi: 546 | :path: "../node_modules/react-native/ReactCommon/jsi" 547 | React-jsiexecutor: 548 | :path: "../node_modules/react-native/ReactCommon/jsiexecutor" 549 | React-jsinspector: 550 | :path: "../node_modules/react-native/ReactCommon/jsinspector" 551 | React-logger: 552 | :path: "../node_modules/react-native/ReactCommon/logger" 553 | react-native-pitch-detector: 554 | :path: "../.." 555 | React-perflogger: 556 | :path: "../node_modules/react-native/ReactCommon/reactperflogger" 557 | React-RCTActionSheet: 558 | :path: "../node_modules/react-native/Libraries/ActionSheetIOS" 559 | React-RCTAnimation: 560 | :path: "../node_modules/react-native/Libraries/NativeAnimation" 561 | React-RCTAppDelegate: 562 | :path: "../node_modules/react-native/Libraries/AppDelegate" 563 | React-RCTBlob: 564 | :path: "../node_modules/react-native/Libraries/Blob" 565 | React-RCTImage: 566 | :path: "../node_modules/react-native/Libraries/Image" 567 | React-RCTLinking: 568 | :path: "../node_modules/react-native/Libraries/LinkingIOS" 569 | React-RCTNetwork: 570 | :path: "../node_modules/react-native/Libraries/Network" 571 | React-RCTSettings: 572 | :path: "../node_modules/react-native/Libraries/Settings" 573 | React-RCTText: 574 | :path: "../node_modules/react-native/Libraries/Text" 575 | React-RCTVibration: 576 | :path: "../node_modules/react-native/Libraries/Vibration" 577 | React-runtimeexecutor: 578 | :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" 579 | ReactCommon: 580 | :path: "../node_modules/react-native/ReactCommon" 581 | RNPermissions: 582 | :path: "../node_modules/react-native-permissions" 583 | Yoga: 584 | :path: "../node_modules/react-native/ReactCommon/yoga" 585 | 586 | SPEC CHECKSUMS: 587 | Beethoven: e318691697c38933a69081d4bf4d2506213505fd 588 | boost: 57d2868c099736d80fcd648bf211b4431e51a558 589 | CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 590 | DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 591 | FBLazyVector: f1897022b53abf1469d6ad692ee2c69f57d967f3 592 | FBReactNativeSpec: 627fd07f1b9d498c9fa572e76d7f1a6b1ee9a444 593 | Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 594 | Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c 595 | Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 596 | Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b 597 | Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 598 | Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 599 | Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 600 | Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 601 | FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 602 | fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 603 | glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b 604 | hermes-engine: 0784cadad14b011580615c496f77e0ae112eed75 605 | libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 606 | OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c 607 | Pitchy: 15407e4425b6d88fa3e7eef8927ba659fab52d7a 608 | RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 609 | RCTRequired: bd6045fbd511da5efe6db89eecb21e4e36bd7cbf 610 | RCTTypeSafety: c06d9f906faa69dd1c88223204c3a24767725fd8 611 | React: b9ea33557ef1372af247f95d110fbdea114ed3b2 612 | React-callinvoker: 112f941fcb98722c72736b8e229edcb3c1d84b45 613 | React-Codegen: df704c74e2563b0f73fa44f533b6bfef6534ae81 614 | React-Core: c40d8ec76944536e6d4f8306cbda17a7c254585c 615 | React-CoreModules: 7dec7d883bf29bd0d753a93f37326e3031f8f546 616 | React-cxxreact: 63154d7b113bd6e74ae221c1091e10591d7ae651 617 | React-hermes: 187e42638c92a54ad7d270079dda4d59cf8c7229 618 | React-jsi: 6a633d20f5bb094d8f43c3f23c03f724acab005e 619 | React-jsiexecutor: 1579bf3207afadc72ac3638a66a102d1bf5263e3 620 | React-jsinspector: 14a342151ab810862998dfc99e2720746734e9b3 621 | React-logger: 94ec392ae471683635e4bf874d4e82f675399d2d 622 | react-native-pitch-detector: 1208843b2b47df38210a8ed5cf4905e35457b858 623 | React-perflogger: 883a55a9a899535eaf06d0029108ef9ef22cce92 624 | React-RCTActionSheet: 1a3b8416688a3d291367be645022886f71d6842a 625 | React-RCTAnimation: e5560cb72d91ba35151d51e2eb0d467b42763f43 626 | React-RCTAppDelegate: 07a38817f7b30447eb4416384f430812e7c30551 627 | React-RCTBlob: 1ef41cdcc5bf8761b0a11a5c3be588f4787f8845 628 | React-RCTImage: 944297be6fcc0bac7cfe1afb7d2f4f346c2592cd 629 | React-RCTLinking: 0dd37faa7222e8f840edb83cbdd2a68f130ebdf1 630 | React-RCTNetwork: 481afbec12d5a60aac319593797c590464234fcd 631 | React-RCTSettings: f308db1e99737d776cce43732b5bd38c973cfa2c 632 | React-RCTText: 402f609ee727f2dbbf5af8ce1692c64d8c1c17cc 633 | React-RCTVibration: f0f5ad6417803de42e022d99247a6b1ddaf46c13 634 | React-runtimeexecutor: 511f4301d85daf85abface9afb8d2df2d49f87d3 635 | ReactCommon: 4f43b72066f27bfe1f63838c61763f59e7112536 636 | RNPermissions: 4b2444625e1224765a39613e61fe5526ab7aeb3c 637 | SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 638 | Yoga: cd7d7f509dbfac14ee7f31a6c750acb957cd5022 639 | YogaKit: f782866e155069a2cca2517aafea43200b01fd5a 640 | 641 | PODFILE CHECKSUM: e1a35f99a5ea7ae63f7a22475172adabacf5a743 642 | 643 | COCOAPODS: 1.12.0 644 | -------------------------------------------------------------------------------- /example/metro.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const escape = require('escape-string-regexp'); 3 | const exclusionList = require('metro-config/src/defaults/exclusionList'); 4 | const pak = require('../package.json'); 5 | 6 | const root = path.resolve(__dirname, '..'); 7 | 8 | const modules = Object.keys({ 9 | ...pak.peerDependencies, 10 | }); 11 | 12 | module.exports = { 13 | projectRoot: __dirname, 14 | watchFolders: [root], 15 | 16 | // We need to make sure that only one version is loaded for peerDependencies 17 | // So we block them at the root, and alias them to the versions in example's node_modules 18 | resolver: { 19 | blacklistRE: exclusionList( 20 | modules.map( 21 | (m) => 22 | new RegExp(`^${escape(path.join(root, 'node_modules', m))}\\/.*$`) 23 | ) 24 | ), 25 | 26 | extraNodeModules: modules.reduce((acc, name) => { 27 | acc[name] = path.join(__dirname, 'node_modules', name); 28 | return acc; 29 | }, {}), 30 | }, 31 | 32 | transformer: { 33 | getTransformOptions: async () => ({ 34 | transform: { 35 | experimentalImportSupport: false, 36 | inlineRequires: true, 37 | }, 38 | }), 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PitchDetectorExample", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "pods": "pod-install --quiet", 10 | "postinstall": "patch-package && react-native setup-ios-permissions" 11 | }, 12 | "dependencies": { 13 | "react": "18.2.0", 14 | "react-native": "0.71.5", 15 | "react-native-permissions": "^3.8.0" 16 | }, 17 | "devDependencies": { 18 | "@babel/core": "^7.20.0", 19 | "@babel/preset-env": "^7.20.0", 20 | "@babel/runtime": "^7.20.0", 21 | "babel-plugin-module-resolver": "^4.1.0", 22 | "metro-react-native-babel-preset": "0.73.9", 23 | "patch-package": "^6.5.1" 24 | }, 25 | "reactNativePermissionsIOS": [ 26 | "Microphone" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /example/patches/react-native+0.71.5.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/react-native/scripts/react_native_pods.rb b/node_modules/react-native/scripts/react_native_pods.rb 2 | index 8819959..9e2b874 100644 3 | --- a/node_modules/react-native/scripts/react_native_pods.rb 4 | +++ b/node_modules/react-native/scripts/react_native_pods.rb 5 | @@ -347,7 +347,7 @@ def __apply_Xcode_12_5_M1_post_install_workaround(installer) 6 | deployment_target = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f 7 | should_upgrade = deployment_target < 11.0 && deployment_target != 0.0 8 | if should_upgrade 9 | - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 10 | + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0' 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /example/react-native.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const pak = require('../package.json'); 3 | 4 | module.exports = { 5 | dependencies: { 6 | [pak.name]: { 7 | root: path.join(__dirname, '..'), 8 | }, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /example/src/App.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable react-native/no-inline-styles */ 2 | import * as React from 'react'; 3 | import { StyleSheet, View, Text, TouchableOpacity } from 'react-native'; 4 | import { PitchDetector } from 'react-native-pitch-detector'; 5 | 6 | export default function App() { 7 | const [data, setData] = React.useState({ tone: '--', frequency: 0 }); 8 | const [isRecording, setIsRecording] = React.useState(false); 9 | 10 | const start = async () => { 11 | await PitchDetector.start(); 12 | const status = await PitchDetector.isRecording(); 13 | setIsRecording(status); 14 | }; 15 | 16 | const stop = async () => { 17 | await PitchDetector.stop(); 18 | const status = await PitchDetector.isRecording(); 19 | setIsRecording(status); 20 | }; 21 | 22 | React.useEffect(() => { 23 | PitchDetector.addListener(setData); 24 | return () => { 25 | PitchDetector.removeListener(); 26 | }; 27 | }, []); 28 | 29 | return ( 30 | 31 | {data?.tone} 32 | {data?.frequency?.toFixed(1)}hz 33 | 34 | {isRecording ? 'ON' : 'OFF'} 35 | 36 | 40 | {isRecording ? 'STOP' : 'START'} 41 | 42 | 43 | ); 44 | } 45 | 46 | const styles = StyleSheet.create({ 47 | tone: { 48 | fontSize: 40, 49 | fontColor: 'black', 50 | }, 51 | 52 | frequency: { 53 | fontSize: 20, 54 | }, 55 | 56 | button: { 57 | marginTop: 20, 58 | backgroundColor: 'black', 59 | width: '50%', 60 | minHeight: 50, 61 | borderRadius: 100, 62 | justifyContent: 'center', 63 | }, 64 | 65 | label: { 66 | color: 'white', 67 | fontSize: 20, 68 | textAlign: 'center', 69 | }, 70 | 71 | status: { 72 | marginTop: 16, 73 | color: 'black', 74 | }, 75 | 76 | container: { 77 | flex: 1, 78 | alignItems: 'center', 79 | justifyContent: 'center', 80 | }, 81 | 82 | box: { 83 | width: 60, 84 | height: 60, 85 | marginVertical: 20, 86 | }, 87 | }); 88 | -------------------------------------------------------------------------------- /example/src/types/index.ts: -------------------------------------------------------------------------------- 1 | import { PermissionStatus, Rationale } from 'react-native-permissions'; 2 | 3 | export type TComparableCallback = (status: PermissionStatus) => boolean; 4 | 5 | export type TPermissionsHandlers = { 6 | RequestPermission: ( 7 | rationale?: Rationale, 8 | compare?: TComparableCallback 9 | ) => Promise; 10 | CheckPermission: ( 11 | compare?: TComparableCallback 12 | ) => Promise; 13 | }; 14 | -------------------------------------------------------------------------------- /ios/PitchDetector-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // PitchDetector-Bridging-Header.h 3 | // PitchDetector 4 | // 5 | // Created by Fábio Pereira on 03/04/23. 6 | // Copyright © 2023 PitchDetector. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | -------------------------------------------------------------------------------- /ios/PitchDetector.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 339FC44329DC7EB7005F4A95 /* AlgorithmsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339FC44229DC7EB7005F4A95 /* AlgorithmsUtils.swift */; }; 11 | 339FC44429DC9DD5005F4A95 /* PitchDetector-Bridging-Header.h in Sources */ = {isa = PBXBuildFile; fileRef = F4FF95D5245B92E700C19C63 /* PitchDetector-Bridging-Header.h */; }; 12 | 339FC44629DCAA23005F4A95 /* EventEmitterUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 339FC44529DCAA23005F4A95 /* EventEmitterUtils.swift */; }; 13 | 7D89A7B529DB6F2B003874E3 /* BaseProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D89A7B429DB6F2B003874E3 /* BaseProcessor.swift */; }; 14 | 7D89A8DF29DB8895003874E3 /* PromiseUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D89A8DE29DB8895003874E3 /* PromiseUtils.swift */; }; 15 | 7D89A8E229DB88B6003874E3 /* PitchDetectorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D89A8E129DB88B5003874E3 /* PitchDetectorModule.swift */; }; 16 | 7D89A99029DB8B50003874E3 /* PitchDetectorModuleBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D89A98F29DB8B50003874E3 /* PitchDetectorModuleBridge.m */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | 58B511D91A9E6C8500147676 /* CopyFiles */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = "include/$(PRODUCT_NAME)"; 24 | dstSubfolderSpec = 16; 25 | files = ( 26 | ); 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXCopyFilesBuildPhase section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 134814201AA4EA6300B7C361 /* libPitchDetector.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPitchDetector.a; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 339FC44229DC7EB7005F4A95 /* AlgorithmsUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmsUtils.swift; sourceTree = ""; }; 34 | 339FC44529DCAA23005F4A95 /* EventEmitterUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventEmitterUtils.swift; sourceTree = ""; }; 35 | 7D89A7B429DB6F2B003874E3 /* BaseProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseProcessor.swift; sourceTree = ""; }; 36 | 7D89A8DE29DB8895003874E3 /* PromiseUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PromiseUtils.swift; sourceTree = ""; }; 37 | 7D89A8E129DB88B5003874E3 /* PitchDetectorModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PitchDetectorModule.swift; sourceTree = ""; }; 38 | 7D89A98F29DB8B50003874E3 /* PitchDetectorModuleBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PitchDetectorModuleBridge.m; sourceTree = ""; }; 39 | F4FF95D5245B92E700C19C63 /* PitchDetector-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PitchDetector-Bridging-Header.h"; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 58B511D81A9E6C8500147676 /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 134814211AA4EA7D00B7C361 /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 134814201AA4EA6300B7C361 /* libPitchDetector.a */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | 339FC44129DC7C4E005F4A95 /* PitchDetector */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 7D89A7B329DB6F0A003874E3 /* Utils */, 65 | 7D89A7B229DB6EF9003874E3 /* Processors */, 66 | 7D89A8E129DB88B5003874E3 /* PitchDetectorModule.swift */, 67 | 7D89A98F29DB8B50003874E3 /* PitchDetectorModuleBridge.m */, 68 | ); 69 | path = PitchDetector; 70 | sourceTree = ""; 71 | }; 72 | 58B511D21A9E6C8500147676 = { 73 | isa = PBXGroup; 74 | children = ( 75 | 339FC44129DC7C4E005F4A95 /* PitchDetector */, 76 | F4FF95D5245B92E700C19C63 /* PitchDetector-Bridging-Header.h */, 77 | 134814211AA4EA7D00B7C361 /* Products */, 78 | ); 79 | sourceTree = ""; 80 | }; 81 | 7D89A7B229DB6EF9003874E3 /* Processors */ = { 82 | isa = PBXGroup; 83 | children = ( 84 | 7D89A7B429DB6F2B003874E3 /* BaseProcessor.swift */, 85 | ); 86 | path = Processors; 87 | sourceTree = ""; 88 | }; 89 | 7D89A7B329DB6F0A003874E3 /* Utils */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 7D89A8DE29DB8895003874E3 /* PromiseUtils.swift */, 93 | 339FC44229DC7EB7005F4A95 /* AlgorithmsUtils.swift */, 94 | 339FC44529DCAA23005F4A95 /* EventEmitterUtils.swift */, 95 | ); 96 | path = Utils; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | 58B511DA1A9E6C8500147676 /* PitchDetector */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "PitchDetector" */; 105 | buildPhases = ( 106 | 58B511D71A9E6C8500147676 /* Sources */, 107 | 58B511D81A9E6C8500147676 /* Frameworks */, 108 | 58B511D91A9E6C8500147676 /* CopyFiles */, 109 | ); 110 | buildRules = ( 111 | ); 112 | dependencies = ( 113 | ); 114 | name = PitchDetector; 115 | productName = RCTDataManager; 116 | productReference = 134814201AA4EA6300B7C361 /* libPitchDetector.a */; 117 | productType = "com.apple.product-type.library.static"; 118 | }; 119 | /* End PBXNativeTarget section */ 120 | 121 | /* Begin PBXProject section */ 122 | 58B511D31A9E6C8500147676 /* Project object */ = { 123 | isa = PBXProject; 124 | attributes = { 125 | LastUpgradeCheck = 0920; 126 | ORGANIZATIONNAME = Facebook; 127 | TargetAttributes = { 128 | 58B511DA1A9E6C8500147676 = { 129 | CreatedOnToolsVersion = 6.1.1; 130 | }; 131 | }; 132 | }; 133 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "PitchDetector" */; 134 | compatibilityVersion = "Xcode 3.2"; 135 | developmentRegion = English; 136 | hasScannedForEncodings = 0; 137 | knownRegions = ( 138 | English, 139 | en, 140 | ); 141 | mainGroup = 58B511D21A9E6C8500147676; 142 | productRefGroup = 58B511D21A9E6C8500147676; 143 | projectDirPath = ""; 144 | projectRoot = ""; 145 | targets = ( 146 | 58B511DA1A9E6C8500147676 /* PitchDetector */, 147 | ); 148 | }; 149 | /* End PBXProject section */ 150 | 151 | /* Begin PBXSourcesBuildPhase section */ 152 | 58B511D71A9E6C8500147676 /* Sources */ = { 153 | isa = PBXSourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 339FC44629DCAA23005F4A95 /* EventEmitterUtils.swift in Sources */, 157 | 339FC44429DC9DD5005F4A95 /* PitchDetector-Bridging-Header.h in Sources */, 158 | 7D89A8DF29DB8895003874E3 /* PromiseUtils.swift in Sources */, 159 | 339FC44329DC7EB7005F4A95 /* AlgorithmsUtils.swift in Sources */, 160 | 7D89A8E229DB88B6003874E3 /* PitchDetectorModule.swift in Sources */, 161 | 7D89A7B529DB6F2B003874E3 /* BaseProcessor.swift in Sources */, 162 | 7D89A99029DB8B50003874E3 /* PitchDetectorModuleBridge.m in Sources */, 163 | ); 164 | runOnlyForDeploymentPostprocessing = 0; 165 | }; 166 | /* End PBXSourcesBuildPhase section */ 167 | 168 | /* Begin XCBuildConfiguration section */ 169 | 58B511ED1A9E6C8500147676 /* Debug */ = { 170 | isa = XCBuildConfiguration; 171 | buildSettings = { 172 | ALWAYS_SEARCH_USER_PATHS = NO; 173 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 174 | CLANG_CXX_LIBRARY = "libc++"; 175 | CLANG_ENABLE_MODULES = YES; 176 | CLANG_ENABLE_OBJC_ARC = YES; 177 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 178 | CLANG_WARN_BOOL_CONVERSION = YES; 179 | CLANG_WARN_COMMA = YES; 180 | CLANG_WARN_CONSTANT_CONVERSION = YES; 181 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 182 | CLANG_WARN_EMPTY_BODY = YES; 183 | CLANG_WARN_ENUM_CONVERSION = YES; 184 | CLANG_WARN_INFINITE_RECURSION = YES; 185 | CLANG_WARN_INT_CONVERSION = YES; 186 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 187 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 188 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 189 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 190 | CLANG_WARN_STRICT_PROTOTYPES = YES; 191 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 192 | CLANG_WARN_UNREACHABLE_CODE = YES; 193 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 194 | COPY_PHASE_STRIP = NO; 195 | ENABLE_STRICT_OBJC_MSGSEND = YES; 196 | ENABLE_TESTABILITY = YES; 197 | "EXCLUDED_ARCHS[sdk=*]" = arm64; 198 | GCC_C_LANGUAGE_STANDARD = gnu99; 199 | GCC_DYNAMIC_NO_PIC = NO; 200 | GCC_NO_COMMON_BLOCKS = YES; 201 | GCC_OPTIMIZATION_LEVEL = 0; 202 | GCC_PREPROCESSOR_DEFINITIONS = ( 203 | "DEBUG=1", 204 | "$(inherited)", 205 | ); 206 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 214 | MTL_ENABLE_DEBUG_INFO = YES; 215 | ONLY_ACTIVE_ARCH = YES; 216 | SDKROOT = iphoneos; 217 | }; 218 | name = Debug; 219 | }; 220 | 58B511EE1A9E6C8500147676 /* Release */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = NO; 224 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 225 | CLANG_CXX_LIBRARY = "libc++"; 226 | CLANG_ENABLE_MODULES = YES; 227 | CLANG_ENABLE_OBJC_ARC = YES; 228 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 229 | CLANG_WARN_BOOL_CONVERSION = YES; 230 | CLANG_WARN_COMMA = YES; 231 | CLANG_WARN_CONSTANT_CONVERSION = YES; 232 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 233 | CLANG_WARN_EMPTY_BODY = YES; 234 | CLANG_WARN_ENUM_CONVERSION = YES; 235 | CLANG_WARN_INFINITE_RECURSION = YES; 236 | CLANG_WARN_INT_CONVERSION = YES; 237 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 238 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 241 | CLANG_WARN_STRICT_PROTOTYPES = YES; 242 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | COPY_PHASE_STRIP = YES; 246 | ENABLE_NS_ASSERTIONS = NO; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | "EXCLUDED_ARCHS[sdk=*]" = arm64; 249 | GCC_C_LANGUAGE_STANDARD = gnu99; 250 | GCC_NO_COMMON_BLOCKS = YES; 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 258 | MTL_ENABLE_DEBUG_INFO = NO; 259 | SDKROOT = iphoneos; 260 | VALIDATE_PRODUCT = YES; 261 | }; 262 | name = Release; 263 | }; 264 | 58B511F01A9E6C8500147676 /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | HEADER_SEARCH_PATHS = ( 268 | "$(inherited)", 269 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 270 | "$(SRCROOT)/../../../React/**", 271 | "$(SRCROOT)/../../react-native/React/**", 272 | ); 273 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 274 | OTHER_LDFLAGS = "-ObjC"; 275 | PRODUCT_NAME = PitchDetector; 276 | SKIP_INSTALL = YES; 277 | SWIFT_OBJC_BRIDGING_HEADER = "PitchDetector-Bridging-Header.h"; 278 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 279 | SWIFT_VERSION = 5.0; 280 | }; 281 | name = Debug; 282 | }; 283 | 58B511F11A9E6C8500147676 /* Release */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | HEADER_SEARCH_PATHS = ( 287 | "$(inherited)", 288 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 289 | "$(SRCROOT)/../../../React/**", 290 | "$(SRCROOT)/../../react-native/React/**", 291 | ); 292 | LIBRARY_SEARCH_PATHS = "$(inherited)"; 293 | OTHER_LDFLAGS = "-ObjC"; 294 | PRODUCT_NAME = PitchDetector; 295 | SKIP_INSTALL = YES; 296 | SWIFT_OBJC_BRIDGING_HEADER = "PitchDetector-Bridging-Header.h"; 297 | SWIFT_VERSION = 5.0; 298 | }; 299 | name = Release; 300 | }; 301 | /* End XCBuildConfiguration section */ 302 | 303 | /* Begin XCConfigurationList section */ 304 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "PitchDetector" */ = { 305 | isa = XCConfigurationList; 306 | buildConfigurations = ( 307 | 58B511ED1A9E6C8500147676 /* Debug */, 308 | 58B511EE1A9E6C8500147676 /* Release */, 309 | ); 310 | defaultConfigurationIsVisible = 0; 311 | defaultConfigurationName = Release; 312 | }; 313 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "PitchDetector" */ = { 314 | isa = XCConfigurationList; 315 | buildConfigurations = ( 316 | 58B511F01A9E6C8500147676 /* Debug */, 317 | 58B511F11A9E6C8500147676 /* Release */, 318 | ); 319 | defaultConfigurationIsVisible = 0; 320 | defaultConfigurationName = Release; 321 | }; 322 | /* End XCConfigurationList section */ 323 | }; 324 | rootObject = 58B511D31A9E6C8500147676 /* Project object */; 325 | } 326 | -------------------------------------------------------------------------------- /ios/PitchDetector/PitchDetectorModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PitchDetectorModule.swift 3 | // PitchDetector 4 | // 5 | // Created by Fábio Pereira on 03/04/23. 6 | // Copyright © 2023 PitchDetector. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @objc(PitchDetectorModule) 12 | open class PitchDetectorModule: RCTEventEmitter { 13 | private let processor = BaseProcessor() 14 | private var recording = false 15 | 16 | override public init() { 17 | super.init() 18 | EventEmitterUtils.shared.register(withRCTEventEmitter: self) 19 | } 20 | 21 | @objc 22 | override open func supportedEvents() -> [String]! { 23 | return Events.allCases.map({ $0.rawValue }) 24 | } 25 | 26 | @objc 27 | override open func startObserving() { 28 | EventEmitterUtils.shared.restore() 29 | } 30 | 31 | @objc 32 | override open func stopObserving() { 33 | EventEmitterUtils.shared.suspend() 34 | } 35 | 36 | @objc(start:resolve:reject:) 37 | func start(_ config: Dictionary, resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void { 38 | if (!self.recording) { 39 | let promise = PromiseUtils(resolve, reject) 40 | 41 | processor.start(config) 42 | self.recording = true 43 | 44 | return promise.resolve(nil) 45 | } 46 | } 47 | 48 | @objc(stop:reject:) 49 | func stop(resolve:@escaping RCTPromiseResolveBlock,reject:@escaping RCTPromiseRejectBlock) -> Void { 50 | if (self.recording) { 51 | let promise = PromiseUtils(resolve, reject) 52 | 53 | processor.stop() 54 | self.recording = false 55 | 56 | return promise.resolve(nil) 57 | } 58 | } 59 | 60 | @objc(isRecording:reject:) 61 | func isRecording(resolve:@escaping RCTPromiseResolveBlock,reject:@escaping RCTPromiseRejectBlock) -> Void { 62 | let promise = PromiseUtils(resolve, reject) 63 | return promise.resolve(self.recording) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ios/PitchDetector/PitchDetectorModuleBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // PitchDetectorModuleBridge.m 3 | // PitchDetector 4 | // 5 | // Created by Fábio Pereira on 03/04/23. 6 | // Copyright © 2023 PitchDetector. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RCT_EXTERN_MODULE(PitchDetectorModule, NSObject) 12 | 13 | + (BOOL)requiresMainQueueSetup 14 | { 15 | return NO; 16 | } 17 | 18 | RCT_EXTERN_METHOD(supportedEvents) 19 | 20 | RCT_EXTERN_METHOD(startObserving) 21 | 22 | RCT_EXTERN_METHOD(stopObserving) 23 | 24 | 25 | RCT_EXTERN_METHOD( 26 | start: (NSDictionary *)server 27 | resolve: (RCTPromiseResolveBlock)resolve 28 | reject: (RCTPromiseRejectBlock)reject 29 | ) 30 | 31 | RCT_EXTERN_METHOD(stop:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) 32 | 33 | RCT_EXTERN_METHOD(isRecording:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /ios/PitchDetector/Processors/BaseProcessor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BaseProcessor.swift 3 | // PitchDetector 4 | // 5 | // Created by Fábio Pereira on 03/04/23. 6 | // Copyright © 2023 PitchDetector. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Beethoven 11 | import Pitchy 12 | import AVFAudio 13 | 14 | class BaseProcessor: PitchEngineDelegate { 15 | private var processor: PitchEngine? 16 | 17 | func pitchEngine(_ pitchEngine: PitchEngine, didReceivePitch pitch: Pitch) { 18 | let regex = try! NSRegularExpression(pattern: "[0-9]{1,2}", options: NSRegularExpression.Options.caseInsensitive) 19 | let range = NSMakeRange(0, pitch.note.string.count) 20 | 21 | let tone = regex.stringByReplacingMatches(in: pitch.note.string, range: range, withTemplate: "") 22 | let frequency = pitch.frequency 23 | 24 | var data = Dictionary() 25 | data["tone"] = tone 26 | data["frequency"] = frequency 27 | 28 | EventEmitterUtils.shared.dispatch(Events.DATA, data) 29 | } 30 | 31 | func prepare(_ config: Dictionary) { 32 | let bufferSize = config["bufferSize"] as! Int 33 | let algorithm = AlgorithmUtils.parse(for: config["algorithm"] as! String) 34 | 35 | let config = Config(bufferSize: AVAudioFrameCount(bufferSize), estimationStrategy: algorithm) 36 | processor = PitchEngine(config: config, delegate: self) 37 | processor?.levelThreshold = -30.0 38 | } 39 | 40 | func start(_ config: Dictionary) { 41 | prepare(config) 42 | 43 | if ((processor?.active) != nil && !processor!.active) { 44 | processor?.start() 45 | } 46 | } 47 | 48 | func stop() { 49 | if ((processor?.active) != nil) { 50 | processor?.stop() 51 | } 52 | } 53 | 54 | func pitchEngine(_ pitchEngine: PitchEngine, didReceiveError error: Error) { 55 | print(error) 56 | } 57 | 58 | public func pitchEngineWentBelowLevelThreshold(_ pitchEngine: PitchEngine) { 59 | print("Below level threshold") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ios/PitchDetector/Utils/AlgorithmsUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlgorithmsUtils.swift 3 | // PitchDetector 4 | // 5 | // Created by Fabio Pereira on 04/04/23. 6 | // Copyright © 2023 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Beethoven 11 | 12 | class AlgorithmUtils { 13 | static func parse(for algorithm: String) -> EstimationStrategy { 14 | switch algorithm { 15 | case "MAX_VALUE": return .maxValue 16 | case "QUADRADIC": return .quadradic 17 | case "BARYCENTRIC": return .barycentric 18 | case "QUINNS_FIRST": return .quinnsFirst 19 | case "QUINNS_SECONDARY": return .quinnsSecond 20 | case "JAINS": return .jains 21 | case "HPS": return .hps 22 | case "YIN": return .yin 23 | default: return .yin 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ios/PitchDetector/Utils/EventEmitterUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EventEmitterUtils.swift 3 | // PitchDetector 4 | // 5 | // Created by Fabio Pereira on 04/04/23. 6 | // Copyright © 2023 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum Events: String, CaseIterable { 12 | case DATA = "data" 13 | } 14 | 15 | class EventEmitterUtils { 16 | public static let shared = EventEmitterUtils() 17 | private static var rctEventEmitter: RCTEventEmitter! 18 | private var suspended = true 19 | 20 | private init() {} 21 | 22 | func register(withRCTEventEmitter: RCTEventEmitter) { 23 | Self.rctEventEmitter = withRCTEventEmitter 24 | } 25 | 26 | func suspend() { 27 | suspended = true 28 | } 29 | 30 | func restore() { 31 | suspended = false 32 | } 33 | 34 | func dispatch(_ event: Events, _ body: Any? = nil) { 35 | if suspended { 36 | return 37 | } 38 | 39 | Self.rctEventEmitter.sendEvent(withName: event.rawValue, body: body) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ios/PitchDetector/Utils/PromiseUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PromiseUtils.swift 3 | // PitchDetector 4 | // 5 | // Created by Fábio Pereira on 03/04/23. 6 | // Copyright © 2023 PitchDetector. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class PromiseUtils { 12 | private var resolver: RCTPromiseResolveBlock? 13 | private var rejecter: RCTPromiseRejectBlock? 14 | 15 | init(_ resolver: @escaping RCTPromiseResolveBlock, _ rejecter: @escaping RCTPromiseRejectBlock) { 16 | self.resolver = resolver 17 | self.rejecter = rejecter 18 | } 19 | 20 | func resolve(_ result: Any?) -> Void { 21 | resolver!(result) 22 | } 23 | 24 | func reject(_ error: NSError) -> Void { 25 | rejecter!(error.domain, String(error.code), nil) 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from 'jest'; 2 | 3 | const config: Config = { 4 | preset: 'react-native', 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], 6 | transformIgnorePatterns: ['./node_modules/(?!@react-native|react-native)'], 7 | setupFiles: ['/.jest/jest.setup.ts'], 8 | modulePathIgnorePatterns: [ 9 | '/example/node_modules', 10 | '/lib/', 11 | ], 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /lefthook.yml: -------------------------------------------------------------------------------- 1 | pre-commit: 2 | parallel: true 3 | commands: 4 | lint: 5 | files: git diff --name-only @{push} 6 | glob: "*.{js,ts,jsx,tsx}" 7 | run: npx eslint {files} 8 | 9 | types: 10 | files: git diff --name-only @{push} 11 | glob: "*.{js,ts, jsx, tsx}" 12 | run: npx tsc --noEmit 13 | 14 | circular: 15 | files: git diff --name-only @{push} 16 | glob: "*.{js,ts, jsx, tsx}" 17 | run: npx madge --circular src/index.ts --no-spinner --warning 18 | 19 | commit-msg: 20 | parallel: true 21 | commands: 22 | commitlint: 23 | run: npx commitlint --edit 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pitch-detector", 3 | "version": "0.1.6", 4 | "description": "High performance real time pitch detection.", 5 | "main": "lib/commonjs/index", 6 | "module": "lib/module/index", 7 | "types": "lib/typescript/index.d.ts", 8 | "react-native": "src/index", 9 | "source": "src/index", 10 | "scripts": { 11 | "test": "jest --coverage --detectOpenHandles --silent", 12 | "typecheck": "tsc --noEmit", 13 | "lint": "eslint \"**/*.{js,ts,tsx}\"", 14 | "prepack": "bob build", 15 | "release": "release-it", 16 | "example": "yarn --cwd example", 17 | "bootstrap": "yarn example && yarn install && yarn example pods", 18 | "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build", 19 | "sonar": "sonar-scanner -Dsonar.host.url=https://sonarcloud.io", 20 | "circular": "madge --circular src/index.ts --no-spinner --warning" 21 | }, 22 | "keywords": [ 23 | "react-native", 24 | "ios", 25 | "android" 26 | ], 27 | "repository": "https://github.com/1fabiopereira/react-native-pitch-detector", 28 | "author": "Fábio Pereira (https://github.com/1fabiopereira)", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/1fabiopereira/react-native-pitch-detector/issues" 32 | }, 33 | "homepage": "https://github.com/1fabiopereira/react-native-pitch-detector#readme", 34 | "publishConfig": { 35 | "registry": "https://registry.npmjs.org/" 36 | }, 37 | "devDependencies": { 38 | "@commitlint/config-conventional": "^17.0.2", 39 | "@evilmartians/lefthook": "^1.2.2", 40 | "@react-native-community/eslint-config": "^3.0.2", 41 | "@release-it/conventional-changelog": "^5.0.0", 42 | "@types/jest": "^28.1.2", 43 | "@types/react": "~17.0.21", 44 | "@types/react-native": "0.70.0", 45 | "commitlint": "^17.0.2", 46 | "del-cli": "^5.0.0", 47 | "eslint": "^8.4.1", 48 | "eslint-config-prettier": "^8.5.0", 49 | "eslint-plugin-prettier": "^4.0.0", 50 | "jest": "^28.1.1", 51 | "madge": "^6.0.0", 52 | "pod-install": "^0.1.0", 53 | "prettier": "^2.0.5", 54 | "react": "18.2.0", 55 | "react-native": "0.71.5", 56 | "react-native-builder-bob": "^0.20.0", 57 | "release-it": "^15.0.0", 58 | "sonar-scanner": "^3.1.0", 59 | "ts-node": "^10.9.1", 60 | "typescript": "^4.5.2" 61 | }, 62 | "resolutions": { 63 | "@types/react": "17.0.21" 64 | }, 65 | "peerDependencies": { 66 | "react": "*", 67 | "react-native": "*", 68 | "react-native-permissions": "*" 69 | }, 70 | "engines": { 71 | "node": ">= 16.0.0" 72 | }, 73 | "commitlint": { 74 | "extends": [ 75 | "@commitlint/config-conventional" 76 | ] 77 | }, 78 | "release-it": { 79 | "git": { 80 | "commitMessage": "chore: release ${version}", 81 | "tagName": "v${version}" 82 | }, 83 | "npm": { 84 | "publish": true 85 | }, 86 | "github": { 87 | "release": true 88 | }, 89 | "plugins": { 90 | "@release-it/conventional-changelog": { 91 | "preset": "angular" 92 | } 93 | } 94 | }, 95 | "eslintConfig": { 96 | "root": true, 97 | "extends": [ 98 | "@react-native-community", 99 | "prettier" 100 | ], 101 | "rules": { 102 | "prettier/prettier": [ 103 | "error", 104 | { 105 | "quoteProps": "consistent", 106 | "singleQuote": true, 107 | "tabWidth": 2, 108 | "trailingComma": "es5", 109 | "useTabs": false 110 | } 111 | ] 112 | } 113 | }, 114 | "eslintIgnore": [ 115 | "node_modules/", 116 | "lib/" 117 | ], 118 | "prettier": { 119 | "quoteProps": "consistent", 120 | "singleQuote": true, 121 | "tabWidth": 2, 122 | "trailingComma": "es5", 123 | "useTabs": false 124 | }, 125 | "react-native-builder-bob": { 126 | "source": "src", 127 | "output": "lib", 128 | "targets": [ 129 | "commonjs", 130 | "module", 131 | [ 132 | "typescript", 133 | { 134 | "project": "tsconfig.build.json" 135 | } 136 | ] 137 | ] 138 | }, 139 | "dependencies": { 140 | "react-native-permissions": "^3.8.0" 141 | } 142 | } -------------------------------------------------------------------------------- /react-native-pitch-detector.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' 5 | 6 | Pod::Spec.new do |s| 7 | s.name = package["name"] 8 | s.version = package["version"] 9 | s.summary = package["description"] 10 | s.homepage = package["homepage"] 11 | s.license = package["license"] 12 | s.authors = package["author"] 13 | 14 | s.platforms = { :ios => "12.0" } 15 | s.source = { :git => "https://github.com/1fabiopereira/react-native-pitch-detector.git", :tag => "#{s.version}" } 16 | 17 | s.source_files = "ios/**/*.{h,m,mm,swift}" 18 | 19 | s.dependency "React-Core" 20 | s.dependency "Beethoven" 21 | 22 | # Don't install the dependencies when we run `pod install` in the old architecture. 23 | if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then 24 | s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1" 25 | s.pod_target_xcconfig = { 26 | "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"", 27 | "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1", 28 | "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" 29 | } 30 | s.dependency "React-Codegen" 31 | s.dependency "RCT-Folly" 32 | s.dependency "RCTRequired" 33 | s.dependency "RCTTypeSafety" 34 | s.dependency "ReactCommon/turbomodule/core" 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /scripts/bootstrap.js: -------------------------------------------------------------------------------- 1 | const os = require('os'); 2 | const path = require('path'); 3 | const child_process = require('child_process'); 4 | 5 | const root = path.resolve(__dirname, '..'); 6 | const args = process.argv.slice(2); 7 | const options = { 8 | cwd: process.cwd(), 9 | env: process.env, 10 | stdio: 'inherit', 11 | encoding: 'utf-8', 12 | }; 13 | 14 | if (os.type() === 'Windows_NT') { 15 | options.shell = true; 16 | } 17 | 18 | let result; 19 | 20 | if (process.cwd() !== root || args.length) { 21 | // We're not in the root of the project, or additional arguments were passed 22 | // In this case, forward the command to `yarn` 23 | result = child_process.spawnSync('yarn', args, options); 24 | } else { 25 | // If `yarn` is run without arguments, perform bootstrap 26 | result = child_process.spawnSync('yarn', ['bootstrap'], options); 27 | } 28 | 29 | process.exitCode = result.status; 30 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.organization=code-leak 2 | sonar.projectKey=code-leak_react-native-pitch-detector 3 | sonar.projectName=react-native-pitch-detector 4 | sonar.sourceEncoding=UTF-8 5 | sonar.inclusions=src/** 6 | sonar.exclusions=**/__mocks__/**,**/__tests__/**,**/*.test.ts,**/*.test.tsx 7 | sonar.typescript.tsconfigPath=tsconfig.json 8 | sonar.javascript.lcov.reportPaths="coverage/lcov.info" -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './internal/pitch-detector'; 2 | -------------------------------------------------------------------------------- /src/internal/erros/__tests__/errors.spec.ts: -------------------------------------------------------------------------------- 1 | import { PitchDetectorErrors } from '../../../types'; 2 | import { PitchDetectorError } from '..'; 3 | 4 | describe('Errors', () => { 5 | it('should create base error', () => { 6 | const error: any = new PitchDetectorError(PitchDetectorErrors.BASE); 7 | 8 | expect(error?.message).toMatch(/You are not using Expo Go/); 9 | expect(error?.message).toMatch( 10 | /You rebuilt the app after installing the package/ 11 | ); 12 | }); 13 | 14 | it('should create link error', () => { 15 | const error: any = new PitchDetectorError( 16 | PitchDetectorErrors.LINKING_ERROR 17 | ); 18 | 19 | expect(error?.message).toMatch(/doesn't seem to be linked/); 20 | }); 21 | 22 | it('should create permission error', () => { 23 | const error: any = new PitchDetectorError( 24 | PitchDetectorErrors.PERMISSIONS_ERROR 25 | ); 26 | 27 | expect(error?.message).toMatch(/need audio record permission/); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/internal/erros/index.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native'; 2 | import { PitchDetectorErrors } from '../../types'; 3 | 4 | const base = 5 | `The package 'react-native-pitch-detector' find a error. Make sure: \n\n` + 6 | '- You rebuilt the app after installing the package\n' + 7 | '- You are not using Expo Go\n'; 8 | 9 | const linking = 10 | `The package 'react-native-pitch-detector' doesn't seem to be linked. Make sure: \n\n` + 11 | Platform.select({ 12 | ios: "- You have run 'pod install'\n", 13 | android: '', 14 | }) + 15 | '- You rebuilt the app after installing the package\n' + 16 | '- You are not using Expo Go\n'; 17 | 18 | const permission = 19 | `The package 'react-native-pitch-detector' need audio record permission. Make sure: \n\n` + 20 | Platform.select({ 21 | ios: '- You have added Microphone access permission before start record.', 22 | android: `- You have added '' on AndroidManifest.xml and request permission before start record.\n`, 23 | }); 24 | 25 | export class PitchDetectorError { 26 | constructor(type: PitchDetectorErrors) { 27 | if (type === PitchDetectorErrors.LINKING_ERROR) { 28 | return new Error(linking); 29 | } 30 | 31 | if (type === PitchDetectorErrors.PERMISSIONS_ERROR) { 32 | return new Error(permission); 33 | } 34 | 35 | return new Error(base); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/internal/permissions/__tests__/permissions.spec.ts: -------------------------------------------------------------------------------- 1 | import { PermissionStatus } from 'react-native-permissions'; 2 | import { 3 | isBlocked, 4 | isDenied, 5 | isGranted, 6 | isLimited, 7 | isUnavailable, 8 | } from '../../permissions'; 9 | 10 | describe('Permissions', () => { 11 | it.each([ 12 | ['isBlocked', 'blocked', true, isBlocked], 13 | ['isDenied', 'denied', true, isDenied], 14 | ['isGranted', 'granted', true, isGranted], 15 | ['isLimited', 'limited', true, isLimited], 16 | ['isUnavailable', 'unavailable', true, isUnavailable], 17 | ])( 18 | 'should call %s function and return %s', 19 | ( 20 | _: string, 21 | params: any, 22 | expected: boolean, 23 | fn: (status: PermissionStatus) => boolean 24 | ) => { 25 | const result = fn(params); 26 | 27 | expect(result).toBe(expected); 28 | } 29 | ); 30 | }); 31 | -------------------------------------------------------------------------------- /src/internal/permissions/factory/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | check, 3 | Permission, 4 | Rationale, 5 | request, 6 | RESULTS, 7 | } from 'react-native-permissions'; 8 | 9 | import type { Comparable, PermissionsHandlers, Response } from '../../../types'; 10 | 11 | const BLOCKED = 'Permission is denied and not requestable anymore'; 12 | const DENIED = "Permission hasn't been requested / is denied but requestable"; 13 | const GRANTED = 'Permission is granted'; 14 | const LIMITED = 'Permission is limited: some actions are possible'; 15 | const UNAVAILABLE = 'This feature is not available.'; 16 | 17 | const MESSAGES = new Map([ 18 | [RESULTS.BLOCKED, BLOCKED], 19 | [RESULTS.DENIED, DENIED], 20 | [RESULTS.GRANTED, GRANTED], 21 | [RESULTS.LIMITED, LIMITED], 22 | [RESULTS.UNAVAILABLE, UNAVAILABLE], 23 | ]); 24 | 25 | export default ( 26 | targetPermission: Permission, 27 | TAG: string 28 | ): PermissionsHandlers => { 29 | const CheckPermission = async (compare?: Comparable): Response => { 30 | try { 31 | const result = await check(targetPermission); 32 | console.log(TAG, MESSAGES.get(result)); 33 | return compare ? compare(result) : result; 34 | } catch (error: any) { 35 | console.log(TAG, error.message); 36 | return null; 37 | } 38 | }; 39 | 40 | const RequestPermission = async ( 41 | rationale?: Rationale, 42 | compare?: Comparable 43 | ): Response => { 44 | try { 45 | const result = await request(targetPermission, rationale); 46 | console.log(TAG, MESSAGES.get(result)); 47 | return compare ? compare(result) : result; 48 | } catch (error: any) { 49 | console.log(TAG, error.message); 50 | return null; 51 | } 52 | }; 53 | 54 | return { CheckPermission, RequestPermission }; 55 | }; 56 | -------------------------------------------------------------------------------- /src/internal/permissions/index.ts: -------------------------------------------------------------------------------- 1 | import { Platform } from 'react-native'; 2 | import { 3 | PERMISSIONS, 4 | Permission, 5 | PermissionStatus, 6 | RESULTS, 7 | } from 'react-native-permissions'; 8 | 9 | import Factory from './factory'; 10 | 11 | export const isDenied = (status: PermissionStatus) => status === RESULTS.DENIED; 12 | 13 | export const isGranted = (status: PermissionStatus) => 14 | status === RESULTS.GRANTED; 15 | 16 | export const isBlocked = (status: PermissionStatus) => 17 | status === RESULTS.BLOCKED; 18 | 19 | export const isLimited = (status: PermissionStatus) => 20 | status === RESULTS.LIMITED; 21 | 22 | export const isUnavailable = (status: PermissionStatus) => 23 | status === RESULTS.UNAVAILABLE; 24 | 25 | export class Permissions { 26 | static async audio() { 27 | const MICROPHONE_PERMISSION = Platform.select({ 28 | android: PERMISSIONS.ANDROID.RECORD_AUDIO, 29 | ios: PERMISSIONS.IOS.MICROPHONE, 30 | }) as Permission; 31 | 32 | const rationale = { 33 | title: 'Acesso ao microfone', 34 | message: 'Para que possamos executar', 35 | buttonPositive: 'Permitir', 36 | buttonNegative: 'Negar', 37 | }; 38 | 39 | const audio = Factory(MICROPHONE_PERMISSION, 'AUDIO PERMISSION:'); 40 | 41 | const denied = await audio.CheckPermission(isDenied); 42 | const blocked = await audio.CheckPermission(isBlocked); 43 | 44 | if (denied || blocked) { 45 | return await audio.RequestPermission(rationale, isGranted); 46 | } 47 | 48 | return await audio.CheckPermission(isGranted); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/internal/pitch-detector/__tests__/pitch-detector.spec.ts: -------------------------------------------------------------------------------- 1 | import { NativeModules } from 'react-native'; 2 | 3 | import { PitchDetectorErrors } from '../../../types'; 4 | import { PitchDetectorError } from '../../erros'; 5 | 6 | import { Permissions } from '../../permissions'; 7 | import { PitchDetector } from '..'; 8 | 9 | const Module = NativeModules.PitchDetectorModule; 10 | const asyncMock = (value: T) => jest.fn().mockResolvedValue(value); 11 | const asyncMockThrow = (error: T) => 12 | jest.fn().mockImplementation(() => { 13 | throw error; 14 | }); 15 | 16 | describe('PitchDetector', () => { 17 | beforeEach(() => jest.clearAllMocks()); 18 | 19 | it.each([ 20 | ['start', 1], 21 | ['isRecording', 1], 22 | ['stop', 1], 23 | ])( 24 | 'should call %s method %s time(s) from native module', 25 | async (method: string, times: number) => { 26 | const spy = jest.spyOn(Module, method as any); 27 | 28 | await Object(PitchDetector)[method](); 29 | 30 | expect(spy).toBeCalledTimes(times); 31 | } 32 | ); 33 | 34 | it.each([ 35 | ['hasPermissions', 'start'], 36 | ['getDefaultConfig', 'start'], 37 | ])( 38 | 'should call %s method when %s method will be called', 39 | async (target: string, method: string) => { 40 | const spy = jest.spyOn(PitchDetector, target as any); 41 | 42 | await Object(PitchDetector)[method](); 43 | 44 | expect(spy).toBeCalledTimes(1); 45 | } 46 | ); 47 | 48 | it('should call audio permission method when start method will be called', async () => { 49 | const spy = jest.spyOn(Permissions, 'audio'); 50 | 51 | await PitchDetector.start(); 52 | 53 | expect(spy).toBeCalledTimes(1); 54 | }); 55 | 56 | it('should throw error when start method will be called and not have audio record permission', async () => { 57 | const error = new PitchDetectorError(PitchDetectorErrors.PERMISSIONS_ERROR); 58 | const spy = jest.spyOn(console, 'warn'); 59 | 60 | Permissions.audio = asyncMock(false); 61 | await PitchDetector.start(); 62 | 63 | expect(spy).toBeCalledTimes(1); 64 | expect(spy).toHaveBeenCalledWith(error); 65 | }); 66 | 67 | it.each([ 68 | ['addListener', 'addListener'], 69 | ['removeAllListeners', 'removeAllListeners'], 70 | ['removeAllListeners', 'removeListener'], 71 | ])( 72 | 'should call %s method from event emitter when %s method will be called', 73 | async (target: string, method: string) => { 74 | const spy = jest.spyOn(Object(PitchDetector).event, target as any); 75 | 76 | await Object(PitchDetector)[method](1); 77 | 78 | expect(spy).toBeCalledTimes(1); 79 | } 80 | ); 81 | 82 | it.each([['start'], ['stop'], ['isRecording']])( 83 | 'should throw error when native %s method fail', 84 | async (method: string) => { 85 | const error = new Error('Some error message'); 86 | const spy = jest.spyOn(console, 'warn'); 87 | 88 | Permissions.audio = asyncMock(true); 89 | Object(PitchDetector).module[method] = asyncMockThrow(error); 90 | 91 | await Object(PitchDetector)[method](); 92 | 93 | expect(spy).toBeCalledTimes(1); 94 | expect(spy).toBeCalledWith(error); 95 | } 96 | ); 97 | }); 98 | -------------------------------------------------------------------------------- /src/internal/pitch-detector/index.ts: -------------------------------------------------------------------------------- 1 | import { NativeModules, NativeEventEmitter, Platform } from 'react-native'; 2 | import { Permissions } from '../permissions'; 3 | import { PitchDetectorError } from '../erros'; 4 | import { merge } from '../utils'; 5 | 6 | import { 7 | type Callback, 8 | type NativeModuleImplementation, 9 | type PitchDetectorConfig, 10 | type Subscription, 11 | type PitchDetectorAndroidConfig, 12 | type PitchDetectorIOSConfig, 13 | PitchDetectorErrors, 14 | } from '../../types'; 15 | 16 | export class InternalPitchDetector { 17 | private module?: NativeModuleImplementation; 18 | private event?: NativeEventEmitter; 19 | 20 | constructor() { 21 | this.module = NativeModules?.PitchDetectorModule; 22 | 23 | if (this.module) { 24 | this.event = new NativeEventEmitter(this.module); 25 | } else { 26 | /* istanbul ignore next */ 27 | throw new PitchDetectorError(PitchDetectorErrors.LINKING_ERROR); 28 | } 29 | } 30 | 31 | /** 32 | * Returns a default PitchDetector configs 33 | * @returns PitchDetectorConfig 34 | * @example 35 | * ```ts 36 | * { 37 | * android: { 38 | * algorithm: 'YIN', 39 | * bufferOverLap: 0, 40 | * bufferSize: 1024, 41 | * sampleRate: 22050, 42 | * }, 43 | * ios: { 44 | * algorithm: 'YIN', 45 | * bufferSize: 1024, 46 | * } 47 | * } 48 | */ 49 | private getDefaultConfig(): PitchDetectorConfig { 50 | return { 51 | android: { 52 | algorithm: 'YIN', 53 | bufferOverLap: 0, 54 | bufferSize: 1024, 55 | sampleRate: 22050, 56 | }, 57 | ios: { 58 | algorithm: 'YIN', 59 | bufferSize: 1024, 60 | }, 61 | }; 62 | } 63 | 64 | /** 65 | * Get current audio permission 66 | * @returns Promise 67 | */ 68 | private async hasPermissions(): Promise { 69 | return !!(await Permissions.audio()); 70 | } 71 | 72 | /** 73 | * Get current status 74 | * @returns Promise 75 | */ 76 | async isRecording(): Promise { 77 | try { 78 | const status = await this.module?.isRecording(); 79 | return !!status; 80 | } catch (err) { 81 | console.warn(err); 82 | return false; 83 | } 84 | } 85 | 86 | /** 87 | * Trigger audio recording and pitch detection with provided configs 88 | * @param config 89 | * @returns Promise 90 | */ 91 | async start(config?: PitchDetectorConfig): Promise { 92 | try { 93 | const permission = await this.hasPermissions(); 94 | 95 | if (!permission) { 96 | throw new PitchDetectorError(PitchDetectorErrors.PERMISSIONS_ERROR); 97 | } 98 | 99 | const configuration = merge( 100 | this.getDefaultConfig(), 101 | config ?? {} 102 | ); 103 | 104 | const params = Platform.select({ 105 | android: configuration.android as unknown, 106 | ios: configuration.ios as unknown, 107 | }) as PitchDetectorIOSConfig | PitchDetectorAndroidConfig; 108 | 109 | await this.module?.start(params); 110 | } catch (err: unknown) { 111 | console.warn(err); 112 | } 113 | } 114 | 115 | /** 116 | * Stop audio recording and pitch detection 117 | * @returns Promise 118 | */ 119 | async stop(): Promise { 120 | try { 121 | await this.module?.stop(); 122 | } catch (err: unknown) { 123 | console.warn(err); 124 | } 125 | } 126 | 127 | /** 128 | * Register a event listener 129 | */ 130 | addListener(callback: Callback): Subscription { 131 | return this.event?.addListener('data', callback); 132 | } 133 | 134 | /** 135 | * Method event listeners 136 | * @alias removeAllListeners 137 | */ 138 | removeListener(): void { 139 | this.event?.removeAllListeners('data'); 140 | } 141 | 142 | /** 143 | * Method remove all event listeners 144 | */ 145 | removeAllListeners(): void { 146 | this.event?.removeAllListeners('data'); 147 | } 148 | } 149 | 150 | /** 151 | * Export an instance of InternalPitchDetector 152 | */ 153 | export const PitchDetector = new InternalPitchDetector(); 154 | -------------------------------------------------------------------------------- /src/internal/utils/__tests__/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { isObject, merge } from '..'; 2 | 3 | describe('Utils', () => { 4 | it.each([ 5 | [false, 'array', []], 6 | [false, 'NaN', NaN], 7 | [false, 'number', 10], 8 | [false, 'symbol', Symbol()], 9 | [false, 'date', new Date()], 10 | [true, 'object', {}], 11 | ])( 12 | 'should return %s when isObject function will be called with %s', 13 | (expected: boolean, _: string, params: any) => { 14 | const result = isObject(params); 15 | expect(result).toBe(expected); 16 | } 17 | ); 18 | 19 | it('should not merge when one params is not object', () => { 20 | const result = merge({ name: 'Fábio' }, NaN); 21 | 22 | expect(result).toHaveProperty('name'); 23 | }); 24 | 25 | it('should merge two complex object', () => { 26 | const obj1 = { 27 | person: { 28 | name: 'Fábio', 29 | address: { 30 | street: { name: 'Street name', number: 'Street number' }, 31 | city: { name: 'City name' }, 32 | }, 33 | }, 34 | }; 35 | 36 | const obj2 = { 37 | person: { 38 | age: 29, 39 | address: { 40 | city: { postalCode: 1212000, name: 'City name 2' }, 41 | coords: { 42 | lat: 0, 43 | lgn: 0, 44 | }, 45 | }, 46 | }, 47 | }; 48 | 49 | const result: any = merge(obj1, obj2); 50 | 51 | expect(result.person).toHaveProperty('name'); 52 | expect(result.person).toHaveProperty('age'); 53 | 54 | expect(result.person.address.street).toHaveProperty('name'); 55 | expect(result.person.address.street).toHaveProperty('number'); 56 | 57 | expect(result.person.address.city).toHaveProperty('name'); 58 | expect(result.person.address.city).toHaveProperty('postalCode'); 59 | 60 | expect(result.person.address.coords).toHaveProperty('lat'); 61 | expect(result.person.address.coords).toHaveProperty('lgn'); 62 | 63 | expect(result.person.address.city.name).toBe(obj2.person.address.city.name); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /src/internal/utils/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple object check. 3 | * @param item 4 | * @returns {boolean} 5 | */ 6 | export function isObject(item: any) { 7 | return Boolean( 8 | item && 9 | typeof item === 'object' && 10 | !Array.isArray(item) && 11 | !(item instanceof Date) 12 | ); 13 | } 14 | 15 | /** 16 | * Deep merge two objects. 17 | * @param target 18 | * @param ...sources 19 | */ 20 | export function merge(target: any, ...sources: any): T { 21 | if (!sources.length) return target; 22 | const source = sources.shift(); 23 | 24 | if (isObject(target) && isObject(source)) { 25 | for (const key in source) { 26 | if (isObject(source[key])) { 27 | if (!target[key]) Object.assign(target, { [key]: {} }); 28 | merge(target[key], source[key]); 29 | } else { 30 | Object.assign(target, { [key]: source[key] }); 31 | } 32 | } 33 | } 34 | 35 | return merge(target, ...sources); 36 | } 37 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { NativeModule, EmitterSubscription } from 'react-native'; 2 | import type { Float, Int32 } from 'react-native/Libraries/Types/CodegenTypes'; 3 | import { PermissionStatus, Rationale } from 'react-native-permissions'; 4 | 5 | /** 6 | * Permission handler comparable callback 7 | */ 8 | export type Comparable = (status: PermissionStatus) => boolean; 9 | 10 | /** 11 | * Permission handler response 12 | */ 13 | export type Response = Promise; 14 | 15 | /** 16 | * Permission handler 17 | */ 18 | export type PermissionsHandlers = { 19 | /** 20 | * Request permission 21 | * @returns Promise 22 | */ 23 | RequestPermission: (rationale?: Rationale, compare?: Comparable) => Response; 24 | 25 | /** 26 | * Check permission 27 | * @returns Promise 28 | */ 29 | CheckPermission: (compare?: Comparable) => Response; 30 | }; 31 | 32 | export enum PitchDetectorErrors { 33 | BASE, 34 | LINKING_ERROR, 35 | PERMISSIONS_ERROR, 36 | } 37 | 38 | /** 39 | * Event emitter subscription 40 | */ 41 | export type Subscription = EmitterSubscription | undefined; 42 | 43 | /** 44 | * Available musical tones. 45 | * @see `https://en.wikipedia.org/wiki/Musical_tone` 46 | */ 47 | export type Tone = 48 | | 'C' 49 | | 'C#' 50 | | 'D' 51 | | 'D#' 52 | | 'E' 53 | | 'F' 54 | | 'F#' 55 | | 'G' 56 | | 'G#' 57 | | 'A' 58 | | 'A#' 59 | | 'B'; 60 | 61 | /** 62 | * Result generated by pitch estimation process. 63 | */ 64 | export type Data = { 65 | /** 66 | * Pitch frequency in hertz. 67 | */ 68 | frequency: Float; 69 | tone: Tone; 70 | }; 71 | 72 | /** 73 | * A callback function called by event emitted from native side. 74 | */ 75 | export type Callback = (data: Data) => void; 76 | 77 | /** 78 | * Available pitch estimation algorithm for Android. 79 | * @see `https://0110.be/releases/TarsosDSP/TarsosDSP-latest/TarsosDSP-latest-Documentation/` 80 | */ 81 | export type PitchEstimationAndroidAlgorithm = 82 | | 'AMDF' 83 | | 'DYNAMIC_WAVELET' 84 | | 'FFT_PITCH' 85 | | 'FFT_YIN' 86 | | 'MPM' 87 | | 'YIN'; 88 | 89 | /** 90 | * Available pitch estimation algorithm for IOS. 91 | * @see `https://github.com/vadymmarkov/Beethoven#configuration` 92 | */ 93 | export type PitchEstimationIOSAlgorithm = 94 | | 'BARYCENTRIC' 95 | | 'HPS' 96 | | 'JAINS' 97 | | 'MAX_VALUE' 98 | | 'QUADRACTIC' 99 | | 'QUINNS_FIRST' 100 | | 'QUINNS_SECOND' 101 | | 'YIN'; 102 | 103 | export type PitchDetectorAndroidConfig = { 104 | algorithm?: PitchEstimationAndroidAlgorithm; 105 | bufferOverLap?: Int32; 106 | bufferSize?: Int32; 107 | sampleRate?: Float; 108 | }; 109 | 110 | export type PitchDetectorIOSConfig = { 111 | algorithm?: PitchEstimationIOSAlgorithm; 112 | bufferSize?: Int32; 113 | }; 114 | 115 | /** 116 | * Pitch detector configuration. 117 | */ 118 | export type PitchDetectorConfig = { 119 | android?: PitchDetectorAndroidConfig; 120 | ios?: PitchDetectorIOSConfig; 121 | }; 122 | 123 | /** 124 | * PitchDetector native module interface 125 | */ 126 | export interface NativeModuleImplementation extends NativeModule { 127 | /** 128 | * Start audio recording and pitch detection with provided configs 129 | * @param config 130 | * @returns Promise 131 | */ 132 | start: ( 133 | config: PitchDetectorAndroidConfig | PitchDetectorIOSConfig 134 | ) => Promise; 135 | 136 | /** 137 | * Stop audio recording and pitch detection 138 | * @returns Promise 139 | */ 140 | stop: () => Promise; 141 | 142 | /** 143 | * Get current status 144 | * @returns Promise 145 | */ 146 | isRecording: () => Promise; 147 | } 148 | -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["example", "website", "jest.config.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "paths": { 5 | "react-native-pitch-detector": [ 6 | "./src/index" 7 | ] 8 | }, 9 | "allowUnreachableCode": false, 10 | "allowUnusedLabels": false, 11 | "esModuleInterop": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "jsx": "react", 14 | "lib": [ 15 | "esnext" 16 | ], 17 | "module": "esnext", 18 | "moduleResolution": "node", 19 | "noFallthroughCasesInSwitch": true, 20 | "noImplicitReturns": true, 21 | "noImplicitUseStrict": false, 22 | "noStrictGenericChecks": false, 23 | "noUncheckedIndexedAccess": true, 24 | "noUnusedLocals": true, 25 | "noUnusedParameters": true, 26 | "resolveJsonModule": true, 27 | "skipLibCheck": true, 28 | "strict": true, 29 | "target": "esnext" 30 | }, 31 | "exclude": [ 32 | "node_modules", 33 | "website" 34 | ] 35 | } -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/README.md: -------------------------------------------------------------------------------- 1 | # Website 2 | 3 | This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. 4 | 5 | ### Installation 6 | 7 | ``` 8 | $ yarn 9 | ``` 10 | 11 | ### Local Development 12 | 13 | ``` 14 | $ yarn start 15 | ``` 16 | 17 | This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. 18 | 19 | ### Build 20 | 21 | ``` 22 | $ yarn build 23 | ``` 24 | 25 | This command generates static content into the `build` directory and can be served using any static contents hosting service. 26 | 27 | ### Deployment 28 | 29 | Using SSH: 30 | 31 | ``` 32 | $ USE_SSH=true yarn deploy 33 | ``` 34 | 35 | Not using SSH: 36 | 37 | ``` 38 | $ GIT_USER= yarn deploy 39 | ``` 40 | 41 | If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch. 42 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/before-you-start.md: -------------------------------------------------------------------------------- 1 | # Before you start 2 | 3 | React Native Pitch Detector is a module created to be used alongside [React Native](https://github.com/facebook/react-native), so previous experience is required. If you need, can start with their [Getting Started](https://reactnative.dev/docs/getting-started) tutorial and come back here after. 4 | 5 | This module is compatible with Android and iOS devices, we assume that you have Android and iOS environment configured, in the case that you don't have, we suggest that you setup enviroment before. 6 | 7 | For android devices we use a [TarsosDSP](https://github.com/JorenSix/TarsosDSP) library to perform a pitch estimation and for iOS devices we use [Beethoven](https://github.com/vadymmarkov/Beethoven) library, you can see more about these on yours respectives documentations. 8 | 9 | If you see something wrong, feel free to report an issue on [Github](https://github.com/1fabiopereira/react-native-pitch-detector), pull requests are encouraged. Know more about it on [Contributing](https://1fabiopereira.github.io/react-native-pitch-detector/docs/contributing) session. 10 | 11 | :open_book: **TarsosDSP** - https://github.com/JorenSix/TarsosDSP 12 | 13 | :open_book: **Beethoven** - https://github.com/vadymmarkov/Beethoven 14 | 15 | -------------------------------------------------------------------------------- /website/docs/code-of-conduct.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | [translations]: https://www.contributor-covenant.org/translations 133 | -------------------------------------------------------------------------------- /website/docs/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are always welcome, no matter how large or small! 4 | 5 | We want this community to be friendly and respectful to each other. Please follow it in all your interactions with the project. Before contributing, please read the [code of conduct](./code-of-conduct.md). 6 | 7 | ## Development workflow 8 | 9 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: 10 | 11 | ```sh 12 | yarn 13 | ``` 14 | 15 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development. 16 | 17 | While developing, you can run the [example app](./playground.md) to test your changes. Any changes you make in your library's JavaScript code will be reflected in the example app without a rebuild. If you change any native code, then you'll need to rebuild the example app. 18 | 19 | To start the packager: 20 | 21 | ```sh 22 | yarn example start 23 | ``` 24 | 25 | To run the example app on Android: 26 | 27 | ```sh 28 | yarn example android 29 | ``` 30 | 31 | To run the example app on iOS: 32 | 33 | ```sh 34 | yarn example ios 35 | ``` 36 | 37 | Make sure your code passes TypeScript and ESLint. Run the following to verify: 38 | 39 | ```sh 40 | yarn typecheck 41 | yarn lint 42 | ``` 43 | 44 | To fix formatting errors, run the following: 45 | 46 | ```sh 47 | yarn lint --fix 48 | ``` 49 | 50 | Remember to add tests for your change if possible. Run the unit tests by: 51 | 52 | ```sh 53 | yarn test 54 | ``` 55 | 56 | To edit the Objective-C or Swift files, open `example/ios/PitchDetectorExample.xcworkspace` in XCode and find the source files at `Pods > Development Pods > react-native-pitch-detector`. 57 | 58 | To edit the Java or Kotlin files, open `example/android` in Android studio and find the source files at `react-native-pitch-detector` under `Android`. 59 | 60 | 61 | ### Commit message convention 62 | 63 | We follow the [conventional commits specification](https://www.conventionalcommits.org/en) for our commit messages: 64 | 65 | - `fix`: bug fixes, e.g. fix crash due to deprecated method. 66 | - `feat`: new features, e.g. add new method to the module. 67 | - `refactor`: code refactor, e.g. migrate from class components to hooks. 68 | - `docs`: changes into documentation, e.g. add usage example for the module.. 69 | - `test`: adding or updating tests, e.g. add integration tests using detox. 70 | - `chore`: tooling changes, e.g. change CI config. 71 | 72 | Our pre-commit hooks verify that your commit message matches this format when committing. 73 | 74 | ### Linting and tests 75 | 76 | [ESLint](https://eslint.org/), [Prettier](https://prettier.io/), [TypeScript](https://www.typescriptlang.org/) 77 | 78 | We use [TypeScript](https://www.typescriptlang.org/) for type checking, [ESLint](https://eslint.org/) with [Prettier](https://prettier.io/) for linting and formatting the code, and [Jest](https://jestjs.io/) for testing. 79 | 80 | Our pre-commit hooks verify that the linter and tests pass when committing. 81 | 82 | ### Publishing to npm 83 | 84 | We use [release-it](https://github.com/release-it/release-it) to make it easier to publish new versions. It handles common tasks like bumping version based on semver, creating tags and releases etc. 85 | 86 | To publish new versions, run the following: 87 | 88 | ```sh 89 | yarn release 90 | ``` 91 | 92 | ### Scripts 93 | 94 | The `package.json` file contains various scripts for common tasks: 95 | 96 | - `yarn bootstrap`: setup project by installing all dependencies and pods. 97 | - `yarn typecheck`: type-check files with TypeScript. 98 | - `yarn lint`: lint files with ESLint. 99 | - `yarn test`: run unit tests with Jest. 100 | - `yarn example start`: start the Metro server for the example app. 101 | - `yarn example android`: run the example app on Android. 102 | - `yarn example ios`: run the example app on iOS. 103 | 104 | ### Sending a pull request 105 | 106 | > **Working on your first pull request?** You can learn how from this _free_ series: [How to Contribute to an Open Source Project on GitHub](https://app.egghead.io/playlists/how-to-contribute-to-an-open-source-project-on-github). 107 | 108 | When you're sending a pull request: 109 | 110 | - Prefer small pull requests focused on one change. 111 | - Verify that linters and tests are passing. 112 | - Review the documentation to make sure it looks good. 113 | - Follow the pull request template when opening a pull request. 114 | - For pull requests that change the API or implementation, discuss with maintainers first by opening an issue. 115 | -------------------------------------------------------------------------------- /website/docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ```sh 4 | yarn add react-native-pitch-detector 5 | ``` 6 | 7 | Or using npm: 8 | 9 | ```sh 10 | npm install react-native-pitch-detector 11 | ``` 12 | 13 | ### iOS 14 | 15 | After install you need run: 16 | ```sh 17 | (cd ios && pod install) 18 | ``` 19 | 20 | ### Android 21 | 22 | > **Version compatibility**: `react-native@>=0.66` is required. 23 | 24 | -------------------------------------------------------------------------------- /website/docs/license.md: -------------------------------------------------------------------------------- 1 | # License 2 | 3 | MIT License 4 | 5 | Copyright (c) 2023 Fábio Pereira 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | 24 | 25 | -------------------------------------------------------------------------------- /website/docs/playground.md: -------------------------------------------------------------------------------- 1 | # Playground 2 | 3 | > :bulb: It is important to note that you need to use a real device to test the audio input. 4 | 5 | To get started with the project, run `yarn` in the root directory to install the required dependencies for each package: 6 | 7 | ```sh 8 | yarn 9 | ``` 10 | 11 | > While it's possible to use [`npm`](https://github.com/npm/cli), the tooling is built around [`yarn`](https://classic.yarnpkg.com/), so you'll have an easier time if you use `yarn` for development. 12 | 13 | To start the packager: 14 | 15 | ```shell 16 | yarn example start 17 | ``` 18 | 19 | To run the example app on Android: 20 | 21 | ```shell 22 | yarn example android 23 | ``` 24 | 25 | To run the example app on iOS: 26 | 27 | ```shell 28 | yarn example ios 29 | ``` 30 | 31 | > If all goes well you will see something like: 32 | 33 | > ![Stopped Example](../static/img/stopped.jpeg) 34 | > ![Stopped Example](../static/img/recording.jpeg) 35 | -------------------------------------------------------------------------------- /website/docs/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | ### API 4 | Below you can see small code snippet that shows how to import and use the main functions. 5 | 6 | ```ts 7 | import { PitchDetector } from 'react-native-pitch-detector'; 8 | 9 | // To start recording 10 | await PitchDetector.start(); // Promise 11 | 12 | // To stop recording 13 | await PitchDetector.stop(); // Promise 14 | 15 | // To get current status 16 | await PitchDetector.isRecording(); // Promise 17 | 18 | // To listener results 19 | const subscription = PitchDetector.addListener(console.log) // { frequency: 440.14782, tone: "C#" } 20 | 21 | // To stop listen results 22 | PitchDetector.removeListener() 23 | 24 | ``` 25 | 26 | > You can see a complete implementation at [Playground](./playground.md). 27 | 28 | ### Permissions 29 | To use microphone we need give permission to our app, for that we use a [react-native-permissions](https://github.com/zoontek/react-native-permissions) library. 30 | 31 | ```shell 32 | yarn add react-native-permissions@3 33 | ``` 34 | 35 | Or using npm: 36 | 37 | ```shell 38 | npm install react-native-permissions@3 39 | ``` 40 | 41 | After that, on `package.json` file add de following lines: 42 | 43 | ```json 44 | "reactNativePermissionsIOS": [ 45 | "Microphone" 46 | ] 47 | ``` 48 | 49 | For iOS you need edit `Info.plist`, add: 50 | 51 | ```xml 52 | NSMicrophoneUsageDescription 53 | Perform pitch detection 54 | ``` 55 | 56 | Lastly for iOS you need execute: 57 | 58 | ```shell 59 | (cd ios && pod install) 60 | ``` 61 | 62 | For Android you need change `AndroidManifest.xml`, and add: 63 | 64 | ```xml 65 | 66 | ``` 67 | 68 | and finally recompile your project both platforms. 69 | 70 | > :bulb: In future the idea is remove react-native-permission dependency and develop in house permission manager. 71 | 72 | 73 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Note: type annotations allow type checking and IDEs autocompletion 3 | 4 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 5 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 6 | 7 | /** @type {import('@docusaurus/types').Config} */ 8 | const config = { 9 | title: 'React Native Pitch Detector', 10 | staticDirectories: ['static'], 11 | tagline: 'High performance real time pitch detection.', 12 | url: 'https://1fabiopereira.github.io/', 13 | baseUrl: '/react-native-pitch-detector/', 14 | onBrokenLinks: 'throw', 15 | onBrokenMarkdownLinks: 'warn', 16 | favicon: 'img/favicon.ico', 17 | 18 | // GitHub pages deployment config. 19 | // If you aren't using GitHub pages, you don't need these. 20 | organizationName: '1fabiopereira', // Usually your GitHub org/user name. 21 | projectName: 'react-native-pitch-detector', // Usually your repo name. 22 | trailingSlash: false, 23 | 24 | // Even if you don't use internalization, you can use this field to set useful 25 | // metadata like html lang. For example, if your site is Chinese, you may want 26 | // to replace "en" with "zh-Hans". 27 | i18n: { 28 | defaultLocale: 'en', 29 | locales: ['en'], 30 | }, 31 | 32 | presets: [ 33 | [ 34 | 'classic', 35 | /** @type {import('@docusaurus/preset-classic').Options} */ 36 | ({ 37 | docs: { 38 | sidebarPath: require.resolve('./sidebars.js'), 39 | editCurrentVersion: true, 40 | editUrl: 41 | 'https://github.com/1fabiopereira/react-native-pitch-detector/edit/master/website', 42 | }, 43 | theme: { 44 | customCss: require.resolve('./src/css/custom.css'), 45 | }, 46 | }), 47 | ], 48 | ], 49 | 50 | themeConfig: 51 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 52 | ({ 53 | navbar: { 54 | title: 'React Native Pitch Detector', 55 | logo: { 56 | alt: 'React Native Pitch Detector', 57 | src: 'img/react-native-pitch-detector.svg', 58 | }, 59 | items: [ 60 | { 61 | type: 'doc', 62 | docId: 'before-you-start', 63 | position: 'left', 64 | label: 'Docs', 65 | }, 66 | { 67 | href: 'https://github.com/1fabiopereira/react-native-pitch-detector', 68 | label: 'GitHub', 69 | position: 'right', 70 | }, 71 | ], 72 | }, 73 | footer: { 74 | style: 'dark', 75 | links: [ 76 | { 77 | title: 'Docs', 78 | items: [ 79 | { 80 | label: 'Docs', 81 | to: '/docs/before-you-start', 82 | }, 83 | ], 84 | }, 85 | ], 86 | copyright: `Copyright © ${new Date().getFullYear()} Fábio Pereira.`, 87 | }, 88 | prism: { 89 | theme: lightCodeTheme, 90 | darkTheme: darkCodeTheme, 91 | }, 92 | }), 93 | }; 94 | 95 | module.exports = config; 96 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-pitch-detector-docs", 3 | "version": "0.1.2", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "typecheck": "tsc" 16 | }, 17 | "dependencies": { 18 | "@docusaurus/core": "2.0.0-beta.21", 19 | "@docusaurus/preset-classic": "2.0.0-beta.21", 20 | "@mdx-js/react": "^1.6.22", 21 | "clsx": "^1.1.1", 22 | "prism-react-renderer": "^1.3.3", 23 | "react-dom": "^17.0.2", 24 | "react": "^17.0.2" 25 | }, 26 | "devDependencies": { 27 | "@docusaurus/module-type-aliases": "2.0.0-beta.21", 28 | "@tsconfig/docusaurus": "^1.0.5", 29 | "typescript": "^4.6.4" 30 | }, 31 | "browserslist": { 32 | "production": [ 33 | ">0.5%", 34 | "not dead", 35 | "not op_mini all" 36 | ], 37 | "development": [ 38 | "last 1 chrome version", 39 | "last 1 firefox version", 40 | "last 1 safari version" 41 | ] 42 | } 43 | } -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | // tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | tutorialSidebar: [ 21 | { 22 | collapsible: false, 23 | type: 'category', 24 | label: 'Getting Started', 25 | items: ['before-you-start', 'installation', 'usage', 'playground'], 26 | }, 27 | { 28 | collapsible: false, 29 | type: 'category', 30 | label: 'Meta', 31 | items: ['contributing', 'code-of-conduct', 'license'], 32 | }, 33 | ], 34 | }; 35 | 36 | module.exports = sidebars; 37 | -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import styles from './styles.module.css'; 4 | 5 | type FeatureItem = { 6 | title: string; 7 | Svg: React.ComponentType>; 8 | description: JSX.Element; 9 | }; 10 | 11 | const FeatureList: FeatureItem[] = [ 12 | { 13 | title: 'Easy to Use', 14 | Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, 15 | description: ( 16 | <> 17 | Docusaurus was designed from the ground up to be easily installed and 18 | used to get your website up and running quickly. 19 | 20 | ), 21 | }, 22 | { 23 | title: 'Focus on What Matters', 24 | Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, 25 | description: ( 26 | <> 27 | Docusaurus lets you focus on your docs, and we'll do the chores. Go 28 | ahead and move your docs into the docs directory. 29 | 30 | ), 31 | }, 32 | { 33 | title: 'Powered by React', 34 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, 35 | description: ( 36 | <> 37 | Extend or customize your website layout by reusing React. Docusaurus can 38 | be extended while reusing the same header and footer. 39 | 40 | ), 41 | }, 42 | ]; 43 | 44 | function Feature({ title, Svg, description }: FeatureItem) { 45 | return ( 46 |

47 |
48 | 49 |
50 |
51 |

{title}

52 |

{description}

53 |
54 |
55 | ); 56 | } 57 | 58 | export default function HomepageFeatures(): JSX.Element { 59 | return ( 60 |
61 |
62 |
63 | {FeatureList.map((props, idx) => ( 64 | 65 | ))} 66 |
67 |
68 |
69 | ); 70 | } 71 | -------------------------------------------------------------------------------- /website/src/components/HomepageFeatures/styles.module.css: -------------------------------------------------------------------------------- 1 | .features { 2 | display: flex; 3 | align-items: center; 4 | padding: 2rem 0; 5 | width: 100%; 6 | } 7 | 8 | .featureSvg { 9 | height: 200px; 10 | width: 200px; 11 | } 12 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #7d30a1; 10 | --ifm-color-primary-dark: #702b91; 11 | --ifm-color-primary-darker: #6a2989; 12 | --ifm-color-primary-darkest: #582271; 13 | --ifm-color-primary-light: #8a35b1; 14 | --ifm-color-primary-lighter: #9037b9; 15 | --ifm-color-primary-lightest: #9f47c8; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #ecb8ff; 23 | --ifm-color-primary-dark: #e08cff; 24 | --ifm-color-primary-darker: #da76ff; 25 | --ifm-color-primary-darkest: #c934ff; 26 | --ifm-color-primary-light: #f8e4ff; 27 | --ifm-color-primary-lighter: #fefaff; 28 | --ifm-color-primary-lightest: #ffffff; 29 | --ifm-code-font-size: 95%; 30 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 31 | } -------------------------------------------------------------------------------- /website/src/pages/index.module.css: -------------------------------------------------------------------------------- 1 | /** 2 | * CSS files with the .module.css suffix will be treated as CSS modules 3 | * and scoped locally. 4 | */ 5 | 6 | .heroBanner { 7 | padding: 4rem 0; 8 | text-align: center; 9 | position: relative; 10 | overflow: hidden; 11 | } 12 | 13 | @media screen and (max-width: 996px) { 14 | .heroBanner { 15 | padding: 2rem; 16 | } 17 | } 18 | 19 | .buttons { 20 | display: flex; 21 | align-items: center; 22 | justify-content: center; 23 | } 24 | -------------------------------------------------------------------------------- /website/src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import clsx from 'clsx'; 3 | import Link from '@docusaurus/Link'; 4 | import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; 5 | import Layout from '@theme/Layout'; 6 | 7 | import styles from './index.module.css'; 8 | 9 | function HomepageHeader() { 10 | const { siteConfig } = useDocusaurusContext(); 11 | return ( 12 |
13 |
14 |

🎸

15 |

{siteConfig.title}

16 |

{siteConfig.tagline}

17 |
18 | 22 | See docs 23 | 24 |
25 |
26 |
27 | ); 28 | } 29 | 30 | export default function Home(): JSX.Element { 31 | const { siteConfig } = useDocusaurusContext(); 32 | return ( 33 | 37 | 38 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /website/static/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/website/static/.nojekyll -------------------------------------------------------------------------------- /website/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/website/static/img/favicon.ico -------------------------------------------------------------------------------- /website/static/img/react-native-pitch-detector.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /website/static/img/recording.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/website/static/img/recording.jpeg -------------------------------------------------------------------------------- /website/static/img/stopped.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1fabiopereira/react-native-pitch-detector/127fb45dac647e7fe018f8be66b90e538141da71/website/static/img/stopped.jpeg -------------------------------------------------------------------------------- /website/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // This file is not used in compilation. It is here just for a nice editor experience. 3 | "extends": "@tsconfig/docusaurus/tsconfig.json", 4 | "compilerOptions": { 5 | "baseUrl": "." 6 | } 7 | } 8 | --------------------------------------------------------------------------------