(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.EssentiaPlot = {}));
}(this, (function (exports) { 'use strict';

    /*! *****************************************************************************
    Copyright (c) Microsoft Corporation. All rights reserved.
    Licensed under the Apache License, Version 2.0 (the "License"); you may not use
    this file except in compliance with the License. You may obtain a copy of the
    License at http://www.apache.org/licenses/LICENSE-2.0

    THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
    WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
    MERCHANTABLITY OR NON-INFRINGEMENT.

    See the Apache Version 2.0 License for specific language governing permissions
    and limitations under the License.
    ***************************************************************************** */
    /* global Reflect, Promise */

    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);
    };

    function __extends(d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    }

    /**
     * @license
     * Copyright (C) 2006-2020  Music Technology Group - Universitat Pompeu Fabra
     *
     * This file is part of Essentia
     *
     * Essentia is free software: you can redistribute it and/or modify it under
     * the terms of the GNU Affero General Public License as published by the Free
     * Software Foundation (FSF), either version 3 of the License, or (at your
     * option) any later version.
     *
     * This program is distributed in the hope that it will be useful, but WITHOUT
     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
     * details.
     *
     * You should have received a copy of the Affero GNU General Public License
     * version 3 along with this program.  If not, see http://www.gnu.org/licenses/
     */
    // default plot config for EssentiaPlot base class
    var PlotConfig = {
        isPlotting: false,
        startTimeIndex: 0
    };
    // default layout settings for melody contour plots
    var LayoutMelodyContourPlot = {
        title: "Melody Contour",
        plot_bgcolor: "transparent",
        paper_bgcolor: "#FCF7F7",
        autosize: false,
        width: 670,
        height: 300,
        xaxis: {
            type: "time",
            title: "Time"
        },
        yaxis: {
            autorange: false,
            range: [30, 3000],
            type: "linear",
            title: "Frequency (Hz)"
        }
    };
    // default layout settings for chroma heatmap plot
    var LayoutChromaPlot = {
        title: "",
        plot_bgcolor: "transparent",
        paper_bgcolor: "#FCF7F7",
        autosize: false,
        width: 670,
        height: 300,
        xaxis: {
            autorange: true,
            time: 'Time',
            title: 'Time'
        },
        yaxis: {
            title: 'Pitch class',
            range: [0, 11]
        },
    };
    // default layout settings for spectrogram heatmap plot
    var LayoutSpectrogramPlot = {
        title: "",
        plot_bgcolor: "transparent",
        paper_bgcolor: "#FCF7F7",
        autosize: false,
        width: 670,
        height: 300,
        xaxis: {
            title: 'Time',
            autorange: true,
            time: 'Time',
        },
        yaxis: {
            title: 'Bands',
            range: null,
            type: 'linear',
        },
    };
    /**
     * Base class for essentia.js-plot*
     * @class
     */
    var EssentiaPlot = /** @class */ (function () {
        /**
         *Creates an instance of EssentiaPlot.
        * @param {*} Plotly plotly.js global import object (see https://plotly.com/javascript/)
        * @param {*} [options=CONFIG] config options for the plot
        * @constructs
        */
        function EssentiaPlot(Plotly, options) {
            if (options === void 0) { options = PlotConfig; }
            this.Plotly = Plotly;
            this.options = options;
            this.isPlotting = options.isPlotting;
            this.startTimeIndex = options.startTimeIndex;
        }
        /**
         * Returns evenly spaced samples, calculated over the interval [start, stop].
         * @param {*} start The starting value of the sequence.
         * @param {*} stop The end value of the sequence
         * @param {*} num Number of samples to generate. Must be non-negative.
         * @returns {Array}
         * @memberof EssentiaPlot
         */
        EssentiaPlot.prototype.makeLinearSpace = function (start, stop, num) {
            if (typeof num === "undefined")
                num = Math.max(Math.round(stop - start) + 1, 1);
            if (num < 2) {
                return num === 1 ? [start] : [];
            }
            var i, ret = Array(num);
            num--;
            for (i = num; i >= 0; i--) {
                ret[i] = (i * stop + (num - i) * start) / num;
            }
            return ret;
        };
        return EssentiaPlot;
    }());
    /**
     * @class PlotMelodyContour
     * @extends {EssentiaPlot}
     */
    var PlotMelodyContour = /** @class */ (function (_super) {
        __extends(PlotMelodyContour, _super);
        /**
         * Creates an instance of PlotMelodyContour
         * @param {*} Plotly plotly.js global object import (see https://plotly.com/javascript/)
         * @param {string} divId HTML div container id
         * @param {*} [plotLayout=LayoutMelodyContour]
         * @constructs
         */
        function PlotMelodyContour(Plotly, divId, plotLayout) {
            if (plotLayout === void 0) { plotLayout = LayoutMelodyContourPlot; }
            var _this = _super.call(this, Plotly) || this;
            _this.Plotly = Plotly;
            _this.divId = divId;
            _this.plotLayout = plotLayout;
            return _this;
        }
        /**
         * Create the single line plot with the given input array using Plotly.js
         * @method
         * @param {Float32Array} featureArray 1D feature input array
         * @param {string} plotTitle title of the plot
         * @param {number} audioFrameSize length of input audio data in samples
         * @param {number} audioSampleRate sample rate of input audio
         * @memberof PlotMelodyContour
         */
        PlotMelodyContour.prototype.create = function (featureArray, plotTitle, audioFrameSize, audioSampleRate) {
            this.plotLayout.title = plotTitle;
            // time axis
            var timeAxis = this.makeLinearSpace(this.startTimeIndex, audioFrameSize / audioSampleRate, featureArray.length);
            // Create a plotly plot instance if a plot hasn't been created before
            if (!this.isPlotting) {
                this.Plotly.newPlot(this.divId, [{
                        x: timeAxis,
                        y: featureArray,
                        mode: 'lines',
                        line: { color: '#2B6FAC', width: 2 }
                    }], this.plotLayout);
                this.isPlotting = true;
                this.startTimeIndex = timeAxis[timeAxis.length - 1];
            }
            else {
                timeAxis = this.makeLinearSpace(this.startTimeIndex, this.startTimeIndex + (audioFrameSize / audioSampleRate), featureArray.length);
                this.startTimeIndex = timeAxis[timeAxis.length - 1];
                this.Plotly.extendTraces(this.divId, {
                    x: [timeAxis],
                    y: [featureArray],
                }, [0]);
            }
        };
        /**
         * Destroy the existing Plotly traces
         * @method
         * @memberof PlotMelodyContour
         */
        PlotMelodyContour.prototype.destroy = function () {
            this.Plotly.deleteTraces(this.divId, 0);
            this.isPlotting = false;
            this.startTimeIndex = 0;
        };
        return PlotMelodyContour;
    }(EssentiaPlot));
    /**
     * @class PlotHeatmap
     * @extends {EssentiaPlot}
     */
    var PlotHeatmap = /** @class */ (function (_super) {
        __extends(PlotHeatmap, _super);
        /**
         *Creates an instance of PlotHeatmap
        * @param {*} Plotly plotly.js global object import (see https://plotly.com/javascript/)
        * @param {string} divId HTML div container id
        * @param {string} [plotType='chroma'] type of plot to configure the y-axis
        * @param {*} [plotLayout=LayoutSpectrogramPlot]
        * @constructs
        */
        function PlotHeatmap(Plotly, divId, plotType, plotLayout) {
            if (plotType === void 0) { plotType = "chroma"; }
            if (plotLayout === void 0) { plotLayout = LayoutSpectrogramPlot; }
            var _this = _super.call(this, Plotly) || this;
            _this.Plotly = Plotly;
            _this.divId = divId;
            _this.plotType = plotType;
            _this.plotLayout = plotLayout;
            if (plotType === "chroma") {
                // we set chroma bin labels as yAxis for the heatmap
                _this.yAxis = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
            }
            else if (plotType === "spectrogram") {
                _this.yAxis = null;
            }
            else {
                throw "Invalid value for argument 'plotType'. Should be either 'chroma' or 'spectrogram'";
            }
            return _this;
        }
        /**
         * Create Plotly.js heatmap plot with given input array and type
         * @param {Array} featureArray 2D feature array where 'x' axis denotes temporal evolution of features
         * @param {string} plotTitle title of the plot
         * @param {*} audioFrameSize length of input audio data in samples
         * @param {*} audioSampleRate sample rate of input audio
         * @param {*} [hopSize=0] hopSize used for the feture extraction if applies.
         * @param {string} [colorscale='Jet']
         * @memberof PlotHeatmap
         */
        PlotHeatmap.prototype.create = function (featureArray, plotTitle, audioFrameSize, audioSampleRate, hopSize, colorscale) {
            if (colorscale === void 0) { colorscale = 'Jet'; }
            this.plotLayout.title = plotTitle;
            if (this.plotType === "spectrogram") {
                var numBands = featureArray[0].length;
                this.plotLayout.yaxis.range = [0, numBands + 1];
            }
            if (!this.isPlotting) {
                var heatmapFeature = void 0;
                var timeAxis = void 0;
                if ((featureArray[0].constructor === Array) || (featureArray[0].constructor === Float32Array)) {
                    if (featureArray.length == 1) {
                        heatmapFeature = featureArray;
                        timeAxis = [this.startTimeIndex + hopSize / audioSampleRate, this.startTimeIndex + audioFrameSize / audioSampleRate];
                    }
                    else {
                        heatmapFeature = featureArray;
                        timeAxis = this.makeLinearSpace(this.startTimeIndex, audioFrameSize / audioSampleRate, heatmapFeature.length);
                    }
                }
                else {
                    throw "Got 1D array as input, expect a 2D array...";
                }
                var data = {
                    x: timeAxis,
                    y: this.yAxis,
                    z: heatmapFeature,
                    colorscale: colorscale,
                    type: 'heatmap',
                    transpose: true,
                };
                this.Plotly.newPlot(this.divId, [data], this.plotLayout);
                this.isPlotting = true;
                this.startTimeIndex = timeAxis[timeAxis.length - 1];
            }
            else {
                // realtime mode
                var heatmapFeature = void 0;
                var timeAxis = void 0;
                if ((featureArray[0].constructor === Array) || (featureArray[0].constructor === Float32Array)) {
                    if (featureArray.length == 1) {
                        heatmapFeature = featureArray;
                        timeAxis = [this.startTimeIndex + hopSize / audioSampleRate, this.startTimeIndex + audioFrameSize / audioSampleRate];
                    }
                    else {
                        heatmapFeature = featureArray;
                        timeAxis = this.makeLinearSpace(this.startTimeIndex, audioFrameSize / audioSampleRate, heatmapFeature.length);
                    }
                }
                else {
                    throw "Got 1D array as input, expect a 2D array...";
                }
                this.startTimeIndex = timeAxis[timeAxis.length - 1];
                // realtime mode  
                this.Plotly.extendTraces(this.divId, {
                    x: [timeAxis],
                    z: [featureArray],
                }, [0]);
            }
        };
        /**
         * Destroy the existing Plotly plot traces
         * @method
         * @memberof PlotHeatmap
         */
        PlotHeatmap.prototype.destroy = function () {
            this.Plotly.deleteTraces(this.divId, 0);
            this.isPlotting = false;
            this.startTimeIndex = 0;
        };
        return PlotHeatmap;
    }(EssentiaPlot));

    exports.EssentiaPlot = EssentiaPlot;
    exports.LayoutChromaPlot = LayoutChromaPlot;
    exports.LayoutMelodyContourPlot = LayoutMelodyContourPlot;
    exports.LayoutSpectrogramPlot = LayoutSpectrogramPlot;
    exports.PlotConfig = PlotConfig;
    exports.PlotHeatmap = PlotHeatmap;
    exports.PlotMelodyContour = PlotMelodyContour;

    Object.defineProperty(exports, '__esModule', { value: true });

})));
