{"id":18645160,"url":"https://github.com/danigb/polytone","last_synced_at":"2025-10-25T04:34:23.305Z","repository":{"id":52194239,"uuid":"60759472","full_name":"danigb/polytone","owner":"danigb","description":"Create polyphonic instruments from audio sources (Web Audio API)","archived":false,"fork":false,"pushed_at":"2016-10-11T10:27:15.000Z","size":1134,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-25T13:46:29.805Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danigb.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-09T08:16:26.000Z","updated_at":"2023-09-21T02:46:34.000Z","dependencies_parsed_at":"2022-08-27T14:56:28.768Z","dependency_job_id":null,"html_url":"https://github.com/danigb/polytone","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danigb%2Fpolytone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danigb%2Fpolytone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danigb%2Fpolytone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danigb%2Fpolytone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danigb","download_url":"https://codeload.github.com/danigb/polytone/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248401954,"owners_count":21097328,"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":[],"created_at":"2024-11-07T06:14:53.002Z","updated_at":"2025-10-25T04:34:23.232Z","avatar_url":"https://github.com/danigb.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# polytone [![npm](https://img.shields.io/npm/v/polytone.svg?style=flat-square)](https://www.npmjs.com/package/polytone)\n\n[![Build Status](https://img.shields.io/travis/danigb/polytone/master.svg?style=flat-square)](https://travis-ci.org/danigb/polytone)\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard) [![license](https://img.shields.io/npm/l/polytone.svg?style=flat-square)](https://www.npmjs.com/package/polytone)\n\n\u003e Create polyphonic instruments from audio sources\n\n`polytone` provides a clean API to work with web audio source nodes. It handles common tasks like converting from note names to frequency, add gain, envelope and filter support, events, scheduling or even handling audio context and node lifecycles.\n\nThe gist:\n\n```js\nvar polytone = require('polytone')\n\n// Create a function that returns an audio source node\nfunction synth (options) {\n  var osc = options.context.createOscillator()\n  osc.frequency.value = options.frequency\n  return osc\n}\n\n// specify the default options and the synth function\nvar inst = polytone(synth, { gain: 0.5, attack: 0.01, release: 0.2 })\n// pass the note name and receive the frequency and midi note number\ninst.start({ note: 'C4' })\n// works when passing just the note\ninst.start('C4')\n// override any option\ninst.start({ gain: 0.8, release: 0.4, duration: 1 })\n// stop all sounds after 3 seconds\ninst.stop(null, 3)\n```\n\n## Examples\n\n#### Create a audio buffer player\n\n```js\nvar snare = polytone(\u003cAudioBuffer\u003e)\nsnare.start() // play the buffer\nsnare.start({ gain: 0.5 }, null, 1) // =\u003e play after 1 second\n```\n\n#### Create an oscillator voice\n\n```js\nvar sine = polytone('sine')\nsine.start({ note: 'C4' })\nsine.start({ note: 'G4' })\nsine.stop(null, 1) // =\u003e stop all after 1 second\n```\n\n#### Create a sampled instrument\n\nYou can combine multiple AudioBuffers in one polytone instrument:\n\n```js\nvar drumMachine = polytone({ snare: \u003cAudioBuffer\u003e, kick: \u003cAudioBuffer\u003e, ... })\ndrumMachine.start('kick') // =\u003e play the kick\ndrumMachine.start('snare', null, 1) // =\u003e play the snare after 1 second\ndrumMachine.start({ name: 'conga', gain: 0.5 }) // =\u003e play the conga with options\n```\n\nIf the sample names are notes, some conversions are performed:\n\n```js\nvar piano = polytone({ 'C4': \u003cAudioBuffer\u003e, 'C#4': \u003cAudioBuffer\u003e, 'D4': ... })\npiano.start('Db4') // =\u003e handles enharmonic notes\npiano.start(70) // =\u003e can use midi numbers\npiano.start(70.5) // =\u003e if midi is float, the buffer is detuned\npiano.start({ note: 'C4', duration: 1 })\n```\n\n#### Create a synthetized drum machine\n\n```js\nvar dm = polytone(null, {\n  snare: function(options) { /* returns an AudioNode or similar object */ },\n  kick: function(options) { /* returns an AudioNode or similar object */ },\n  hihat: function(options) { /* returns an AudioNode or similar object */ },\n  ...\n})\ndm.start('snare')\ndm.start({ name: 'kick', gain: 1.2 })\n```\n\nSee my [Tiny808]() gist for a complete example.\n\n## Usage\n\n#### Note names midi note numbers, frequency and detune\n\nNote names or midi numbers are converted to frequencies:\n\n```js\nvar instrument = polytone(synth)\ninstrument.start('A4') // =\u003e Options are { note: 'A4', midi: 69, frequency: 440 }\ninstrument.start(60.2) // =\u003e options are { midi: 60, detune: 20, frequency: ... }\ninstrument.start({ note: 'C4 '}) // the same as passing the note directly\ninstrument.start({ name: 'C4 '}) // the same as before\n```\n\n### Gain, Envelope and Filter\n\nYou can set the gain:\n\n```js\ninstrument.start({ note: 'C4', gain: 0.2 })\n```\n\nUse a simple envelope with `attack` and `release`:\n\n```js\ninstrument.start({ note: 'C4', attack: 0.2, release: 0.5, duration: 1 })\n// (the real duration of the note will be 1 + 0.5 secs of the release envelope)\n```\n\nOr a filter:\n\n```js\ninstrument.start({ note: 'Db3', filter: { type: 'lowpass', frequency: 500 }})\n```\n\n#### Events\n\nYou can listen all events:\n```js\nvar instrument = polytone(synth).on('*', function (event, time, node) {\n  console.log('EVENT: ', event, time, node)\n})\ninstrument.play('C4') // =\u003e all events to the console\n```\n\nOr to single events (`start`, `stop`, `ended`, `disconnect` are accepted):\n\n```js\nvar instrument = polytone(synth)\ninstrument.on('start', function (event, time, node) {\n  console.log('EVENT: ', event, time, node)\n})\ninstrument.start(440) // =\u003e only 'start' events are displayed\n```\n\n\n#### Audio Context\n\nBy default, polytone uses [audio-context](https://www.npmjs.com/package/audio-context) module to get the audio context, so no initialization is required. Anyway, you can pass your own context if you prefer:\n\n```js\nvar context = new AudioContext()\nvar instrument = polytone({ context: context }, synth)\n```\n\nYou can provide any option either to the polytone constructor or the `start` function:\n\n```js\nfunction synth (options) { console.log(options) }\nvar instrument = polytone({ one: 1, two: 2 }, synth)\ninstrument.start({ two: 22, three: 333 })\n// =\u003e { context: \u003cAudioContext\u003e, one: 1, two: 22, three: 333 }\n```\n\n#### Connect and disconnect\n\nBy default, all sources are automatically connected to the audio context destination, but you can override this option:\n\n```js\nvar reverb = /* \u003cAudioNode\u003e */\nvar instrument = polytone(synth, { connect: reverb })\ninstrument.start('d4')\n```\n\nOr for each instance individually:\n\n```js\nvar instrument = polytone(synth)\ninstrument.start({ note: 'C4', gain: 0.2, connect: reverb })\n```\n\nAre nodes are disconnected automatically after they stop.\n\n### Connect to midi inputs via Web Midi API\n\n```js\nvar piano = polytone({ 'c2': \u003cAudioBuffer\u003e, 'c#2': \u003cAudioBuffer\u003e, ... })\nwindow.navigator.requestMIDIAccess().then(function (midiAccess) {\n  midiAccess.inputs.forEach(function (midiInput) {\n    piano.listenToMidi(midiInput)\n  })\n})\n```\n\n### Schedule events\n\nA simple convenient function is provide to schedule a group of events:\n\n```js\nvar piano = polytone(...)\npiano.schedule([\n  { time: 0, note: 'C4' },\n  { time: 0.5, note: 'G4' }\n], null, 3) // =\u003e shedule it after 3 second\n```\n\nOr more compact:\n\n```js\npiano.schedule('C4 G4 C5'.split(' ').map(function (note, i) {\n  return { time: 0.5 * i, note: note }\n}))\n```\n\n\n## Documentation, tests and examples\n\nTo run the examples, install [budo](https://github.com/mattdesl/budo): `npm i -g budo` and then:\n\n```bash\nbudo examples/index\n```\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanigb%2Fpolytone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanigb%2Fpolytone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanigb%2Fpolytone/lists"}