diff --git a/web/app/assets/javascripts/faderHelpers.js b/web/app/assets/javascripts/faderHelpers.js
index 4fce20c60..49f4814fc 100644
--- a/web/app/assets/javascripts/faderHelpers.js
+++ b/web/app/assets/javascripts/faderHelpers.js
@@ -1,241 +1,248 @@
/**
-* Functions related to faders (slider controls for volume).
-* These functions are intimately tied to the markup defined in
-* the templates in _faders.html.erb
-*/
-(function(g, $) {
+ * Functions related to faders (slider controls for volume).
+ * These functions are intimately tied to the markup defined in
+ * the templates in _faders.html.erb
+ */
+(function (g, $) {
- "use strict";
+ "use strict";
- g.JK = g.JK || {};
+ g.JK = g.JK || {};
- var $draggingFaderHandle = null;
- var $draggingFader = null;
- var draggingOrientation = null;
+ var $draggingFaderHandle = null;
+ var $draggingFader = null;
+ var draggingOrientation = null;
- var subscribers = {};
- var logger = g.JK.logger;
+ var subscribers = {};
+ var logger = g.JK.logger;
- function faderClick(e) {
- e.stopPropagation();
-
- var $fader = $(this);
- draggingOrientation = $fader.attr('orientation');
- var faderId = $fader.attr("fader-id");
- var offset = $fader.offset();
- var position = { top: e.pageY - offset.top, left: e.pageX - offset.left}
+ function faderClick(e) {
+ e.stopPropagation();
- var faderPct = faderValue($fader, e, position);
+ var $fader = $(this);
+ draggingOrientation = $fader.attr('orientation');
+ var faderId = $fader.attr("fader-id");
+ var offset = $fader.offset();
+ var position = { top: e.pageY - offset.top, left: e.pageX - offset.left}
- if (faderPct < 0 || faderPct > 100) {
- return false;
- }
+ var faderPct = faderValue($fader, e, position);
- // Notify subscribers of value change
- g._.each(subscribers, function(changeFunc, index, list) {
- if (faderId === index) {
- changeFunc(faderId, faderPct, false);
- }
- });
-
- setHandlePosition($fader, faderPct);
- return false;
+ if (faderPct < 0 || faderPct > 100) {
+ return false;
}
- function setHandlePosition($fader, value) {
- var ratio, position;
- var $handle = $fader.find('div[control="fader-handle"]');
- var handleCssAttribute = getHandleCssAttribute($fader);
+ // Notify subscribers of value change
+ g._.each(subscribers, function (changeFunc, index, list) {
+ if (faderId === index) {
+ changeFunc(faderId, faderPct, false);
+ }
+ });
- if(draggingOrientation === "horizontal") {
- ratio = value / 100;
- position = ((ratio * $fader.width()) - (ratio * handleWidth(draggingOrientation))) + 'px';
- }
- else {
- ratio = (100 - value) / 100;
- position = ((ratio * $fader.height()) - (ratio * handleWidth(draggingOrientation))) + 'px';
- }
- $handle.css(handleCssAttribute, position);
+ setHandlePosition($fader, faderPct);
+ return false;
+ }
+
+ function setHandlePosition($fader, value) {
+ var ratio, position;
+ var $handle = $fader.find('div[control="fader-handle"]');
+
+ var orientation = $fader.attr('orientation');
+ var handleCssAttribute = getHandleCssAttribute($fader);
+
+ // required because this method is entered directly when from a callback
+
+ if (draggingOrientation === "horizontal") {
+ ratio = value / 100;
+ position = ((ratio * $fader.width()) - (ratio * handleWidth(draggingOrientation))) + 'px';
+ }
+ else {
+ ratio = (100 - value) / 100;
+ position = ((ratio * $fader.height()) - (ratio * handleWidth(draggingOrientation))) + 'px';
}
- function faderValue($fader, e, offset) {
- var orientation = $fader.attr('orientation');
- var getPercentFunction = getVerticalFaderPercent;
- var relativePosition = offset.top;
- if (orientation && orientation == 'horizontal') {
- getPercentFunction = getHorizontalFaderPercent;
- relativePosition = offset.left;
- }
- return getPercentFunction(relativePosition, $fader);
+ $handle.css(handleCssAttribute, position);
+ }
+
+ function faderValue($fader, e, offset) {
+ var orientation = $fader.attr('orientation');
+ var getPercentFunction = getVerticalFaderPercent;
+ var relativePosition = offset.top;
+ if (orientation && orientation == 'horizontal') {
+ getPercentFunction = getHorizontalFaderPercent;
+ relativePosition = offset.left;
+ }
+ return getPercentFunction(relativePosition, $fader);
+ }
+
+ function getHandleCssAttribute($fader) {
+ var orientation = $fader.attr('orientation');
+ return (orientation === 'horizontal') ? 'left' : 'top';
+ }
+
+ function getVerticalFaderPercent(eventY, $fader) {
+ return getFaderPercent(eventY, $fader, 'vertical');
+ }
+
+ function getHorizontalFaderPercent(eventX, $fader) {
+ return getFaderPercent(eventX, $fader, 'horizontal');
+ }
+
+ /**
+ * Returns the current value of the fader as int percent 0-100
+ */
+ function getFaderPercent(value, $fader, orientation) {
+ var faderSize, faderPct;
+
+ // the handle takes up room, and all calculations use top. So when the
+ // handle *looks* like it's at the bottom by the user, it won't give a 0% value.
+ // so, we subtract handleWidth from the size of it's parent
+
+ if (orientation === "horizontal") {
+ faderSize = $fader.width();
+ faderPct = Math.round(( value + (value / faderSize * handleWidth(orientation))) / faderSize * 100);
+ }
+ else {
+ faderSize = $fader.height();
+ faderPct = Math.round((faderSize - handleWidth(orientation) - value) / (faderSize - handleWidth(orientation)) * 100);
}
- function getHandleCssAttribute($fader) {
- var orientation = $fader.attr('orientation');
- return (orientation === 'horizontal') ? 'left' : 'top';
+ return faderPct;
+ }
+
+ function onFaderDrag(e, ui) {
+ var faderId = $draggingFader.attr("fader-id");
+ var faderPct = faderValue($draggingFader, e, ui.position);
+
+ // protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
+ if (faderPct < 0 || faderPct > 100) {
+ return false;
}
- function getVerticalFaderPercent(eventY, $fader) {
- return getFaderPercent(eventY, $fader, 'vertical');
+ // Notify subscribers of value change
+ g._.each(subscribers, function (changeFunc, index, list) {
+ if (faderId === index) {
+ changeFunc(faderId, faderPct, true);
+ }
+ });
+ }
+
+ function onFaderDragStart(e, ui) {
+ $draggingFaderHandle = $(this);
+ $draggingFader = $draggingFaderHandle.closest('div[control="fader"]');
+ draggingOrientation = $draggingFader.attr('orientation');
+ }
+
+ function onFaderDragStop(e, ui) {
+ var faderId = $draggingFader.attr("fader-id");
+ var faderPct = faderValue($draggingFader, e, ui.position);
+
+ // protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
+ // do not return 'false' though, because that stops future drags from working, for some reason
+ if (faderPct < 0 || faderPct > 100) {
+ return;
}
- function getHorizontalFaderPercent(eventX, $fader) {
- return getFaderPercent(eventX, $fader, 'horizontal');
- }
+ // Notify subscribers of value change
+ g._.each(subscribers, function (changeFunc, index, list) {
+ if (faderId === index) {
+ changeFunc(faderId, faderPct, false);
+ }
+ });
+ $draggingFaderHandle = null;
+ $draggingFader = null;
+ draggingOrientation = null;
+ }
+
+ function handleWidth(orientation) {
+ return orientation === "horizontal" ? 8 : 11;
+ }
+
+ g.JK.FaderHelpers = {
/**
- * Returns the current value of the fader as int percent 0-100
+ * Subscribe to fader change events. Provide a subscriber id
+ * and a function in the form: change(faderId, newValue) which
+ * will be called anytime a fader changes value.
*/
- function getFaderPercent(value, $fader, orientation) {
- var faderSize, faderPct;
+ subscribe: function (subscriberId, changeFunction) {
+ subscribers[subscriberId] = changeFunction;
+ },
- // the handle takes up room, and all calculations use top. So when the
- // handle *looks* like it's at the bottom by the user, it won't give a 0% value.
- // so, we subtract handleWidth from the size of it's parent
+ /**
+ * Render a fader into the element identifed by the provided
+ * selector, with the provided options.
+ */
+ renderFader: function (selector, userOptions) {
+ if (userOptions === undefined) {
+ throw ("renderFader: userOptions is required");
+ }
+ if (!(userOptions.hasOwnProperty("faderId"))) {
+ throw ("renderFader: userOptions.faderId is required");
+ }
+ var renderDefaults = {
+ faderType: "vertical",
+ height: 83, // only used for vertical
+ width: 83 // only used for horizontal
+ };
+ var options = $.extend({}, renderDefaults, userOptions);
+ var templateSelector = (options.faderType === 'horizontal') ?
+ "#template-fader-h" : '#template-fader-v';
+ var templateSource = $(templateSelector).html();
- if (orientation === "horizontal") {
- faderSize = $fader.width();
- faderPct = Math.round( ( value + (value / faderSize * handleWidth(orientation))) / faderSize * 100);
- }
- else {
- faderSize = $fader.height();
- faderPct = Math.round((faderSize - handleWidth(orientation) - value)/(faderSize - handleWidth(orientation)) * 100);
+ $(selector).html(g._.template(templateSource, options));
+
+ $('div[control="fader-handle"]', $(selector)).draggable({
+ drag: onFaderDrag,
+ start: onFaderDragStart,
+ stop: onFaderDragStop,
+ containment: "parent",
+ axis: options.faderType === 'horizontal' ? 'x' : 'y'
+ })
+
+ // Embed any custom styles, applied to the .fader below selector
+ if ("style" in options) {
+ for (var key in options.style) {
+ $(selector + ' .fader').css(key, options.style[key]);
}
+ }
+ },
- return faderPct;
+ convertLinearToDb: function (input) {
+ var temp;
+ temp = 0.0;
+ // coefficients
+ var a = -8.0013990435159329E+01;
+ var b = 4.1755639785242042E+00;
+ var c = -1.4036729740086906E-01;
+ var d = 3.1788545454166156E-03;
+ var f = -3.5148685730880861E-05;
+ var g = 1.4221429222004657E-07;
+ temp += a +
+ b * input +
+ c * Math.pow(input, 2.0) +
+ d * Math.pow(input, 3.0) +
+ f * Math.pow(input, 4.0) +
+ g * Math.pow(input, 5.0);
+
+ return temp;
+ },
+
+ setFaderValue: function (faderId, faderValue) {
+ var $fader = $('[fader-id="' + faderId + '"]');
+ this.setHandlePosition($fader, faderValue);
+ },
+
+ setHandlePosition: function ($fader, faderValue) {
+ draggingOrientation = $fader.attr('orientation');
+ setHandlePosition($fader, faderValue);
+ draggingOrientation = null;
+ },
+
+ initialize: function () {
+ $('body').on('click', 'div[control="fader"]', faderClick);
}
- function onFaderDrag(e, ui) {
- var faderId = $draggingFader.attr("fader-id");
- var faderPct = faderValue($draggingFader, e, ui.position);
-
- // protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
- if (faderPct < 0 || faderPct > 100) {
- return false;
- }
-
- // Notify subscribers of value change
- g._.each(subscribers, function(changeFunc, index, list) {
- if (faderId === index) {
- changeFunc(faderId, faderPct, true);
- }
- });
- }
-
- function onFaderDragStart(e, ui) {
- $draggingFaderHandle = $(this);
- $draggingFader = $draggingFaderHandle.closest('div[control="fader"]');
- draggingOrientation = $draggingFader.attr('orientation');
- }
-
- function onFaderDragStop(e, ui) {
- var faderId = $draggingFader.attr("fader-id");
- var faderPct = faderValue($draggingFader, e, ui.position);
-
- // protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows
- // do not return 'false' though, because that stops future drags from working, for some reason
- if (faderPct < 0 || faderPct > 100) {
- return;
- }
-
- // Notify subscribers of value change
- g._.each(subscribers, function(changeFunc, index, list) {
- if (faderId === index) {
- changeFunc(faderId, faderPct, false);
- }
- });
- $draggingFaderHandle = null;
- $draggingFader = null;
- draggingOrientation = null;
- }
-
- function handleWidth(orientation) {
- return orientation === "horizontal" ? 8 : 11;
- }
-
- g.JK.FaderHelpers = {
-
- /**
- * Subscribe to fader change events. Provide a subscriber id
- * and a function in the form: change(faderId, newValue) which
- * will be called anytime a fader changes value.
- */
- subscribe: function(subscriberId, changeFunction) {
- subscribers[subscriberId] = changeFunction;
- },
-
- /**
- * Render a fader into the element identifed by the provided
- * selector, with the provided options.
- */
- renderFader: function(selector, userOptions) {
- if (userOptions === undefined) {
- throw ("renderFader: userOptions is required");
- }
- if (!(userOptions.hasOwnProperty("faderId"))) {
- throw ("renderFader: userOptions.faderId is required");
- }
- var renderDefaults = {
- faderType: "vertical",
- height: 83, // only used for vertical
- width: 83 // only used for horizontal
- };
- var options = $.extend({}, renderDefaults, userOptions);
- var templateSelector = (options.faderType === 'horizontal') ?
- "#template-fader-h" : '#template-fader-v';
- var templateSource = $(templateSelector).html();
-
- $(selector).html(g._.template(templateSource, options));
-
- $('div[control="fader-handle"]', $(selector)).draggable({
- drag: onFaderDrag,
- start: onFaderDragStart,
- stop: onFaderDragStop,
- containment: "parent",
- axis: options.faderType === 'horizontal' ? 'x' : 'y'
- })
-
- // Embed any custom styles, applied to the .fader below selector
- if ("style" in options) {
- for (var key in options.style) {
- $(selector + ' .fader').css(key, options.style[key]);
- }
- }
- },
-
- convertLinearToDb: function(input) {
- var temp;
- temp = 0.0;
- // coefficients
- var a = -8.0013990435159329E+01;
- var b = 4.1755639785242042E+00;
- var c = -1.4036729740086906E-01;
- var d = 3.1788545454166156E-03;
- var f = -3.5148685730880861E-05;
- var g = 1.4221429222004657E-07;
- temp += a +
- b * input +
- c * Math.pow(input, 2.0) +
- d * Math.pow(input, 3.0) +
- f * Math.pow(input, 4.0) +
- g * Math.pow(input, 5.0);
-
- return temp;
- },
-
- setFaderValue: function(faderId, faderValue) {
- var $fader = $('[fader-id="' + faderId + '"]');
- this.setHandlePosition($fader, faderValue);
- },
-
- setHandlePosition: function($fader, faderValue) {
- setHandlePosition($fader, faderValue);
- },
-
- initialize: function() {
- $('body').on('click', 'div[control="fader"]', faderClick);
- }
-
- };
+ };
})(window, jQuery);
\ No newline at end of file
diff --git a/web/app/assets/javascripts/ftue.js b/web/app/assets/javascripts/ftue.js
index 610b81d77..9587649c7 100644
--- a/web/app/assets/javascripts/ftue.js
+++ b/web/app/assets/javascripts/ftue.js
@@ -1,793 +1,804 @@
/**
-* FtueAudioSelectionScreen
-* Javascript that goes with the screen where initial
-* selection of the audio devices takes place.
-* Corresponds to /#ftue2
-*/
-(function(context,$) {
-
- "use strict";
-
- context.JK = context.JK || {};
- context.JK.FtueWizard = function(app) {
- context.JK.FtueWizard.latencyTimeout = true;
- context.JK.FtueWizard.latencyMS = Number.MAX_VALUE;
- var rest = context.JK.Rest();
-
- var logger = context.JK.logger;
- var jamClient = context.jamClient;
- var win32 = true;
-
- var deviceSetMap = {
- 'audio-input': jamClient.FTUESetMusicInput,
- 'audio-output': jamClient.FTUESetMusicOutput,
- 'voice-chat-input': jamClient.FTUESetChatInput
- };
-
- var faderMap = {
- 'ftue-2-audio-input-fader': jamClient.FTUESetInputVolume,
- 'ftue-2-voice-input-fader': jamClient.FTUESetOutputVolume,
- 'ftue-audio-input-fader': jamClient.FTUESetInputVolume,
- 'ftue-voice-input-fader': jamClient.FTUESetChatInputVolume,
- 'ftue-audio-output-fader': jamClient.FTUESetOutputVolume
- };
-
- function latencyTimeoutCheck() {
- if (context.JK.FtueWizard.latencyTimeout) {
- jamClient.FTUERegisterLatencyCallback('');
- context.JK.app.setWizardStep("5");
- }
- }
-
- function afterHide(data) {
- // Unsubscribe from FTUE VU callbacks.
- jamClient.FTUERegisterVUCallbacks('','','');
- }
-
- function beforeShow(data) {
- var vuMeters = [
- '#ftue-2-audio-input-vu-left',
- '#ftue-2-audio-input-vu-right',
- '#ftue-2-voice-input-vu-left',
- '#ftue-2-voice-input-vu-right',
- '#ftue-audio-input-vu-left',
- '#ftue-audio-input-vu-right',
- '#ftue-voice-input-vu-left',
- '#ftue-voice-input-vu-right',
- '#ftue-audio-output-vu-left',
- '#ftue-audio-output-vu-right'
- ];
- $.each(vuMeters, function() {
- context.JK.VuHelpers.renderVU(this,
- {vuType:"horizontal", lightCount: 12, lightWidth: 15, lightHeight: 3});
- });
-
- var faders = context._.keys(faderMap);
- $.each(faders, function() {
- var fid = this;
- context.JK.FaderHelpers.renderFader('#' + fid,
- {faderId: fid, faderType:"horizontal", width:163});
- context.JK.FaderHelpers.subscribe(fid, faderChange);
- });
- }
-
- function afterShow(data) {}
-
- function faderChange(faderId, newValue, dragging) {
- var setFunction = faderMap[faderId];
- // TODO - using hardcoded range of -80 to 20 for output levels.
- var mixerLevel = newValue - 80; // Convert our [0-100] to [-80 - +20] range
- setFunction(mixerLevel);
- }
-
- function settingsInit() {
- jamClient.FTUEInit();
- setLevels(0);
- // Always reset the driver select box to "Choose..." which forces everything
- // to sync properly when the user reselects their driver of choice.
- // VRFS-375 and VRFS-561
- $('[layout-wizard="ftue"] [layout-wizard-step="0"] .settings-2-device select').val("");
- $('[layout-wizard="ftue"] [layout-wizard-step="0"] .settings-2-voice select').val("");
- $('[layout-wizard="ftue"] [layout-wizard-step="2"] .asio-settings .settings-driver select').val("");
- }
-
- function setLevels(db) {
- if (db < -80 || db > 20) {
- throw ("BUG! ftue.js:setLevels db arg must be between -80 and 20");
- }
- var trackIds = jamClient.SessionGetIDs();
- var controlStates = jamClient.SessionGetControlState(trackIds);
- $.each(controlStates, function(index, value) {
- context.JK.Mixer.fillTrackVolume(value, false);
- // Default input/output to 0 DB
- context.trackVolumeObject.volL = db;
- context.trackVolumeObject.volR = db;
- jamClient.SessionSetControlState(trackIds[index]);
- });
- $.each(context._.keys(faderMap), function(index, faderId) {
- // faderChange takes a value from 0-100
- var $fader = $('[fader-id="' + faderId + '"]');
- context.JK.FaderHelpers.setHandlePosition($fader, db + 80);
- });
- }
-
- function testComplete() {
- logger.debug("Test complete");
- var latencyMS = context.JK.FtueWizard.latencyMS;
- var ftueSucceeded = latencyMS <= 20;
- if (ftueSucceeded) {
- logger.debug(latencyMS + " is <= 20. Setting FTUE status to true");
- ftueSave(true); // Save the profile
- context.jamClient.FTUESetStatus(true); // No FTUE wizard next time
- rest.userCertifiedGear({success:true});
-
- // notify anyone curious about how it went
- $('div[layout-id=ftue]').trigger('ftue_success');
- }
- else {
- rest.userCertifiedGear({success:false, reason:"latency=" + latencyMS});
- }
-
- updateGauge();
- }
-
- function updateGauge() {
- var latencyMS = context.JK.FtueWizard.latencyMS;
- // Round to 2 decimal places
- latencyMS = (Math.round(latencyMS * 100)) / 100;
- logger.debug("Latency Value: " + latencyMS);
- if (latencyMS > 20) {
- $('#ftue-latency-congrats').hide();
- $('#ftue-latency-fail').show();
- } else {
- $('#ftue-latency-ms').html(latencyMS);
- $('#ftue-latency-congrats').show();
- $('#ftue-latency-fail').hide();
- if (latencyMS <= 10) {
- $('[layout-wizard-step="6"] .btnHelp').hide();
- $('[layout-wizard-step="6"] .btnRepeat').hide();
- }
- }
- setNeedleValue(latencyMS);
- }
-
- // Function to calculate an absolute value and an absolute value range into
- // a number of degrees on a circualar "speedometer" gauge. The 0 degrees value
- // points straight up to the middle of the real-world value range.
- // Arguments:
- // value: The real-world value (e.g. 20 milliseconds)
- // minValue: The real-world minimum value (e.g. 0 milliseconds)
- // maxValue: The real-world maximum value (e.g. 40 milliseconds)
- // degreesUsed: The number of degrees used to represent the full real-world
- // range. 360 would be the entire circle. 270 would be 3/4ths
- // of the circle. The unused gap will be at the bottom of the
- // gauge.
- // (e.g. 300)
- function degreesFromRange(value, minValue, maxValue, degreesUsed) {
- if (value > maxValue) { value = maxValue; }
- if (value < minValue) { value = minValue; }
- var range = maxValue-minValue;
- var floatVal = value/range;
- var degrees = Math.round(floatVal * degreesUsed);
- degrees -= Math.round(degreesUsed/2);
- if (degrees < 0) {
- degrees += 360;
- }
- return degrees;
- }
-
- // Given a number of MS, and assuming the gauge has a range from
- // 0 to 40 ms. Update the gauge to the proper value.
- function setNeedleValue(ms) {
- logger.debug("setNeedleValue: " + ms);
- var deg = degreesFromRange(ms, 0, 40, 300);
-
- // Supporting Firefix, Chrome, Safari, Opera and IE9+.
- // Should we need to support < IE9, this will need more work
- // to compute the matrix transformations in those browsers -
- // and I don't believe they support transparent PNG graphic
- // rotation, so we'll have to change the needle itself.
- var css = {
- //"behavior":"url(-ms-transform.htc)",
- /* Firefox */
- "-moz-transform":"rotate(" + deg + "deg)",
- /* Safari and Chrome */
- "-webkit-transform":"rotate(" + deg + "deg)",
- /* Opera */
- "-o-transform":"rotate(" + deg + "deg)",
- /* IE9 */
- "-ms-transform":"rotate(" + deg + "deg)"
- /* IE6,IE7 */
- //"filter": "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)",
- /* IE8 */
- //"-ms-filter": '"progid:DXImageTransform.Microsoft.Matrix(SizingMethod=\'auto expand\', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"'
- };
-
- $('#ftue-latency-numerical').html(ms);
- $('#ftue-latency-needle').css(css);
-
- }
-
- function testLatency() {
- // we'll just register for call back right here and unregister in the callback.
- context.JK.FtueWizard.latencyTimeout = true;
- var cbFunc = 'JK.ftueLatencyCallback';
- logger.debug("Registering latency callback: " + cbFunc);
- jamClient.FTUERegisterLatencyCallback('JK.ftueLatencyCallback');
- var now = new Date();
- logger.debug("Starting Latency Test..." + now);
- context.setTimeout(latencyTimeoutCheck, 300 * 1000); // Timeout to 5 minutes
- jamClient.FTUEStartLatency();
- }
-
- function openASIOControlPanel(evt) {
- if (win32) {
- logger.debug("Calling FTUEOpenControlPanel()");
- jamClient.FTUEOpenControlPanel();
- }
- }
-
- function asioResync(evt) {
- jamClient.FTUERefreshDevices();
- ftueSave(false);
- }
-
- function ftueSave(persist) {
- // Explicitly set inputs and outputs to dropdown values
- // before save as the client seems to want this on changes to
- // things like frame size, etc..
- var $audioSelects = $('[layout-wizard-step="2"] .settings-controls select');
- $.each($audioSelects, function(index, value) {
- var $select = $(value);
- setAudioDevice($select);
- });
- if (musicInAndOutSet()) {
-
- // If there is no voice-chat-input selected, let the back-end know
- // that we're using music for voice-chat.
- if ($('[layout-wizard-step="2"] select[data-device="voice-chat-input"]').val()) {
- // Voice input selected
- jamClient.TrackSetChatEnable(true);
- } else {
- // No voice input selected.
- jamClient.TrackSetChatEnable(false);
- }
-
- setDefaultInstrumentFromProfile();
-
- logger.debug("Calling FTUESave(" + persist + ")");
- var response = jamClient.FTUESave(persist);
- setLevels(0);
- if (response) {
- logger.warn(response);
- // TODO - we may need to do something about errors on save.
- // per VRFS-368, I'm hiding the alert, and logging a warning.
- // context.alert(response);
- }
- } else {
- logger.debug("Aborting FTUESave as we need input + output selected.");
- }
- }
-
- function setAsioFrameSize(evt) {
- var val = parseFloat($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetFrameSize(" + val + ")");
- jamClient.FTUESetFrameSize(val);
- ftueSave(false);
- }
- function setAsioInputLatency(evt) {
- var val = parseInt($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetInputLatency(" + val + ")");
- jamClient.FTUESetInputLatency(val);
- ftueSave(false);
- }
- function setAsioOutputLatency(evt) {
- var val = parseInt($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetOutputLatency(" + val + ")");
- jamClient.FTUESetOutputLatency(val);
- ftueSave(false);
- }
-
- function videoLinkClicked(evt) {
- var myOS = jamClient.GetOSAsString();
- var link;
- if (myOS === 'MacOSX') {
- link = $(evt.currentTarget).attr('external-link-mac');
- } else if (myOS === 'Win32') {
- link = $(evt.currentTarget).attr('external-link-win');
- }
- if (link) {
- context.jamClient.OpenSystemBrowser(link);
- }
- }
-
- function events() {
- $('.ftue-video-link').hover(
- function(evt) { // handlerIn
- $(this).addClass('hover');
- },
- function(evt) { // handlerOut
- $(this).removeClass('hover');
- }
- );
- $('.ftue-video-link').on('click', videoLinkClicked);
- $('[layout-wizard-step="2"] .settings-driver select').on('change', audioDriverChanged);
- $('[layout-wizard-step="2"] .settings-controls select').on('change', audioDeviceChanged);
- $('#btn-asio-control-panel').on('click', openASIOControlPanel);
- $('#btn-asio-resync').on('click', asioResync);
- $('#asio-framesize').on('change', setAsioFrameSize);
- $('#asio-input-latency').on('change', setAsioInputLatency);
- $('#asio-output-latency').on('change', setAsioOutputLatency);
- // New FTUE events
- $('.ftue-new .settings-2-device select').on('change', newFtueAudioDeviceChanged);
- $('.ftue-new .settings-2-voice select').on('change', newFtueAudioDeviceChanged);
- $('#btn-ftue-2-asio-resync').on('click', newFtueAsioResync);
- $('#btn-ftue-2-asio-control-panel').on('click', openASIOControlPanel);
- $('#ftue-2-asio-framesize').on('change', newFtueSetAsioFrameSize);
- $('#ftue-2-asio-input-latency').on('change', newFtueSetAsioInputLatency);
- $('#ftue-2-asio-output-latency').on('change', newFtueSetAsioOutputLatency);
- $('#btn-ftue-2-save').on('click', newFtueSaveSettingsHandler);
- }
-
- /**
- * This function loads the available audio devices from jamClient, and
- * builds up the select dropdowns in the audio-settings step of the FTUE wizard.
- */
- function loadAudioDevices() {
- var funcs = [
- jamClient.FTUEGetMusicInputs,
- jamClient.FTUEGetChatInputs,
- jamClient.FTUEGetMusicOutputs
- ];
- var selectors = [
- '[layout-wizard-step="2"] .audio-input select',
- '[layout-wizard-step="2"] .voice-chat-input select',
- '[layout-wizard-step="2"] .audio-output select'
- ];
- var optionsHtml = '';
- var deviceOptionFunc = function(deviceKey, index, list) {
- optionsHtml += '';
- };
- for (var i=0; i' +
- drivers[driverKey] + '';
- };
-
- var optionsHtml = '';
- var selectors = [
- '[layout-wizard-step="0"] .settings-2-device select',
- '[layout-wizard-step="0"] .settings-2-voice select',
- '[layout-wizard-step="2"] .settings-driver select'
- ];
- var sortedDeviceKeys = context._.keys(drivers).sort();
- context._.each(sortedDeviceKeys, driverOptionFunc);
- $.each(selectors, function(index, selector) {
- var $select = $(selector);
- $select.empty();
- $select.html(optionsHtml);
- context.JK.dropdown($select);
- });
- }
-
- /** Once a configuration is decided upon, we set the user's default instrument based on data from their profile */
- function setDefaultInstrumentFromProfile() {
- var defaultInstrumentId;
- if (context.JK.userMe.instruments && context.JK.userMe.instruments.length > 0) {
- defaultInstrumentId = context.JK.instrument_id_to_instrument[context.JK.userMe.instruments[0].instrument_id].client_id;
- }
- else {
- defaultInstrumentId = context.JK.server_to_client_instrument_map['Other'].client_id;
- }
-
- jamClient.TrackSetInstrument(1, defaultInstrumentId);
- }
-
- /**
- * Handler for the new FTUE save button.
- */
- function newFtueSaveSettingsHandler(evt) {
- evt.preventDefault();
- var $saveButton = $('#btn-ftue-2-save');
- if ($saveButton.hasClass('disabled')) {
- return;
- }
- var selectedAudioDevice = $('.ftue-new .settings-2-device select').val();
- if (!(selectedAudioDevice)) {
- app.notify({
- title: "Please select an audio device",
- text: "Please choose a usable audio device, or select cancel."
- });
- return false;
- }
-
- setDefaultInstrumentFromProfile();
-
- jamClient.FTUESave(true);
- jamClient.FTUESetStatus(true); // No FTUE wizard next time
- rest.userCertifiedGear({success:true});
- app.layout.closeDialog('ftue');
- if (app.afterFtue) {
- // If there's a function to invoke, invoke it.
- app.afterFtue();
- app.afterFtue = null;
- }
- return false;
- }
-
- // Handler for when the audio device is changed in the new FTUE screen
- // This works differently from the old FTUE. There is no input/output selection,
- // as soon as the user chooses a driver, we auto-assign inputs and outputs.
- // We also call jamClient.FTUEGetExpectedLatency, which returns a structure like:
- // { latency: 11.1875, latencyknown: true, latencyvar: 1}
- function newFtueAudioDeviceChanged(evt) {
- var $select = $(evt.currentTarget);
-
- var $audioSelect = $('.ftue-new .settings-2-device select');
- var $voiceSelect = $('.ftue-new .settings-2-voice select');
- var audioDriverId = $audioSelect.val();
- var voiceDriverId = $voiceSelect.val();
- jamClient.FTUESetMusicDevice(audioDriverId);
- jamClient.FTUESetChatInput(voiceDriverId);
- if (voiceDriverId) { // Let the back end know whether a voice device is selected
- jamClient.TrackSetChatEnable(true);
- } else {
- jamClient.TrackSetChatEnable(false);
- }
- if (!audioDriverId) {
- // reset back to 'Choose...'
- newFtueEnableControls(false);
- return;
- }
- var musicInputs = jamClient.FTUEGetMusicInputs();
- var musicOutputs = jamClient.FTUEGetMusicOutputs();
-
- // set the music input to the first available input,
- // and output to the first available output
- var kin = null, kout = null, k = null;
- // TODO FIXME - this jamClient call returns a dictionary.
- // It's difficult to know what to auto-choose.
- // For example, with my built-in audio, the keys I get back are
- // digital in, line in, mic in and stereo mix. Which should we pick for them?
- for (k in musicInputs) {
- kin = k;
- break;
- }
- for (k in musicOutputs) {
- kout = k;
- break;
- }
- var result;
- if (kin && kout) {
- jamClient.FTUESetMusicInput(kin);
- jamClient.FTUESetMusicOutput(kout);
- } else {
- // TODO FIXME - how to handle a driver selection where we are unable to
- // autoset both inputs and outputs? (I'd think this could happen if either
- // the input or output side returned no values)
- return;
- }
-
- newFtueEnableControls(true);
- newFtueOsSpecificSettings();
- setLevels(0);
- newFtueUpdateLatencyView('loading');
- jamClient.FTUESave(false);
- setVuCallbacks();
-
- var latency = jamClient.FTUEGetExpectedLatency();
- newFtueUpdateLatencyView(latency);
- }
-
- function newFtueSave(persist) {
- newFtueUpdateLatencyView('loading');
- jamClient.FTUESave(persist);
- var latency = jamClient.FTUEGetExpectedLatency();
- newFtueUpdateLatencyView(latency);
- }
-
- function newFtueAsioResync(evt) {
- // In theory, we should be calling the following, but it causes
- // us to not have both inputs/outputs loaded, and simply calling
- // FTUE Save appears to resync things.
- //jamClient.FTUERefreshDevices();
- newFtueSave(false);
- }
-
- function newFtueSetAsioFrameSize(evt) {
- var val = parseFloat($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetFrameSize(" + val + ")");
- jamClient.FTUESetFrameSize(val);
- newFtueSave(false);
- }
- function newFtueSetAsioInputLatency(evt) {
- var val = parseInt($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetInputLatency(" + val + ")");
- jamClient.FTUESetInputLatency(val);
- newFtueSave(false);
- }
- function newFtueSetAsioOutputLatency(evt) {
- var val = parseInt($(evt.currentTarget).val(),10);
- if (isNaN(val)) {
- return;
- }
- logger.debug("Calling FTUESetOutputLatency(" + val + ")");
- jamClient.FTUESetOutputLatency(val);
- newFtueSave(false);
- }
-
- // Enable or Disable the frame/buffer controls in the new FTUE screen
- function newFtueEnableControls(enable) {
- var $frame = $('#ftue-2-asio-framesize');
- var $bin = $('#ftue-2-asio-input-latency');
- var $bout = $('#ftue-2-asio-output-latency');
- if (enable) {
- $frame.removeAttr("disabled").easyDropDown('enable');
- $bin.removeAttr("disabled").easyDropDown('enable');
- $bout.removeAttr("disabled").easyDropDown('enable');
- } else {
- $frame.attr("disabled", "disabled").easyDropDown('disable');
- $bin.attr("disabled", "disabled").easyDropDown('disable');
- $bout.attr("disabled", "disabled".easyDropDown('disable'));
- }
- }
-
- // Based on OS and Audio Hardware, set Frame/Buffer settings appropriately
- // and show/hide the ASIO button.
- function newFtueOsSpecificSettings() {
- var $frame = $('#ftue-2-asio-framesize');
- var $bin = $('#ftue-2-asio-input-latency');
- var $bout = $('#ftue-2-asio-output-latency');
- var $asioBtn = $('#btn-ftue-2-asio-control-panel');
- if (jamClient.GetOSAsString() === "Win32") {
- if (jamClient.FTUEHasControlPanel()) {
- // Win32 + ControlPanel = ASIO
- // frame=2.5, buffers=0
- $asioBtn.show();
- $frame.val('2.5');
- $bin.val('0');
- $bout.val('0');
- } else {
- // Win32, no ControlPanel = WDM/Kernel Streaming
- // frame=10, buffers=0
- $asioBtn.hide();
- $frame.val('10');
- // TODO FIXME - the old FTUE set the buffers to 1 for WDM/Kernel streaming
- // The new FTUE spec says to use 0, as I've done here...
- $bin.val('0');
- $bout.val('0');
- }
- } else { // Assuming Mac. TODO: Linux check here
- // frame=2.5, buffers=0
- $asioBtn.hide();
- $frame.val('2.5');
- $bin.val('0');
- $bout.val('0');
- }
-
- }
-
- // Given a latency structure, update the view.
- function newFtueUpdateLatencyView(latency) {
- var $report = $('.ftue-new .latency .report');
- var $instructions = $('.ftue-new .latency .instructions');
- var latencyClass = "neutral";
- var latencyValue = "N/A";
- var $saveButton = $('#btn-ftue-2-save');
- if (latency && latency.latencyknown) {
- latencyValue = latency.latency;
- // Round latency to two decimal places.
- latencyValue = Math.round(latencyValue * 100) / 100;
- if (latency.latency <= 10) {
- latencyClass = "good";
- $saveButton.removeClass('disabled');
- } else if (latency.latency <= 20) {
- latencyClass = "acceptable";
- $saveButton.removeClass('disabled');
- } else {
- latencyClass = "bad";
- $saveButton.addClass('disabled');
- }
- } else {
- latencyClass = "unknown";
- $saveButton.addClass('disabled');
- }
-
- $('.ms-label', $report).html(latencyValue);
- $('p', $report).html('milliseconds');
-
- $report.removeClass('good acceptable bad');
- $report.addClass(latencyClass);
-
- var instructionClasses = ['neutral', 'good', 'acceptable', 'bad', 'start', 'loading'];
- $.each(instructionClasses, function(idx, val) {
- $('p.' + val, $instructions).hide();
- });
- if (latency === 'loading') {
- $('p.loading', $instructions).show();
- } else {
- $('p.' + latencyClass, $instructions).show();
- }
- }
-
- function audioDriverChanged(evt) {
- var $select = $(evt.currentTarget);
- var driverId = $select.val();
- jamClient.FTUESetMusicDevice(driverId);
- loadAudioDevices();
- setAsioSettingsVisibility();
- }
-
- function audioDeviceChanged(evt) {
- var $select = $(evt.currentTarget);
- setAudioDevice($select);
- if (musicInAndOutSet()) {
- ftueSave(false);
- setVuCallbacks();
- }
- }
-
- function setAudioDevice($select) {
- var device = $select.data('device');
- var deviceId = $select.val();
- // Note: We always set, even on the "Choose" value of "", which clears
- // the current setting.
- var setFunction = deviceSetMap[device];
- setFunction(deviceId);
- }
-
- /**
- * Return a boolean indicating whether both the MusicInput
- * and MusicOutput devices are set.
- */
- function musicInAndOutSet() {
- var audioInput = $('[layout-wizard-step="2"] .audio-input select').val();
- var audioOutput = $('[layout-wizard-step="2"] .audio-output select').val();
- return (audioInput && audioOutput);
- }
-
- function setVuCallbacks() {
- jamClient.FTUERegisterVUCallbacks(
- "JK.ftueAudioOutputVUCallback",
- "JK.ftueAudioInputVUCallback",
- "JK.ftueChatInputVUCallback"
- );
- jamClient.SetVURefreshRate(200);
- }
-
- function setAsioSettingsVisibility() {
- logger.debug("jamClient.FTUEHasControlPanel()=" + jamClient.FTUEHasControlPanel());
- if (jamClient.FTUEHasControlPanel()) {
- logger.debug("Showing ASIO button");
- $('#btn-asio-control-panel').show();
- }
- else {
- logger.debug("Hiding ASIO button");
- $('#btn-asio-control-panel').hide();
- }
- }
-
- function initialize() {
- // If not on windows, hide ASIO settings
- if (jamClient.GetOSAsString() != "Win32") {
- logger.debug("Not on Win32 - modifying UI for Mac/Linux");
- win32 = false;
- $('[layout-wizard-step="2"] p[os="win32"]').hide();
- $('[layout-wizard-step="2"] p[os="mac"]').show();
- $('#btn-asio-control-panel').hide();
- $('[layout-wizard-step="2"] .settings-controls select').removeAttr("disabled");
- loadAudioDevices();
- }
-
- setAsioSettingsVisibility();
-
- events();
- var dialogBindings = { 'beforeShow': beforeShow,
- 'afterShow': afterShow, 'afterHide': afterHide };
- app.bindDialog('ftue', dialogBindings);
- app.registerWizardStepFunction("0", settingsInit);
- app.registerWizardStepFunction("2", settingsInit);
- app.registerWizardStepFunction("4", testLatency);
- app.registerWizardStepFunction("6", testComplete);
- loadAudioDrivers();
- }
-
- // Expose publics
- this.initialize = initialize;
-
- // Expose degreesFromRange outside for testing
- this._degreesFromRange = degreesFromRange;
-
- return this;
+ * FtueAudioSelectionScreen
+ * Javascript that goes with the screen where initial
+ * selection of the audio devices takes place.
+ * Corresponds to /#ftue2
+ */
+(function (context, $) {
+
+ "use strict";
+
+ context.JK = context.JK || {};
+ context.JK.FtueWizard = function (app) {
+ context.JK.FtueWizard.latencyTimeout = true;
+ context.JK.FtueWizard.latencyMS = Number.MAX_VALUE;
+ var rest = context.JK.Rest();
+
+ var logger = context.JK.logger;
+ var jamClient = context.jamClient;
+ var win32 = true;
+
+ var deviceSetMap = {
+ 'audio-input': jamClient.FTUESetMusicInput,
+ 'audio-output': jamClient.FTUESetMusicOutput,
+ 'voice-chat-input': jamClient.FTUESetChatInput
};
-
-
- // Common VU updater taking a dbValue (-80 to 20) and a CSS selector for the VU.
- context.JK.ftueVUCallback = function(dbValue, selector) {
- // Convert DB into a value from 0.0 - 1.0
- var floatValue = (dbValue + 80) / 100;
- context.JK.VuHelpers.updateVU(selector, floatValue);
+ var faderMap = {
+ 'ftue-2-audio-input-fader': jamClient.FTUESetInputVolume,
+ 'ftue-2-voice-input-fader': jamClient.FTUESetOutputVolume,
+ 'ftue-audio-input-fader': jamClient.FTUESetInputVolume,
+ 'ftue-voice-input-fader': jamClient.FTUESetChatInputVolume,
+ 'ftue-audio-output-fader': jamClient.FTUESetOutputVolume
};
- context.JK.ftueAudioInputVUCallback = function(dbValue) {
- context.JK.ftueVUCallback(dbValue, '#ftue-2-audio-input-vu-left');
- context.JK.ftueVUCallback(dbValue, '#ftue-2-audio-input-vu-right');
- context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-left');
- context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-right');
- };
- context.JK.ftueAudioOutputVUCallback = function(dbValue) {
- context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-left');
- context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-right');
- };
- context.JK.ftueChatInputVUCallback = function(dbValue) {
- context.JK.ftueVUCallback(dbValue, '#ftue-2-voice-input-vu-left');
- context.JK.ftueVUCallback(dbValue, '#ftue-2-voice-input-vu-right');
- context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-left');
- context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-right');
- };
+ function latencyTimeoutCheck() {
+ if (context.JK.FtueWizard.latencyTimeout) {
+ jamClient.FTUERegisterLatencyCallback('');
+ context.JK.app.setWizardStep("5");
+ }
+ }
- // Latency Callback
- context.JK.ftueLatencyCallback = function(latencyMS) {
- // We always show gauge screen if we hit this.
- // Clear out the 'timeout' variable.
- context.JK.FtueWizard.latencyTimeout = false;
- var now = new Date();
- context.console.debug("ftueLatencyCallback: " + now);
- context.JK.FtueWizard.latencyMS = latencyMS;
+ function afterHide(data) {
+ // Unsubscribe from FTUE VU callbacks.
+ jamClient.FTUERegisterVUCallbacks('', '', '');
+ }
- // Unregister callback:
- context.jamClient.FTUERegisterLatencyCallback('');
- // Go to 'congrats' screen -- although latency may be too high.
- context.JK.app.setWizardStep("6");
- };
+ function beforeShow(data) {
+ var vuMeters = [
+ '#ftue-2-audio-input-vu-left',
+ '#ftue-2-audio-input-vu-right',
+ '#ftue-2-voice-input-vu-left',
+ '#ftue-2-voice-input-vu-right',
+ '#ftue-audio-input-vu-left',
+ '#ftue-audio-input-vu-right',
+ '#ftue-voice-input-vu-left',
+ '#ftue-voice-input-vu-right',
+ '#ftue-audio-output-vu-left',
+ '#ftue-audio-output-vu-right'
+ ];
+ $.each(vuMeters, function () {
+ context.JK.VuHelpers.renderVU(this,
+ {vuType: "horizontal", lightCount: 12, lightWidth: 15, lightHeight: 3});
+ });
+
+ var faders = context._.keys(faderMap);
+ $.each(faders, function () {
+ var fid = this;
+ context.JK.FaderHelpers.renderFader('#' + fid,
+ {faderId: fid, faderType: "horizontal", width: 163});
+ context.JK.FaderHelpers.subscribe(fid, faderChange);
+ });
+ }
+
+ function afterShow(data) {
+ }
+
+ function faderChange(faderId, newValue, dragging) {
+ var setFunction = faderMap[faderId];
+ // TODO - using hardcoded range of -80 to 20 for output levels.
+ var mixerLevel = newValue - 80; // Convert our [0-100] to [-80 - +20] range
+ setFunction(mixerLevel);
+ }
+
+ function settingsInit() {
+ jamClient.FTUEInit();
+ setLevels(0);
+ // Always reset the driver select box to "Choose..." which forces everything
+ // to sync properly when the user reselects their driver of choice.
+ // VRFS-375 and VRFS-561
+ $('[layout-wizard="ftue"] [layout-wizard-step="0"] .settings-2-device select').val("");
+ $('[layout-wizard="ftue"] [layout-wizard-step="0"] .settings-2-voice select').val("");
+ $('[layout-wizard="ftue"] [layout-wizard-step="2"] .asio-settings .settings-driver select').val("");
+ }
+
+ function setLevels(db) {
+ if (db < -80 || db > 20) {
+ throw ("BUG! ftue.js:setLevels db arg must be between -80 and 20");
+ }
+ var trackIds = jamClient.SessionGetIDs();
+ var controlStates = jamClient.SessionGetControlState(trackIds);
+ $.each(controlStates, function (index, value) {
+ context.JK.Mixer.fillTrackVolume(value, false);
+ // Default input/output to 0 DB
+ context.trackVolumeObject.volL = db;
+ context.trackVolumeObject.volR = db;
+ jamClient.SessionSetControlState(trackIds[index]);
+ });
+ $.each(context._.keys(faderMap), function (index, faderId) {
+ // faderChange takes a value from 0-100
+ var $fader = $('[fader-id="' + faderId + '"]');
+
+ var faderPct = db + 80;
+ context.JK.FaderHelpers.setHandlePosition($fader, faderPct);
+ faderChange(faderId, faderPct);
+ });
+ }
+
+ function testComplete() {
+ logger.debug("Test complete");
+ var latencyMS = context.JK.FtueWizard.latencyMS;
+ var ftueSucceeded = latencyMS <= 20;
+ if (ftueSucceeded) {
+ logger.debug(latencyMS + " is <= 20. Setting FTUE status to true");
+ ftueSave(true); // Save the profile
+ context.jamClient.FTUESetStatus(true); // No FTUE wizard next time
+ rest.userCertifiedGear({success: true});
+
+ // notify anyone curious about how it went
+ $('div[layout-id=ftue]').trigger('ftue_success');
+ }
+ else {
+ rest.userCertifiedGear({success: false, reason: "latency=" + latencyMS});
+ }
+
+ updateGauge();
+ }
+
+ function updateGauge() {
+ var latencyMS = context.JK.FtueWizard.latencyMS;
+ // Round to 2 decimal places
+ latencyMS = (Math.round(latencyMS * 100)) / 100;
+ logger.debug("Latency Value: " + latencyMS);
+ if (latencyMS > 20) {
+ $('#ftue-latency-congrats').hide();
+ $('#ftue-latency-fail').show();
+ } else {
+ $('#ftue-latency-ms').html(latencyMS);
+ $('#ftue-latency-congrats').show();
+ $('#ftue-latency-fail').hide();
+ if (latencyMS <= 10) {
+ $('[layout-wizard-step="6"] .btnHelp').hide();
+ $('[layout-wizard-step="6"] .btnRepeat').hide();
+ }
+ }
+ setNeedleValue(latencyMS);
+ }
+
+ // Function to calculate an absolute value and an absolute value range into
+ // a number of degrees on a circualar "speedometer" gauge. The 0 degrees value
+ // points straight up to the middle of the real-world value range.
+ // Arguments:
+ // value: The real-world value (e.g. 20 milliseconds)
+ // minValue: The real-world minimum value (e.g. 0 milliseconds)
+ // maxValue: The real-world maximum value (e.g. 40 milliseconds)
+ // degreesUsed: The number of degrees used to represent the full real-world
+ // range. 360 would be the entire circle. 270 would be 3/4ths
+ // of the circle. The unused gap will be at the bottom of the
+ // gauge.
+ // (e.g. 300)
+ function degreesFromRange(value, minValue, maxValue, degreesUsed) {
+ if (value > maxValue) {
+ value = maxValue;
+ }
+ if (value < minValue) {
+ value = minValue;
+ }
+ var range = maxValue - minValue;
+ var floatVal = value / range;
+ var degrees = Math.round(floatVal * degreesUsed);
+ degrees -= Math.round(degreesUsed / 2);
+ if (degrees < 0) {
+ degrees += 360;
+ }
+ return degrees;
+ }
+
+ // Given a number of MS, and assuming the gauge has a range from
+ // 0 to 40 ms. Update the gauge to the proper value.
+ function setNeedleValue(ms) {
+ logger.debug("setNeedleValue: " + ms);
+ var deg = degreesFromRange(ms, 0, 40, 300);
+
+ // Supporting Firefix, Chrome, Safari, Opera and IE9+.
+ // Should we need to support < IE9, this will need more work
+ // to compute the matrix transformations in those browsers -
+ // and I don't believe they support transparent PNG graphic
+ // rotation, so we'll have to change the needle itself.
+ var css = {
+ //"behavior":"url(-ms-transform.htc)",
+ /* Firefox */
+ "-moz-transform": "rotate(" + deg + "deg)",
+ /* Safari and Chrome */
+ "-webkit-transform": "rotate(" + deg + "deg)",
+ /* Opera */
+ "-o-transform": "rotate(" + deg + "deg)",
+ /* IE9 */
+ "-ms-transform": "rotate(" + deg + "deg)"
+ /* IE6,IE7 */
+ //"filter": "progid:DXImageTransform.Microsoft.Matrix(sizingMethod='auto expand', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)",
+ /* IE8 */
+ //"-ms-filter": '"progid:DXImageTransform.Microsoft.Matrix(SizingMethod=\'auto expand\', M11=0.7071067811865476, M12=-0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"'
+ };
+
+ $('#ftue-latency-numerical').html(ms);
+ $('#ftue-latency-needle').css(css);
+
+ }
+
+ function testLatency() {
+ // we'll just register for call back right here and unregister in the callback.
+ context.JK.FtueWizard.latencyTimeout = true;
+ var cbFunc = 'JK.ftueLatencyCallback';
+ logger.debug("Registering latency callback: " + cbFunc);
+ jamClient.FTUERegisterLatencyCallback('JK.ftueLatencyCallback');
+ var now = new Date();
+ logger.debug("Starting Latency Test..." + now);
+ context.setTimeout(latencyTimeoutCheck, 300 * 1000); // Timeout to 5 minutes
+ jamClient.FTUEStartLatency();
+ }
+
+ function openASIOControlPanel(evt) {
+ if (win32) {
+ logger.debug("Calling FTUEOpenControlPanel()");
+ jamClient.FTUEOpenControlPanel();
+ }
+ }
+
+ function asioResync(evt) {
+ jamClient.FTUERefreshDevices();
+ ftueSave(false);
+ }
+
+ function ftueSave(persist) {
+ // Explicitly set inputs and outputs to dropdown values
+ // before save as the client seems to want this on changes to
+ // things like frame size, etc..
+ var $audioSelects = $('[layout-wizard-step="2"] .settings-controls select');
+ $.each($audioSelects, function (index, value) {
+ var $select = $(value);
+ setAudioDevice($select);
+ });
+ if (musicInAndOutSet()) {
+
+ // If there is no voice-chat-input selected, let the back-end know
+ // that we're using music for voice-chat.
+ if ($('[layout-wizard-step="2"] select[data-device="voice-chat-input"]').val()) {
+ // Voice input selected
+ jamClient.TrackSetChatEnable(true);
+ } else {
+ // No voice input selected.
+ jamClient.TrackSetChatEnable(false);
+ }
+
+ setDefaultInstrumentFromProfile();
+
+ logger.debug("Calling FTUESave(" + persist + ")");
+ var response = jamClient.FTUESave(persist);
+ setLevels(0);
+ if (response) {
+ logger.warn(response);
+ // TODO - we may need to do something about errors on save.
+ // per VRFS-368, I'm hiding the alert, and logging a warning.
+ // context.alert(response);
+ }
+ } else {
+ logger.debug("Aborting FTUESave as we need input + output selected.");
+ }
+ }
+
+ function setAsioFrameSize(evt) {
+ var val = parseFloat($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetFrameSize(" + val + ")");
+ jamClient.FTUESetFrameSize(val);
+ ftueSave(false);
+ }
+
+ function setAsioInputLatency(evt) {
+ var val = parseInt($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetInputLatency(" + val + ")");
+ jamClient.FTUESetInputLatency(val);
+ ftueSave(false);
+ }
+
+ function setAsioOutputLatency(evt) {
+ var val = parseInt($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetOutputLatency(" + val + ")");
+ jamClient.FTUESetOutputLatency(val);
+ ftueSave(false);
+ }
+
+ function videoLinkClicked(evt) {
+ var myOS = jamClient.GetOSAsString();
+ var link;
+ if (myOS === 'MacOSX') {
+ link = $(evt.currentTarget).attr('external-link-mac');
+ } else if (myOS === 'Win32') {
+ link = $(evt.currentTarget).attr('external-link-win');
+ }
+ if (link) {
+ context.jamClient.OpenSystemBrowser(link);
+ }
+ }
+
+ function events() {
+ $('.ftue-video-link').hover(
+ function (evt) { // handlerIn
+ $(this).addClass('hover');
+ },
+ function (evt) { // handlerOut
+ $(this).removeClass('hover');
+ }
+ );
+ $('.ftue-video-link').on('click', videoLinkClicked);
+ $('[layout-wizard-step="2"] .settings-driver select').on('change', audioDriverChanged);
+ $('[layout-wizard-step="2"] .settings-controls select').on('change', audioDeviceChanged);
+ $('#btn-asio-control-panel').on('click', openASIOControlPanel);
+ $('#btn-asio-resync').on('click', asioResync);
+ $('#asio-framesize').on('change', setAsioFrameSize);
+ $('#asio-input-latency').on('change', setAsioInputLatency);
+ $('#asio-output-latency').on('change', setAsioOutputLatency);
+ // New FTUE events
+ $('.ftue-new .settings-2-device select').on('change', newFtueAudioDeviceChanged);
+ $('.ftue-new .settings-2-voice select').on('change', newFtueAudioDeviceChanged);
+ $('#btn-ftue-2-asio-resync').on('click', newFtueAsioResync);
+ $('#btn-ftue-2-asio-control-panel').on('click', openASIOControlPanel);
+ $('#ftue-2-asio-framesize').on('change', newFtueSetAsioFrameSize);
+ $('#ftue-2-asio-input-latency').on('change', newFtueSetAsioInputLatency);
+ $('#ftue-2-asio-output-latency').on('change', newFtueSetAsioOutputLatency);
+ $('#btn-ftue-2-save').on('click', newFtueSaveSettingsHandler);
+ }
+
+ /**
+ * This function loads the available audio devices from jamClient, and
+ * builds up the select dropdowns in the audio-settings step of the FTUE wizard.
+ */
+ function loadAudioDevices() {
+ var funcs = [
+ jamClient.FTUEGetMusicInputs,
+ jamClient.FTUEGetChatInputs,
+ jamClient.FTUEGetMusicOutputs
+ ];
+ var selectors = [
+ '[layout-wizard-step="2"] .audio-input select',
+ '[layout-wizard-step="2"] .voice-chat-input select',
+ '[layout-wizard-step="2"] .audio-output select'
+ ];
+ var optionsHtml = '';
+ var deviceOptionFunc = function (deviceKey, index, list) {
+ optionsHtml += '';
+ };
+ for (var i = 0; i < funcs.length; i++) {
+ optionsHtml = '';
+
+ var devices = funcs[i](); // returns hash of device id: device name
+ var $select = $(selectors[i]);
+ $select.empty();
+ var sortedDeviceKeys = context._.keys(devices).sort();
+ context._.each(sortedDeviceKeys, deviceOptionFunc);
+ $select.html(optionsHtml);
+ context.JK.dropdown($select);
+ $select.removeAttr("disabled");
+ $('[layout-wizard-step="2"] .settings-asio select').removeAttr("disabled").easyDropDown('enable')
+ // Set selects to lowest possible values to start:
+ $('#asio-framesize').val('2.5').change();
+ $('#asio-input-latency').val('0').change();
+ $('#asio-output-latency').val('0').change();
+ // Special-case for a non-ASIO device, set to 1
+ if (jamClient.GetOSAsString() === "Win32") { // Limit this check to Windows only.
+ if (!(jamClient.FTUEHasControlPanel())) {
+ $('#asio-input-latency').val('1').change();
+ $('#asio-output-latency').val('1').change();
+ }
+ }
+ }
+ }
+
+ /**
+ * Load available drivers and populate the driver select box.
+ */
+ function loadAudioDrivers() {
+ var drivers = jamClient.FTUEGetDevices();
+
+ var driverOptionFunc = function (driverKey, index, list) {
+ optionsHtml += '';
+ };
+
+ var optionsHtml = '';
+ var selectors = [
+ '[layout-wizard-step="0"] .settings-2-device select',
+ '[layout-wizard-step="0"] .settings-2-voice select',
+ '[layout-wizard-step="2"] .settings-driver select'
+ ];
+ var sortedDeviceKeys = context._.keys(drivers).sort();
+ context._.each(sortedDeviceKeys, driverOptionFunc);
+ $.each(selectors, function (index, selector) {
+ var $select = $(selector);
+ $select.empty();
+ $select.html(optionsHtml);
+ context.JK.dropdown($select);
+ });
+ }
+
+ /** Once a configuration is decided upon, we set the user's default instrument based on data from their profile */
+ function setDefaultInstrumentFromProfile() {
+ var defaultInstrumentId;
+ if (context.JK.userMe.instruments && context.JK.userMe.instruments.length > 0) {
+ defaultInstrumentId = context.JK.instrument_id_to_instrument[context.JK.userMe.instruments[0].instrument_id].client_id;
+ }
+ else {
+ defaultInstrumentId = context.JK.server_to_client_instrument_map['Other'].client_id;
+ }
+
+ jamClient.TrackSetInstrument(1, defaultInstrumentId);
+ }
+
+ /**
+ * Handler for the new FTUE save button.
+ */
+ function newFtueSaveSettingsHandler(evt) {
+ evt.preventDefault();
+ var $saveButton = $('#btn-ftue-2-save');
+ if ($saveButton.hasClass('disabled')) {
+ return;
+ }
+ var selectedAudioDevice = $('.ftue-new .settings-2-device select').val();
+ if (!(selectedAudioDevice)) {
+ app.notify({
+ title: "Please select an audio device",
+ text: "Please choose a usable audio device, or select cancel."
+ });
+ return false;
+ }
+
+ setDefaultInstrumentFromProfile();
+
+ jamClient.FTUESave(true);
+ jamClient.FTUESetStatus(true); // No FTUE wizard next time
+ rest.userCertifiedGear({success: true});
+ app.layout.closeDialog('ftue');
+ if (app.afterFtue) {
+ // If there's a function to invoke, invoke it.
+ app.afterFtue();
+ app.afterFtue = null;
+ }
+ return false;
+ }
+
+ // Handler for when the audio device is changed in the new FTUE screen
+ // This works differently from the old FTUE. There is no input/output selection,
+ // as soon as the user chooses a driver, we auto-assign inputs and outputs.
+ // We also call jamClient.FTUEGetExpectedLatency, which returns a structure like:
+ // { latency: 11.1875, latencyknown: true, latencyvar: 1}
+ function newFtueAudioDeviceChanged(evt) {
+ var $select = $(evt.currentTarget);
+
+ var $audioSelect = $('.ftue-new .settings-2-device select');
+ var $voiceSelect = $('.ftue-new .settings-2-voice select');
+ var audioDriverId = $audioSelect.val();
+ var voiceDriverId = $voiceSelect.val();
+ jamClient.FTUESetMusicDevice(audioDriverId);
+ jamClient.FTUESetChatInput(voiceDriverId);
+ if (voiceDriverId) { // Let the back end know whether a voice device is selected
+ jamClient.TrackSetChatEnable(true);
+ } else {
+ jamClient.TrackSetChatEnable(false);
+ }
+ if (!audioDriverId) {
+ // reset back to 'Choose...'
+ newFtueEnableControls(false);
+ return;
+ }
+ var musicInputs = jamClient.FTUEGetMusicInputs();
+ var musicOutputs = jamClient.FTUEGetMusicOutputs();
+
+ // set the music input to the first available input,
+ // and output to the first available output
+ var kin = null, kout = null, k = null;
+ // TODO FIXME - this jamClient call returns a dictionary.
+ // It's difficult to know what to auto-choose.
+ // For example, with my built-in audio, the keys I get back are
+ // digital in, line in, mic in and stereo mix. Which should we pick for them?
+ for (k in musicInputs) {
+ kin = k;
+ break;
+ }
+ for (k in musicOutputs) {
+ kout = k;
+ break;
+ }
+ var result;
+ if (kin && kout) {
+ jamClient.FTUESetMusicInput(kin);
+ jamClient.FTUESetMusicOutput(kout);
+ } else {
+ // TODO FIXME - how to handle a driver selection where we are unable to
+ // autoset both inputs and outputs? (I'd think this could happen if either
+ // the input or output side returned no values)
+ return;
+ }
+
+ newFtueEnableControls(true);
+ newFtueOsSpecificSettings();
+ setLevels(0);
+ newFtueUpdateLatencyView('loading');
+ jamClient.FTUESave(false);
+ setVuCallbacks();
+
+ var latency = jamClient.FTUEGetExpectedLatency();
+ newFtueUpdateLatencyView(latency);
+ }
+
+ function newFtueSave(persist) {
+ newFtueUpdateLatencyView('loading');
+ jamClient.FTUESave(persist);
+ var latency = jamClient.FTUEGetExpectedLatency();
+ newFtueUpdateLatencyView(latency);
+ }
+
+ function newFtueAsioResync(evt) {
+ // In theory, we should be calling the following, but it causes
+ // us to not have both inputs/outputs loaded, and simply calling
+ // FTUE Save appears to resync things.
+ //jamClient.FTUERefreshDevices();
+ newFtueSave(false);
+ }
+
+ function newFtueSetAsioFrameSize(evt) {
+ var val = parseFloat($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetFrameSize(" + val + ")");
+ jamClient.FTUESetFrameSize(val);
+ newFtueSave(false);
+ }
+
+ function newFtueSetAsioInputLatency(evt) {
+ var val = parseInt($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetInputLatency(" + val + ")");
+ jamClient.FTUESetInputLatency(val);
+ newFtueSave(false);
+ }
+
+ function newFtueSetAsioOutputLatency(evt) {
+ var val = parseInt($(evt.currentTarget).val(), 10);
+ if (isNaN(val)) {
+ return;
+ }
+ logger.debug("Calling FTUESetOutputLatency(" + val + ")");
+ jamClient.FTUESetOutputLatency(val);
+ newFtueSave(false);
+ }
+
+ // Enable or Disable the frame/buffer controls in the new FTUE screen
+ function newFtueEnableControls(enable) {
+ var $frame = $('#ftue-2-asio-framesize');
+ var $bin = $('#ftue-2-asio-input-latency');
+ var $bout = $('#ftue-2-asio-output-latency');
+ if (enable) {
+ $frame.removeAttr("disabled").easyDropDown('enable');
+ $bin.removeAttr("disabled").easyDropDown('enable');
+ $bout.removeAttr("disabled").easyDropDown('enable');
+ } else {
+ $frame.attr("disabled", "disabled").easyDropDown('disable');
+ $bin.attr("disabled", "disabled").easyDropDown('disable');
+ $bout.attr("disabled", "disabled".easyDropDown('disable'));
+ }
+ }
+
+ // Based on OS and Audio Hardware, set Frame/Buffer settings appropriately
+ // and show/hide the ASIO button.
+ function newFtueOsSpecificSettings() {
+ var $frame = $('#ftue-2-asio-framesize');
+ var $bin = $('#ftue-2-asio-input-latency');
+ var $bout = $('#ftue-2-asio-output-latency');
+ var $asioBtn = $('#btn-ftue-2-asio-control-panel');
+ if (jamClient.GetOSAsString() === "Win32") {
+ if (jamClient.FTUEHasControlPanel()) {
+ // Win32 + ControlPanel = ASIO
+ // frame=2.5, buffers=0
+ $asioBtn.show();
+ $frame.val('2.5');
+ $bin.val('0');
+ $bout.val('0');
+ } else {
+ // Win32, no ControlPanel = WDM/Kernel Streaming
+ // frame=10, buffers=0
+ $asioBtn.hide();
+ $frame.val('10');
+ // TODO FIXME - the old FTUE set the buffers to 1 for WDM/Kernel streaming
+ // The new FTUE spec says to use 0, as I've done here...
+ $bin.val('0');
+ $bout.val('0');
+ }
+ } else { // Assuming Mac. TODO: Linux check here
+ // frame=2.5, buffers=0
+ $asioBtn.hide();
+ $frame.val('2.5');
+ $bin.val('0');
+ $bout.val('0');
+ }
+
+ }
+
+ // Given a latency structure, update the view.
+ function newFtueUpdateLatencyView(latency) {
+ var $report = $('.ftue-new .latency .report');
+ var $instructions = $('.ftue-new .latency .instructions');
+ var latencyClass = "neutral";
+ var latencyValue = "N/A";
+ var $saveButton = $('#btn-ftue-2-save');
+ if (latency && latency.latencyknown) {
+ latencyValue = latency.latency;
+ // Round latency to two decimal places.
+ latencyValue = Math.round(latencyValue * 100) / 100;
+ if (latency.latency <= 10) {
+ latencyClass = "good";
+ $saveButton.removeClass('disabled');
+ } else if (latency.latency <= 20) {
+ latencyClass = "acceptable";
+ $saveButton.removeClass('disabled');
+ } else {
+ latencyClass = "bad";
+ $saveButton.addClass('disabled');
+ }
+ } else {
+ latencyClass = "unknown";
+ $saveButton.addClass('disabled');
+ }
+
+ $('.ms-label', $report).html(latencyValue);
+ $('p', $report).html('milliseconds');
+
+ $report.removeClass('good acceptable bad');
+ $report.addClass(latencyClass);
+
+ var instructionClasses = ['neutral', 'good', 'acceptable', 'bad', 'start', 'loading'];
+ $.each(instructionClasses, function (idx, val) {
+ $('p.' + val, $instructions).hide();
+ });
+ if (latency === 'loading') {
+ $('p.loading', $instructions).show();
+ } else {
+ $('p.' + latencyClass, $instructions).show();
+ }
+ }
+
+ function audioDriverChanged(evt) {
+ var $select = $(evt.currentTarget);
+ var driverId = $select.val();
+ jamClient.FTUESetMusicDevice(driverId);
+ loadAudioDevices();
+ setAsioSettingsVisibility();
+ }
+
+ function audioDeviceChanged(evt) {
+ var $select = $(evt.currentTarget);
+ setAudioDevice($select);
+ if (musicInAndOutSet()) {
+ ftueSave(false);
+ setVuCallbacks();
+ }
+ }
+
+ function setAudioDevice($select) {
+ var device = $select.data('device');
+ var deviceId = $select.val();
+ // Note: We always set, even on the "Choose" value of "", which clears
+ // the current setting.
+ var setFunction = deviceSetMap[device];
+ setFunction(deviceId);
+ }
+
+ /**
+ * Return a boolean indicating whether both the MusicInput
+ * and MusicOutput devices are set.
+ */
+ function musicInAndOutSet() {
+ var audioInput = $('[layout-wizard-step="2"] .audio-input select').val();
+ var audioOutput = $('[layout-wizard-step="2"] .audio-output select').val();
+ return (audioInput && audioOutput);
+ }
+
+ function setVuCallbacks() {
+ jamClient.FTUERegisterVUCallbacks(
+ "JK.ftueAudioOutputVUCallback",
+ "JK.ftueAudioInputVUCallback",
+ "JK.ftueChatInputVUCallback"
+ );
+ jamClient.SetVURefreshRate(200);
+ }
+
+ function setAsioSettingsVisibility() {
+ logger.debug("jamClient.FTUEHasControlPanel()=" + jamClient.FTUEHasControlPanel());
+ if (jamClient.FTUEHasControlPanel()) {
+ logger.debug("Showing ASIO button");
+ $('#btn-asio-control-panel').show();
+ }
+ else {
+ logger.debug("Hiding ASIO button");
+ $('#btn-asio-control-panel').hide();
+ }
+ }
+
+ function initialize() {
+ // If not on windows, hide ASIO settings
+ if (jamClient.GetOSAsString() != "Win32") {
+ logger.debug("Not on Win32 - modifying UI for Mac/Linux");
+ win32 = false;
+ $('[layout-wizard-step="2"] p[os="win32"]').hide();
+ $('[layout-wizard-step="2"] p[os="mac"]').show();
+ $('#btn-asio-control-panel').hide();
+ $('[layout-wizard-step="2"] .settings-controls select').removeAttr("disabled");
+ loadAudioDevices();
+ }
+
+ setAsioSettingsVisibility();
+
+ events();
+ var dialogBindings = { 'beforeShow': beforeShow,
+ 'afterShow': afterShow, 'afterHide': afterHide };
+ app.bindDialog('ftue', dialogBindings);
+ app.registerWizardStepFunction("0", settingsInit);
+ app.registerWizardStepFunction("2", settingsInit);
+ app.registerWizardStepFunction("4", testLatency);
+ app.registerWizardStepFunction("6", testComplete);
+ loadAudioDrivers();
+ }
+
+ // Expose publics
+ this.initialize = initialize;
+
+ // Expose degreesFromRange outside for testing
+ this._degreesFromRange = degreesFromRange;
+
+ return this;
+ };
- })(window,jQuery);
\ No newline at end of file
+ // Common VU updater taking a dbValue (-80 to 20) and a CSS selector for the VU.
+ context.JK.ftueVUCallback = function (dbValue, selector) {
+ // Convert DB into a value from 0.0 - 1.0
+ var floatValue = (dbValue + 80) / 100;
+ context.JK.VuHelpers.updateVU(selector, floatValue);
+ };
+
+ context.JK.ftueAudioInputVUCallback = function (dbValue) {
+ context.JK.ftueVUCallback(dbValue, '#ftue-2-audio-input-vu-left');
+ context.JK.ftueVUCallback(dbValue, '#ftue-2-audio-input-vu-right');
+ context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-left');
+ context.JK.ftueVUCallback(dbValue, '#ftue-audio-input-vu-right');
+ };
+ context.JK.ftueAudioOutputVUCallback = function (dbValue) {
+ context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-left');
+ context.JK.ftueVUCallback(dbValue, '#ftue-audio-output-vu-right');
+ };
+ context.JK.ftueChatInputVUCallback = function (dbValue) {
+ context.JK.ftueVUCallback(dbValue, '#ftue-2-voice-input-vu-left');
+ context.JK.ftueVUCallback(dbValue, '#ftue-2-voice-input-vu-right');
+ context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-left');
+ context.JK.ftueVUCallback(dbValue, '#ftue-voice-input-vu-right');
+ };
+
+ // Latency Callback
+ context.JK.ftueLatencyCallback = function (latencyMS) {
+ // We always show gauge screen if we hit this.
+ // Clear out the 'timeout' variable.
+ context.JK.FtueWizard.latencyTimeout = false;
+ var now = new Date();
+ context.console.debug("ftueLatencyCallback: " + now);
+ context.JK.FtueWizard.latencyMS = latencyMS;
+
+ // Unregister callback:
+ context.jamClient.FTUERegisterLatencyCallback('');
+ // Go to 'congrats' screen -- although latency may be too high.
+ context.JK.app.setWizardStep("6");
+ };
+
+
+})(window, jQuery);
\ No newline at end of file
diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js
index 90e669640..7540d7f75 100644
--- a/web/app/assets/javascripts/session.js
+++ b/web/app/assets/javascripts/session.js
@@ -512,6 +512,7 @@
context.JK.FaderHelpers.subscribe(faderId, faderChanged);
// Visually update fader to underlying mixer start value.
// Always do this, even if gainPercent is zero.
+
context.JK.FaderHelpers.setFaderValue(faderId, gainPercent);
}