/* * This file is part of Toolkit. * * Toolkit is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * Toolkit 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU General * Public License along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ "use strict"; (function(w, TK){ function range_set(value, key) { this.range_x.set(key, value); this.range_y.set(key, value); } TK.Dynamics = TK.class({ /** * TK.Dynamics are based on {@link TK.Chart} and display the characteristics of dynamic * processors. They are square widgets drawing a {@link TK.Grid} automatically based on * the range. * * @class TK.Dynamics * * @extends TK.Chart * * @property {Object} options * * @param {Number} [options.min=-96] - Minimum decibels to display. * @param {Number} [options.max=24] - Maximum decibels to display. * @param {String} [options.scale="linear"] - Scale of the display, see {@link TK.Range} for details. * @param {String} [options.type=false] - Type of the dynamics: compressor, expander, gate, limiter or false to draw your own graph. * @param {Number} [options.threshold=0] - Threshold of the dynamics. * @param {Number} [options.ratio=1] - Ratio of the dynamics. * @param {Number} [options.makeup=0] - Makeup of the dynamics. This raises the whole graph after all other parameters are applied. * @param {Number} [options.range=0] - Range of the dynamics. Only used in type expander. The maximum gain reduction. * @param {Number} [options.gain=0] - Input gain of the dynamics. * @param {Number} [options.reference=0] - Input reference of the dynamics. * @param {Function} [options.grid_labels=function (val) { return val + (!val ? "dB":""); }] - Callback to format the labels of the {@link TK.Grid}. * @param {Number} [options.db_grid=12] - Draw a grid line every [n] decibels. */ _class: "Dynamics", Extends: TK.Chart, _options: Object.assign(Object.create(TK.Chart.prototype._options), { size: "number", // deprecated, undocumented. Is set via CSS. min: "number", max: "number", scale: "string", type: "string", threshold: "number", ratio: "number", makeup: "number", range: "number", gain: "number", reference: "number", grid_labels: "function", db_grid: "number", }), options: { db_grid: 12, min: -96, max: 24, scale: "linear", type: false, threshold: 0, ratio: 1, makeup: 0, range: 0, gain: 0, reference: 0, grid_labels: function (val) { return val + (!val ? "dB":""); } }, static_events: { set_size: function(value) { TK.warn("using deprecated 'size' option"); this.set("width", value); this.set("height", value); }, set_min: range_set, set_max: range_set, set_scale: range_set, }, initialize: function (options) { TK.Chart.prototype.initialize.call(this, options, true); var O = this.options; /** * @member {HTMLDivElement} TK.Dynamics#element - The main DIV container. * Has class toolkit-dynamics. */ TK.add_class(this.element, "toolkit-dynamics"); this.set("scale", O.scale); if (O.size) this.set("size", O.size); this.set("min", O.min); this.set("max", O.max); /** * @member {TK.Graph} TK.Dynamics#steady - The graph drawing the zero line. Has class toolkit-steady */ this.steady = this.add_graph({ dots: [{x:O.min, y:O.min}, {x:O.max, y:O.max}], "class": "toolkit-steady", mode: "line" }); }, redraw: function () { var O = this.options; var I = this.invalid; TK.Chart.prototype.redraw.call(this); if (I.validate("size", "min", "max", "scale")) { var grid_x = []; var grid_y = []; var min = this.range_x.get("min"); var max = this.range_x.get("max"); var step = O.db_grid; var cls; for (var i = min; i <= max; i += step) { cls = i ? "" : "toolkit-highlight"; grid_x.push({ pos: i, label: i === min ? "" : O.grid_labels(i), "class": cls }); grid_y.push({ pos: i, label: i === min ? "" : O.grid_labels(i), "class": cls }); } if (this.grid) { this.grid.set("grid_x", grid_x); this.grid.set("grid_y", grid_y); } if (this.steady) this.steady.set("dots", [{x:O.min, y:O.min}, {x:O.max, y:O.max}]); } if (I.type) { if (O._last_type) TK.remove_class(this.element, "toolkit-" + O._last_type); TK.add_class(this.element, "toolkit-" + O.type); } if (I.validate("ratio", "threshold", "range", "makeup", "gain", "reference")) { this.draw_graph(); } }, resize: function() { var O = this.options; var E = this.element; var S = this.svg; /* bypass the Chart resize logic here */ TK.Widget.prototype.resize.call(this); var tmp = TK.css_space(S, "border", "padding"); var w = TK.inner_width(E) - tmp.left - tmp.right; var h = TK.inner_height(E) - tmp.top - tmp.bottom; var s = Math.min(h, w); if (s > 0 && s !== O._width) { this.set("_width", s); this.set("_height", s); this.range_x.set("basis", s); this.range_y.set("basis", s); } }, draw_graph: function () { var O = this.options; if (O.type === false) return; if (!this.graph) { this.graph = this.add_graph({ dots: [{x: O.min, y: O.min}, {x: O.max, y: O.max}] }); } var curve = []; var range = O.range; var ratio = O.ratio; var thres = O.threshold; var gain = O.gain; var ref = O.reference; var makeup = O.makeup; var min = O.min; var max = O.max; var s; if (ref == 0) { s = 0; } else if (!isFinite(ratio)) { s = ref; } else { s = (1 / (Math.max(ratio, 1.001) - 1)) * ratio * ref; } var l = 5; // estimated width of line. dirty workaround for // keeping the line end out of sight in case // salient point is outside the visible are switch (O.type) { case "compressor": // entry point curve.push({x: min - l, y: min + makeup - gain + ref - l}); // salient point curve.push({x: thres + gain - s, y: thres + makeup - s + ref}); // exit point if (isFinite(ratio) && ratio > 0) { curve.push({x: max, y: thres + makeup + (max - thres - gain) / ratio }); } else if (ratio === 0) { curve.push({x: thres, y: max }); } else { curve.push({x: max, y: thres + makeup }); } break; case "limiter": curve.push({x: min, y: min + makeup - gain}); curve.push({x: thres + gain, y: thres + makeup}); curve.push({x: max, y: thres + makeup}); break; case "gate": curve.push({x: thres, y: min}); curve.push({x: thres, y: thres + makeup}); curve.push({x: max, y: max + makeup}); break; case "expander": if (O.ratio !== 1) { curve.push({x: min, y: min + makeup + range}); var y = (ratio * range + (ratio - 1) * thres) / (ratio - 1); curve.push({x: y - range, y: y + makeup}); curve.push({x: thres, y: thres + makeup}); } else curve.push({x: min, y: min + makeup}); curve.push({x: max, y: max + makeup}); break; default: TK.warn("Unsupported type", O.type); } this.graph.set("dots", curve); }, set: function (key, val) { if (key == "type") this.options._last_type = this.options.type; return TK.Chart.prototype.set.call(this, key, val); }, }); })(this, this.TK);