audio-2.0.0
Version:
Class for high-level audio manipulations
869 lines (583 loc) • 27.5 kB
Markdown
# Audio API
## Table of Contents
**1. [Creation](#creation)**
* [ ] [new Audio(src?, opts?)]()
* [x] [Audio.from(a, b?, ...c?, opts?)]()
* [ ] [Audio.load(url, opts?, cb?)]()
* [ ] [Audio.decode(buf, opts?, cb?)]()
* [ ] [Audio.record(stream, opts?)]()
**2. [Properties](#properties)**
* [ ] [audio.buffer]()
* [ ] [audio.channels]()
* [ ] [audio.duration]()
* [ ] [audio.length]()
* [ ] [audio.sampleRate]()
**3. [Utilities](#utilities)**
* [x] [Audio.equal(a, b, ...c)]()
* [x] [Audio.gain(db)]()
* [x] [Audio.db(gain)]()
* [x] [audio.time(offset)]()
* [x] [audio.offset(time)]()
* [ ] [audio.convert(format)]()
* [ ] [audio.save(filename, opts?)]()
* [ ] [audio.stream(dst, opts?, onend?)]()
**4. [Manipulations](#manipulations)**
* [x] [audio.read(t?, dur?, dst|opts?)]()
* [x] [audio.write(src, t?, dur?, opts?)]()
* [x] [audio.insert(src, t?, dur?, opts?)]()
* [x] [audio.remove(t?, dur?, opts?)]()
* [x] [audio.slice(t?, dur?, opts?)]()
* [x] [audio.trim(opts?)]()
* [x] [audio.pad(dur, opts?)]()
* [x] [audio.shift(amt, t?, opts?)]()
* [ ] [audio.reverse(t?, dur?, opts?)]()
* [ ] [audio.repeat(times, t?, dur?, opts?)]()
* [ ] [audio.invert(t?, dur?, opts?)]()
* [ ] [audio.gain(db, t?, dur?, opts?)]()
* [ ] [audio.fade(t?, dur, opts?)]()
* [ ] [audio.normalize(t?, dur?, opts?)]()
* [ ] [audio.pan(amt, t?, dur?, opts?)]()
* [ ] [audio.mix(audio, t?, dur?, opts?)]()
* [ ] [audio.scale(amt, t?, opts?)]()
* [ ] [audio.through(fn, t?, dur?, opts?)]()
**5. [Metrics](#metrics)**
* [ ] [audio.statistics(t?, dur?, opts?)]()
* [ ] [audio.bounds(t?, dur?, opts?)]()
* [ ] [audio.spectrum(t?, dur, opts?)]()
* [ ] [audio.cepstrum(t?, dur)]()
* [ ] [audio.loudness(t?, dur)]()
* [ ] [audio.memory(t?, dur, opts?)]()
**6. [Playback](#playback)**
* [ ] [audio.play(t?, dur?, opts?)]()
* [ ] [audio.pause()]()
* [ ] [audio.muted]()
* [ ] [audio.loop]()
* [ ] [audio.rate]()
* [ ] [audio.volume]()
* [ ] [audio.paused]() <kbd>readonly</kbd>
* [ ] [audio.currentTime]()
<!-- TODO: remove unnecessary tables from readme to allow for easier read flow -->
## Creation
### let audio = new Audio(source?, channels|format|options?)
Create `audio` instance from `source` with optional `channels` number, `format` string or `options` object.
```js
// Create blank audio
let blankAudio = new Audio()
// Create one second of silence in stereo
let silentAudio = new Audio(1, 2)
// Create from AudioBuffer
let bufAudio = new Audio(audioCtx.createBuffer(2, 22050, 44100))
// Create from raw planar data
let rawAudio = new Audio(new Float32Array([0,1,.2,.3,...]), 'stereo planar')
// Create from channels data
let chAudio = new Audio([[0,0,0], [.1,.1,.1], [.2,.2,.2]])
// Create from object
let optAudio = new Audio({
channels: 3,
length: 2000
})
// Create from data-uri string
let dataUriAudio = Audio('data:application/octet-stream;base64,AP8A/w==', 'uint8')
// Create from Buffer
let buf2Audio = Audio(Buffer.from([0, 255, 0, 127]), 'interleaved')
// Create from ndarray
let ndAudio = Audio(ndarray, {sampleRate: 48000})
```
#### `source`
Type | Meaning
---|---
_Number_ | Create silence of the indicated duration in seconds.
_AudioBuffer_ | Create from [AudioBuffer](https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer)).
_AudioBufferList_ | Create from [audio-buffer-list](https://github.com/audiojs/audio-buffer-list).
_Audio_ | Create from other audio instance by copying its data
_Object_ | Create from options object with `duration`/`length`, `channels` and `sampleRate` properties. `length` defines number of samples, `duration` defines time.
_Array_ of _Arrays_ | Create from channels data with `[[l, l, l...], [r, r, r...]]` layout.
_Array_ of _Numbers_ | Create from raw samples data, interpreted by `format`.
_Float32Array_, _Float64Array_ | Create from raw samples data with `±1` amplitude range.
_TypedArray_, _ArrayBuffer_, _Buffer_ | Create from PCM data, interpreted by `format` argument (see [pcm-convert](https://github.com/audiojs/pcm-convert)) for available audio data formats.
`base64`/`dataURI` string | [Base64](https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding)-encoded or [DataURI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) string.
`ndarray` | Create from [ndarray](https://npmjs.org/package/ndarray) instance. The `shape` property is considered as `[length, channels]`.
`ndsamples` | Create from [ndsamples](https://npmjs.org/package/ndsamples) instance, similar to ndarray.
_none_ | Create 0-duration blank audio.
#### `format` or `options`
Can be an object or string, specifying `source` data format.
Example string: `'interleaved le stereo 44100'`, `'3-channel 96000'` etc. See [audio-format](https://github.com/audiojs/audio-format) package for the full list of available format strings.
Options may provide the following properties, extending format:
Property | Default | Description
---|---|---
`channels`, `numberOfChannels` | `source` channels or `1` | _Number_ or _Array_, indicating source channels count or channels layout.
`sampleRate`, `rate` | `source` or `context` sample rate. | Source sample rate.
`interleaved` | Auto | If `source` data has interleaved or planar layout.
`context` | [`audio-context`](https://github.com/audiojs/audio-context) | Web audio context instance, optional. In case if _Audio_ is used with [web-audio-api](https://github.com/audiojs/web-audio-api) or other modules.
<!-- `stats` | Track statistics. Increases memory consumption 3 times, but allows for fetching metrics data `O(C)`, useful for rendering purposes. | `false` -->
#### Related APIs
* [audio-buffer](https://github.com/audiojs/audio-buffer)
* [audio-buffer-list](https://github.com/audiojs/audio-buffer-list)
* [audio-buffer-from](https://github.com/audiojs/audio-buffer-from)
### Audio.from(...sources, format|options?)
Alias: `Audio.join`, `Audio.concat`, `Audio.create`
Create audio by joining multiple sources. Every `source` can be an array of sources as well. `options` may specify common options for the set of sources.
```js
// Create from multiple sources with 1s of silence at the beginning/end
let joinedAudio = Audio.from(1, audio1, audio2, audio3, 1)
```
### Audio.load(source, (error, audio) => {}?)
Load and decode local or remote audio file or list of files. Callback is invoked when all data is loaded and decoded. Returns promise.
```js
// Load remote file, promise style
Audio.load('https://remote.url/file.mp3').then(audio => {}, error => {})
// Load local file, callback style
Audio.load('./chopin.mp3', (error, audio) => {
audio.normalize().trim().fade(-1).insert(intro, 0).saveAs('concert.wav')
})
// Load multiple sources
Audio.load([
'./intro.wav',
'https://remote.url/file.mp3',
Audio.load('./outro.wav'),
Audio(2)
]).then(items => {
let joined = Audio.from(...items)
})
```
#### Source
| Type | Meaning |
|---|---|
| Local path: `./*`, `/*`, `../*`, `C:\*` etc. | Load or read local file relative to caller module's directory, ie. from the place where `Audio.load()` is invoked. In browser it is relative to current URL. |
| Remote path: `http[s]://*` | Load and decode remote file. |
| TODO: data-uri string | |
| _Array_ of anything | Listed sources are loaded in parallel and callback is invoked when all sources are ready. |
TODO: freesound loader, soundcloud loader
#### Related APIs
* [audio-load](https://github.com/audiojs/audio-load) − load data from URL
* [audio-loader](https://github.com/audiojs/audio-loader) − load data from audio APIs
### Audio.decode(source, (error, audio) => {}?)
Decode audio data from `source` container. `wav` and `mp3` formats are supported out of the box, to enable other formats, include proper codec from [audiocogs](https://github.com/audiocogs), such as [flac.js](https://github.com/audiocogs/flac.js), [opus.js](https://github.com/audiocogs/opus.js) and others.
```js
// Decode binary data, callback style
Audio.decode(require('audio-lena/mp3'), (err, audio) => {})
// Decode flac data-uri string, promise style
require('flac.js')
Audio.decode(require('audio-lena/flac-datauri')).then(audio => {}, err => {})
// Decode multiple sources, create single audio with joined sources
Audio.decode([a, b, c], (err, [a, b, c]) => {
let audio = Audio.from(a, b, c)
})
```
#### Source
| Type | Meaning |
|---|---|
| _ArrayBuffer_ | Array buffer instance with encoded data, default for browser/node. |
| _Buffer_ | [Nodejs buffer](https://nodejs.org/api/buffer.html) with encoded data. |
| _Blob_ | [Blob](https://developer.mozilla.org/en/docs/Web/API/Blob) instance with encoded data. |
| _File_ | [File](https://developer.mozilla.org/en/docs/Web/API/File) with encoded data, the name will be dropped. |
| dataURI string | [Data-URI](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs) string of a kind `data:audio/<type>;base64,<data>` .|
| Base64 string | String with [base64](https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding)-encoded data. |
| _AudioBufferView_ | _Float32Array_, _UInt8Array_ etc. with encoded data. |
| _Array_ of above | Decode list of sources, invoke callback when everything succeeded. |
#### Format
| Format | Package |
|---|---|
| `wav` | shipped by default |
| `mp3` | shipped by default via [mp3.js](https://github.com/audiocogs/mp3.js) |
| `mp4` | [mp4.js](https://github.com/audiocogs/mp4.js) |
| `aac` | [aac.js](https://github.com/audiocogs/mp4.js) |
| `flac` | [flac.js](https://github.com/audiocogs/flac.js) |
| `alac` | [alac.js](https://github.com/audiocogs/alac.js) |
| `opus` | [opus.js](https://github.com/audiocogs/opus.js) |
| `ogg` | TODO: not working due to issues in [vorbis.js](https://github.com/audiocogs/vorbis.js/issues/3) |
#### Related APIs
* [audio-decode](https://github.com/audiojs/audio-decode)
* [audio-type](https://github.com/audiojs/audio-type)
* [aurora](https://github.com/audiocogs/aurora.js)
### Audio.record(source, duration|options?, (error, audio)=>{}?)
Create audio instance by recording stream-ish source. If callback provided, it will be called when the source is Promise recieves `progress` clause.
```js
// record mic input
navigator.getUserMedia({audio: true, video: false}, stream => {
Audio.record(stream, 5).then(audio => {
//`audio` contains 5 seconds of recorded mic input
})
})
// record HTML audio
let audioEl = document.createElement('audio')
audioEl.src = 'https://remote.url/audio.mp3'
Audio.record(audioEl, (err, audio) => {
//`audio` here is ready
})
// record web-audio
let ctx = new AudioContext()
let oscillator = ctx.createOscillator()
oscillator.type = 'square'
oscillator.frequency.value = 440
oscillator.start()
Audio.record(oscillator, (err, audio) => {
//this callback is invoked once oscillator is stopped
})
setTimeout(() => {
oscillator.stop()
}, 2000)
// record node-stream with pcm data
// FIXME: get real case of node stream source
let stream = require('mic-input')
Audio.record(stream, (err, audio) => {
//callback is invoked once stream is ended
})
// record pull-stream
// FIXME: get real case of pull stream source
let source = require('pull--source')
Audio.record(source).then(audio => {
})
// record multiple sources
Audio.record([a, b, c], (err, audio) => {
//callback is invoked once all three of sources are recorded
})
```
#### Source
Type | Meaning
---|---
_Stream_ |
_pull-stream_ |
_Function_ |
_MediaStream_ |
_WebAudioNode_ |
_HTMLAudioElement_, _HTMLMediaElement_ |
_Array_ with sources |
#### Options
Property | Meaning
---|---
`duration`, `from`, `to` | Recording interval in seconds
`length`, `start`, `end | Recording interval in samples
`channel`, `channels` | Channels to record
``
<!--
* **Stream** − [_Stream_](https://nodejs.org/api/stream.html), [_pull-stream_](https://github.com/pull-stream/pull-stream), _Function_, [_MediaStream_](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)_WebAudioNode_ or _Array_ with sequence of any sources. Starts recording, updating contents until input stream ends or max duration reaches. `data` and `end` events are emitted during stream consumption. Returned thenable takes arguments `.then(success, error, progress)`. Plays role of [audiorecorder](https://npmjs.org/package/audiorecorder).
-->
<!--
| _HTMLAudioElement_, _HTMLMediaElement_ | Wrap [`<audio>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio) or [`<video>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video) element, capture it's contents. Puts audio into recording state. | stream |
-->
---
## Properties
### audio.buffer
[_AudioBufferList_](https://github.com/audiojs/audio-buffer-list) with audio data. Readable, writable.
### audio.channels
Alias: `audio.channel`, `audio.numberOfChannels`
Number of channels. Changing this property will up-mix or down-mix channels, see interpretation table in [audio-buffer-remix](https://github.com/audiojs/audio-buffer-remix).
### audio.sampleRate
Alias: `audio.rate`
Buffer sample rate. Changing this property will resample audio to target rate. (WIP)
### audio.duration
Buffer duration. Changing this property will trim or pad the data.
### audio.length
Get total length of audio in samples.
---
## Utilities
### Audio.equal(a, b, ..., options)
Alias: `Audio.isEqual`, `Audio.equals`
Test if audio instances have same content. Comparison can be done by frequencies or samples with defined precision.
### Audio.db(level), Audio.gain(db)
Convert gain to decibels or backwards, see [decibels](https://github.com/audiojs/decibels).
### audio.save(fileName, done?)
Alias: `audio.saveAs`, `audio.download`
Download as a wav file in browser, write audio to file in node. In node file is going to be saved to the same directory as the caller's one. To redefine directory, use absolute path as `audio.save(__dirname + '/my-audio.wav')`. See [save-file](https://github.com/dfcreative/save-file) for details.
```js
// save as wav file
audio.save('my-audio.wav', (err, audio) => {
if (err) throw err;
})
```
If you need custom output format, like _ogg_, _mp3_ or other, please use [audio-encode](https://github.com/audiojs/audio-encode).
```js
// save as ogg file
const encode = require('audio-encode/ogg')
const save = require('save-file')
encode(audio.buffer, (err, buf) => {
save(buf, 'my-audio.ogg')
})
```
### audio.stream()
### audio.time()
### audio.offset()
---
## Playback
### audio.play(time=0, duration?, {rate, loop, volume}?, onended?)
Start playback from the indicated `start` time offset, invoke callback on end.
### audio.pause()
Pause current playback. Calling `audio.play()` once again will continue from the point of pause.
### audio.muted
Mute playback not pausing it.
### audio.loop
Repeat playback when the end is reached.
### audio.rate
Playback rate, by default `1`.
### audio.volume
Playback volume, defaults to `1`.
### audio.paused
If playback is paused.
### audio.currentTime
Current playback time in seconds. Setting this value seeks the audio to the new time.
---
## Metrics
### audio.limits(time=0, duration?, {channel|channels}?)
Find amplitudes boundaries (range) for the indicated time interval. Returns an array with `min, max` values. Accounts for all channels, unless specified.
```js
// get min/max amplitude for the .5s interval starting from 1s
let [min, max] = audio.limits(1, .5)
// get min/max amplitude in left channel
let [lMin, lMax] = audio.limits({channel: 0})
```
### audio.spectrum(time=0, options?)
Get array with spectral component magnitudes (magnitude is length of a [phasor](wiki) — real and imaginary parts). [fourier-transform](https://www.npmjs.com/package/fourier-transform) is used internally.
Possible `options`:
name | default | meaning
---|---|---
_size_ | `1024` | Size of FFT transform, e. g. number of frequencies to capture.
_channel_ | `0` | Channel number to get data for, `0` is left channel, `1` is right etc.
_db_ | `false` | Convert resulting magnitudes from `0..1` range to decibels `-100..0`.
### audio.loudness(time=0, duration?, options|method?)
Get loudness estimation for the interval indicated by `time` and `duration`. Returns an array with per-channel loudness values.
```js
// calculate RMS for 2 channels for the 120ms duration, starting from 1s
let [leftRms, rightRms] = audio.loudness(1, .12)
```
#### Options
Property | Default | Meaning
---|---|---
`method` | `'rms'` | Method of calculating loudness estimation. `'rms'` (root mean square) is used by default as fastest. Available methods: `TODO`
`channel`, `channels` | `null` | Target channels to calculate loudness for
#### Related API
* [audio-loudness](https://github.com/audiojs/audio-loudness) − loudness estimation algorithms.
### audio.cepstrum(time, duration)
### audio.statistics(time, duration)
Alias: `audio.stats`
### audio.variance(time, duration)
### audio.clip(time, duration)
### audio.size(time, duration)
<!--
Ideas:
* chord/scale detection
* tonic, or main frequency for the range — returns scientific notation `audio.pitch(time=0, (err, note) => {})`
* tempo for the range `audio.tempo(time=0, (err, bpm) => {})`
-->
---
## Manipulations
### audio.read(time=0, duration?, {channel[s], format, destination}?)
Alias: `audio.get`
Read audio data from the indicated range, put result into `destination`. If destination is not defined, an array or object will be created based on `format`. By default returns an array with channels data.
```js
// get channels data for the 5s subrange starting from the 1s
let [leftChannel, rightChannel] = audio.read(1, 5)
// get audiobuffer with whole audio data
let abuf = audio.read({format: 'audiobuffer'})
// get 1s of SR and SL channels data, starting from 0.5s
let [slChannel, srChannel] = audio.read(.5, 1, {channels: [2,3]})
// get last 1000 samples of right channel data
let rightChannelData = audio.read(new Float32Array(1000), Audio.time(-1000), {channel: 1})
// read 10 samples of left channel as uint8 numbers, put into destination container
let uintArr = a.read(0, a.time(10), {dest: new Uint8Array(10), channel: 0})
```
#### Options
Property | Description | Default
---|---|---
`channel`, `channels` | Channel number or array with channel numbers to read data from. | all channels
`format` or `dtype` | Returned data type. | `destination` type
`destination`, `dest`, `dst` | Data container to put data. | `null`
### audio.write(data|value|fn, time=0, duration?, {channel|channels, format}?)
Alias: `audio.set`, `audio.fill`
Write `data` to audio, starting at the indicated `time`, sliced by the `duration`. Optionally indicate `format` of data source or `channels` to write data to.
```js
// write data to left and right channels
audio.write([new Float32Array(100), new Float32Array(100)])
// write L and R buffer channels to SL and SR channels starting from 0.5s of the duration .25s
audio.write(audioCtx.createBuffer(2, 22050, 44100), .5, .25, {channels: [2,3]})
// write 100 samples to the right channel starting from 1000 sample
audio.write(new Float32Array(100).fill(0), audio.time(1000), {channel: 1})
// fill 1s of audio starting from .5s with constant value .25
audio.write(.25, .5, 1)
// create 1000 samples filled with constant value 1
let constAudio = Audio({length: 1000}).write(1)
// create 1000 samples filled with sine wave
let sinAudio = Audio({length: 1000, channels: 2}).write((v, i, c, a) => {
return Math.sin(Math.PI * 2 * 440 * i / a.sampleRate)
})
// reset left channel to zero value
sinAudio.write(0, {channels: [0]})
```
#### Data type
Type | Meaning
---|---
`Number` | Constant value to fill interval with.
`Function` | Function, returning number. Takes value `v`, sample index `i` and channel number `ch` arguments.
`Array<Array>` | Array with channels data.
`AudioBuffer`, `AudioBufferList`, `Audio` | Other audio source.
`Array<Number>`, `Float32Array`, `Float64Array` | Raw samples from `-1..+1` range, interpreted by `options.format` |
`Int8Array`, `Uint8Array`, `TypedArray` | Other typed array, interpreted by `options.format`.
`ArrayBuffer`, `Buffer` | Raw data, interpreted by `options.format`.
`base64`, `dataURI` string | String with raw data, decoded based on `options.format`.
`ndarray`, `ndsamples` | n-dimensional array with `[length, channels]` shape.
#### Options
Property | Meaning
---|---
`channels`, `channel` | Target channels to write source data, can be an array or number.
`format` or `dtype` | Source data format, if necessary, like `'uint8 stereo interleaved'`.
#### Related API
* [audio-format](https://github.com/audiojs/audio-format)
* [audio-buffer-from](https://github.com/audiojs/audio-buffer-from)
### audio.insert(data|value|fn, time=-0, duration?, {channel|channels}?)
Alias: `audio.push`, `audio.put`, `audio.concat`, `audio.add`, `audio.append`
Insert data at the indicated `time`. If `time` is omitted, the `data` will be appended to the end of audio. `data` may have the same types as `audio.write`. `channels` indicate channels to affect.
```js
// append data to the end
audio.insert([new Float32Array(100), new Float32Array(100)])
// prepend L and R buffer channels to SL and SR channels
audio.insert(ctx.createBuffer(2, 22050, 44100), {channels: [2, 3]})
// insert async data
Audio.load('./src.mp3').then(audio =>
Audio.load('./src2.mp3').then(audio2 => audio.insert(audio2))
).then(audio => {
//...audio here contains both src and src2
})
```
### audio.remove(time=0, duration?, {keep}?)
Alias: `audio.delete`, `audio.keep`, `audio.consume`
Remove fragment of the interval indicated by `time` and `duration`. Returns modified audio. Pass `keep` flag to return removed fragment.
```js
// delete 1s starting at .5s
audio.remove(.5, 1)
// remove 1s starting at 0.5s, return the fragment
let fragment = audio.remove(.5, 1, {keep: true})
```
### audio.slice(time=0, duration?, {copy}?)
Alias: `audio.copy`, `audio.clone`, `audio.subaudio`
Get fragment of audio with indicated part. By default creates a new audio fragment (immutable behavior), unless `{copy: false}` flag is passed, then modifies original audio in-place, which is faster.
```js
// clone audio
let dup = audio.slice()
// get 100 samples of audio content
let samples = audio.slice(audio.time(100), audio.time(100))
// slice to 1s starting from .5s
audio.slice(.5, 1, {copy: false})
```
### audio.trim({threshold:-40, left|right}?)
Alias: `audio.crop`
Trim silence at the beginning/end. `threshold` in decibels may define tolerance, `left` and `right` may indicate trim direction.
```js
// trim silence from ends
Audio([0,0,0,.1,.2,-.1,-.2,0,0], 1).trim()
// <.1, .2, -.1, -.2>
// trim samples from the beginning below -30 db
Audio([0.0001, 0, .1, .2, ...], 1).trim({threshold: -30, left: true})
// <.1, .2, ...>
// remove samples below .02 level from the end
Audio([.1, .2, -.1, -.2, 0, .0001]).trim({threshold: Audio.db(.02), left: false})
// <.1, .2, -.1, -.2>
```
### audio.pad(duration, value=0|{value, left}?)
Alias: `audio.leftPad`, `audio.rightPad`
Make sure the duration of the audio is at least the indicated `duration`. Pass `{left: true}` to pad left. Optionally indicate `value`, defaults to `0`.
```js
// pad right, same as audio.duration = 10
audio.pad(10)
// pad left with value 1
audio.pad(10, {left: true, value: 1})
// pad right with .1 constant value
audio.pad(10, .1)
```
### audio.shift(amount=0, {rotate: false, channel|channels?})
Alias: `audio.rotate`
Shift contents of audio to the left or right on the `amount` of time in seconds. Indicate `rotate` flag to shift in circular fashion. Pass `channel` or `channels` to shift specific channels only.
```js
// shift contents for 0.5s to the left
audio.shift(-.5)
// shift 100 samples of the left channel to the right in circular fashion
audio.shift(audio.time(100), {rotate: true, channel: 0})
```
### audio.fade(time=0, duration=0.4, {gain:-40db, easing, start, end,channels}?)`
Fade in or fade out volume for the `duration` starting from `time`. Duration can be negative, in that case it will fade backwards, i.e. fade out. Options may supply `easing` function or specific `gain`.
Default `easing` is linear, but any of the [eases](https://npmjs.org/package/eases) functions can be used. `easing` function has signature `v = ease(t)`, where `t` and `v` are from `0..1` range.
Fading is done by decibels to compensate logarithmic volume perception.
```js
const eases = require('eases')
Audio.load('./source.ogg', audio => {
//fade in 1s from the beginning
audio.fade(1, easing.cubicInOut)
//fade out 1s from the end
.fade(-1, easing.quadIn)
//fade in 20db during .2s starting at .6s
.fade(.6, .2, {gain: -20})
//fade out 5db during .2s starting at .8s (ending at 1s)
.fade(1, .2, {gain: -5})
})
```
### audio.repeat(times)
Repeat existing contents of audio indicated number of times.
```js
// empty audio
zero = audio.repeat(0)
// no operation
audio = audio.repeat(1)
// repeat two times
twiceAudio = audio.repeat(2)
```
### audio.normalize(time=0, duration?, {start, end, channels}?)
Normalize indicated interval or full audio, i.e. bring amplitudes to -1..+1 range. Max amplitude is found within all defined `channels`.
```js
// normalize full contents
let audio = Audio(new Float32Array([0,.1,0,-.1]), {channels: 1}).normalize()
audio.get({channels: 0}) //[0, 1, 0, -1]
// normalize 0 and 1 channels
audio = Audio(new Float32Array([0,.1, 0,.2, 0,.3]), {channels: 3}).normalize({channel: [0, 1]})
audio.get() //[[0, .5], [0, 1], [0, .3]]
```
| Property | Meaning |
|---|---|
| `channels` | Channels to affect, by default all. |
| `start` | Start from the position. |
| `end` | End at the position. |
| `dcOffset` | TODO: Remove DC offset, by default `true`. Can be a number. |
| `range` | TODO: Amplitudes range, by default `[-1, 1]`. |
### audio.gain(volume, time=0, duration?, {start, end, channels}?)
Change volume of the interval of `duration` starting at `time`. `volume` is in decibels.
```js
// make half as loud
let audio = new Audio(Array(44100).fill(1), 1).gain(-20)
```
### audio.reverse(time=0, duration?, {start, end, channels}?)
Negate samples for the indicated part.
```js
Audio('./sample.mp3', audio => {
//reverse first three seconds of audio and play
audio.reverse(0, 3).play()
})
```
### audio.pan(balance=.5, {gain: -5})
Apply stereo panning with audio compensation.
```js
```
### audio.mix(otherAudio, time=0, duration?, {channels}?)
Lay second audio over the first one at the indicated interval.
```js
```
### audio.scale(amount, time=0, duration?, options)
Stretch or shrink audio for the fragment.
```js
```
### audio.through(buf => buf, time=0, duration?, {channels, block}?)`
Alias: `audio.process`
Process audio or part of it with a function.
```js
// generate 2s of gray noise in stereo
let filter = require('audio-loudness')()
let noise = require('audio-noise/white')()
let grayNoise = Audio(2, 'stereo').through(noise).through(filter)
// create oscillator with LPF
let biquad = require('audio-biquad')({type: 'lpf', frequency: 880})
let saw = require('audio-oscillator')({type: 'saw', frequency: 440})
let dimmedSaw = Audio(2).through(saw).through(biquad)
```
#### Options
Property | Default | Meaning
--|---|---
`frame`, `block` | `false` | Enforce processing block size, ie. `1024` samples per block.
`channel`, `channels` | `all` | Affect only indicated channels, can be a number or array.
---