UNPKG

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
"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