Skip to content

Commit

Permalink
Update audio-buffer to v4.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dy committed May 24, 2017
1 parent 224a8f9 commit a55d8e1
Show file tree
Hide file tree
Showing 4 changed files with 342 additions and 94 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,18 @@ Utility functions for [_AudioBuffers_](https://github.com/audiojs/audio-buffer)

[![npm install audio-buffer-utils](https://nodei.co/npm/audio-buffer-utils.png?mini=true)](https://npmjs.org/package/audio-buffer-utils/)

### `const util = require('audio-buffer-utils')`
Get utils toolset.

_AudioBuffer_ data layout is considered horizontal, in that samples are arranged horizontally and channels vertically. Functions arguments take sample index first and channel index second.

Sample values range from `-1` to `1`, but not limited to it.

### `util.create(data|length, channels=2, sampleRate=44100)`
Create a new buffer from any argument.
Data can be a length, an array with channels' data, an other buffer or plain array.

```js
//mono buffer with 100 samples
let a = util.create(100, 1)
let a = util.create(100)

//stereo buffer with predefined channels data
let b = util.create([Array(100).fill(0.5), Array(100).fill(0.4)])

//minimal length buffer (1 sample, 2 channels)
//minimal length buffer (1 sample, 1 channel)
let c = util.create()

//create 2 seconds buffer with reduced sample rate
Expand Down Expand Up @@ -125,7 +118,19 @@ util.fill(a, (value, i, channel)=>Math.sin(Math.PI * 2 * frequency * i / rate))
Create a new buffer by slicing the current one.

### `util.subbuffer(buffer, start=0, end=-0)`
Create a new buffer by subreferencing the current one. The new buffer represents a handle for the source buffer, working on it's data.
Create a new buffer by subreferencing the current one. The new buffer represents a handle for the source buffer, working on it's data. Note that it is null-context buffer, meaning that it is not bound to web audio API. To convert it to real _AudioBuffer_, use `util.create`.

```js
var a = util.create(100, 2)
var b = util.subbuffer(10, 90)

//b references a
b.getChannelData(0)[0] = 1
a.getChannelData(0)[10] // 1

//convert b to web-audio-api buffer
b = util.slice(b)
```

### `util.concat(buffer1, [buffer2, buffer3], bufferN, ...)`
Create a new buffer by concatting buffers or list.
Expand Down
99 changes: 91 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@

'use strict'

require('typedarray-methods')
var AudioBuffer = require('audio-buffer')
var isAudioBuffer = require('is-audio-buffer')
var isBrowser = require('is-browser')
var nidx = require('negative-index')
var clamp = require('clamp')
var context = require('audio-context')
var context = require('audio-context')()
var isBuffer = require('is-buffer')
var b2ab = require('buffer-to-arraybuffer')

module.exports = {
context: context,
create: create,
copy: copy,
shallow: shallow,
Expand Down Expand Up @@ -42,13 +44,85 @@ module.exports = {
subbuffer: subbuffer
}

var defaultRate = context && context.sampleRate || 44100


/**
* Create buffer from any argument
* Create buffer from any argument.
* Better constructor than audio-buffer.
*/
function create (len, channels, rate, options) {
if (!options) options = {}
return new AudioBuffer(channels, len, rate, options);
function create (src, channels, sampleRate) {
var length, data

if (channels == null) channels = src && src.numberOfChannels || 1
if (sampleRate == null) sampleRate = src && src.sampleRate || defaultRate;

//if audio buffer passed - create fast clone of it
if (isAudioBuffer(src)) {
length = src.length;

data = []

//take channel's data
for (var c = 0, l = channels; c < l; c++) {
data[c] = src.getChannelData(c)
}
}

//if create(number, channels? rate?) = create new array
//this is the default WAA-compatible case
else if (typeof src === 'number') {
length = src
data = null
}

//TypedArray, Buffer, DataView etc, ArrayBuffer or plain array
//NOTE: node 4.x+ detects Buffer as ArrayBuffer view
else if (ArrayBuffer.isView(src) || src instanceof ArrayBuffer || isBuffer(src) || (Array.isArray(src) && !(src[0] instanceof Object))) {
if (isBuffer(src)) {
src = b2ab(src);
}
//convert non-float array to floatArray
if (!(src instanceof Float32Array) && !(src instanceof Float64Array)) {
src = new Float32Array(src.buffer || src);
}
length = Math.floor(src.length / channels);
data = []
for (var c = 0; c < channels; c++) {
data[c] = src.subarray(c * length, (c + 1) * length);
}
}
//if array - parse channeled data
else if (Array.isArray(src)) {
//if separated src passed already - send sub-arrays to channels
length = src[0].length;
data = []
channels = src.length
for (var c = 0; c < channels; c++ ) {
data[c] = ((src[c] instanceof Float32Array) || (src[c] instanceof Float64Array)) ? src[c] : new Float32Array(src[c])
}
}
//if ndarray, typedarray or other data-holder passed - redirect plain databuffer
else if (src && (src.data || src.buffer)) {
if (src.shape) channels = src.shape[1]
return create(src.data || src.buffer, channels, sampleRate);
}

//create buffer of proper length
let audioBuffer = new AudioBuffer(context, {
length: length,
numberOfChannels: channels,
sampleRate: sampleRate
})

//fill channels
if (data) {
for (var c = 0; c < channels; c++) {
audioBuffer.getChannelData(c).set(data[c]);
}
}

return audioBuffer
}


Expand Down Expand Up @@ -88,7 +162,7 @@ function shallow (buffer) {
//workaround for faster browser creation
//avoid extra checks & copying inside of AudioBuffer class
if (isBrowser) {
return context().createBuffer(buffer.numberOfChannels, buffer.length, buffer.sampleRate);
return context.createBuffer(buffer.numberOfChannels, buffer.length, buffer.sampleRate);
}

return create(buffer.length, buffer.numberOfChannels, buffer.sampleRate);
Expand Down Expand Up @@ -281,7 +355,16 @@ function subbuffer (buffer, start, end) {
var channelData = buffer.getChannelData(channel)
data.push(channelData.subarray(start, end));
}
return create(data, buffer.numberOfChannels, buffer.sampleRate, {isWAA: false});

//null-context buffer covers web-audio-api buffer functions
var buf = new AudioBuffer(null, {length: 0, sampleRate: buffer.sampleRate, numberOfChannels: buffer.numberOfChannels})

//FIXME: not reliable hack to replace data. Mb use audio-buffer-list?
buf.length = data[0].length
buf._data = null
buf._channelData = data

return buf
}

/**
Expand Down
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@
"devDependencies": {
"almost-equal": "^1.1.0",
"is-browser": "^2.0.1",
"ndarray": "^1.0.18",
"tape": "^4.6.3"
},
"dependencies": {
"audio-buffer": "^3.1.1",
"audio-buffer": "^4.0.0",
"audio-context": "^1.0.0",
"buffer-to-arraybuffer": "0.0.4",
"clamp": "^1.0.1",
"is-audio-buffer": "^1.0.0",
"is-audio-buffer": "^1.0.8",
"is-browser": "^2.0.1",
"negative-index": "^1.0.2",
"typedarray-methods": "^1.0.0"
"is-buffer": "^1.1.5",
"negative-index": "^1.0.2"
}
}
Loading

0 comments on commit a55d8e1

Please sign in to comment.