qambi
Version:
MIDI sequencer, loads MIDI files, can record and playback MIDI, uses WebMIDI and WebAudio
409 lines (341 loc) • 15.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Sampler = undefined;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _instrument = require('./instrument');
var _note = require('./note');
var _parse_audio = require('./parse_audio');
var _util = require('./util');
var _fetch_helpers = require('./fetch_helpers');
var _sample_buffer = require('./sample_buffer');
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var instanceIndex = 0;
var Sampler = exports.Sampler = function (_Instrument) {
_inherits(Sampler, _Instrument);
function Sampler(name) {
_classCallCheck(this, Sampler);
var _this = _possibleConstructorReturn(this, (Sampler.__proto__ || Object.getPrototypeOf(Sampler)).call(this));
_this.id = _this.constructor.name + '_' + instanceIndex++ + '_' + new Date().getTime();
_this.name = name || _this.id;
_this.clearAllSampleData();
return _this;
}
_createClass(Sampler, [{
key: 'clearAllSampleData',
value: function clearAllSampleData() {
// create a samples data object for all 128 velocity levels of all 128 notes
this.samplesData = new Array(128).fill(-1);
this.samplesData = this.samplesData.map(function () {
return new Array(128).fill(-1);
});
}
}, {
key: 'createSample',
value: function createSample(event) {
return new _sample_buffer.SampleBuffer(this.samplesData[event.data1][event.data2], event);
}
}, {
key: '_loadJSON',
value: function _loadJSON(data) {
if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === 'object' && typeof data.url === 'string') {
return (0, _fetch_helpers.fetchJSON)(data.url);
}
return Promise.resolve(data);
}
// load and parse
}, {
key: 'parseSampleData',
value: function parseSampleData(data) {
var _this2 = this;
// check if we have to clear the currently loaded samples
var clearAll = data.clearAll;
// check if we have to overrule the baseUrl of the sampels
var baseUrl = null;
if (typeof data.baseUrl === 'string') {
baseUrl = data.baseUrl;
}
if (typeof data.release !== 'undefined') {
this.setRelease(data.release[0], data.release[1]);
//console.log(1, data.release[0], data.release[1])
}
//return Promise.resolve()
return new Promise(function (resolve, reject) {
_this2._loadJSON(data).then(function (json) {
//console.log(json)
data = json;
if (baseUrl !== null) {
json.baseUrl = baseUrl;
}
if (typeof data.release !== 'undefined') {
_this2.setRelease(data.release[0], data.release[1]);
//console.log(2, data.release[0], data.release[1])
}
return (0, _parse_audio.parseSamples)(data);
}).then(function (result) {
if (clearAll === true) {
_this2.clearAllSampleData();
}
if ((typeof result === 'undefined' ? 'undefined' : _typeof(result)) === 'object') {
// single concatenated sample
if (typeof result.sample !== 'undefined') {
var buffer = result.sample;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = Object.keys(data)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var noteId = _step.value;
if (noteId === 'sample' || noteId === 'release' || noteId === 'baseUrl' || noteId === 'info') {
continue;
}
var sampleData = {
segment: data[noteId],
note: parseInt(noteId, 10),
buffer: buffer
};
_this2._updateSampleData(sampleData);
//console.log(sampleData)
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
} else {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
var _loop = function _loop() {
var noteId = _step2.value;
var buffer = result[noteId];
var sampleData = data[noteId];
if (typeof sampleData === 'undefined') {
console.log('sampleData is undefined', noteId);
} else if ((0, _util.typeString)(buffer) === 'array') {
//console.log(buffer, sampleData)
sampleData.forEach(function (sd, i) {
//console.log(noteId, buffer[i])
if (typeof sd === 'string') {
sd = {
buffer: buffer[i]
};
} else {
sd.buffer = buffer[i];
}
sd.note = parseInt(noteId, 10);
_this2._updateSampleData(sd);
});
} else {
if (typeof sampleData === 'string') {
sampleData = {
buffer: buffer
};
} else {
sampleData.buffer = buffer;
}
sampleData.note = parseInt(noteId, 10);
_this2._updateSampleData(sampleData);
}
};
for (var _iterator2 = Object.keys(result)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
_loop();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
} else {
result.forEach(function (sample) {
var sampleData = data[sample];
if (typeof sampleData === 'undefined') {
console.log('sampleData is undefined', sample);
} else {
if (typeof sampleData === 'string') {
sampleData = {
buffer: sample.buffer
};
} else {
sampleData.buffer = sample.buffer;
}
sampleData.note = sample;
_this2._updateSampleData(sampleData);
//this.updateSampleData(sampleData)
}
});
}
//console.log(new Date().getTime())
resolve();
});
});
}
/*
@param config (optional)
{
note: can be note name (C4) or note number (60)
buffer: AudioBuffer
sustain: [sustainStart, sustainEnd], // optional, in millis
release: [releaseDuration, releaseEnvelope], // optional
pan: panPosition // optional
velocity: [velocityStart, velocityEnd] // optional, for multi-layered instruments
}
*/
}, {
key: 'updateSampleData',
value: function updateSampleData() {
var _this3 = this;
for (var _len = arguments.length, data = Array(_len), _key = 0; _key < _len; _key++) {
data[_key] = arguments[_key];
}
data.forEach(function (noteData) {
// support for multi layered instruments
//console.log(noteData, typeString(noteData))
if ((0, _util.typeString)(noteData) === 'array') {
noteData.forEach(function (velocityLayer) {
_this3._updateSampleData(velocityLayer);
});
} else {
_this3._updateSampleData(noteData);
}
});
}
}, {
key: '_updateSampleData',
value: function _updateSampleData() {
var _this4 = this;
var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
//console.log(data)
var note = data.note,
_data$buffer = data.buffer,
buffer = _data$buffer === undefined ? null : _data$buffer,
_data$sustain = data.sustain,
sustain = _data$sustain === undefined ? [null, null] : _data$sustain,
_data$segment = data.segment,
segment = _data$segment === undefined ? [null, null] : _data$segment,
_data$release = data.release,
release = _data$release === undefined ? [null, 'linear'] : _data$release,
_data$pan = data.pan,
pan = _data$pan === undefined ? null : _data$pan,
_data$velocity = data.velocity,
velocity = _data$velocity === undefined ? [0, 127] : _data$velocity;
if (typeof note === 'undefined') {
console.warn('please provide a notenumber or a notename');
return;
}
// get notenumber from notename and check if the notenumber is valid
var n = (0, _note.getNoteData)({ number: note });
if (n === false) {
console.warn('not a valid note id');
return;
}
note = n.number;
var _sustain = _slicedToArray(sustain, 2),
sustainStart = _sustain[0],
sustainEnd = _sustain[1];
var _release = _slicedToArray(release, 2),
releaseDuration = _release[0],
releaseEnvelope = _release[1];
var _segment = _slicedToArray(segment, 2),
segmentStart = _segment[0],
segmentDuration = _segment[1];
var _velocity = _slicedToArray(velocity, 2),
velocityStart = _velocity[0],
velocityEnd = _velocity[1];
if (sustain.length !== 2) {
sustainStart = sustainEnd = null;
}
if (releaseDuration === null) {
releaseEnvelope = null;
}
// console.log(note, buffer)
// console.log(sustainStart, sustainEnd)
// console.log(releaseDuration, releaseEnvelope)
// console.log(pan)
// console.log(velocityStart, velocityEnd)
this.samplesData[note].forEach(function (sampleData, i) {
if (i >= velocityStart && i <= velocityEnd) {
if (sampleData === -1) {
sampleData = {
id: note
};
}
sampleData.buffer = buffer || sampleData.buffer;
sampleData.sustainStart = sustainStart || sampleData.sustainStart;
sampleData.sustainEnd = sustainEnd || sampleData.sustainEnd;
sampleData.segmentStart = segmentStart || sampleData.segmentStart;
sampleData.segmentDuration = segmentDuration || sampleData.segmentDuration;
sampleData.releaseDuration = releaseDuration || sampleData.releaseDuration;
sampleData.releaseEnvelope = releaseEnvelope || sampleData.releaseEnvelope;
sampleData.pan = pan || sampleData.pan;
if ((0, _util.typeString)(sampleData.releaseEnvelope) === 'array') {
sampleData.releaseEnvelopeArray = sampleData.releaseEnvelope;
sampleData.releaseEnvelope = 'array';
} else {
delete sampleData.releaseEnvelopeArray;
}
_this4.samplesData[note][i] = sampleData;
}
//console.log('%O', this.samplesData[note])
});
}
// stereo spread
}, {
key: 'setKeyScalingPanning',
value: function setKeyScalingPanning() {
// sets panning based on the key value, e.g. higher notes are panned more to the right and lower notes more to the left
}
}, {
key: 'setKeyScalingRelease',
value: function setKeyScalingRelease() {}
// set release based on key value
/*
@duration: milliseconds
@envelope: linear | equal_power | array of int values
*/
}, {
key: 'setRelease',
value: function setRelease(duration, envelope) {
// set release for all keys, overrules values set by setKeyScalingRelease()
this.samplesData.forEach(function (samples, id) {
samples.forEach(function (sample, i) {
if (sample === -1) {
sample = {
id: id
};
}
sample.releaseDuration = duration;
sample.releaseEnvelope = envelope;
samples[i] = sample;
});
});
//console.log('%O', this.samplesData)
}
}]);
return Sampler;
}(_instrument.Instrument);