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.