From 85ffa2ec21ecad0f1aff9eab57c112dfd126dc0c Mon Sep 17 00:00:00 2001 From: Seth Call Date: Thu, 19 Feb 2015 09:31:30 -0600 Subject: [PATCH] * VRFS-2802 - moving media files mixers in personal mode actually affect master mode now --- web/app/assets/javascripts/faderHelpers.js | 28 +++- web/app/assets/javascripts/session.js | 157 +++++++++++---------- web/app/assets/javascripts/sessionModel.js | 8 ++ web/app/views/clients/_help.html.slim | 4 + web/app/views/dialogs/_banner.html.slim | 3 + 5 files changed, 125 insertions(+), 75 deletions(-) diff --git a/web/app/assets/javascripts/faderHelpers.js b/web/app/assets/javascripts/faderHelpers.js index 7beca59db..b4cb3823d 100644 --- a/web/app/assets/javascripts/faderHelpers.js +++ b/web/app/assets/javascripts/faderHelpers.js @@ -28,6 +28,15 @@ return false; } + if($fader.data('showHelpAboutMediaMixers')) { + if(window.JK.CurrentSessionModel) { + if(!window.JK.CurrentSessionModel.hasShownAudioMediaMixerHelp()) { + window.JK.prodBubble($fader, 'volume-media-mixers', {}, {positions:['top'], offsetParent: $fader.closest('.screen')}) + window.JK.CurrentSessionModel.markShownAudioMediaMixerHelp() + } + } + } + draggingOrientation = $fader.attr('orientation'); var offset = $fader.offset(); var position = { top: e.pageY - offset.top, left: e.pageX - offset.left} @@ -137,6 +146,16 @@ } function onFaderDragStop(e, ui) { + + if($draggingFader.data('showHelpAboutMediaMixers')) { + if(window.JK.CurrentSessionModel) { + if(!window.JK.CurrentSessionModel.hasShownAudioMediaMixerHelp()) { + window.JK.prodBubble($draggingFader, 'volume-media-mixers', {}, {positions:['bottom'], offsetParent: $draggingFader.closest('.screen')}) + window.JK.CurrentSessionModel.markShownAudioMediaMixerHelp() + } + } + } + var faderPct = faderValue($draggingFader, e, ui.position); // protect against attempts to drag outside of the slider, which jquery.draggable sometimes allows @@ -179,7 +198,10 @@ selector.html(g._.template(templateSource, options)); - selector.find('div[control="fader"]').data('media-controls-disabled', selector.data('media-controls-disabled')).data('media-track-opener', selector.data('media-track-opener')) + selector.find('div[control="fader"]') + .data('media-controls-disabled', selector.data('media-controls-disabled')) + .data('media-track-opener', selector.data('media-track-opener')) + .data('showHelpAboutMediaMixers', selector.data('showHelpAboutMediaMixers')) selector.find('div[control="fader-handle"]').draggable({ drag: onFaderDrag, @@ -187,7 +209,9 @@ stop: onFaderDragStop, containment: "parent", axis: options.faderType === 'horizontal' ? 'x' : 'y' - }).data('media-controls-disabled', selector.data('media-controls-disabled')).data('media-track-opener', selector.data('media-track-opener')) + }).data('media-controls-disabled', selector.data('media-controls-disabled')) + .data('media-track-opener', selector.data('media-track-opener')) + .data('showHelpAboutMediaMixers', selector.data('showHelpAboutMediaMixers')) // Embed any custom styles, applied to the .fader below selector if ("style" in options) { diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 3b00b6dea..655fac730 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -13,6 +13,48 @@ var modUtils = context.JK.ModUtils; var logger = context.JK.logger; var self = this; + + var defaultParticipant = { + tracks: [{ + instrument_id: "unknown" + }], + user: { + first_name: 'Unknown', + last_name: 'User', + photo_url: null + } + }; + + // Be sure to copy/extend these instead of modifying in place + var trackVuOpts = { + vuType: "vertical", + lightCount: 13, + lightWidth: 3, + lightHeight: 17 + }; + // Must add faderId key to this + var trackFaderOpts = { + faderType: "vertical", + height: 83 + }; + + // Recreate ChannelGroupIDs ENUM from C++ + var ChannelGroupIds = { + "MasterGroup": 0, + "MonitorGroup": 1, + "AudioInputMusicGroup": 2, + "AudioInputChatGroup": 3, + "MediaTrackGroup": 4, + "StreamOutMusicGroup": 5, + "StreamOutChatGroup": 6, + "UserMusicInputGroup": 7, + "UserChatInputGroup": 8, + "PeerAudioInputMusicGroup": 9, + "PeerMediaTrackGroup": 10, + "JamTrackGroup": 11, + "MetronomeGroup": 12 + }; + var sessionModel = null; var sessionId; var tracks = {}; @@ -52,51 +94,11 @@ var $mixModeDropdown = null; var $templateMixerModeChange = null; var $closePlaybackRecording = null; + var mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]; var rest = context.JK.Rest(); var RENDER_SESSION_DELAY = 750; // When I need to render a session, I have to wait a bit for the mixers to be there. - var defaultParticipant = { - tracks: [{ - instrument_id: "unknown" - }], - user: { - first_name: 'Unknown', - last_name: 'User', - photo_url: null - } - }; - - // Be sure to copy/extend these instead of modifying in place - var trackVuOpts = { - vuType: "vertical", - lightCount: 13, - lightWidth: 3, - lightHeight: 17 - }; - // Must add faderId key to this - var trackFaderOpts = { - faderType: "vertical", - height: 83 - }; - - // Recreate ChannelGroupIDs ENUM from C++ - var ChannelGroupIds = { - "MasterGroup": 0, - "MonitorGroup": 1, - "AudioInputMusicGroup": 2, - "AudioInputChatGroup": 3, - "MediaTrackGroup": 4, - "StreamOutMusicGroup": 5, - "StreamOutChatGroup": 6, - "UserMusicInputGroup": 7, - "UserChatInputGroup": 8, - "PeerAudioInputMusicGroup": 9, - "PeerMediaTrackGroup": 10, - "JamTrackGroup": 11, - "MetronomeGroup": 12 - }; - function beforeShow(data) { sessionId = data.id; if(!sessionId) { @@ -849,9 +851,8 @@ } function _renderLocalMediaTracks() { - //console.log("_renderLocalMediaTracks") // local media mixers come in different groups (MediaTrack, JamTrack, Metronome), but peer mixers are always PeerMediaTrackGroup - var localMediaMixers = _mixersForGroupIds([ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup], MIX_MODES.MASTER); + var localMediaMixers = _mixersForGroupIds(mediaTrackGroups, MIX_MODES.MASTER); var peerLocalMediaMixers = _mixersForGroupId(ChannelGroupIds.PeerMediaTrackGroup, MIX_MODES.MASTER); var recordedBackingTracks = sessionModel.recordedBackingTracks(); @@ -981,7 +982,6 @@ var noCorrespondingTracks = false; $.each(backingTrackMixers, function(index, mixer) { - console.log("hunting for backing tracks:", backingTrackMixers, backingTracks) // find the track or tracks that correspond to the mixer var correspondingTracks = [] @@ -1053,22 +1053,22 @@ if (mixer.mute) { muteClass = "muted"; } + trackData.gainPercent = gainPercent; trackData.muteClass = muteClass; trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) + trackData.mediaTrackOpener = isOpener; + trackData.mediaControlsDisabled = !isOpener; + trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - if (sessionModel.isPersonalMixMode() || !isOpener) { - trackData.mediaControlsDisabled = true; - trackData.mediaTrackOpener = isOpener; - } _addRecordingTrack(trackData, mixer); }); } function renderJamTracks(jamTrackMixers) { - console.log("rendering jam tracks") + logger.debug("rendering jam tracks") var jamTracks = sessionModel.jamTracks(); // pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer) @@ -1145,11 +1145,10 @@ trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) + trackData.mediaTrackOpener = isOpener; + trackData.mediaControlsDisabled = !isOpener; + trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - if(sessionModel.isPersonalMixMode() || !isOpener) { - trackData.mediaControlsDisabled = true; - trackData.mediaTrackOpener = isOpener; - } _addRecordingTrack(trackData); }); @@ -1164,7 +1163,7 @@ function renderMetronomeTracks(metronomeTrackMixers) { var metronomeActive = sessionModel.metronomeActive(); - console.log("rendering metronome track",metronomeActive) + logger.debug("rendering metronome track",metronomeActive) // pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer) // if it's a locally opened track (MediaTrackGroup), then we can say this person is the opener @@ -1248,11 +1247,10 @@ trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) + trackData.mediaTrackOpener = isOpener; + trackData.mediaControlsDisabled = !isOpener; + trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - if(sessionModel.isPersonalMixMode() || !isOpener) { - //trackData.mediaControlsDisabled = true; - trackData.mediaTrackOpener = isOpener; - } _addRecordingTrack(trackData, mixer); }// if @@ -1274,7 +1272,6 @@ if(recordedTracks) { $('.session-recording-name').text(sessionModel.getCurrentSession().claimed_recording.name); - console.log("renderRecordingTracks", recordingMixers, recordedTracks) var noCorrespondingTracks = false; $.each(recordingMixers, function(index, mixer) { var preMasteredClass = ""; @@ -1348,11 +1345,10 @@ trackData.mixerId = mixer.id; // the master mixer controls the volume control for recordings (no personal controls in either master or personal mode) trackData.vuMixerId = mixer.id; // the master mixer controls the VUs for recordings (no personal controls in either master or personal mode) trackData.muteMixerId = mixer.id; // the master mixer controls the mute for recordings (no personal controls in either master or personal mode) + trackData.mediaControlsDisabled = !isOpener; + trackData.mediaTrackOpener = isOpener; + trackData.showHelpAboutMediaMixers = sessionModel.isPersonalMixMode() && isOpener; - if(sessionModel.isPersonalMixMode() || !isOpener) { - trackData.mediaControlsDisabled = true; - trackData.mediaTrackOpener = isOpener; - } _addRecordingTrack(trackData, mixer); }); @@ -1589,6 +1585,9 @@ if(track.mediaControlsDisabled) { $fader.data('media-controls-disabled', true).data('media-track-opener', track.mediaTrackOpener) // this we be applied later to the fader handle $element } + $fader.data('showHelpAboutMediaMixers', track.showHelpAboutMediaMixers) + + var $track = $(trackSelector); // Set mixer-id attributes and render VU/Fader @@ -1788,6 +1787,7 @@ $trackIconMute.data('media-controls-disabled', true).data('media-track-opener', trackData.mediaTrackOpener) } $trackIconMute.data('mixer', mixer).data('opposite-mixer', null) + $trackIconMute.data('showHelpAboutMediaMixers', trackData.showHelpAboutMediaMixers) if(trackData.showLoop) { @@ -1817,8 +1817,8 @@ var mixerIds = faderId.split(','); $.each(mixerIds, function(i,v) { var broadcast = !(data.dragging); // If fader is still dragging, don't broadcast - fillTrackVolumeObject(v, broadcast); - setMixerVolume(v, data.percentage); + var mixer = fillTrackVolumeObject(v, broadcast); + setMixerVolume(mixer, data.percentage); if(groupId == ChannelGroupIds.UserMusicInputGroup) { // there may be other mixers with this same ID in the case of a Peer Music Stream, so update them as well @@ -1841,7 +1841,7 @@ // } function handleMetronomeCallback(args) { - console.log("MetronomeCallback: ", args) + logger.debug("MetronomeCallback: ", args) metroTempo = args.bpm // This isn't actually there, so we rely on the metroSound as set from select on form: @@ -1931,7 +1931,6 @@ rest.openBackingTrack({id: context.JK.CurrentSessionModel.id(), backing_track_path: result.file}) .done(function(response) { var openResult = context.jamClient.SessionOpenBackingTrackFile(result.file, false); - console.log("BackingTrackPlay response: %o", openResult); //context.JK.CurrentSessionModel.refreshCurrentSession(true); sessionModel.setBackingTrack(result.file); }) @@ -2015,6 +2014,13 @@ return false; } + if($control.data('showHelpAboutMediaMixers')) { + if(!sessionModel.hasShownAudioMediaMixerHelp()) { + context.JK.prodBubble($control, 'volume-media-mixers', {}, {positions:['bottom'], offsetParent: $control.closest('.screen')}) + sessionModel.markShownAudioMediaMixerHelp() + } + } + $.each(mixerIds, function(i,v) { var mixerId = v; // behavior: if this is the user's track in personal mode, then we mute the track globally @@ -2033,7 +2039,7 @@ } // look for all controls matching this mixer id (important when it's personal mode + UserMusicInputGroup) - var $controls = $screen.find('.track-icon-mute[mixer-id=' + mixerId +']'); + var $controls = $screen.find('.track-icon-mute[mixer-id="' + mixerId +'"]'); _toggleVisualMuteControl($controls, muting); }); } @@ -2079,6 +2085,7 @@ // trackVolumeObject doesn't have a place for range min/max currentMixerRangeMin = mixer.range_low; currentMixerRangeMax = mixer.range_high; + return mixer; } // Given a mixer's min/max and current value, return it as @@ -2113,7 +2120,7 @@ // Given a volume percent (0-100), set the underlying // audio volume level of the passed mixerId to the correct // value. - function setMixerVolume(mixerId, volumePercent) { + function setMixerVolume(mixer, volumePercent) { // The context.trackVolumeObject has been filled with the mixer values // that go with mixerId, and the range of that mixer // has been set in currentMixerRangeMin-Max. @@ -2125,13 +2132,17 @@ context.trackVolumeObject.volL = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent); context.trackVolumeObject.volR = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent); // Special case for L2M mix: - if (mixerId === '__L2M__') { + if (mixer.id === '__L2M__') { logger.debug("L2M volumePercent=" + volumePercent); var dbValue = context.JK.FaderHelpers.convertLinearToDb(volumePercent); context.jamClient.SessionSetMasterLocalMix(dbValue); // context.jamClient.SessionSetMasterLocalMix(sliderValue); } else { - context.jamClient.SessionSetControlState(mixerId, sessionModel.getMixMode()); + var isMediaMixer = mediaTrackGroups.indexOf(mixer.group_id) > -1; + + // if this is a media file (Metronome, JamTrack, BackingTrack, RecordedTrack), then we only modify master + var mixMode = isMediaMixer ? MIX_MODES.MASTER : sessionModel.getMixMode(); + context.jamClient.SessionSetControlState(mixer.id, mixMode); } } @@ -2371,7 +2382,7 @@ var unstable = unstableNTPClocks() if (unstable.length > 0) { var names = unstable.join(", ") - console.log("Unstable clocks: ", names, unstable) + logger.debug("Unstable clocks: ", names, unstable) app.notify({ "title": "Couldn't open metronome", "text": "The metronome feature requires that every user's computer in the session must agree on the current time. The computers of " + names + " have not successfully synchronized to the current time. The JamKazam service is trying to automatically correct this error condition. Please close this message, wait about 10 seconds, and then try opening the metronome again. If this problem persists after a couple of attempts, we recommend that the unsynchronized users restart the JamKazam application. If this error persists after a restart, please have the users with the issue contact support@jamkazam.com.", @@ -2385,7 +2396,7 @@ context.JK.CurrentSessionModel.refreshCurrentSession(true) }) .fail(function(jqXHR) { - console.log(jqXHR, jqXHR) + logger.debug(jqXHR, jqXHR) app.notify({ "title": "Couldn't open metronome", "text": "Couldn't inform the server to open metronome. msg=" + jqXHR.responseText, diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js index e0360ece3..7487dec2d 100644 --- a/web/app/assets/javascripts/sessionModel.js +++ b/web/app/assets/javascripts/sessionModel.js @@ -36,6 +36,7 @@ var joinDeferred = null; var previousBackingTracks = []; var openBackingTrack = null; + var shownAudioMediaMixerHelp = false; var mixerMode = MIX_MODES.PERSONAL; @@ -350,6 +351,7 @@ currentParticipants = {} previousBackingTracks = [] openBackingTrack = null + shownAudioMediaMixerHelp = false } // you should only update currentSession with this function @@ -853,6 +855,12 @@ this.getBackingTrack = function() { return openBackingTrack; }; + this.hasShownAudioMediaMixerHelp = function() { + return shownAudioMediaMixerHelp; + } + this.markShownAudioMediaMixerHelp = function() { + shownAudioMediaMixerHelp = true; + } // call to report if the current user was able to establish audio with the specified clientID diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim index 1f0efda08..4fda8bda3 100644 --- a/web/app/views/clients/_help.html.slim +++ b/web/app/views/clients/_help.html.slim @@ -199,6 +199,10 @@ script type="text/template" id="template-help-media-controls-disabled" | Only the person who opened the recording can control the volume levels. | {% } %} + +script type="text/template" id="template-help-volume-media-mixers" + | Audio files only expose master mix controls, so any change here will also affect everyone in the session. + script type="text/template" id="template-help-downloaded-jamtrack" .downloaded-jamtrack p When a JamTrack is first purchased, a user-specific version of it is created on the server. Once it's ready, it's then downloaded to the client. diff --git a/web/app/views/dialogs/_banner.html.slim b/web/app/views/dialogs/_banner.html.slim index d79584383..4083903e3 100644 --- a/web/app/views/dialogs/_banner.html.slim +++ b/web/app/views/dialogs/_banner.html.slim @@ -60,6 +60,9 @@ script type='text/template' id='template-mixer-mode-change' li span.definition Personal Mix div The personal mix controls the audio mix that you individually hear while playing in the session, and you can customize this mix to hear more or less of the music stream from each other musician playing in the session. This does not affect the master mix used for recordings or broadcasts. With personal mix selected, when you adjust the faders on the session screen up or down, it changes the personal mix only for you locally. + li + span.definition Note on Audio Files + div The volume control on any audio file is always a master volume control, regardless of the current mode. br div | For more detailed information on this topic, read our knowledge base article on