audio-buffer-from
Version:
Create AudioBuffer from any source
150 lines (125 loc) • 4 kB
JavaScript
/**
* @module audio-dtype
*/
var AudioBuffer = require('audio-buffer')
var isAudioBuffer = require('is-audio-buffer')
var isObj = require('is-plain-obj')
var getContext = require('audio-context')
var convert = require('pcm-convert')
var format = require('audio-format')
var str2ab = require('string-to-arraybuffer')
var pick = require('pick-by-alias')
module.exports = function createBuffer (source, options) {
var length, data, channels, sampleRate, format, c, l
//src, channels
if (typeof options === 'number') {
options = {channels: options}
}
else if (typeof options === 'string') {
options = {format: options}
}
//{}
else if (options === undefined) {
if (isObj(source)) {
options = source
source = undefined
}
else {
options = {}
}
}
options = pick(options, {
format: 'format type dtype dataType',
channels: 'channel channels numberOfChannels channelCount',
sampleRate: 'sampleRate rate',
length: 'length size',
duration: 'duration time'
})
//detect options
channels = options.channels
sampleRate = options.sampleRate
if (options.format) format = getFormat(options.format)
if (format) {
if (channels && !format.channels) format.channels = channels
else if (format.channels && !channels) channels = format.channels
if (!sampleRate && format.sampleRate) sampleRate = format.sampleRate
}
//empty buffer
if (source == null) {
if (options.duration != null) {
if (!sampleRate) sampleRate = 44100
length = sampleRate * options.duration
}
else length = options.length
}
//if audio buffer passed - create fast clone of it
else if (isAudioBuffer(source)) {
length = source.length
if (channels == null) channels = source.numberOfChannels
if (sampleRate == null) sampleRate = source.sampleRate
if (source._channelData) {
data = source._channelData.slice(0, channels)
}
else {
data = []
for (c = 0, l = channels; c < l; c++) {
data[c] = source.getChannelData(c)
}
}
}
//if create(number, channels? rate?) = create new array
//this is the default WAA-compatible case
else if (typeof source === 'number') {
length = source
}
//if array with channels - parse channeled data
else if (Array.isArray(source) && (Array.isArray(source[0]) || ArrayBuffer.isView(source[0]))) {
length = source[0].length;
data = []
if (!channels) channels = source.length
for (c = 0; c < channels; c++) {
data[c] = source[c] instanceof Float32Array ? source[c] : new Float32Array(source[c])
}
}
//if ndarray, ndsamples, or anything with data
else if (source.shape && source.data) {
if (source.shape) channels = source.shape[1]
if (!sampleRate && source.format) sampleRate = source.format.sampleRate
return createBuffer(source.data, {
channels: channels,
sampleRate: sampleRate
})
}
//TypedArray, Buffer, DataView etc, ArrayBuffer, Array etc.
//NOTE: node 4.x+ detects Buffer as ArrayBuffer view
else {
if (typeof source === 'string') {
source = str2ab(source)
}
if (!format) format = getFormat(source)
if (!channels) channels = format.channels || 1
source = convert(source, format, 'float32 planar')
length = Math.floor(source.length / channels);
data = []
for (c = 0; c < channels; c++) {
data[c] = source.subarray(c * length, (c + 1) * length);
}
}
//create buffer of proper length
var audioBuffer = new AudioBuffer((options.context === null || length === 0) ? null : options.context || getContext(), {
length: length == null ? 1 : length,
numberOfChannels: channels || 1,
sampleRate: sampleRate || 44100
})
//fill channels
if (data) {
for (c = 0, l = data.length; c < l; c++) {
audioBuffer.getChannelData(c).set(data[c]);
}
}
return audioBuffer
}
function getFormat (arg) {
return typeof arg === 'string' ? format.parse(arg) : format.detect(arg)
}