UNPKG

sono

Version:

A simple yet powerful JavaScript library for working with Web Audio

559 lines (463 loc) 16.7 kB
'use strict'; exports.__esModule = true; var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _createClass2 = require('babel-runtime/helpers/createClass'); var _createClass3 = _interopRequireDefault(_createClass2); var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); var _context = require('./context'); var _context2 = _interopRequireDefault(_context); var _bufferSource = require('./source/buffer-source'); var _bufferSource2 = _interopRequireDefault(_bufferSource); var _effects = require('./effects'); var _effects2 = _interopRequireDefault(_effects); var _emitter = require('./utils/emitter'); var _emitter2 = _interopRequireDefault(_emitter); var _file = require('./utils/file'); var _file2 = _interopRequireDefault(_file); var _firefox = require('./utils/firefox'); var _firefox2 = _interopRequireDefault(_firefox); var _utils = require('./utils/utils'); var _utils2 = _interopRequireDefault(_utils); var _isSafeNumber = require('./utils/isSafeNumber'); var _isSafeNumber2 = _interopRequireDefault(_isSafeNumber); var _loader = require('./utils/loader'); var _loader2 = _interopRequireDefault(_loader); var _audioSource = require('./source/audio-source'); var _audioSource2 = _interopRequireDefault(_audioSource); var _mediaSource = require('./source/media-source'); var _mediaSource2 = _interopRequireDefault(_mediaSource); var _microphoneSource = require('./source/microphone-source'); var _microphoneSource2 = _interopRequireDefault(_microphoneSource); var _oscillatorSource = require('./source/oscillator-source'); var _oscillatorSource2 = _interopRequireDefault(_oscillatorSource); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var Sound = function (_Emitter) { (0, _inherits3.default)(Sound, _Emitter); function Sound(config) { (0, _classCallCheck3.default)(this, Sound); var _this = (0, _possibleConstructorReturn3.default)(this, _Emitter.call(this)); _this.id = config.id || null; _this._context = config.context || _context2.default; _this._destination = config.destination || _this._context.destination; _this._effects = new _effects2.default(_this._context); _this._gain = _this._context.createGain(); _this._config = config; _this._data = null; _this._fadeTimeout = null; _this._isTouchLocked = false; _this._loader = null; _this._loop = false; _this._offset = 0; _this._playbackRate = 1; _this._playWhenReady = null; _this._source = null; _this._wave = null; _this._userData = {}; _this._effects.setDestination(_this._gain); _this._gain.connect(_this._destination); _this._onEnded = _this._onEnded.bind(_this); _this._onLoad = _this._onLoad.bind(_this); _this._onLoadError = _this._onLoadError.bind(_this); return _this; } Sound.prototype.prepare = function prepare() { var newConfig = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; var force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; var skipLoad = !force && !this._source && !!this._config.deferLoad; if (newConfig) { var configSrc = _file2.default.getSrc(newConfig); var src = _file2.default.getSupportedFile(configSrc) || this._config.src; this._config = Object.assign(this._config, newConfig, { src: src }); } if (this._source && this._data && this._data.tagName) { this._source.load(this._config.src); } else { this._loader = new _loader2.default(this._config.src, skipLoad); this._loader.audioContext = !!this._config.asMediaElement || this._context.isFake ? null : this._context; this._loader.isTouchLocked = this._isTouchLocked; this._loader.once('loaded', this._onLoad); this._loader.once('error', this._onLoadError); } return this; }; Sound.prototype.load = function load() { var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; this.stop(); this._source = null; if (!config || _file2.default.containsURL(config)) { if (this._loader) { this._loader.destroy(); } this.prepare(config, true); this._loader.start(); } else { this.data = config.data || config; } return this; }; Sound.prototype.play = function play(delay, offset) { var _this2 = this; if (!this._source || this._isTouchLocked) { this._playWhenReady = function () { if (_this2._source) { _this2.play(delay, offset); } }; if (!!this._config.deferLoad) { if (!this._loader) { this.prepare(null, true); } this._loader.start(true); } return this; } this._playWhenReady = null; this._effects.setSource(this._source.sourceNode); if (this._offset && typeof offset === 'undefined') { offset = this._offset; this._offset = 0; } this._source.play(delay, offset); if (this._source.hasOwnProperty('volume')) { this._source.volume = this._gain.gain.value; } if (this._source.hasOwnProperty('loop')) { this._source.loop = this._loop; } this.emit('play', this); return this; }; Sound.prototype.pause = function pause() { this._source && this._source.pause(); this.emit('pause', this); return this; }; Sound.prototype.stop = function stop(delay) { this._source && this._source.stop(delay || 0); this.emit('stop', this); return this; }; Sound.prototype.seek = function seek(value) { this.currentTime = value; return this; }; Sound.prototype.fade = function fade(volume) { var duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; if (!this._source) { return this; } var param = this._gain.gain; if (this._context && !this._context.isFake && !_firefox2.default) { var time = this._context.currentTime; param.cancelScheduledValues(time); param.setValueAtTime(param.value, time); param.linearRampToValueAtTime(volume, time + duration); } else { this._fadePolyfill(volume, duration); } this.emit('fade', this, volume); return this; }; Sound.prototype._fadePolyfill = function _fadePolyfill(toVolume, duration) { var _this3 = this; var ramp = function ramp(value, step) { _this3._fadeTimeout = window.setTimeout(function () { _this3.volume = _this3.volume + (value - _this3.volume) * 0.2; if (Math.abs(_this3.volume - value) > 0.05) { ramp(value, step); return; } _this3.volume = value; }, step * 1000); }; window.clearTimeout(this._fadeTimeout); ramp(toVolume, duration / 10); return this; }; Sound.prototype.unload = function unload() { this._source && this._source.destroy(); this._loader && this._loader.destroy(); this._data = null; this._playWhenReady = null; this._source = null; this._loader = null; this._config.deferLoad = true; this.emit('unload', this); }; Sound.prototype.reload = function reload() { return this.load(null, true); }; Sound.prototype.destroy = function destroy() { this._source && this._source.destroy(); this._effects && this._effects.destroy(); this._gain && this._gain.disconnect(); if (this._loader) { this._loader.off('loaded'); this._loader.off('error'); this._loader.destroy(); } this._gain = null; this._context = null; this._destination = null; this._data = null; this._playWhenReady = null; this._source = null; this._effects = null; this._loader = null; this._config = null; this.emit('destroy', this); this.off(); }; Sound.prototype.waveform = function waveform(length) { var _this4 = this; if (!this._wave) { this._wave = _utils2.default.waveform(); } if (!this._data) { this.once('ready', function () { return _this4._wave(_this4._data, length); }); } return this._wave(this._data, length); }; Sound.prototype._createSource = function _createSource(data) { var isAudioBuffer = _file2.default.isAudioBuffer(data); if (isAudioBuffer || _file2.default.isMediaElement(data)) { var Fn = isAudioBuffer ? _bufferSource2.default : _mediaSource2.default; this._source = new _audioSource2.default(Fn, data, this._context, this._onEnded); this._source.singlePlay = !!this._config.singlePlay; this._source.playbackRate = this._playbackRate; this._source.currentTime = this._offset; } else if (_file2.default.isMediaStream(data)) { this._source = new _microphoneSource2.default(data, this._context); } else if (_file2.default.isOscillatorType(data && data.type || data)) { this._source = new _oscillatorSource2.default(data.type || data, this._context); } else { throw new Error('Cannot detect data type: ' + data); } this._effects.setSource(this._source.sourceNode); this.emit('ready', this); if (this._playWhenReady) { this._playWhenReady(); } }; Sound.prototype._onEnded = function _onEnded() { this.emit('ended', this); }; Sound.prototype._onLoad = function _onLoad(data) { this._data = data; this.emit('loaded', this); this._createSource(data); }; Sound.prototype._onLoadError = function _onLoadError(err) { if (this.listenerCount('error')) { this.emit('error', this, err); return; } console.error('Sound load error', this._loader.url); }; (0, _createClass3.default)(Sound, [{ key: 'context', get: function get() { return this._context; } }, { key: 'currentTime', get: function get() { return this._source ? this._source.currentTime : this._offset; }, set: function set(value) { if (this._source) { var playing = this._source.playing; this._source.stop(); this._source.currentTime = value; if (playing) { this.play(0, value); } } else { this._offset = value; } } }, { key: 'data', get: function get() { return this._data; }, set: function set(value) { if (!value) { return; } this._data = value; this._createSource(value); } }, { key: 'duration', get: function get() { return this._source ? this._source.duration : 0; } }, { key: 'effects', get: function get() { return this._effects._nodes; }, set: function set(value) { this._effects.removeAll().add(value); } }, { key: 'fx', get: function get() { return this.effects; }, set: function set(value) { this.effects = value; } }, { key: 'ended', get: function get() { return !!this._source && this._source.ended; } }, { key: 'frequency', get: function get() { return this._source ? this._source.frequency : 0; }, set: function set(value) { if (this._source && this._source.hasOwnProperty('frequency')) { this._source.frequency = value; } } }, { key: 'gain', get: function get() { return this._gain; } // for media element source }, { key: 'groupVolume', get: function get() { return this._source.groupVolume; }, set: function set(value) { if (this._source && this._source.hasOwnProperty('groupVolume')) { this._source.groupVolume = value; } } }, { key: 'isTouchLocked', set: function set(value) { this._isTouchLocked = value; if (this._loader) { this._loader.isTouchLocked = value; } if (!value && this._playWhenReady) { this._playWhenReady(); } } }, { key: 'loader', get: function get() { return this._loader; } }, { key: 'loop', get: function get() { return this._loop; }, set: function set(value) { this._loop = !!value; if (this._source && this._source.hasOwnProperty('loop') && this._source.loop !== this._loop) { this._source.loop = this._loop; } } }, { key: 'singlePlay', get: function get() { return this._config.singlePlay; }, set: function set(value) { this._config.singlePlay = value; this._source.singlePlay = value; } }, { key: 'config', get: function get() { return this._config; } }, { key: 'paused', get: function get() { return !!this._source && this._source.paused; } }, { key: 'playing', get: function get() { return !!this._source && this._source.playing; } }, { key: 'playbackRate', get: function get() { return this._playbackRate; }, set: function set(value) { this._playbackRate = value; if (this._source) { this._source.playbackRate = value; } } }, { key: 'progress', get: function get() { return this._source ? this._source.progress || 0 : 0; } }, { key: 'sourceInfo', get: function get() { return this._source && this._source.info ? this._source.info : {}; } }, { key: 'sourceNode', get: function get() { return this._source ? this._source.sourceNode : null; } }, { key: 'volume', get: function get() { return this._gain.gain.value; }, set: function set(value) { if (!(0, _isSafeNumber2.default)(value)) { return; } window.clearTimeout(this._fadeTimeout); value = Math.min(Math.max(value, 0), 1); var param = this._gain.gain; var time = this._context.currentTime; param.cancelScheduledValues(time); param.value = value; if (!_firefox2.default) { param.setValueAtTime(value, time); } if (this._source && this._source.hasOwnProperty('volume')) { this._source.volume = value; } } }, { key: 'userData', get: function get() { return this._userData; } }]); return Sound; }(_emitter2.default); // expose for unit tests exports.default = Sound; Sound.__source = { BufferSource: _bufferSource2.default, MediaSource: _mediaSource2.default, MicrophoneSource: _microphoneSource2.default, OscillatorSource: _oscillatorSource2.default };