diff --git a/web/app/assets/javascripts/backend_alerts.js b/web/app/assets/javascripts/backend_alerts.js index 2bd2b3737..705f9ec29 100644 --- a/web/app/assets/javascripts/backend_alerts.js +++ b/web/app/assets/javascripts/backend_alerts.js @@ -138,7 +138,8 @@ context.VideoActions.videoWindowClosed() } else if (type === ALERT_NAMES.VST_CHANGED) { - context.ConfigureTracksActions.onVstChanged() + console.log("VST CHANGED!") + context.ConfigureTracksActions.vstChanged() } else if((!context.JK.CurrentSessionModel || !context.JK.CurrentSessionModel.inSession()) && (ALERT_NAMES.INPUT_IO_RATE == type || ALERT_NAMES.INPUT_IO_JTR == type || ALERT_NAMES.OUTPUT_IO_RATE == type || ALERT_NAMES.OUTPUT_IO_JTR== type)) { diff --git a/web/app/assets/javascripts/configureTracksHelper2.js b/web/app/assets/javascripts/configureTracksHelper2.js index 7c4f07128..d87319a53 100644 --- a/web/app/assets/javascripts/configureTracksHelper2.js +++ b/web/app/assets/javascripts/configureTracksHelper2.js @@ -22,136 +22,7 @@ var $instrumentsHolder = null; var isDragging = false; - function removeHoverer($hoverChannel) { - var $channel = $hoverChannel.data('original') - $channel.data('cloned', null); - $hoverChannel.remove(); - } - function hoverIn($channel) { - if(isDragging) return; - - var $container = $channel.closest('.target'); - var inTarget = $container.length > 0; - if(!inTarget) { - $container = $channel.closest('.channels-holder') - } - - var $inputs = $container.find('.ftue-input'); - - var index = $inputs.index($channel); - // $channel.css('padding', '0 5px'); - if(inTarget) { - $channel.data('container', $container) - $channel.addClass('hovering'); - $channel.css('color', 'white') - $channel.css('background-color', '#333'); - $channel.css('border', '#333'); - $channel.css('border-radius', '2px'); - $channel.css('min-width', '49%'); - $channel.css('width', 'auto'); - $channel.css('position', 'absolute'); - $container.css('overflow', 'visible'); - } - else { - var $offsetParent = $channel.offsetParent(); - var parentOffset = $offsetParent.offset(); - - var hoverChannel = $(context._.template($templateAssignablePort.html(), {id: 'bogus', name: $channel.text(), direction: 'bogus'}, { variable: 'data' })); - hoverChannel - .css('position', 'absolute') - .css('color', 'white') - .css('left', $channel.position().left) - .css('top', $channel.position().top) - .css('background-color', '#333') - .css('min-width', $channel.width()) - .css('min-height', $channel.height()) - .css('z-index', 10000) - .css('background-position', '4px 6px') - .css('padding-left', '14px') - .data('original', $channel); - - $channel.data('cloned', hoverChannel); - hoverChannel - .hover(function(e) { - var hoverCheckTimeout = hoverChannel.data('hoverCheckTimeout'); - if(hoverCheckTimeout) { - clearTimeout(hoverCheckTimeout); - hoverChannel.data('hoverCheckTimeout', null); - } - }, function() { removeHoverer($(this)); }) - .mousedown(function(e) { - // because we have obscured the element the user wants to drag, - // we proxy a mousedown on the hover-element to the covered .ftue-input ($channel). - // this causes jquery.drag to get going even though the user clicked a different element - $channel.trigger(e) - }) - hoverChannel.data('hoverCheckTimeout', setTimeout(function() { - // check if element has already been left - hoverChannel.data('hoverCheckTimeout', null); - removeHoverer(hoverChannel); - }, 500)); - hoverChannel.prependTo($offsetParent); - } - - $channel.css('z-index', 10000) - if(inTarget && $inputs.length == 2) { - - if(index == 0) { - $channel.css('right', '50%') - } - else { - $channel.css('left', '51%') - } - } - - } - - function hoverOut($channel) { - - var $cloned = $channel.data('cloned'); - if($cloned) { - return; // let the cloned handle the rest of hover out logic when it's hovered-out - } - - $channel - .removeClass('hovering') - .css('color', '') - .css('font-weight', '') - .css('position', '') - .css('width', '') - .css('background-color', '') - .css('padding', '') - .css('padding-left', '') - .css('background-position', '') - .css('border', '') - .css('border-radius', '') - .css('right', '') - .css('left', '') - .css('min-width', '') - .css('z-index', '') - .css('margin-left', '') - .css('max-width', 'auto'); - - //var $container = $channel.closest('.target'); - var $container = $channel.data('container'); - if($container) { - $container.css('overflow', '') - } - } - - function fixClone($clone) { - $clone - .css('color', '') - .css('font-weight', '') - .css('width', 'auto') - .css('background-color', '') - .css('padding', '') - .css('border', '') - .css('border-radius', '') - .css('right', '') - .css('min-width', '') - } // inputChannelFilter is an optional argument that is used by the Gear Wizard. // basically, if an input channel isn't in there, it's not going to be displayed @@ -176,11 +47,6 @@ var $channel = $(context._.template($templateAssignablePort.html(), $.extend({}, inputChannel, {direction:'in'}), { variable: 'data' })); - $channel.hover( - function() { hoverIn ($(this)) }, - function() { hoverOut($(this)) } - ); - if(forceInputsToUnassign || inputChannel.assignment == ASSIGNMENT.UNASSIGNED) { unassignInputChannel($channel); } @@ -205,10 +71,7 @@ context._.each(outputChannels, function (outputChannel, index) { var $channel = $(context._.template($templateAssignablePort.html(), $.extend({}, outputChannel, {direction:'out'}), { variable: 'data' })); - $channel.hover( - function() { hoverIn ($(this)) }, - function() { hoverOut($(this)) } - ); + if(outputChannel.assignment == ASSIGNMENT.UNASSIGNED) { unassignOutputChannel($channel); @@ -223,29 +86,6 @@ } addChannelToOutput($channel, $output.find('.output-target')); } - - $channel.draggable({ - helper: 'clone', - start: function(e,ui) { - isDragging = true; - var $channel = $(this); - fixClone(ui.helper); - var $output = $channel.closest('.output-target'); - var isUnassigned = $output.length == 0; - if(isUnassigned) { - $outputChannelHolder.find('.output-target').addClass('possible-target'); - } - else { - $outputChannelHolder.find('.output-target').addClass('possible-target'); - $unassignedOutputsHolder.addClass('possible-target'); - } - }, - stop: function() { - isDragging = false; - $outputChannelHolder.find('.output-target').removeClass('possible-target'); - $unassignedOutputsHolder.removeClass('possible-target') - } - }); }); } @@ -439,112 +279,9 @@ $originallyAssignedTrack.attr('output-count', $originallyAssignedTrack.find('.ftue-input:not(.ui-draggable-dragging)').length) } - - function initializeUnassignedOutputDroppable() { - $unassignedOutputsHolder.droppable( - { - accept: '.ftue-input[data-direction="out"]', - activeClass: 'drag-in-progress', - hoverClass: 'drag-hovering', - drop: function( event, ui ) { - var $channel = ui.draggable; - - //$channel.css('left', '0').css('top', '0'); - unassignOutputChannel($channel); - } - }); - } - - function initializeUnassignedInputDroppable() { - $unassignedInputsHolder.droppable( - { - accept: '.ftue-input[data-direction="in"]', - activeClass: 'drag-in-progress', - hoverClass: 'drag-hovering', - drop: function( event, ui ) { - var $channel = ui.draggable; - //$channel.css('left', '0').css('top', '0'); - unassignInputChannel($channel); - } - }); - } - - function initializeOutputDroppables() { - var i; - for(i = 0; i < MAX_OUTPUTS; i++) { - var $target = $(context._.template($templateOutputTarget.html(), {num: i }, { variable: 'data' })); - $outputChannelHolder.append($target); - $target.find('.output-target').droppable( - { - accept: '.ftue-input[data-direction="out"]', - activeClass: 'drag-in-progress', - hoverClass: 'drag-hovering', - drop: function( event, ui ) { - var $slot = $(this); - if($slot.attr('output-count') == 1) { - return false; // max of 1 output per slot - } - var $channel = ui.draggable; - //$channel.css('left', '0').css('top', '0'); - addChannelToOutput($channel, $slot); - } - }); - } - } - - function initializeTrackDroppables() { - var i; - for(i = 0; i < MAX_TRACKS; i++) { - var $target = $(context._.template($templateTrackTarget.html(), {num: i }, { variable: 'data' })); - $tracksHolder.append($target); - $target.find('.track-target').droppable( - { - accept: '.ftue-input[data-direction="in"]', - activeClass: 'drag-in-progress', - hoverClass: 'drag-hovering', - drop: function( event, ui ) { - var $track = $(this); - if($track.attr('track-count') == 2) { - return false; // max of 2 inputs per track - } - - var $channel = ui.draggable; - //$channel.css('left', '0').css('top', '0'); - addChannelToTrack($channel, $track); - } - }); - } - } - - function initializeInstrumentDropdown() { - var i; - for(i = 0; i < MAX_TRACKS; i++) { - var $root = $('
'); - $root.instrumentSelector().attr('data-num', i); - $instrumentsHolder.append($root); - } - } - - function initialize(_$parent) { $parent = _$parent; - $templateAssignablePort = $('#template-assignable-port'); - $templateTrackTarget = $('#template-track-target'); - $templateOutputTarget = $('#template-output-target'); - $unassignedInputsHolder = $parent.find('.unassigned-input-channels') - $unassignedOutputsHolder = $parent.find('.unassigned-output-channels'); - $tracksHolder = $parent.find('.tracks'); - $instrumentsHolder = $parent.find('.instruments'); - $outputChannelHolder = $parent.find('.output-channels'); - - - initializeUnassignedInputDroppable(); - initializeTrackDroppables(); - initializeInstrumentDropdown(); - - initializeUnassignedOutputDroppable(); - initializeOutputDroppables(); } this.initialize = initialize; diff --git a/web/app/assets/javascripts/dialog/configureTrackDialog.js b/web/app/assets/javascripts/dialog/configureTrackDialog.js index 20801cfa6..17989b205 100644 --- a/web/app/assets/javascripts/dialog/configureTrackDialog.js +++ b/web/app/assets/javascripts/dialog/configureTrackDialog.js @@ -50,7 +50,7 @@ function setInstructions(type) { if (type === 'audio') { - $instructions.html('Choose your audio device. Drag and drop to assign input ports to tracks, and specify the instrument for each track. Drag and drop to assign a pair of output ports for session stereo audio monitoring.') + $instructions.html("Click the 'ADD LIVE TRACK' button to add more tracks. You may set up a live track for each instrumental and/or vocal part to perform in sessions. You must also set up exactly two Session Audio Output ports to deliver the stereo audio in your sessions.") return; var os = context.jamClient.GetOSAsString(); $instructions.html(configure_audio_instructions[os]); @@ -91,7 +91,7 @@ } function validateAudioSettings() { - return configureTracksHelper.trySave(); + return true; } function showVoiceChatPanel() { @@ -103,7 +103,7 @@ $musicAudioTabSelector.click(function () { // validate voice chat settings if (validateVoiceChatSettings()) { - configureTracksHelper.reset(); + window.ConfigureTracksActions.reset(false); voiceChatHelper.reset(); showMusicAudioPanel(); } @@ -113,7 +113,7 @@ // validate audio settings if (validateAudioSettings()) { logger.debug("initializing voice chat helper") - configureTracksHelper.reset(); + window.ConfigureTracksActions.reset(false); voiceChatHelper.reset(); showVoiceChatPanel(); } @@ -133,7 +133,7 @@ //}); $btnUpdateTrackSettings.click(function() { - if(configureTracksHelper.trySave() && voiceChatHelper.trySave()) { + if(voiceChatHelper.trySave()) { app.layout.closeDialog('configure-tracks'); } @@ -152,7 +152,7 @@ }); $certifiedAudioProfile.html(optionsHtml); - context.JK.dropdown($certifiedAudioProfile); + //context.JK.dropdown($certifiedAudioProfile); } function deviceChanged() { @@ -183,7 +183,7 @@ currentProfile = profile; - configureTracksHelper.reset(); + window.ConfigureTracksActions.reset(false); } function beforeShow() { @@ -207,13 +207,16 @@ return; } - configureTracksHelper.reset(); + window.ConfigureTracksActions.reset(false); voiceChatHelper.reset(); voiceChatHelper.beforeShow(); } function afterShow() { sessionUtils.SessionPageEnter(); + + //context.ConfigureTracksActions.vstScan(); + } function onCancel() { @@ -247,8 +250,8 @@ $btnAddNewGear = $dialog.find('.btn-add-new-audio-gear'); $btnUpdateTrackSettings = $dialog.find('.btn-update-settings'); - configureTracksHelper = new context.JK.ConfigureTracksHelper(app); - configureTracksHelper.initialize($dialog); + //configureTracksHelper = new context.JK.ConfigureTracksHelper(app); + //configureTracksHelper.initialize($dialog); voiceChatHelper = new context.JK.VoiceChatHelper(app); voiceChatHelper.initialize($dialog, 'configure_track_dialog', true, {vuType: "vertical", lightCount: 10, lightWidth: 3, lightHeight: 17}, 191); diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js index 077ad4ced..8b1b8477a 100644 --- a/web/app/assets/javascripts/fakeJamClient.js +++ b/web/app/assets/javascripts/fakeJamClient.js @@ -1052,6 +1052,16 @@ function GetAutoStart() { return true; } function SaveSettings() {} + + function VSTScan(callback) {setTimeout(eval(callback+ "()"), 1000)} + function hasVstHost() { return false;} + function getPluginList() { return {vsts:[]} } + + function clearPluginList() {} + function listTrackAssignments() { + return {} + } + // Javascript Bridge seems to camel-case // Set the instance functions: this.AbortRecording = AbortRecording; @@ -1315,6 +1325,11 @@ this.StopNetworkTest = StopNetworkTest; this.log = log; this.getOperatingMode = getOperatingMode; + this.VSTScan = VSTScan; + this.hasVstHost = hasVstHost; + this.getPluginList = getPluginList; + this.clearPluginList = clearPluginList; + this.listTrackAssignments = listTrackAssignments; this.clientID = "devtester"; }; diff --git a/web/app/assets/javascripts/globals.js b/web/app/assets/javascripts/globals.js index 8c5895a7f..148b5ecc5 100644 --- a/web/app/assets/javascripts/globals.js +++ b/web/app/assets/javascripts/globals.js @@ -53,7 +53,9 @@ METRONOME_PLAYBACK_MODE_SELECTED: 'metronome_playback_mode_selected', CHECKOUT_SIGNED_IN: 'checkout_signed_in', CHECKOUT_SKIP_SIGN_IN: 'checkout_skip_sign_in', - PREVIEW_PLAYED: 'preview_played' + PREVIEW_PLAYED: 'preview_played', + VST_OPERATION_SELECTED: 'vst_operation_selected', + VST_EFFECT_SELECTED: 'vst_effect_selected' }; context.JK.PLAYBACK_MONITOR_MODE = { diff --git a/web/app/assets/javascripts/jquery.manageVsts.js b/web/app/assets/javascripts/jquery.manageVsts.js new file mode 100644 index 000000000..a14cec2e1 --- /dev/null +++ b/web/app/assets/javascripts/jquery.manageVsts.js @@ -0,0 +1,71 @@ +(function(context, $) { + + "use strict"; + + context.JK = context.JK || {}; + + + // creates an iconic/graphical instrument selector. useful when there is minimal real-estate + + $.fn.manageVsts = function(options) { + + return this.each(function(index) { + + function close() { + $parent.btOff(); + $parent.focus(); + } + + var $parent = $(this); + + function onManageVstSelected() { + var $li = $(this); + var vstOperation = $li.attr('data-manage-vst-option'); + + close(); + $parent.triggerHandler(context.JK.EVENTS.VST_OPERATION_SELECTED, {vstOperation: vstOperation}); + return false; + }; + + // if the user goes into the bubble, remove + function waitForBubbleHover($bubble) { + $bubble.hoverIntent({ + over: function() { + if(timeout) { + clearTimeout(timeout); + timeout = null; + } + }, + out: function() { + $parent.btOff(); + }}); + } + + var timeout = null; + + context.JK.hoverBubble($parent, $('#template-manage-vsts').html(), { + trigger:'none', + cssClass: 'manage-vsts-popup', + spikeGirth:0, + spikeLength:0, + width:190, + closeWhenOthersOpen: true, + offsetParent: $parent.closest('.dialog'), + positions:['bottom'], + preShow: function() { + }, + postShow:function(container) { + $(container).find('li').click(onManageVstSelected) + if(timeout) { + clearTimeout(timeout); + timeout = null; + } + waitForBubbleHover($(container)) + timeout = setTimeout(function() {$parent.btOff()}, 3000) + } + }); + }); + } + + +})(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/jquery.trackEffects.js b/web/app/assets/javascripts/jquery.trackEffects.js new file mode 100644 index 000000000..b0a15c74e --- /dev/null +++ b/web/app/assets/javascripts/jquery.trackEffects.js @@ -0,0 +1,75 @@ +(function(context, $) { + + "use strict"; + + context.JK = context.JK || {}; + + + // creates an iconic/graphical instrument selector. useful when there is minimal real-estate + + $.fn.trackEffects = function(options) { + + return this.each(function(index) { + + function close() { + $parent.btOff(); + $parent.focus(); + } + + var $parent = $(this); + + function onOptionSelected() { + var $li = $(this); + var vstOperation = $li.attr('data-manage-vst-option'); + + close(); + $parent.triggerHandler(context.JK.EVENTS.VST_EFFECT_SELECTED, {vstOperation: vstOperation}); + return false; + }; + + // if the user goes into the bubble, remove + function waitForBubbleHover($bubble) { + $bubble.hoverIntent({ + over: function() { + if(timeout) { + clearTimeout(timeout); + timeout = null; + } + }, + out: function() { + $parent.btOff(); + }}); + } + + var timeout = null; + + context.JK.hoverBubble($parent, $('#template-vst-effects').html(), { + trigger:'none', + cssClass: 'vst-effects-popup', + spikeGirth:0, + spikeLength:0, + width:220, + closeWhenOthersOpen: true, + offsetParent: $parent.closest('.screen'), + positions:['bottom'], + preShow: function() { + + }, + postShow:function(container) { + if (options && options['postShow']) { + options['postShow']($(container)) + } + $(container).find('li').click(onOptionSelected) + if(timeout) { + clearTimeout(timeout); + timeout = null; + } + waitForBubbleHover($(container)) + timeout = setTimeout(function() {$parent.btOff()}, 3000) + } + }); + }); + } + + +})(window, jQuery); \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js index 2b0e733d8..cfc88f9ff 100644 --- a/web/app/assets/javascripts/react-components.js +++ b/web/app/assets/javascripts/react-components.js @@ -9,6 +9,7 @@ //= require ./react-components/stores/SessionStore //= require ./react-components/stores/SessionStatsStore //= require ./react-components/stores/MixerStore +//= require ./react-components/stores/ConfigureTracksStore //= require ./react-components/stores/JamTrackStore //= require ./react-components/stores/SessionNotificationStore //= require ./react-components/stores/MediaPlaybackStore diff --git a/web/app/assets/javascripts/react-components/ConfigureAudioTrack.js.jsx.coffee b/web/app/assets/javascripts/react-components/ConfigureAudioTrack.js.jsx.coffee new file mode 100644 index 000000000..e69de29bb diff --git a/web/app/assets/javascripts/react-components/ConfigureLiveTracksDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/ConfigureLiveTracksDialog.js.jsx.coffee new file mode 100644 index 000000000..3bc426721 --- /dev/null +++ b/web/app/assets/javascripts/react-components/ConfigureLiveTracksDialog.js.jsx.coffee @@ -0,0 +1,419 @@ +context = window +ConfigureTracksStore = @ConfigureTracksStore +@ConfigureLiveTracksDialog = React.createClass({ + + mixins: [Reflux.listenTo(@ConfigureTracksStore,"onConfigureTracksChanged"), Reflux.listenTo(@AppStore, "onAppInit")] + + onConfigureTracksChanged:(configureTracks) -> + @setState({configureTracks: configureTracks}) + + onAppInit: (@app) -> + + getInitialState: () -> + {configureTracks: null, midiInterface: null} + + renderAudio: () -> + inputOneOptions = [] + inputTwoOptions = [] + + defaultSelectionOne = `` + defaultSelectionTwo = `` + + inputOneOptions.push(defaultSelectionOne) + inputTwoOptions.push(defaultSelectionTwo) + inputOneValue = '' + inputTwoValue = '' + selectedInstrument = '' + selectedVst = 'NONE' + + + instruments = [] + instruments.push(``) + for displayName, value of context.JK.server_to_client_instrument_map + instruments.push(``) + + vsts = [] + + instrumentDisabled = true + vstDisabled = true + + + if @state.configureTracks? + + if @state.configureTracks.scanningVsts + scan = + `
+
Scanning your system
for VST & AU plug-ins...
+
` + + selectedInstrument = @state.configureTracks.editingTrack.instrument_id if @state.configureTracks.editingTrack.instrument_id? + + if @state.configureTracks.editingTrack.length == 1 + input = @state.configureTracks.editingTrack[0] + if input.number == 0 + inputOneValue = input.id + else + inputTwoValue = input.id + + if @state.configureTracks.editingTrack.length > 1 + inputOneValue = @state.configureTracks.editingTrack[0].id + inputTwoValue = @state.configureTracks.editingTrack[1].id + + instrumentDisabled = @state.configureTracks.editingTrack.length == 0 + vstDisabled = @state.configureTracks.editingTrack.length == 0 + + for input in @state.configureTracks.musicPorts.inputs + + include = false + # we need to see that this input is unassigned, or one of the two selected + for unassignedInputs in @state.configureTracks.trackAssignments.inputs.unassigned + if unassignedInputs.id == input.id + include = true + break + + if !include + # not see if it's the currently edited track + for currentInput in @state.configureTracks.editingTrack + if currentInput.id == input.id + include = true + + if include + item = `` + inputOneOptions.push(item) + inputTwoOptions.push(item) + + + for plugin in @state.configureTracks.vstPluginList.vsts + if plugin.isInstrument == false && plugin.category == 'Effect' + vsts.push(``) + else if plugin.category == 'NONE' + vsts.push(``) + + if @state.configureTracks.editingTrack.vst? + vstAssignedThisTrack = true + selectedVst = @state.configureTracks.editingTrack.vst.file + + vstSettingBtnClasses = classNames({'button-orange': vstAssignedThisTrack, 'button-grey': !vstAssignedThisTrack}) + `
+
+

Audio Input Ports

+

Select one or two inputs ports to assign to this track. Note that if you assign a single input port, the app will automatically duplicate this port into a stereo track.

+ + +
+
+

Instrument

+ +
+
+

Audio Effects (optional)

+ + manage audio plugins
+
+ SETTINGS . . . +
+ {scan} +
+
` + + renderMidi: () -> + midiInterfaces = [] + midiInterfaces.push(``) + midiInstruments = [] + + instruments = [] + for displayName, value of context.JK.server_to_client_instrument_map + instruments.push(``) + + selectedMidiInterface = '' + selectedInstrument = context.JK.client_to_server_instrument_map[50].server_id # default to electric guitar + selectedMidiInstrument = '' + + instrumentDisabled = true + midiInstrumentDisabled = true + vstAssignedThisTrack = false + + if @state.configureTracks? + + logger.debug("current midi device: " + @state.configureTracks.editingTrack.midiDeviceIndex) + selectedMidiInterface = @state.configureTracks.editingTrack.midiDeviceIndex + + selectedInstrument = @state.configureTracks.editingTrack.instrument_id if @state.configureTracks.editingTrack.instrument_id? + instrumentDisabled = !@state.midiInterface? || !selectedMidiInterface? + midiInstrumentDisabled = !@state.midiInterface? || !selectedMidiInterface? + midiInstrumentDisabled = false + instrumentDisabled = false + + if @state.configureTracks.editingTrack.vst? + vstAssignedThisTrack = true + selectedMidiInstrument = @state.configureTracks.editingTrack.vst.file + vstSettingBtnClasses = classNames({'button-orange': vstAssignedThisTrack, 'button-grey': !vstAssignedThisTrack}) + + for midiDevice in @state.configureTracks.attachedMidiDevices.midiDevices + midiInterfaces.push(``) + + for plugin in @state.configureTracks.vstPluginList.vsts + if plugin.isInstrument == true + midiInstruments.push(``) + else if plugin.category == 'NONE' + midiInstruments.push(``) + + `
+
+

MIDI Interface

+ + scan for connected MIDI interfaces +
+
+

Instrument

+ +
+
+

MIDI Instrument (VST or AU Plugin)

+ + manage audio plugins
+
+ SETTING . . . +
+
+
` + + render: () -> + + action = 'ADD TRACK' + header = 'add track' + + isAudio = !@state.configureTracks? || @state.configureTracks.trackType == 'audio' + isMidi = !isAudio + + if isAudio + activeElement = @renderAudio() + else + activeElement = @renderMidi() + + if !@state.configureTracks?.newTrack + action = 'CLOSE' + header = 'update track' + else + cancelBtn = `CANCEL` + + `
+
+ +

{header}

+
+
+
+

Track Type

+
+
+
+ + {activeElement} + +
+ {cancelBtn} + {action} +
+
+
` + + inputChanged: (e) -> + $root = $(@getDOMNode()) + $select1 = $root.find('.input-one') + $select2 = $root.find('.input-two') + + audioInput1 = $select1.val() + audioInput2 = $select2.val() + + if audioInput1 == '' + audioInput1 = null + + if audioInput2 == '' + audioInput2 = null + + if audioInput1? && audioInput1 == audioInput2 + e.preventDefault() + # TODO: tell user they can't do this + return + + ConfigureTracksActions.associateInputsWithTrack(audioInput1, audioInput2) + + vstsChanged: (e) -> + $root = $(@getDOMNode()) + $select = $root.find('select.vsts') + vstSelected = $select.val() + if vstSelected != 'NONE' + vstSelected = {file: vstSelected} + + if @state.configureTracks?.trackType == 'midi' + @updateMidiAssociations() + else + ConfigureTracksActions.associateVSTWithTrack(vstSelected) + + + @setState({midiInterface: null}) + + instrumentSelected: (e) -> + $root = $(@getDOMNode()) + $select = $root.find('.instrument-pick') + + instrumentId = $select.val() + ConfigureTracksActions.associateInstrumentWithTrack(instrumentId) + + + doClose: (e) -> + e.preventDefault() + # check that instrument is selected + + $root = $(@getDOMNode()) + $instrument = $root.find('.instrument-pick') + + instrumentId = $instrument.val() + + $select1 = $root.find('.input-one') + $select2 = $root.find('.input-two') + + audioInput1 = $select1.val() + audioInput2 = $select2.val() + + if audioInput1 == '' + audioInput1 = null + + if audioInput2 == '' + audioInput2 = null + + if audioInput1 == null && audioInput2 == null + context.JK.Banner.showAlert("At least one input must be specified.") + return + + if instrumentId == null || instrumentId == '' + context.JK.Banner.showAlert("Please select an instrument.") + return + + @app.layout.closeDialog('configure-live-tracks-dialog', false) + + onCancel: (e) -> + + ConfigureTracksActions.cancelEdit() + + @app.layout.closeDialog('configure-live-tracks-dialog', true) + + vstSettings: (e) -> + e.preventDefault() + ConfigureTracksActions.showVstSettings() + + + componentDidMount: () -> + $root = $(@getDOMNode()) + $radio = context.JK.checkbox($root.find('input[type="radio"]')) + $radio.on("ifChanged", @trackTypeChanged); + + componentWillUpdate: () -> + @ignoreICheck = true + $root = $(@getDOMNode()) + $radio = $root.find('input[type="radio"]') + #$radio.iCheck('enable') + $radio.iCheck('enable') + + componentDidUpdate: () -> + $root = $(@getDOMNode()) + $radio = $root.find('input[type="radio"]') + $radio = context.JK.checkbox($root.find('input[type="radio"]')) + $radio.on("ifChanged", @trackTypeChanged); + if @state.configureTracks.editingTrack.assignment == 1 + $radio.iCheck('disable') + else + $radio.iCheck('enable') + + @ignoreICheck = false + + $manageAudioPlugins = $root.find('.manage-audio-plugins') + + unless $manageAudioPlugins.data('initialized') + $manageAudioPlugins.manageVsts().on(context.JK.EVENTS.VST_OPERATION_SELECTED, @vstOperation).data('initialized', true) + + trackTypeChanged: (event) -> + + if @ignoreICheck + logger.debug("ignoring track type changed") + return + + $checkedType = $(event.target); + value = $checkedType.val() + logger.debug("trackTypeChanged: " + value, $checkedType) + ConfigureTracksActions.desiredTrackType(value) + #@setState({trackType: value}) + + vstOperation: (e, data) -> + + if data.vstOperation == 'scan' + ConfigureTracksActions.vstScan() + else if data.vstOperation == 'clear' + ConfigureTracksActions.clearVsts() + + manageAudioPlugins: (e) -> + e.preventDefault() + + $root = $(@getDOMNode()) + $manageAudioPlugins = $root.find('.manage-audio-plugins') + $manageAudioPlugins.btOn() + + scanMidi: (e) -> + e.preventDefault() + + ConfigureTracksActions.midiScan() + + + midiInterfaceChanged: (e) -> + + @updateMidiAssociations() + + updateMidiAssociations: (e) -> + $root = $(@getDOMNode()) + $select = $root.find('select.midi-select') + midiInterface = $select.val() + + $select = $root.find('select.vsts') + vstSelected = $select.val() + + logger.debug("updateMidiAssocations", vstSelected, midiInterface) + if vstSelected != 'NONE' + vstSelected = {file: vstSelected} + else + vstSelected = null + + if midiInterface == '' + midiInterface = null + + midi = @state.midiInterface || midiInterface + + if vstSelected? && midi? + logger.debug("updating midi:#{midi} & vst: #{vstSelected.file}") + + ConfigureTracksActions.associateVSTWithTrack(vstSelected) + setTimeout((() => + ConfigureTracksActions.associateMIDIWithTrack(midi) + ), 250) + + else if midi? + logger.debug("updating midi:#{midiInterface}") + ConfigureTracksActions.associateMIDIWithTrack(midiInterface) + + @setState({midiInterface: midiInterface}) + +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee b/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee new file mode 100644 index 000000000..41affdad2 --- /dev/null +++ b/web/app/assets/javascripts/react-components/ConfigureOutputsDialog.js.jsx.coffee @@ -0,0 +1,87 @@ +context = window +ConfigureTracksStore = @ConfigureTracksStore +@ConfigureOutputsDialog = React.createClass({ + + mixins: [Reflux.listenTo(@ConfigureTracksStore, "onConfigureTracksChanged"), Reflux.listenTo(@AppStore, "onAppInit")] + + onConfigureTracksChanged: (configureTracks) -> + @setState({configureTracks: configureTracks}) + + onAppInit: (@app) -> + + getInitialState: () -> + {configureTracks: null} + + render: () -> + + outputs = [] + outputs.push(``) + + if @state.configureTracks? + for output in @state.configureTracks.musicPorts.outputs + outputs.push(``) + + `
+
+ +

session audio outputs

+
+
+

Select two audio output ports that will be used to deliver the stereo audio of your sessions to your headphones or monitor.

+ + +
+ CANCEL + UPDATE PORTS +
+
+
` + + componentDidUpdate: () -> + $root = $(@getDOMNode()) + $output1 = $root.find('.output-1') + $output2 = $root.find('.output-2') + + if @state.configureTracks? && @state.configureTracks.trackAssignments.outputs.assigned.length == 2 + + output1 = @state.configureTracks.trackAssignments.outputs.assigned[0].id + output2 = @state.configureTracks.trackAssignments.outputs.assigned[1].id + + $output1.val(output1) + $output2.val(output2) + + onClose: (e) -> + e.preventDefault() + + $root = $(@getDOMNode()) + $output1 = $root.find('.output-1') + $output2 = $root.find('.output-2') + + output1 = $output1.val() + output2 = $output2.val() + + if output1 == null || output1 == '' + context.JK.Banner.showAlert("Both output ports must have a selection.") + return + + if output2 == null || output2 == '' + context.JK.Banner.showAlert("Both output ports must have a selection.") + return + + if output1? && output1 != '' && output1 == output2 + context.JK.Banner.showAlert("Both output ports can not be the same.") + return + + ConfigureTracksActions.updateOutputs(output1, output2) + + @app.layout.closeDialog('configure-outputs-dialog', false) + + onCancel: (e) -> + + @app.layout.closeDialog('configure-outputs-dialog', true) + } +) diff --git a/web/app/assets/javascripts/react-components/ConfigureTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/ConfigureTracks.js.jsx.coffee new file mode 100644 index 000000000..24cd6a140 --- /dev/null +++ b/web/app/assets/javascripts/react-components/ConfigureTracks.js.jsx.coffee @@ -0,0 +1,120 @@ +context = window +rest = context.JK.Rest() +ReactCSSTransitionGroup = React.addons.CSSTransitionGroup +ASSIGNMENT = context.JK.ASSIGNMENT +VOICE_CHAT = context.JK.VOICE_CHAT +MAX_TRACKS = context.JK.MAX_TRACKS +MAX_OUTPUTS = context.JK.MAX_OUTPUTS +gearUtils = context.JK.GearUtils + +@ConfigureTracks = React.createClass({ + + mixins: [Reflux.listenTo(@ConfigureTracksStore,"onConfigureTracksChanged")] + + getInitialState: () -> + {configureTracks: null} + + onConfigureTracksChanged: (configureTracks) -> + @setState({configureTracks: configureTracks}) + + render: () -> + + liveTracks = [] + outputs = [] + + trackAssignments = @state.configureTracks?.trackAssignments + + if trackAssignments + + for inputsForTrack in trackAssignments.inputs.assigned + candidate = inputsForTrack[0] + + inputs = [] + for input in inputsForTrack + inputs.push(`
{input.name}
`) + + if !inputsForTrack.instrument_id? + instrument = `?` + else + instrument = `` + + trackTypeLabel = 'AUDIO' + + vstName = 'None' + if inputsForTrack.vst? && inputsForTrack.vst != 'NONE' + vstName = "#{inputsForTrack.vst.name} by #{inputsForTrack.vst.manuf}" + + liveTracks.push( + `
+
{candidate.assignment}:{trackTypeLabel}{inputs}
+
{vstName}
+
{instrument}
+
+ update + delete +
+
`) + + for output, i in trackAssignments.outputs.assigned + outputs.push( + `
+
{i + 1}:
{output.name}
+
`) + + `
+ +
+
+

Session Audio Inputs (Live Performance Tracks)

+

Plugin

+

Instrument

+
+
+ {liveTracks} +
+
+ ADD TRACK . . . +
+
+
+
+

Session Audio Outputs (Requires 2 Ports)

+
+ {outputs} +
+ UPDATE OUTPUTS . . . +
+
+
+
` + + onUpdateLiveTrack:(liveTrack, e) -> + e.preventDefault() + + ConfigureTracksActions.showEditTrack(liveTrack.assignment) + + onDeleteLiveTrack:(liveTrack, e) -> + e.preventDefault() + + if liveTrack.assignment == 1 + # can't delete the last assignment + context.JK.Banner.showAlert('You can not delete the 1st audio track.') + else + context.JK.Banner.showYesNo({ + title: "Confirm Deletion", + html: "Are you sure you want to delete this live track?", + yes: => + ConfigureTracksActions.deleteTrack(liveTrack.assignment) + }) + + + openLiveTrackDialog: (e) -> + e.preventDefault() + + ConfigureTracksActions.showAddNewTrack() + + openOutputTrackDialog: (e) -> + e.preventDefault() + + ConfigureTracksActions.showEditOutputs() +}) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee index fc2a1b424..e5a400560 100644 --- a/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee @@ -1,6 +1,7 @@ context = window MixerActions = @MixerActions +ConfigureTracksActions = @ConfigureTracksActions @SessionMyTrack = React.createClass({ @@ -42,7 +43,9 @@ MixerActions = @MixerActions WebkitTransform: "rotate(#{pan}deg)" } - #
+ if @props.associatedVst? + @equalizerSet = true + vst = `
` `
@@ -55,11 +58,10 @@ MixerActions = @MixerActions
+ {vst}

- -
` @@ -96,6 +98,8 @@ MixerActions = @MixerActions context.JK.helpBubble($root.find('.disabled-track-overlay'), 'missing-my-tracks', {}, {positions:['top'], offsetParent: $root.closest('.top-parent')}) + @initializeVstEffects() + componentWillUpdate: (nextProps, nextState) -> $root = $(this.getDOMNode()) $mute = $root.find('.track-icon-mute') @@ -116,4 +120,32 @@ MixerActions = @MixerActions $mute.on("mouseleave", false) $pan.on("mouseentere", false) $pan.on("mouseleave", false) + + componentDidUpdate:() -> + @initializeVstEffects() + + initializeVstEffects: () -> + $root = $(this.getDOMNode()) + $equalizer = $root.find('.track-icon-equalizer') + if $equalizer.length > 0 && !$equalizer.data('initialized') + logger.debug("initializing trackEffects", $equalizer) + $equalizer.trackEffects({postShow: @prepVstEffects}).on(context.JK.EVENTS.VST_EFFECT_SELECTED, @vstOperation).data('initialized', true).click(() => + logger.debug("clicked!") + $equalizer.btOn() + ) + prepVstEffects: ($container) -> + $container.find('.vst-name').text(@props.associatedVst?.name) + + vstOperation: (e, data) -> + logger.debug("track effect selection: " + data.vstOperation) + + if !@props.associatedVst? + logger.warn("no associated VST") + return + + if data.vstOperation == 'open-vst' + ConfigureTracksActions.showVstSettings(@props.associatedVst.track) + else + ConfigureTracksActions.showEditTrack(@props.associatedVst.track + 1) + }) diff --git a/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee index 97323d6f8..017255665 100644 --- a/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee @@ -5,7 +5,7 @@ ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; @SessionMyTracks = React.createClass({ - mixins: [@SessionMyTracksMixin, Reflux.listenTo(@SessionMyTracksStore,"onInputsChanged"), Reflux.listenTo(@AppStore,"onAppInit")] + mixins: [@SessionMyTracksMixin, Reflux.listenTo(@SessionMyTracksStore,"onInputsChanged"), Reflux.listenTo(@AppStore,"onAppInit"), Reflux.listenTo(@ConfigureTracksStore, "onConfigureTracksChanged")] goToFtue: (e) -> e.preventDefault() diff --git a/web/app/assets/javascripts/react-components/actions/ConfigureTracksActions.js.coffee b/web/app/assets/javascripts/react-components/actions/ConfigureTracksActions.js.coffee index 4a2890385..7b5b3aa2d 100644 --- a/web/app/assets/javascripts/react-components/actions/ConfigureTracksActions.js.coffee +++ b/web/app/assets/javascripts/react-components/actions/ConfigureTracksActions.js.coffee @@ -19,4 +19,5 @@ context = window associateVSTWithTrack: {} associateMIDIWithTrack: {} desiredTrackType: {} + vstChanged: {} }) diff --git a/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee b/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee index 9d808485c..7fc97a850 100644 --- a/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee +++ b/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee @@ -4,9 +4,21 @@ context = window onInputsChanged: (sessionMixers) -> + @sessionMixers = sessionMixers - session = sessionMixers.session - mixers = sessionMixers.mixers + @recompute() + + onConfigureTracksChanged: (configureTracks) -> + + @configureTracks = configureTracks + + @recompute() + + recompute: () -> + return if !@sessionMixers? + + session = @sessionMixers.session + mixers = @sessionMixers.mixers tracks = [] @@ -38,11 +50,30 @@ context = window instrumentIcon = context.JK.getInstrumentIcon45(track.instrument_id); trackName = "#{name}: #{track.instrument}" - tracks.push({track: track, mixerFinder: mixerFinder, mixers: mixerData, hasMixer:hasMixer, name: name, trackName: trackName, instrumentIcon: instrumentIcon, photoUrl: photoUrl, clientId: participant.client_id}) + associatedVst = null + # find any VST info + if hasMixer && @configureTracks? + # bug in the backend; track is wrong for personal mixers (always 1), but correct for master mix + trackAssignment = -1 + if @props.mode == context.JK.MIX_MODES.MASTER + trackAssignment = mixerData.mixer.track + else + trackAssignment = mixerData.oppositeMixer?.track + + console.log("checking associations", @configureTracks.vstTrackAssignments.vsts, mixerData.mixer) + for vst in @configureTracks.vstTrackAssignments.vsts + if vst.track == trackAssignment - 1 && vst.name != 'NONE' + logger.debug("found VST on track", vst, track) + associatedVst = vst + break + + tracks.push({track: track, mixerFinder: mixerFinder, mixers: mixerData, hasMixer:hasMixer, name: name, trackName: trackName, instrumentIcon: instrumentIcon, photoUrl: photoUrl, clientId: participant.client_id, associatedVst: associatedVst}) else logger.warn("SessionMyTracks: unable to find participant") this.setState(tracks: tracks, session:session, chat: chat) + + } \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee b/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee new file mode 100644 index 000000000..b3c2b23a0 --- /dev/null +++ b/web/app/assets/javascripts/react-components/stores/ConfigureTracksStore.js.coffee @@ -0,0 +1,439 @@ +$ = jQuery +context = window +logger = context.JK.logger +ASSIGNMENT = context.JK.ASSIGNMENT +VOICE_CHAT = context.JK.VOICE_CHAT +MAX_TRACKS = context.JK.MAX_TRACKS +MAX_OUTPUTS = context.JK.MAX_OUTPUTS +gearUtils = context.JK.GearUtils + +### + + QVariantMap scanForPlugins(); +QVariantMap VSTListVsts(); +void VSTClearAll(); +QVariantMap VSTSetTrackAssignment(const QVariantMap vst, const QString& trackId); +QVariantMap VSTListTrackAssignments(); +void VSTShowHideGui(bool show,const QString& trackId); +void VST_ScanForMidiDevices(); +QVariantMap VST_GetMidiDeviceList(); +bool VST_EnableMidiForTrack(const QString& trackId, bool enableMidi, int midiDeviceIndex); +### + +@ConfigureTracksStore = Reflux.createStore( + { + listenables: ConfigureTracksActions + + musicPorts: {inputs: [], outputs: []} + trackNumber: null + editingTrack: null + vstPluginList: {vsts: []} + vstTrackAssignments: {vsts: []} + attachedMidiDevices: {midiDevices: []} + midiTrackAssignments: {tracks: []} + scanningVsts: false + trackType: 'audio' + + init: () -> + this.listenTo(context.AppStore, this.onAppInit) + this.listenTo(context.MixerStore, this.onMixersChanged) + + onAppInit: (@app) -> + + editingTrackValid: () -> + true + + onMixersChanged: (mixers) -> + @loadChannels() + @loadTrackInstruments() + @changed() + + onReset: (force) -> + logger.debug("ConfigureTracksStore:reset", this) + @trackNumber = null + @editingTrack = null + @loadChannels() + @loadTrackInstruments() + + if force || context.jamClient.hasVstAssignment() + @performVstScan() + @performMidiScan() + @changed() + + + onTrySave: () -> + logger.debug("ConfigureTracksStore:trySave") + @trySave() + + trySave: () -> + + onVstScan: () -> + @performVstScan(true) + + @changed() + + performVstScan: (sendChanged) -> + @hasVst = gon.global.vst_enabled & context.jamClient.hasVstHost() + logger.debug("hasVst", @hasVst) + if @hasVst + logger.debug("vstScan starting") + @scanningVsts = true + result = context.jamClient.VSTScan("window.ConfigureTracksStore.onVstScanComplete") + + onClearVsts: () -> + context.jamClient.VSTClearAll() + + setTimeout((() => + @listVsts() + + @changed() + ), 250) + + onVstScanComplete: () -> + # XXX must wait a long time to get track assignments after scan/ + console.log("vst scan complete") + @scanningVsts = false + setTimeout((() => + @listVsts() + @changed() + ), 100 ) + + onVstChanged: () -> + setTimeout() + logger.debug("vst changed") + + setTimeout((() => + @listVsts() + @changed() + ), 0) + + listVsts: () -> + + @vstPluginList = context.jamClient.VSTListVsts() + @vstTrackAssignments = context.jamClient.VSTListTrackAssignments() + + console.log("@vstTrackAssignments", @vstTrackAssignments) + + onMidiScan: () -> + @performMidiScan() + @changed() + + performMidiScan: () -> + + if !@hasVst + logger.debug("performMidiScan skipped due to no VST") + return + context.jamClient.VST_ScanForMidiDevices(); + @attachedMidiDevices = context.jamClient.VST_GetMidiDeviceList(); + + # trackNumber is 0-based, and optional + onShowVstSettings: (trackNumber) -> + if !@hasVst + logger.debug("onShowVstSettings skipped due to no VST") + return + + if !trackNumber? + trackNumber = @trackNumber - 1 if @trackNumber? + + logger.debug("show VST GUI", trackNumber) + + context.jamClient.VSTShowHideGui(true, trackNumber) if trackNumber? + + changed: () -> + @editingTrack = [] + @editingTrack.assignment = @trackNumber + + if @trackNumber? + + for inputsForTrack in @trackAssignments.inputs.assigned + if inputsForTrack.assignment == @trackNumber + @editingTrack = inputsForTrack + break + + + # slap on vst, if any, from list of vst assignments + for vst in @vstTrackAssignments.vsts + if vst.track == @editingTrack.assignment - 1 + @editingTrack.vst = vst + @editingTrack.midiDeviceIndex = vst.midiDeviceIndex + break + + for inputsForTrack in @trackAssignments.inputs.assigned + if vst.track == inputsForTrack.assignment - 1 + inputsForTrack.vst = vst + + if @editingTrack.vst? + logger.debug("current track has a VST assigned:" + @editingTrack.vst.file) + + logger.debug("trackAssignments:", @trackAssignments) + logger.debug("editingTrack:", @editingTrack) + + @item = { + musicPorts: @musicPorts, + trackAssignments: @trackAssignments, + trackNumber: @trackNumber, + editingTrack: @editingTrack, + vstPluginList: @vstPluginList, + vstTrackAssignments: @vstTrackAssignments, + attachedMidiDevices: @attachedMidiDevices, + nextTrackNumber: @nextTrackNumber, + newTrack: @newTrack, + midiTrackAssignments: @midiTrackAssignments, + scanningVsts: @scanningVsts, + trackType: @trackType + } + + @trigger(@item) + + loadChannels: (forceInputsToUnassign, inputChannelFilter) -> + # inputChannelFilter is an optional argument that is used by the Gear Wizard. + # basically, if an input channel isn't in there, it's not going to be displayed + @musicPorts = context.jamClient.FTUEGetChannels() + + # let's populate this bad boy + @trackAssignments = {inputs: {unassigned: [], assigned: [], chat: []}, outputs: {unassigned: [], assigned: []}} + + nextTrackNumber = 0 + + for input in @musicPorts.inputs + if input.assignment == ASSIGNMENT.UNASSIGNED + @trackAssignments.inputs.unassigned.push(input) + else if input.assignment == ASSIGNMENT.CHAT + @trackAssignments.inputs.chat.push(input) + else + nextTrackNumber = input.assignment if input.assignment > nextTrackNumber + + # make sure this assignment isn't already preset (you can have multiple inputs per 'track slot') + found = false + for assigned in @trackAssignments.inputs.assigned + if assigned.assignment == input.assignment + assigned.push(input) + found = true + + if !found + initial = [input] + initial.assignment = input.assignment # store the assignment on the array itself, so we don't have to check inside the array for an input's assignment (which will all be the same) + @trackAssignments.inputs.assigned.push(initial) + for output in @musicPorts.outputs + if output.assignment == ASSIGNMENT.OUTPUT + @trackAssignments.outputs.assigned.push(output) + else + @trackAssignments.outputs.unassigned.push(output) + + @nextTrackNumber = nextTrackNumber + 1 + + + loadTrackInstruments: (forceInputsToUnassign) -> + for inputsForTrack in @trackAssignments.inputs.assigned + + clientInstrument = context.jamClient.TrackGetInstrument(inputsForTrack.assignment) + + if clientInstrument == 0 + logger.debug("defaulting track instrument for assignment #{@trackNumber}") + # ensure that we always have an instrument set (50 = electric guitar + context.jamClient.TrackSetInstrument(inputsForTrack.assignment, 50) + clientInstrument = 50 + + instrument = context.JK.client_to_server_instrument_map[clientInstrument]; + + inputsForTrack.instrument_id = instrument?.server_id + + + onAssociateInputsWithTrack: (inputId1, inputId2) -> + return unless @trackNumber? + + for inputs in @editingTrack + context.jamClient.TrackSetAssignment(inputs.id, true, ASSIGNMENT.UNASSIGNED) + + if inputId1? + logger.debug("setting input1 #{inputId1} to #{@trackNumber}") + context.jamClient.TrackSetAssignment(inputId1, true, @trackNumber) + + if inputId2? + logger.debug("setting input2 #{inputId2} to #{@trackNumber}") + context.jamClient.TrackSetAssignment(inputId2, true, @trackNumber) + + result = context.jamClient.TrackSaveAssignments(); + + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + + onAssociateInstrumentWithTrack: (instrumentId) -> + return unless @trackNumber? + + logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", @trackNumber, instrumentId) + + if instrumentId != null && instrumentId != '' + context.jamClient.TrackSetInstrument(@trackNumber, context.JK.instrument_id_to_instrument[instrumentId].client_id) + else + context.jamClient.TrackSetInstrument(@trackNumber, 0) + + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + + + result = context.jamClient.TrackSaveAssignments() + + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + + onAssociateVSTWithTrack: (vst) -> + + if !@hasVst + logger.debug("onAssociateVSTWithTrack skipped due to no VST") + return + + if vst? + logger.debug("associating track:#{@trackNumber - 1} with VST:#{vst.file}") + + found = null + for knownVst in @vstPluginList.vsts + if knownVst.file == vst.file + found = knownVst + break + if found? + context.jamClient.VSTSetTrackAssignment(found, @trackNumber - 1) + else + logger.error("unable to locate vst for #{vst}") + else + logger.debug("unassociated track:#{@trackNumber} with VST") + # no way to unset VST assignment yet + + setTimeout((() => ( + @listVsts() + + @changed() + )), 250) + + onCancelEdit: () -> + if @newTrack + for input in @editingTrack + context.jamClient.TrackSetAssignment(input.id, true, ASSIGNMENT.UNASSIGNED) + result = context.jamClient.TrackSaveAssignments() + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + else + logger.error("unable to process cancel for an existing track") + + onDeleteTrack: (assignment) -> + track = null + for inputsForTrack in @trackAssignments.inputs.assigned + if inputsForTrack.assignment == assignment + track = inputsForTrack + break + + if track? + for input in inputsForTrack + context.jamClient.TrackSetAssignment(input.id, true, ASSIGNMENT.UNASSIGNED) + result = context.jamClient.TrackSaveAssignments() + + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + else + logger.error("unable to find track to delete") + + onShowAddNewTrack: () -> + + # check if we have what we need... namely, free ports + + if @trackAssignments.inputs.unassigned.length == 0 + context.JK.Banner.showAlert('You have no more unassigned input ports.

You can free some up by editing an AUDIO track.') + return + + @openLiveTrackDialog(@nextTrackNumber) + + onShowEditTrack: (trackNumber) -> + @openLiveTrackDialog(trackNumber) + + openLiveTrackDialog: (trackNumber) -> + @trackNumber = trackNumber + logger.debug("opening live track dialog for track #{trackNumber}") + + @newTrack = true + for inputsForTrack in @trackAssignments.inputs.assigned + logger.debug("inputsForTrack.assignment @trackNumber", inputsForTrack.assignment, @trackNumber ) + if inputsForTrack.assignment == @trackNumber + @newTrack = false + break + + if @newTrack + @trackType = 'audio' + else + if @trackNumber == 1 + @trackType = 'audio' + else + @trackType = 'audio' + for trackAssignment in @vstTrackAssignments.vsts + if trackAssignment.track == @trackNumber - 1 + if trackAssignment.midiDeviceIndex > -1 + logger.debug("editing midi track") + @trackType = 'midi' + break + + if @newTrack + + assignment = context.jamClient.TrackGetInstrument(@trackNumber) + + if assignment == 0 + logger.debug("defaulting track instrument for assignment #{@trackNumber}") + # ensure that we always have an instrument set (50 = electric guitar + context.jamClient.TrackSetInstrument(@trackNumber, 50) + + @performVstScan() + @performMidiScan() + + @changed() + + @app.layout.showDialog('configure-live-tracks-dialog') + + onDesiredTrackType: (trackType) -> + @trackType = trackType + + if @trackType == 'midi' + @trackNumber = 100 + @changed() + + onUpdateOutputs: (outputId1, outputId2) -> + + context.jamClient.TrackSetAssignment(outputId1, true, ASSIGNMENT.OUTPUT); + context.jamClient.TrackSetAssignment(outputId2, true, ASSIGNMENT.OUTPUT); + + result = context.jamClient.TrackSaveAssignments(); + + if(!result || result.length == 0) + + else + context.JK.Banner.showAlert('Unable to save assignments. ' + result); + + onShowEditOutputs: () -> + @app.layout.showDialog('configure-outputs-dialog') + + onAssociateMIDIWithTrack: (midiInterface) -> + + @trackNumber = 100 + + if !midiInterface? || midiInterface == '' + logger.debug("disabling midiInterface:#{midiInterface}, track:#{@trackNumber - 1}") + context.jamClient.VST_EnableMidiForTrack(@trackNumber - 1, false, 0) + else + logger.debug("enabling midiInterface:#{midiInterface}, track:#{@trackNumber - 1}") + context.jamClient.VST_EnableMidiForTrack(@trackNumber - 1, true, midiInterface) + + setTimeout((() => ( + @listVsts() + + @changed() + )), 250) + + } +) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee index 61f28e2d6..780126b38 100644 --- a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee +++ b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee @@ -10,6 +10,7 @@ SessionActions = @SessionActions RecordingActions = @RecordingActions NotificationActions = @NotificationActions VideoActions = @VideoActions +ConfigureTracksActions = @ConfigureTracksActions @SessionStore = Reflux.createStore( { @@ -733,6 +734,7 @@ VideoActions = @VideoActions @handleAutoOpenJamTrack() @watchBackendStats() + ConfigureTracksActions.reset(false) ) .fail((xhr) => @updateCurrentSession(null) diff --git a/web/app/assets/javascripts/utils.js b/web/app/assets/javascripts/utils.js index 68aa5b692..c25a3292c 100644 --- a/web/app/assets/javascripts/utils.js +++ b/web/app/assets/javascripts/utils.js @@ -733,6 +733,10 @@ return date.toLocaleTimeString(); } + context.JK.iconMapBase = function() { + return icon_map_base + } + context.JK.formatUtcTime = function(date, change) { if (change) { date.setMinutes(Math.ceil(date.getMinutes() / 30) * 30); diff --git a/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js b/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js index 81c330620..72e97aad3 100644 --- a/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js +++ b/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js @@ -21,14 +21,14 @@ } function handleNext() { - var saved = configureTracksHelper.trySave(); + /** var saved = configureTracksHelper.trySave(); if(saved) { context.JK.GA.trackConfigureTracksCompletion(context.JK.detectOS()); successfullyAssignedOnce = true; } - - return saved; +*/ + return context.ConfigureTracksStore.editingTrackValid() } function newSession() { @@ -38,7 +38,8 @@ function beforeShow() { var forceInputsToUnassigned = !successfullyAssignedOnce; - configureTracksHelper.reset(forceInputsToUnassigned, wizard.getChosenInputs()) + window.ConfigureTracksActions.reset(false); + //configureTracksHelper.reset(forceInputsToUnassigned, wizard.getChosenInputs()) } function initialize(_$step, _wizard) { diff --git a/web/app/assets/stylesheets/client/client.css b/web/app/assets/stylesheets/client/client.css index 277f98cdb..1c0385193 100644 --- a/web/app/assets/stylesheets/client/client.css +++ b/web/app/assets/stylesheets/client/client.css @@ -53,6 +53,8 @@ *= require dialogs/dialog *= require ./iconInstrumentSelect *= require ./muteSelect + *= require ./manageVsts + *= require ./vstEffects *= require ./metronomePlaybackModeSelect *= require ./terms *= require ./createSession diff --git a/web/app/assets/stylesheets/client/manageVsts.css.scss b/web/app/assets/stylesheets/client/manageVsts.css.scss new file mode 100644 index 000000000..a7063e390 --- /dev/null +++ b/web/app/assets/stylesheets/client/manageVsts.css.scss @@ -0,0 +1,23 @@ +@import "client/common"; + +.manage-vsts-popup { + .bt-content { + height:38px; + width:190px; + background-color:#333; + overflow:auto; + border:1px solid #ED3618; + text-align:left; + font-family: 'Raleway', Arial, Helvetica, sans-serif; + ul { + @include vertical-align-column; + height:100%; + margin-left: 0 !important; + } + li { + font-size:12px; + margin-left:0 !important; + list-style-type: none; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/react-components/ConfigureTracks.css.scss b/web/app/assets/stylesheets/client/react-components/ConfigureTracks.css.scss new file mode 100644 index 000000000..72d90891a --- /dev/null +++ b/web/app/assets/stylesheets/client/react-components/ConfigureTracks.css.scss @@ -0,0 +1,170 @@ +@import "client/common"; + +.ConfigureTracks { + + .inputs-view { + border-width:1px 0; + border-color:$ColorText; + border-style:solid; + padding:20px 0; + height:220px; + + .live-tracks { + height:165px; + overflow:auto; + a { + margin-left:3px; + } + } + + .live-input { + display:inline-block; + &:before { + content: '(' + } + &:after { + content: ')' + } + } + .live-track { + margin-bottom:20px; + } + + a.delete-live-track { + margin-left:20px; + } + .assignment { + display:inline-block; + width:20px; + } + + .input-track-info { + @include border_box_sizing; + width:60%; + display:inline-block; + + &.one { + .live-input { + width:50%; + @include border_box_sizing; + } + } + + &.two { + .live-input { + max-width:40%; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + @include border_box_sizing; + &:nth-of-type(1) { + padding-right:5px; + } + &:nth-of-type(2) { + padding-left:5px; + } + } + } + } + + .track-type-label { + display:inline-block; + white-space:nowrap; + padding-right:7px; + } + + .plugin-info { + @include border_box_sizing; + width:30%; + display:inline-block; + white-space:nowrap; + text-overflow: ellipsis; + overflow:hidden; + } + + .plugin-instrument { + @include border_box_sizing; + width:10%; + display:inline-block; + text-align:center; + + img { + vertical-align:middle; + } + } + } + + .outputs-view { + border-width:0 0 1px; + border-color:$ColorText; + border-style:solid; + padding:20px 0; + + .assignment { + display:inline-block; + width:20px; + } + + + .output-tracks { + height:73px; + overflow:auto; + a { + margin-left:3px; + } + } + + + .output-track { + margin-bottom: 20px; + } + + .output-track-info { + display:inline-block; + } + + .output { + display:inline-block; + margin-bottom:0 !important; + &:before { + content: '(' + } + &:after { + content: ')' + } + } + } + h3 { + display:inline-block; + font-size:14px; + margin:0 0 20px; + @include border_box_sizing; + &.session-audio-inputs-header { + color:white; + font-weight:bold; + width:60%; + } + + &.session-audio-outputs-header { + color:white; + font-weight:bold; + width:60%; + } + + &.plugin-header { + width:30%; + } + &.instrument-header { + width:10%; + text-align:center; + } + } + .live-track-actions { + display:block; + padding-left: 17px; + margin-top: 5px; + a { + font-size:12px; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/vstEffects.css.scss b/web/app/assets/stylesheets/client/vstEffects.css.scss new file mode 100644 index 000000000..945e49b10 --- /dev/null +++ b/web/app/assets/stylesheets/client/vstEffects.css.scss @@ -0,0 +1,39 @@ +@import "client/common"; + +.vst-effects-popup { + margin-top: 3px; + margin-left: 120px; + + .bt-content { + width:220px; + background-color:#333; + overflow:auto; + border:1px solid #ED3618; + text-align:left; + font-family: 'Raleway', Arial, Helvetica, sans-serif; + ul { + @include vertical-align-column; + height:100%; + margin-left: 0 !important; + } + li { + font-size:12px; + margin-left:0 !important; + list-style-type: none; + margin-bottom:0 !important; + + padding:7px 0 10px 0; + + .vst-name { + text-overflow:ellipsis; + overflow:hidden; + } + &:nth-of-type(1) { + + border-width:0 0 1px 0 !important; + border-style:solid !important;; + border-color:#ED3618 !important;; + } + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss index 5e6084efc..d7bbb1f80 100644 --- a/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss +++ b/web/app/assets/stylesheets/client/wizard/gearWizard.css.scss @@ -197,7 +197,7 @@ width: 25%; &:nth-of-type(2) { - width: 21%; + width: 71%; } &:nth-of-type(3) { @@ -217,9 +217,64 @@ margin-top: 45px; } - .output-channels, .unassigned-output-channels { + .outputs-view { display:none; } + + .inputs-view { + padding:0; + border-width:0; + + h3.session-audio-inputs-header { + font-weight:normal; + width:70%; + font-size:14px; + color:white; + } + + h3.plugin-header { + width:20%; + font-size:14px; + color:white; + } + + h3.instrument-header { + width:10%; + font-size:14px; + color:white; + } + + .input-track-info { + width:70%; + } + + .plugin-info { + width:20%; + } + + .plugin-instrument { + width:10%; + } + + .live-tracks { + height:198px; + } + .live-input { + display:block; + max-width:90%; + &:before { + content: '' + } + &:after { + content: '' + } + } + .input-track-info .live-input { + padding-left:19px; + padding-right:0; + } + .add-track-action { text-align:center;} + } } .wizard-step[layout-wizard-step="3"] { diff --git a/web/app/assets/stylesheets/dialogs/configureLiveTracksDialog.css.scss b/web/app/assets/stylesheets/dialogs/configureLiveTracksDialog.css.scss new file mode 100644 index 000000000..212e6869d --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/configureLiveTracksDialog.css.scss @@ -0,0 +1,184 @@ +@import "client/common"; + +#configure-live-tracks-dialog { + width: 800px; + + .dialog-inner { + width:auto; + } + + h3 { + color:white; + font-weight:bold; + margin-bottom:10px; + } + + .manage-audio-plugins { + font-size:12px; + } + .actions { + clear:both; + text-align:center; + } + .track-type { + width:100%; + @include border_box_sizing; + padding:10px; + + .track-type-option { + margin-bottom:10px; + } + label { + vertical-align:middle; + display:inline-block; + margin-left:10px; + } + .iradio_minimal { + vertical-align:middle; + display:inline-block; + } + } + .audio-input-ports { + width:60%; + @include border_box_sizing; + float:left; + margin-bottom:40px; + padding:10px; + + select { + width: 90%; + @include border_box_sizing; + margin-bottom:10px; + } + p { + margin-bottom:10px; + line-height:125%; + } + } + + .audio { + .instrument-selection { + width:40%; + @include border_box_sizing; + float:left; + margin-bottom:26px; + padding:10px; + select { + width:90%; + } + } + } + + .midi-interface { + @include border_box_sizing; + float:left; + margin-bottom:20px; + padding:10px; + position:relative; + width:50%; + + select { + width:80%; + margin-bottom:10px; + } + a { + font-size:12px; + } + } + .midi { + .instrument-selection { + width:50%; + @include border_box_sizing; + float:left; + margin-bottom:26px; + padding:10px; + select { + width:80%; + } + } + } + + .midi-instrument { + @include border_box_sizing; + float:left; + margin-bottom:20px; + padding:10px; + position:relative; + width:50%; + clear:both; + + select { + width:80%; + margin-bottom:10px; + } + + .down-arrow { + cursor:pointer; + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #fc0; + position: relative; + top: -8px; + right: -125px; + } + + .settings-holder { + float: right; + margin-right: 65px; + margin-top: -1px; + } + } + .audio-effects { + width:40%; + @include border_box_sizing; + float:left; + margin-bottom:20px; + padding:10px; + position:relative; + + select { + width:90%; + margin-bottom:20px; + } + + a.manage-audio-plugins { + position:relative; + } + .down-arrow { + cursor:pointer; + width: 0; + height: 0; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #fc0; + position: absolute; + top: 2px; + right: -20px; + } + .settings-holder { + right:10%; + text-align:right; + position:absolute; + margin-top: -27px; + @include border_box_sizing; + padding: 10px 0 10px 10px; + } + a.button-orange { + } + } + + .vstScan { + + margin-top:20px; + + .spinner-small { + float:left; + } + + span { + font-size:12px; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/dialogs/configureOutputsDialog.css.scss b/web/app/assets/stylesheets/dialogs/configureOutputsDialog.css.scss new file mode 100644 index 000000000..b0e9e28a4 --- /dev/null +++ b/web/app/assets/stylesheets/dialogs/configureOutputsDialog.css.scss @@ -0,0 +1,36 @@ +@import "client/common"; + +#configure-outputs-dialog { + width: 425px; + + .dialog-inner { + width: auto; + } + + h3 { + color: white; + font-weight: bold; + margin-bottom: 10px; + } + + .actions { + clear: both; + text-align: center; + } + + p { + margin-bottom:10px; + line-height:125%; + } + + select { + width: 100%; + + &.output-1 { + margin-bottom:15px; + } + &.output-2 { + margin-bottom:50px; + } + } +} \ No newline at end of file diff --git a/web/app/assets/stylesheets/dialogs/configureTracksDialog.css.scss b/web/app/assets/stylesheets/dialogs/configureTracksDialog.css.scss index 46b1bd830..aa776ede7 100644 --- a/web/app/assets/stylesheets/dialogs/configureTracksDialog.css.scss +++ b/web/app/assets/stylesheets/dialogs/configureTracksDialog.css.scss @@ -2,8 +2,6 @@ @charset "UTF-8"; #configure-tracks-dialog { - min-height: 700px; - max-height: 700px; width:800px; &[current-screen="account/audio"] { @@ -120,21 +118,21 @@ } .buttons { - bottom: 25px; - position: absolute; - right: 25px; - left:25px; + position:static; + margin-top:20px; + text-align:center; } .btn-add-new-audio-gear { - float:left; + position:absolute; + left:20px; } .btn-cancel { - float:right; + } .btn-update-settings { - float:right; + } } \ No newline at end of file diff --git a/web/app/views/clients/_manageVsts.html.slim b/web/app/views/clients/_manageVsts.html.slim new file mode 100644 index 000000000..d78dcc704 --- /dev/null +++ b/web/app/views/clients/_manageVsts.html.slim @@ -0,0 +1,7 @@ +script type='text/template' id='template-manage-vsts' + ul + li data-manage-vst-option="scan" + a href='#' scan for new or updated plugins + + li data-manage-vst-option="clear" + a href='#' clear plug-in list \ No newline at end of file diff --git a/web/app/views/clients/_vstEffects.html.slim b/web/app/views/clients/_vstEffects.html.slim new file mode 100644 index 000000000..4085f9ecc --- /dev/null +++ b/web/app/views/clients/_vstEffects.html.slim @@ -0,0 +1,9 @@ +script type='text/template' id='template-vst-effects' + ul + li data-manage-vst-option="open-vst" + a href='#' + | Open  + span.vst-name + + li data-manage-vst-option="update-track" + a href='#' Update Track . . . \ No newline at end of file diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index 0dd83c6ae..5bbd11c83 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -20,6 +20,8 @@ <%= render "jamServer" %> <%= render "iconInstrumentSelect" %> <%= render "muteSelect" %> +<%= render "manageVsts" %> +<%= render "vstEffects" %> <%= render "metronome_playback_mode" %> <%= render "clients/wizard/buttons" %> <%= render "clients/wizard/gear/gear_wizard" %> diff --git a/web/app/views/clients/wizard/gear/_gear_wizard.html.haml b/web/app/views/clients/wizard/gear/_gear_wizard.html.haml index c2c1d9b50..4f8f9ab87 100644 --- a/web/app/views/clients/wizard/gear/_gear_wizard.html.haml +++ b/web/app/views/clients/wizard/gear/_gear_wizard.html.haml @@ -81,16 +81,7 @@ .center %a.button-orange.watch-video{href:'https://www.youtube.com/watch?v=SjMeMZpKNR4', rel:'external'} WATCH VIDEO .wizard-step-column - %h2 Unassigned Ports - .unassigned-input-channels.channels-holder - .wizard-step-column - %h2 Track Input Port(s) - .tracks - .wizard-step-column - %h2 Instrument - .instruments - .output-channels - .unassigned-output-channels.channels-holder + = react_component 'ConfigureTracks', {} .wizard-step{ 'layout-wizard-step' => "3", 'dialog-title' => "Configure Voice Chat", 'dialog-purpose' => "ConfigureVoiceChat" } .ftuesteps diff --git a/web/app/views/dialogs/_configureLiveTracksDialog.html.slim b/web/app/views/dialogs/_configureLiveTracksDialog.html.slim new file mode 100644 index 000000000..2c488ddaa --- /dev/null +++ b/web/app/views/dialogs/_configureLiveTracksDialog.html.slim @@ -0,0 +1,2 @@ +.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='configure-live-tracks-dialog' id='configure-live-tracks-dialog' + = react_component 'ConfigureLiveTracksDialog', {} diff --git a/web/app/views/dialogs/_configureOutputsDialog.html.slim b/web/app/views/dialogs/_configureOutputsDialog.html.slim new file mode 100644 index 000000000..bb6f10e7c --- /dev/null +++ b/web/app/views/dialogs/_configureOutputsDialog.html.slim @@ -0,0 +1,2 @@ +.dialog.dialog-overlay-sm.top-parent layout='dialog' layout-id='configure-outputs-dialog' id='configure-outputs-dialog' + = react_component 'ConfigureOutputsDialog', {} diff --git a/web/app/views/dialogs/_configure_tracks_dialog.html.haml b/web/app/views/dialogs/_configure_tracks_dialog.html.haml index 5611533d1..42d6d1d2e 100644 --- a/web/app/views/dialogs/_configure_tracks_dialog.html.haml +++ b/web/app/views/dialogs/_configure_tracks_dialog.html.haml @@ -4,7 +4,7 @@ %h1 configure tracks .dialog-inner .dialog-tabs - %a.selected.tab-configure-audio Music Audio + %a.selected.tab-configure-audio Inputs & Outputs %a.tab-configure-voice Voice Chat .instructions @@ -16,32 +16,8 @@ .tab.no-selection-range{'tab-id' => 'music-audio'} - .column - .certified-audio-profile-section - .sub-header Certified Audio Profile - %select.certified-audio-profile - .clearall + = react_component 'ConfigureTracks', {} - .unused-audio-inputs-section - .sub-header Unused Input Ports - .unassigned-input-channels.channels-holder - - .unused-audio-outputs-section - .sub-header Unused Output Ports - .unassigned-output-channels.channels-holder - - .column - .input-tracks-section - .sub-column - .sub-header Track Input Port(s) - .input-tracks.tracks - .sub-column - .sub-header Instrument - .instruments - - .output-channels-section - .sub-header Audio Output Port - .output-channels .clearall @@ -72,5 +48,6 @@ .buttons %a.btn-add-new-audio-gear.button-grey{'layout-link' => 'add-new-audio-gear'} ADD NEW AUDIO GEAR - %a.button-orange.btn-update-settings{href:'#'} UPDATE SETTINGS %a.button-grey.btn-cancel{href:'#'} CANCEL + %a.button-orange.btn-update-settings{href:'#'} SAVE SETTINGS + diff --git a/web/app/views/dialogs/_dialogs.html.haml b/web/app/views/dialogs/_dialogs.html.haml index 45db4cb3f..2c45d7df2 100644 --- a/web/app/views/dialogs/_dialogs.html.haml +++ b/web/app/views/dialogs/_dialogs.html.haml @@ -44,3 +44,5 @@ = render 'dialogs/recordingSelectorDialog' = render 'dialogs/soundCloudPlayerDialog' = render 'dialogs/deleteVideoConfirmDialog' += render 'dialogs/configureLiveTracksDialog' += render 'dialogs/configureOutputsDialog' \ No newline at end of file diff --git a/web/config/application.rb b/web/config/application.rb index 05814067b..2ae22519d 100644 --- a/web/config/application.rb +++ b/web/config/application.rb @@ -395,5 +395,7 @@ if defined?(Bundler) output_jitter: {warn: 0.5, poor: 1}, } } + config.vst_enabled = true + end end diff --git a/web/config/environments/development.rb b/web/config/environments/development.rb index dbc9da309..fdfbb2d01 100644 --- a/web/config/environments/development.rb +++ b/web/config/environments/development.rb @@ -102,4 +102,6 @@ SampleApp::Application.configure do config.react.variant = :development config.time_shift_style = :sox # or sbsms + + config.vst_enabled = true end diff --git a/web/config/initializers/gon.rb b/web/config/initializers/gon.rb index ba60612db..d58d5fa10 100644 --- a/web/config/initializers/gon.rb +++ b/web/config/initializers/gon.rb @@ -22,4 +22,5 @@ Gon.global.jamtrack_landing_bubbles_enabled = Rails.application.config.jamtrack_ Gon.global.jamtrack_browser_bubbles_enabled = Rails.application.config.jamtrack_browser_bubbles_enabled Gon.global.bugsnag_key = Rails.application.config.bugsnag_key Gon.global.bugsnag_notify_release_stages = Rails.application.config.bugsnag_notify_release_stages +Gon.global.vst_enabled = Rails.application.config.vst_enabled Gon.global.env = Rails.env diff --git a/web/lib/tasks/jam_tracks.rake b/web/lib/tasks/jam_tracks.rake index e764a6de2..88bf63d04 100644 --- a/web/lib/tasks/jam_tracks.rake +++ b/web/lib/tasks/jam_tracks.rake @@ -95,6 +95,11 @@ namespace :jam_tracks do JamTrackImporter.synchronize_all(skip_audio_upload: false) end + task sync_tim_tracks: :environment do |task, args| + JamTrackImporter.storage_format = 'TimTracks' + JamTrackImporter.synchronize_all(skip_audio_upload:false) + end + task tency_dups: :environment do |task, args| end