react-sound-html5
Version:
A tiny React component wich provide simple abstraption to manipulate HTML5 AudioContext API (Equalizer, visualisation, stereo, basic controls)
227 lines • 9.17 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importDefault(require("react"));
var SoundStatus;
(function (SoundStatus) {
SoundStatus["PAUSED"] = "PAUSED";
SoundStatus["PLAYING"] = "PLAYING";
SoundStatus["STOPPED"] = "STOPPED";
})(SoundStatus || (SoundStatus = {}));
/**
* Sound Component
*/
var Sound = /** @class */ (function (_super) {
__extends(Sound, _super);
function Sound(props) {
var _this = _super.call(this, props) || this;
_this.filters = [];
_this.handleVisualizationChange = _this.handleVisualizationChange.bind(_this);
_this.handleTimeUpdate = _this.handleTimeUpdate.bind(_this);
_this.attachRef = _this.attachRef.bind(_this);
return _this;
}
Sound.prototype.attachRef = function (element) {
if (element) {
this.audio = element;
}
};
Sound.prototype.createFilterNodes = function () {
var _this = this;
var lastInChain = this.gainNode;
var _a = this.props, equalizer = _a.equalizer, _b = _a.preAmp, preAmp = _b === void 0 ? 0 : _b;
if (equalizer) {
this.qValues = Object.keys(equalizer).map(function (freq, i, arr) {
if (!i || i === arr.length - 1) {
return null;
}
else {
return (2 * Number(freq)) / Math.abs(Number(arr[i + 1]) - Number(arr[i - 1]));
}
});
Object.keys(equalizer).forEach(function (freq, i, arr) {
var biquadFilter = _this.audioContext.createBiquadFilter();
biquadFilter.type = 'peaking';
biquadFilter.frequency.value = Number(freq);
biquadFilter.gain.value = equalizer[freq] + preAmp;
if (!i || i === arr.length - 1) {
biquadFilter.type = i ? 'highshelf' : 'lowshelf';
}
else {
biquadFilter.Q.value = _this.qValues[i];
}
if (lastInChain) {
lastInChain.connect(biquadFilter);
}
lastInChain = biquadFilter;
_this.filters.push(biquadFilter);
});
}
return lastInChain;
};
Sound.prototype.formatDataVizByFrequency = function (data) {
var equalizer = this.props.equalizer;
var values = [];
var HERTZ_ITER = 23.4;
var currentIndex = 0;
if (equalizer) {
var frequencies = Object.keys(equalizer).map(Number);
for (var i = 0; i <= frequencies[frequencies.length - 1] + HERTZ_ITER; i = i + HERTZ_ITER) {
var freq = frequencies[currentIndex];
if (i > freq && i < freq + HERTZ_ITER) {
currentIndex++;
values.push(data[Math.round(i / HERTZ_ITER)]);
}
}
}
return values;
};
Sound.prototype.handleVisualizationChange = function () {
this.animationFrame = requestAnimationFrame(this.handleVisualizationChange);
this.analyser.getByteFrequencyData(this.frequencyData);
if (this.props.onVisualizationChange) {
this.props.onVisualizationChange(this.formatDataVizByFrequency(this.frequencyData));
}
};
Sound.prototype.handleTimeUpdate = function (_a) {
var target = _a.target;
if (this.props.onPlaying) {
this.props.onPlaying({
position: target.currentTime,
duration: target.duration,
});
}
};
Sound.prototype.setPlayerState = function () {
switch (this.props.playStatus) {
case Sound.status.PAUSED:
this.pause();
break;
case Sound.status.STOPPED:
this.stop();
break;
case Sound.status.PLAYING:
default:
this.play();
break;
}
};
Sound.prototype.shouldUpdatePosition = function (_a) {
var _b = _a.position, prevPosition = _b === void 0 ? 0 : _b;
var position = this.props.position;
if (position) {
var dif = position - prevPosition;
return position < prevPosition || dif > 1;
}
else {
return false;
}
};
Sound.prototype.shouldUpdateEqualizer = function (prevProps) {
var _a = this.props, equalizer = _a.equalizer, preAmp = _a.preAmp;
return (equalizer &&
prevProps.equalizer &&
!(Object.entries(equalizer).toString() ===
Object.entries(prevProps.equalizer).toString())) ||
preAmp !== prevProps.preAmp;
};
Sound.prototype.setVolume = function () {
var _a = this.props.volume, volume = _a === void 0 ? 100 : _a;
this.gainNode.gain.value = volume / 100;
};
Sound.prototype.setPosition = function () {
if (this.props.position) {
this.audio.currentTime = this.props.position;
}
};
Sound.prototype.setStereoPan = function () {
this.stereoPanner.pan.value = this.props.stereoPan || 0;
};
Sound.prototype.play = function () {
var _this = this;
this.audio
.play()
.then(function () {
return !!_this.props.onVisualizationChange &&
!!_this.props.equalizer &&
_this.handleVisualizationChange();
})
.catch(console.error);
};
Sound.prototype.pause = function () {
this.audio.pause();
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
};
Sound.prototype.stop = function () {
this.pause();
this.audio.currentTime = 0;
};
Sound.prototype.componentDidUpdate = function (prevProps) {
var _this = this;
var _a = this.props, volume = _a.volume, playStatus = _a.playStatus, _b = _a.equalizer, equalizer = _b === void 0 ? {} : _b, _c = _a.preAmp, preAmp = _c === void 0 ? 0 : _c, _d = _a.stereoPan, stereoPan = _d === void 0 ? 0 : _d;
if (volume !== prevProps.volume) {
this.setVolume();
}
if (this.shouldUpdatePosition(prevProps)) {
this.setPosition();
}
if (playStatus !== prevProps.playStatus) {
this.setPlayerState();
}
if (stereoPan !== prevProps.stereoPan) {
this.setStereoPan();
}
if (!prevProps.onVisualizationChange && this.props.onVisualizationChange && this.props.equalizer) {
this.handleVisualizationChange();
}
if (prevProps.onVisualizationChange && !this.props.onVisualizationChange) {
cancelAnimationFrame(this.animationFrame);
}
if (this.shouldUpdateEqualizer(prevProps)) {
Object.values(equalizer).forEach(function (value, idx) {
_this.filters[idx].gain.value = value + preAmp;
});
}
};
Sound.prototype.componentDidMount = function () {
this.audioContext = new AudioContext();
this.gainNode = this.audioContext.createGain();
this.stereoPanner = new StereoPannerNode(this.audioContext, { pan: this.props.stereoPan || 0 });
this.source = this.audioContext.createMediaElementSource(this.audio);
this.analyser = this.audioContext.createAnalyser();
this.analyser.fftSize = 32768;
this.frequencyData = new Uint8Array(this.analyser.frequencyBinCount);
this.source.connect(this.gainNode);
this.createFilterNodes()
.connect(this.analyser)
.connect(this.stereoPanner)
.connect(this.audioContext.destination);
this.setVolume();
this.setPlayerState();
this.setStereoPan();
};
Sound.prototype.render = function () {
return (react_1.default.createElement("audio", { crossOrigin: "anonymous", style: { visibility: 'hidden' }, src: this.props.url, ref: this.attachRef, onTimeUpdate: this.props.onPlaying ? this.handleTimeUpdate : undefined, onEnded: this.props.onFinishedPlaying, onLoadStart: this.props.onLoading, onCanPlayThrough: this.props.onLoad }));
};
Sound.status = SoundStatus;
return Sound;
}(react_1.default.Component));
exports.Sound = Sound;
//# sourceMappingURL=index.js.map