An open API service indexing awesome lists of open source software.

https://github.com/danigb/sample-player

A web audio audio sample player
https://github.com/danigb/sample-player

Last synced: 5 months ago
JSON representation

A web audio audio sample player

Awesome Lists containing this project

README

          

# sample-player [![npm](https://img.shields.io/npm/v/sample-player.svg?style=flat-square)](https://www.npmjs.com/package/sample-player)

[![Build Status](https://img.shields.io/travis/danigb/sample-player/master.svg?style=flat-square)](https://travis-ci.org/danigb/sample-player)
[![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/sample-player.svg?style=flat-square)](https://www.npmjs.com/package/sample-player)

⚠️ This is old codebase I don't want to maintain anymore. There are lot of alternatives out there, this is one: https://github.com/danigb/smplr Thanks! ⚠️

Flexible audio sample player for browser:

```js
var player = require('sample-player')
var ac = new AudioContext()

var sample = player(ac, )
sample.start()
sample.start() // can start several samples at the same time
sample.stop() // stop all playing sounds
```

## Features

#### Create multi-sample player

Pass a map of names to audio buffers to create a multi-sample player:

```js
var player = require('sample-player')
var ac = new AudioContext()
var drums = player(ac, {
kick: ,
snare: ,
hihat:
})
drums.start('kick')
drums.start('snare', ac.currentTime, { gain: 0.5 })
```

#### Map note names to midi (and oposite)

If the buffers are mapped to note names, you can pass note names (including enharmonics) or midi numbers:

```js
var samples = { 'C2': , 'Db2': , ... }
var piano = player(ac, samples)
piano.start(69) // => Plays 'A4'
piano.start('C#2') // => Plays 'Db2'
```

Decimal midi note numbers can be used to detune the notes:

```js
piano.start(69.5) // => Plays a note in the middle of 'A4' and 'Bb4'
```

#### Events

You can register event handlers with the `on` function:

```js
var drums = player(ac, { kick: ..., snare: ..., hihat ... })
drums.on('start', function (when, name) {
console.log('start', name)
})
drums.on('ended', function (when, name) {
console.log('ended', name)
})
drums.start('kick')
// console logs 'start kick'
// console.logs 'ended kick' when sound ends
```

To add a listener to all events use: `player.on(function (eventName, when, obj, opts))`.

Currently it fires: `start`, `started`, `stop`, `ended`, `scheduled`

#### Amplitude envelope control

You can apply an amplitude envelope control player-wide or shot-wide. You can pass a signle `adsr` option with an array of `[attack, decay, sustain, release]` or add each parameter to the options object:

```js
// using a single option to set all envelop
var longSound = player(ac, , { adsr: [1.2, 0.5, 0.8, 1.3] })
longSound.start()
// override only the attack
longSound.start(ac.currentTime + 10, { attack: 3 })
```

#### Listen to midi inputs

Easily attach the player to a Web MIDI API `MidiInput`:

```js
var piano = player(...)
window.navigator.requestMIDIAccess().then(function (midiAccess) {
midiAccess.inputs.forEach(function (midiInput) {
piano.listenToMidi(midiInput)
})
})
```

#### Schedule to play buffers at given times

```js
var buffers = { 'C2': , 'Db2': , ... }
var marimba = player(ac, buffers)
marimba.schedule(ac.currentTime, [
{ note: 'c2', time: 0, gain: 0.9 },
{ note: 'e2', time: 0.25, gain: 0.7 },
{ note: 'g2', time: 0.5, gain: 0.5 },
{ note: 'c3', time: 0.75, gain: 0.3 }
])
```

## Install

Via npm: `npm i --save sample-player` or grab the [browser ready file](https://raw.githubusercontent.com/danigb/sample-player/master/dist/sample-player.min.js) which exports `SamplePlayer` as window global.

## Options

The options can be passed to the `SamplePlayer` function to apply to all buffers, or to `start` function to apply to one shot.

- `gain`: float between 0 to 1
- `attack`: the attack time of the amplitude envelope
- `decay`: the decay time of the amplitude envelope
- `sustain`: the sustain gain value of the amplitude envelope
- `release`: the release time of the amplitude envelope
- `adsr`: an array of `[attack, decay, sustain, release]`. Overrides other parameters.
- `duration`: set the playing duration in seconds of the buffer(s)
- `loop`: set to true to loop the audio buffer

## API

## SamplePlayer(ac, source, options) ⇒ player
Create a sample player.

**Returns**: player - the player

| Param | Type | Description |
| --- | --- | --- |
| ac | AudioContext | the audio context |
| source | ArrayBuffer | Object.<String, ArrayBuffer> | |
| options | Onject | (Optional) an options object |

**Example**
```js
var SamplePlayer = require('sample-player')
var ac = new AudioContext()
var snare = SamplePlayer(ac, )
snare.start()
```

* [SamplePlayer(ac, source, options)](#SamplePlayer) ⇒ player
* [.play](#player.play)
* [.start(name, when, options)](#player.start) ⇒ AudioNode
* [.stop(when, nodes)](#player.stop) ⇒ Array
* [.on(event, callback)](#player.on) ⇒ [SamplePlayer](#SamplePlayer)
* [.connect(destination)](#player.connect) ⇒ [SamplePlayer](#SamplePlayer)
* [.schedule(source, map, when)](#player.schedule) ⇒ Array
* [.listenToMidi(input, options)](#player.listenToMidi) ⇒ [SamplePlayer](#SamplePlayer)


### player.play
An alias for `player.start`
**See**: player.start


### player.start(name, when, options) ⇒ AudioNode
Start a sample buffer. The returned object has a function `stop(when)` to stop the sound.

**Returns**: AudioNode - an audio node with a `stop` function

| Param | Type | Description |
| --- | --- | --- |
| name | String | the name of the buffer. If the source of the SamplePlayer is one sample buffer, this parameter is not required |
| when | Float | (Optional) when to start (current time if by default) |
| options | Object | additional sample playing options |

**Example**
```js
// A single sample player
var sample = player(ac, ).connect(ac.destination)
var first = sample.start(ac.currentTime, { loop: true })
var second = sample.start(ac.currentTime + 0.5, { loop: true, gain: 0.7 }) // name not required since is only one AudioBuffer
first.stop(ac.currentTime + 1) // only stops first sound
sample.stop() // stop all sounds
```

**Example**
```js
// A multi-sample player
var drums = player(ac, { snare: , kick: , ... }).connect(ac.destination)
drums.start('snare')
drums.start('snare', 0, { gain: 0.3 })
```


### player.stop(when, nodes) ⇒ Array
Stop some or all samples

**Returns**: Array - an array of ids of the stoped samples

| Param | Type | Description |
| --- | --- | --- |
| when | Float | (Optional) an absolute time in seconds (or currentTime if not specified) |
| nodes | Array | (Optional) an array of nodes or nodes ids to stop |

**Example**
```js
var longSound = player(ac, ).connect(ac.destination)
longSound.start(ac.currentTime)
longSound.start(ac.currentTime + 1)
longSound.start(ac.currentTime + 2)
longSound.stop(ac.currentTime + 3) // stop the three sounds
```


### player.connect(destination) ⇒ AudioPlayer
Connect the player to a destination node

**Chainable**
**Returns**: AudioPlayer - the player

| Param | Type | Description |
| --- | --- | --- |
| destination | AudioNode | the destination node |

**Example**
```js
var sample = player(ac, ).connect(ac.destination)
```


### player.on(event, callback) ⇒ [SamplePlayer](#SamplePlayer)
Adds a listener of an event

**Chainable**
**Returns**: [SamplePlayer](#SamplePlayer) - the player

| Param | Type | Description |
| --- | --- | --- |
| event | String | the event name |
| callback | function | the event handler |

**Example**
```js
player.on('start', function(time, note) {
console.log(time, note)
})
```


### player.schedule(when, events) ⇒ Array

Schedule a list of events to be played at specific time.

It supports two formats of events:

- An array with `[time, note]`
- An array with objects `{ time: ?, [name|note|midi|key]: ? }`

**Returns**: Array - an array of ids

| Param | Type | Description |
| --- | --- | --- |
| when | Float | an absolute time to start (or AudioContext's currentTime if it's less than currentTime) |
| source | Array | the events array |

**Example**
```js
// Event format: [time, note]
var piano = player(ac, ...).connect(ac.destination)
piano.schedule(0, [ [0, 'C2'], [0.5, 'C3'], [1, 'C4'] ])
```

**Example**
```js
// Event format: object { time: , name: }
var drums = player(ac, ...).connect(ac.destination)
drums.schedule(ac.currentTime, [
{ name: 'kick', time: 0 },
{ name: 'snare', time: 0.5 },
{ name: 'kick', time: 1 },
{ name: 'snare', time: 1.5 }
])
```


### player.listenToMidi(input, options) ⇒ [SamplePlayer](#SamplePlayer)
Connect a player to a midi input

The options accepts:

- channel: the channel to listen to. Listen to all channels by default.

**Returns**: [SamplePlayer](#SamplePlayer) - the player

| Param | Type | Description |
| --- | --- | --- |
| input | MIDIInput | |
| options | Object | (Optional) |

**Example**
```js
var piano = player(...)
window.navigator.requestMIDIAccess().then(function (midiAccess) {
midiAccess.inputs.forEach(function (midiInput) {
piano.listenToMidi(midiInput)
})
})
```

## Run tests and examples

To run the test, clone this repo and:

```bash
npm install
npm test
```

To run the examples:

```bash
npm i -g budo
budo examples/microtone.js
```

(Take a look into `examples` folder)

## License

MIT License