UNPKG

qambi

Version:

MIDI sequencer, loads MIDI files, can record and playback MIDI, uses WebMIDI and WebAudio

409 lines (341 loc) 15.5 kB
'use strict'; 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);