{"id":16120563,"url":"https://github.com/a-cordier/noon-io","last_synced_at":"2025-10-30T11:52:48.344Z","repository":{"id":65399891,"uuid":"463934400","full_name":"a-cordier/noon-io","owner":"a-cordier","description":"🎹 Easy io for the Web MIDI API","archived":false,"fork":false,"pushed_at":"2024-03-04T14:41:38.000Z","size":1382,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-01T02:29:41.893Z","etag":null,"topics":["javascript","midi","music","rxjs","web"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/noon-io","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/a-cordier.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-26T18:28:49.000Z","updated_at":"2025-02-19T21:53:07.000Z","dependencies_parsed_at":"2024-03-04T16:35:56.917Z","dependency_job_id":null,"html_url":"https://github.com/a-cordier/noon-io","commit_stats":{"total_commits":107,"total_committers":2,"mean_commits":53.5,"dds":0.009345794392523366,"last_synced_commit":"be9a91540dbfc8688ffedd8a8c6f5bf190d2a4ca"},"previous_names":[],"tags_count":42,"template":false,"template_full_name":null,"purl":"pkg:github/a-cordier/noon-io","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-cordier%2Fnoon-io","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-cordier%2Fnoon-io/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-cordier%2Fnoon-io/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-cordier%2Fnoon-io/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/a-cordier","download_url":"https://codeload.github.com/a-cordier/noon-io/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/a-cordier%2Fnoon-io/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281801957,"owners_count":26564007,"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","status":"online","status_checked_at":"2025-10-30T02:00:06.501Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["javascript","midi","music","rxjs","web"],"created_at":"2024-10-09T20:58:43.529Z","updated_at":"2025-10-30T11:52:48.312Z","avatar_url":"https://github.com/a-cordier.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🎹 noon-io\n\n![tests](https://github.com/a-cordier/noon-io/actions/workflows/tests.yaml/badge.svg)\n![release](https://github.com/a-cordier/noon-io/actions/workflows/release.yaml/badge.svg)\n![doc](https://github.com/a-cordier/noon-io/actions/workflows/doc.yaml/badge.svg)\n\nEasy io for the [Web MIDI API](https://www.w3.org/TR/webmidi/)\n\n## 🚨 Disclaimer\n\nDevelopment has just started and until v1.0.0 has been released, noon-io should be considered unstable.\n\n# 🗒️ API Documentation\n\nA more detailed documentation of noon-io can be found [here](https://a-cordier.github.io/noon-io).\n\n# 🚀 Getting started\n\n## 📦 Install\n\n```bash\nnpm i noon-io\n```\n\n## 📤 Send MIDI messages\n\nSend a A4 `NOTE ON` message on all available MIDI outputs\n\n```typescript\nimport * as MIDI from 'noon-io';\n\n// Gain access to the Web MIDI API\nconst midiAccess = await navigator.requestMIDIAccess();\n\n// Send a Note On message over all available outputs on channel 2\nfor (const output of midiAccess.outputs.values()) {\n    const noteOnMessage = {\n        status: MIDI.Status.NOTE_ON,\n        channel: 2,\n        data: {\n            value: 69, // A4\n            velocity: 127\n        }\n    };\n    output.send(MIDI.write(noteOnMessage));\n}\n```\n\n## 🔨 Using channel message factory functions\n\nFor one dedicated channel, noon-io offers a more concise way of writing messages using factory functions.\n\n```typescript\n// send a CC of 80 for control 71\noutput.send(MIDI.channel(2).controlChange(71, 80));\n// send a A4 note on message with a velocity of 120\noutput.send(MIDI.channel(2).noteOn(69, 120));\n// send the subsequent note off message for our A4 note\noutput.send(MIDI.channel(2).noteOff(69));\n```\n\nFor more information about noon-io factories, you can checkout this [documentation](https://a-cordier.github.io/noon-io/docs/interfaces/ChannelMessageFactory.html)\n\n## 📥 Read MIDI messages\n\n```typescript\nimport * as MIDI from 'noon-io';\n\n// Gain access to the Web MIDI API\nconst midiAccess = await navigator.requestMIDIAccess();\n\n// Bind MIDI reader to all midi inputs\nfor (const input of midiAccess.inputs.values()) {\n    input.onmidimessage = MIDI.read;\n}\n```\n\n## 🎨 Decorating MIDI messages\n\nThe read function can be instantiated through the `reader` factory which takes an optional configuration object. This object allow to define one decorator function per MIDI status,\nin order to populate the `meta` property of the message with application specific data,\nin order to implement custom logic when subscribing to the message.\n\n```typescript\n// example: read current UI state to check if MIDI learning is enabled\ninput.onmidimessage = MIDI.reader({\n    decorators: {\n        [MIDI.Status.CONTROL_CHANGE](message) {\n            return {\n                isMidiLearning: isMidiLearning() \n            };\n        }\n    },\n});\n```\n\n# ⏳ Subscribing to the messages stream\n\nOnce read, messages are exposed through the `Rx` Subject.\n\n```typescript\nimport * as MIDI from 'noon-io';\n\nMIDI.Rx.subscribe(message =\u003e {\n    console.log(message.meta); // log the meta object populated by the custom decorator function\n});\n```\n\n# ⏳ Filtering messages\n\nIn addition to the message stream, noon-io provides a convenient `observe` function,\nwhich will return a observable of MIDI messages matching the given MIDI status and an optional MIDI chanel.\n\n```typescript\nimport * as MIDI from 'noon-io';\n\nMIDI.observe(MIDI.Status.CONTROL_CHANGE, 1)\n    .subscribe(message =\u003e {\n        // handle control change message for channel 1\n    });\n```\n\n## ⚗️ Bank Select / Program Change\n\nSending a bank select followed by a program change can be achieved by sending two consecutive control change messages before \nsending the actual program change. \n\n(The following has been tested on a Dave Smith Instruments Mopho device)\n\n```typescript\nimport * as MIDI from 'noon-io';\n/*\n * Start Bank Select message\n * Selects banks 2 (bank 1 is 0) for channel 2\n */\noutput.send(\n    MIDI.writeMidiMessage({\n        status: MIDI.Status.CONTROL_CHANGE,\n        channel: 2,\n        data: {\n            control: 0, // bank select MSB (always 0)\n            value: 1, // MSB multiplier\n        }\n    })\n);\n\noutput.send(\n    MIDI.writeMidiMessage({\n        status: MIDI.Status.CONTROL_CHANGE,\n        channel: 2,\n        data: {\n            control: 0, // bank select LSB (always 32)\n            value: 1, // LSB multiplier\n        }\n    })\n); // Ends bank select message\n\n/*\n * Now that we have selected bank 2,\n * let's select a random program\n */\noutput.send(\n    MIDI.writeMidiMessage({\n        status: MIDI.Status.PROGRAM_CHANGE,\n        channel: 2,\n        data: {\n            value: Math.ceil(Math.random() * 127),\n        }\n    })\n);\n\n```\n\nOr using the `bankSelectMSB` and `bankSelectLSB` factories provided by noon-io\n\n```typescript\n// Select bank 1\noutput.send(MIDI.channel(2).bankSelectMSB(0));\noutput.send(MIDI.channel(2).bankSelectLSB(0));\n// Select program 109 from bank 1\noutput.send(MIDI.channel(2).programChange(Math.ceil(Math.random() * 127)));\n```\n\n# 🚧 Supported Messages\n\n⚠️ Some of the following MIDI messages may not have been tested on a MIDI port (see the status section of the following tables)\n\n## 🎶 Channel Messages\n\n|Type|Reader|Writer|Status\n|:--|:-:|:-:|:--|\n|NOTE ON|✅|✅|Read and write have been tested on a MIDI port\n|NOTE OFF|✅|✅|Read and write have been tested on a MIDI port\n|PITCH BEND|✅|✅|Read and write have been tested on a MIDI port\n|CONTROL CHANGE|✅|✅|Read and write have been tested on a MIDI port\n|PROGRAM CHANGE|✅|✅|Read and write have been tested on a MIDI port\n|POLYPHONIC AFTER TOUCH|✅|✅|Both read and write have not been tested\n|CHANNEL AFTER TOUCH|✅|✅|Both read and write have not been tested\n\n## 🎛️ System Messages\n\n|Type|Reader|Writer|Status\n|:--|:-:|:-:|:--|\n|TIMING CLOCK|✅|✅|Only Read has been tester on a MIDI port\n|START|✅|✅|Both read and write have not been tested\n|STOP|✅|✅|Both read and write have not been tested\n|CONTINUE|✅|✅|Both read and write have not been tested\n|SYSTEM RESET|✅|✅|Both read and write have not been tested\n|ACTIVE SENSING|✅|✅|Both read and write have not been tested\n|SYSTEM EXCLUSIVE|✅|❌|Reader has not been tested, writer is not implemented\n|MIDI TIME CODE|❌|❌|Not Implemented\n|SONG POSITION|❌|❌|Not Implemented\n|SONG SELECT|❌|❌|Not Implemented\n|TUNE REQUEST|❌|❌|Not Implemented\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa-cordier%2Fnoon-io","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fa-cordier%2Fnoon-io","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fa-cordier%2Fnoon-io/lists"}