webdaw-modules
Version:
a set of modules for building a web-based DAW
454 lines (393 loc) • 15.8 kB
JavaScript
function samplePack() {
'use strict';
var
ajax, //defined in util.js
findItem, //defined in util.js
storeItem, //defined in util.js
deleteItem, //defined in util.js
typeString, //defined in util.js
parseUrl, //defined in util.js
base64ToBinary, // defined in util.js
context, //defined in open_module.js
storage, //defined in open_module.js
parseTime,
folder,
sampleId,
index = 0,
SamplePack;
function parse(samplepack, config) {
var i, mapping = config.mapping, url, path, name, ext, slash, dot, data,
remotePath,
sampleData,
extension;
samplepack.samples = [];
samplepack.samplesById = {};
remotePath = config.remote_path;
remotePath = remotePath === undefined ? false : remotePath;
//console.log(samplepack.folder, samplepack.name);
//console.log(samplepack, config);
for (i in mapping) {
if (mapping.hasOwnProperty(i)) {
sampleData = {
id: i,
folder: samplepack.folder + '/' + samplepack.name,
};
//@TODO: this is not correct! A remote_path is not mandatory for a sample pack with urls!
if (remotePath !== false) {
url = mapping[i];
if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
sampleData.url = url;
} else {
name = url;
// check if the url has a path and/or an extension
slash = url.lastIndexOf('/');
if (slash !== -1) {
name = url.substring(slash + 1);
}
path = url.substring(0, slash);
dot = url.lastIndexOf('.');
extension = config.extension;
if (dot !== -1) {
ext = url.substring(dot + 1);
if (ext.length >= 3 && ext.length <= 4) {
extension = ext;
name = url.substring(slash, dot);
}
}
//console.log('u', url, 'r',remotePath, 'p', path, 'n', name, 'e', extension);
url = remotePath + '/' + path + '/' + name + '.' + extension;
url = url.replace(/\/{2,}/g, '/');
url = url.replace(/^\//, '');
url = url.replace(/$\//, '');
sampleData.url = url;
}
//console.log('loading sample from:', sampleData.url);
} else {
data = mapping[i];
if (data.d !== undefined) {
sampleData.base64 = mapping[i].d;
// get the sustain loop start and end
if (data.s !== undefined) {
sampleData.sustain = data.s;
}
// get the sample specific release duration and envelope, or reference to group release duration
if (data.r !== undefined) {
sampleData.release = data.r;
}
} else {
sampleData.base64 = mapping[i];
}
// store sample data by id so the instrument can easily retreive the loop information per sample
samplepack.samplesById[i] = sampleData;
//console.log(sampleData)
}
samplepack.samples.push(sampleData);
}
}
}
function loadLoop(pack, callback) {
//console.log('load sample pack', pack.name);
loadSamples(pack.samples, function (buffer) {
//console.log('kheb er een ferig', buffer);
}, function () {
pack.loaded = true;
pack.parseTime = parseTime;
if (sequencer.debug >= 2) {
console.info('parsing', pack.name, 'took', parseTime * 1000, 'ms');
}
//console.log(pack.localPath, pack.loaded);
if (callback) {
callback(true);
}
});
}
function cleanup(samplepack, callback) {
samplepack.reset();
samplepack = undefined;
callback(false);
}
function store(samplepack) {
var occupied = findItem(samplepack.localPath, sequencer.storage.samplepacks, true),
action = samplepack.action,
i, samples, sample;
//console.log(action, occupied);
if (occupied && occupied.className === 'SamplePack') {
if (action === 'overwrite') {
samples = occupied.samples;
for (i = samples.length - 1; i >= 0; i--) {
sample = samples[i];
deleteItem(sample.name + '/' + sample.folder, sequencer.storage.audio);
}
} else if (action === 'append') {
samples = occupied.samples;
for (i = samples.length - 1; i >= 0; i--) {
samplepack.samples.push(samples[i]);
}
} else {
if (sequencer.debug >= 2) {
console.warn('there is already a samplepack at', samplepack.localPath);
}
return false;
}
}
storeItem(samplepack, samplepack.localPath, sequencer.storage.samplepacks);
return true;
}
function load(pack, callback) {
// check if sample pack file needs to be loaded first
if (pack.hasMapping !== true) {
ajax({
url: pack.url,
responseType: 'json',
onError: function () {
cleanup(pack, callback);
},
onSuccess: function (data) {
// if the json data is corrupt (for instance because of a trailing comma) data will be null
if (data === null) {
callback(false);
return;
}
if (data.mapping === undefined) {
if (sequencer.debug >= 2) {
console.warn('can\'t create a SamplePack with this data', data);
}
cleanup(pack, callback);
return;
}
if (data.name !== undefined && pack.name === undefined) {
pack.name = data.name;
}
if (data.folder !== undefined && pack.folder === undefined) {
pack.folder = data.folder;
}
if (pack.name === undefined) {
pack.name = parseUrl(pack.url).name;
}
pack.action = data.action;
pack.localPath = pack.folder !== undefined ? pack.folder + '/' + pack.name : pack.name;
if (store(pack) === true) {
parse(pack, data);
loadLoop(pack, callback);
} else {
callback(false);
}
}
});
} else {
if (store(pack) === true) {
loadLoop(pack, callback);
} else {
//console.log(callback);
callback(false);
}
}
}
// private
function loadSamples(samples, callback1, callback2) {
var i = 0,
numSamples = samples.length,
sample = samples[i];
function loaded(buffer) {
//console.log('store item', folder + '/' + sampleId);
// sample.buffer = buffer;
// storeItem(sample, folder + '/' + sampleId, storage.audio);
storeItem(buffer, folder + '/' + sampleId, storage.audio);
if (callback1) {
callback1(buffer);
}
i++;
if (i < numSamples) {
sample = samples[i];
loadSample(sample, loaded);
} else {
callback2();
}
}
loadSample(sample, loaded);
}
// private
function loadSample(data, callback) {
var sample,
url = data.url,
base64 = data.base64;
sampleId = data.id;
folder = data.folder;
sample = findItem(folder + '/' + sampleId, storage.audio, true);
//console.log('load sample', sample, folder, sampleId, callback.name);
//console.log(url);
if (sample !== false) {
// sample has already been loaded
callback(sample);
} else if (base64) {
// sample is stored as base64 data
//console.log(data.id, sample)
//sample = atob(base64);
//console.log(base64.substring(0,10));
if (base64 !== 'TWAAAP') {
sample = base64ToBinary(base64);
parseAudioData(sample, callback);
} else {
callback(sample);
}
data.base64 = '';
} else if (url) {
// sample needs to be loaded from the server
ajax({
url: url,
responseType: 'arraybuffer',
onError: function () {
callback();
},
onSuccess: function (buffer) {
//console.log(sampleId, buffer);
parseAudioData(buffer, callback);
}
});
} else {
console.error('could not load sample', folder + '/' + sampleId);
//callback();
}
}
// private
function parseAudioData(audiodata, callback) {
//console.log(audiodata, typeString(audiodata), audiodata.byteLength, ArrayBuffer.isView(audiodata));
var ts = sequencer.getTime();
//console.log(ts);
if (audiodata !== null) {
try {
context.decodeAudioData(audiodata, function (buffer) {
//console.log(buffer);
parseTime += (sequencer.getTime() - ts);
callback(buffer);
}, function (e) {
console.log('error decoding audiodata', sampleId, e);
callback();
});
} catch (e) {
console.log(sampleId, e);
callback();
}
}
}
SamplePack = function (config) {
this.id = 'SP' + index++ + new Date().getTime();
this.className = 'SamplePack';
this.loaded = false;
this.loadTime = 0;
this.parseTime = parseTime = 0;
this.url = config.url;
this.name = config.name;
this.folder = config.folder;
this.info = config.info || config.samplepack_info;
this.author = config.author || config.samplepack_author;
this.license = config.license || config.samplepack_license;
this.compression = config.compression || config.samplepack_compression;
if (this.compression === undefined) {
if (config.compression_type !== undefined) {
this.compression = config.compression_type + ' ' + config.compression_level;
}
}
this.pack = config.pack;
this.filesize = config.filesize;
if (this.filesize === undefined && this.pack !== undefined) {
this.filesize = this.pack.filesize;
//console.log(this.filesize);
}
if (config.mapping) {
if (this.name === undefined && this.folder === undefined) {
this.name = this.id;
this.localPath = this.id;
} else {
this.localPath = this.folder !== undefined ? this.folder + '/' + this.name : this.name;
}
// set hasMapping to "true" so we know that we don't have to load json data from the server
this.hasMapping = true;
this.action = config.action;
parse(this, config);
} else if (config.url) {
this.url = config.url;
//console.log(this.url);
}
};
SamplePack.prototype.reset = function () {
this.samples = [];
};
sequencer.addSamplePack = function (config, callback, callbackAfterAllTasksAreDone) {
var type = typeString(config),
samplepack, json, name, folder;
callbackAfterAllTasksAreDone = callbackAfterAllTasksAreDone === undefined ? false : callbackAfterAllTasksAreDone;
//console.log(config);
if (type !== 'object') {
if (sequencer.debug >= 2) {
console.warn('can\'t create a SamplePack with this data', config);
}
return false;
}
if (config.json) {
json = config.json;
name = config.name;
folder = config.folder;
if (typeString(json) === 'string') {
try {
json = JSON.parse(json);
} catch (e) {
if (sequencer.debug >= 2) {
console.warn('can\'t create a SamplePack with this data', config);
}
return false;
}
}
if (json.mapping === undefined) {
if (sequencer.debug >= 2) {
console.warn('can\'t create a SamplePack with this data', config);
}
return false;
}
config = {
mapping: json.mapping,
name: name === undefined ? json.name : name,
folder: folder === undefined ? json.folder : folder
};
//console.log('config', name, folder, json.name, json.folder);
}
samplepack = new SamplePack(config);
//console.log(samplepack.filesize);
sequencer.addTask({
type: 'load sample pack',
method: load,
params: samplepack
}, function (value) {
//console.log(samplepack, value);
if (callback) {
if (value === false) {
samplepack = null;
callback(null);
} else {
callback(samplepack);
}
}
}, callbackAfterAllTasksAreDone);
sequencer.startTaskQueue();
/*
load(samplepack, function(){
//console.log(samplepack);
store(samplepack);
if(callback){
callback(samplepack);
}
});
*/
};
sequencer.protectedScope.addInitMethod(function () {
storage = sequencer.storage;
ajax = sequencer.protectedScope.ajax;
context = sequencer.protectedScope.context;
findItem = sequencer.protectedScope.findItem;
parseUrl = sequencer.protectedScope.parseUrl;
storeItem = sequencer.protectedScope.storeItem;
deleteItem = sequencer.protectedScope.deleteItem;
typeString = sequencer.protectedScope.typeString;
base64ToBinary = sequencer.protectedScope.base64ToBinary;
});
}