{"id":14384875,"url":"https://github.com/rakannimer/react-orchestra","last_synced_at":"2025-03-25T04:32:01.524Z","repository":{"id":15179306,"uuid":"76926574","full_name":"rakannimer/react-orchestra","owner":"rakannimer","description":"A declarative toolbox to build interactive musical instruments on web and mobile.","archived":false,"fork":false,"pushed_at":"2022-10-06T00:57:11.000Z","size":16419,"stargazers_count":75,"open_issues_count":71,"forks_count":20,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-08-29T18:36:11.163Z","etag":null,"topics":["instrument","javascript","music","music-composition","music-theory","music-theory-apps","orchestra","react","react-native"],"latest_commit_sha":null,"homepage":"http://react-orchestra.surge.sh/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rakannimer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-12-20T05:37:49.000Z","updated_at":"2024-04-15T18:54:01.000Z","dependencies_parsed_at":"2022-08-09T09:40:21.966Z","dependency_job_id":null,"html_url":"https://github.com/rakannimer/react-orchestra","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rakannimer%2Freact-orchestra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rakannimer%2Freact-orchestra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rakannimer%2Freact-orchestra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rakannimer%2Freact-orchestra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rakannimer","download_url":"https://codeload.github.com/rakannimer/react-orchestra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222035692,"owners_count":16919925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["instrument","javascript","music","music-composition","music-theory","music-theory-apps","orchestra","react","react-native"],"created_at":"2024-08-28T18:01:44.646Z","updated_at":"2024-10-29T11:19:14.662Z","avatar_url":"https://github.com/rakannimer.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# React Orchestra\n\n[![CircleCI](https://circleci.com/gh/RakanNimer/react-orchestra.svg?style=shield\u0026circle-token=6fe92a6008747c5902e40a5038690d7e0118865d)](https://circleci.com/gh/RakanNimer/react-orchestra)\n\n\nA toolbox to build interactive and smart instruments on the web and mobile.\n\nWeb example can be seen [here](http://react-orchestra.surge.sh/)\n\n### [Web example repo](https://github.com/RakanNimer/react-orchestra-web-demo)\n\n### [Native example repo](https://github.com/RakanNimer/react-orchestra-native-demo)\n\n## Getting Started\n\nReact Orchestra can be integrated easily into any project.\n\n### Prerequisites\n\n#### Native\n\n##### Installing peer dependencies\nUnder the hood RO uses :\n\n[react-native-sound](https://github.com/zmxv/react-native-sound) to play mp3 sounds.\n\n[react-native-fs](https://github.com/johanneslumpe/react-native-fs) to cache sounds in the filesystem.\n\n[realm](https://github.com/realm/realm-js) as an offline store for caching and state storage ( might remove this in future versions unless I or someone builds up on realm features to improve react-orchestra functionality )\n\n\nIn your project root :\n\n**Install it :**\n\n**With npm**\n\n```\nnpm install --save react-native-sound react-native-fs realm\n```\n##### With yarn\n```\nyarn add react-native-sound react-native-fs realm\n```\n\n**Then link it :**\n\n```\nreact-native link\n```\n\n#### Web\n\n**IMPORTANT READ THIS:**\n\nThe sound generation and playback for the web orchestra depends on the WebAudio API. Check support for your platform target [here](http://caniuse.com/#feat=audio-api).\nIf your targeted platform is supported you can go ahead and install it.\n\n\n### Install react-orchestra\n\n**With npm**\n\n```\nnpm install --save react-orchestra\n```\n##### With yarn\n```\nyarn add react-orchestra\n```\n\nNo need to link it ! It's plain JS.\n\nAnd you're good to go 💃.\n\nLet's start writing some instruments.\n\n### TLDR; I just want to copy paste stuff !\n\nThere you go :\n\n#### Web\n\n```\nyarn add react-orchestra || { npm i -S react-orchestra; }\n\n```\n#### Native\n```\nyarn add react-native-sound react-native-fs realm || { npm i -S react-native-sound react-native-fs realm; }\nreact-native link react-native-sound react-native-fs realm\nyarn add react-orchestra || { npm i -S react-orchestra; }\n```\n\n## API + Examples\n\nLet's build a couple of use-cases to get familiar with the API.\nOr you can directly check out and run the examples :\n\n- Web example :\n```sh\ngit clone git@github.com:RakanNimer/react-orchestra.git\ncd  react-orchestra/web/\n{yarn \u0026\u0026 yarn start} || {npm i \u0026\u0026 npm start}\n```\n\n- Native example :\n```sh\ngit clone git@github.com:RakanNimer/react-orchestra.git\ncd  react-orchestra/ReactOrchestraNativeDemo/\nyarn || {npm i;}\nnpm run init-app\nreact-native run-ios # or run-android\n```\n\n**1. A non-interactive instrument that can play notes and sync ui.**\n\n```javascript\nimport React from 'react';\nimport { Instrument, Note } from 'react-orchestra/web';\n// If you're using react-native then it's :\n// import { Instrument, Note } from 'react-orchestra/native';\n\nconst delay = ms =\u003e new Promise(resolve =\u003e setTimeout(ms, resolve));\n\nclass App extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      playA: false,\n      playC: false,\n    };\n  }\n  componentDidMount() {\n    this.playMelody();\n  }\n  async playMelody() {\n    await delay(1000);\n    this.setState({ playA: true });\n    await delay(1000);\n    this.setState({ playB: true, playA: false });\n    await delay(1000);\n    this.setState({ playB: false });\n  }\n  render() {\n    return (\n      \u003cInstrument name={'acoustic_grand_piano'} interactive={false}\u003e\n        \u003cNote name={'A3'} play={this.state.playA}\u003e\n          {/*\n            You can put any react element here native or web.\n          */}\n          \u003cdiv\u003e This is what I want my note to look like ! I can put anything in here.\n            \u003cimg\n              alt=\"Some pic\"\n              src=\"https://s-media-cache-ak0.pinimg.com/originals/36/43/e7/3643e7e8dab9b88b3972ee1c9f909dea.jpg\"\n            /\u003e\n          \u003c/div\u003e\n        \u003c/Note\u003e\n        \u003cNote name={'C3'} play={this.state.playC}\u003e\u003cdiv\u003eAnother note\u003c/div\u003e\u003c/Note\u003e\n      \u003c/Instrument\u003e\n    );\n  }\n}\nexport default App;\n\n```\n\nThe API aims to be self-explanatory, for example, in the code above we're creating two controlled note components, that we can play and stop using the play prop.\n\nWhen the component mounts, we start playing a simple melody.\n\n**2. An interactive instrument that the end-user controls.**\n\nLet's build an instrument that the user can play by clicking or tapping on notes.\n\n\n```javascript\nimport React from 'react';\nimport { Instrument, Note } from 'react-orchestra/web';\n// If you're using react-native then it's :\n// import { Instrument, Note } from 'react-orchestra/native';\n\nclass App extends React.Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n    };\n    this.onStartPlaying.bind(this);\n    this.onStopPlaying.bind(this);\n  }\n  onStartPlaying(noteName) {\n    console.warn(`Note played ${noteName}. Use this function if you want to sync your state with the instrument, dispatch redux action or alter mobx observable or just setting state inside your component`);\n  }\n  onStopPlaying(noteName) {\n    console.warn(`Stopped playing ${noteName}. Use this function if you want to sync your state with the instrument, dispatch redux action or alter mobx observable or just setting state inside your component`);\n  }\n  render() {\n    return (\n      \u003cInstrument name={'acoustic_grand_piano'} onStartPlaying={this.onStartPlaying} onStopPlaying={this.onStopPlaying} interactive\u003e\n        \u003cNote name={'A3'}\u003e\n          \u003cdiv\u003e\n            \u003cdiv\u003eClick me to play A3\u003c/div\u003e\n          \u003c/div\u003e\n        \u003c/Note\u003e\n        \u003cNote name={'C3'}\u003e\u003cdiv\u003eClick me to play C3\u003c/div\u003e\u003c/Note\u003e\n      \u003c/Instrument\u003e\n    );\n  }\n}\nexport default App;\n\n```\nYou don't need to listen to clicks or taps setting the ```interactive``` prop to true will attach the right events and clean them up for you !\n\nThe onPlay handler can be used to manage your state.\n\n\n**3. Playing midi and displaying playback.**\n\nAs any orchestra, react-orchestra can learn and play music tracks !\nFor now, it understands MIDI out of the box, more input sources are in the roadmap.\n\nLet's play Beethoven Moonlight's sonata.\n\n```javascript\nimport React from 'react';\nimport { Orchestra } from 'react-orchestra/web';\n// If you're using react-native then it's :\n// import { Orchestra } from 'react-orchestra/native';\nconst midiURL = 'https://s3-eu-west-1.amazonaws.com/ut-music-player/assets/midis/beet1track-medium-fast.mid';\nclass App extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {\n      playSong: false,\n    };\n    this.onMidiLoaded = this.onMidiLoaded.bind(this);\n    this.onInstrumentsReady = this.onInstrumentsReady.bind(this);\n  }\n  componentDidMount() {\n\n  }\n  onMidiLoaded(parsedMidi) {\n    console.warn(`Midi loaded ${JSON.stringify(parsedMidi, 2, 2)}. Loading instruments now ...`);\n    return parsedMidi;\n  }\n  onInstrumentsReady(instruments) {\n    console.warn(`Instruments ${JSON.stringify(instruments, 2, 2)} are loaded into memory and ready !`);\n    this.setState({ play: true });\n    return instruments;\n  }\n  onNotePlayed(noteName) {\n    console.warn(`Note ${noteName} was played, optionally handle this event`);\n  }\n  render() {\n    return (\n      \u003cOrchestra\n        midiURL={midiURL}\n        onMidiLoaded={this.onMidiLoaded}\n        onInstrumentsReady={this.onInstrumentsReady}\n        play={this.state.playSong}\n        selectedTracks={[0, 1]}\n        onNotePlayed={this.onNotePlayed}\n      \u003e\n        \u003cdiv\u003e This is an orchestra it can play complex melodies ! \u003c/div\u003e\n      \u003c/Orchestra\u003e\n    );\n  }\n}\nexport default App;\n```\n\n**4. Creating a note factory **\n\nThis is useful when you want to generate notes that follow a given rule\n\nExample : Render the C Major scale starting at the third octave over 2 octaves\n\n```javascript\nimport React from 'react';\nimport { NoteFactory } from 'react-orchestra/web';\n\nconst renderNote = (instrumentName, noteName) =\u003e \u003cdiv style={{ cursor: 'pointer' }}\u003e I am a note : {instrumentName} {noteName} You can click me ! \u003c/div\u003e;\n\nclass NoteFactoryExample extends React.Component {\n  render() {\n    return (\n      \u003cNoteFactory\n        type=\"scale\"\n        scaleName=\"ionian\"\n        noteName=\"C\"\n        instrumentName=\"acoustic_grand_piano\"\n        startOctave=\"3\"\n        octaveCount=\"1\"\n        renderNote={renderNote}\n      /\u003e\n    );\n  }\n}\nexport default NoteFactoryExample;\n\n```\n## Documentation\n\n- [API](docs/api.md#api)\n  - [`\u003cNote\u003e`](docs/api.md#Note)\n  - [`\u003cInstrument\u003e`](docs/api.md#Instrument)\n  - [`\u003cOrchestra\u003e`](docs/api.md#Orchestra)\n  - [`\u003cNoteFactory\u003e`](docs/api.md#NoteFactory)\n  - [`\u003cKeyBinding\u003e` (*web only*)](docs/api.md#KeyBinding)\n\n## Showcase\n\nDid you build something cool with this library ?\n\nShow it off here by [submittiing a pull request](https://github.com/RakanNimer/react-orchestra/compare).\n\n## Running the tests\n\n```\nnpm test\n```\n\nTests lint all js files using the js airbnb coding style and runs the jest tests in \\_\\_tests__ directory.\n\n\n\n## Contributing\n\nYou can contribute by submitting, and responding to issues. If you'd like to add a new feature PRs are very welcome, but please open an issue beforehand so we can discuss the optimal way to go when adding the feature !\n\n\n## Roadmap\n\n- [x] Create NoteFactory component that takes in a scale name or chord name or Midi URL and creates user-rendered Notes.\n- [ ] Add tests that run on browser\n- [ ] Add react-orchestra/native jest tests\n- [ ] Add more web jest tests\n\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frakannimer%2Freact-orchestra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frakannimer%2Freact-orchestra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frakannimer%2Freact-orchestra/lists"}