From 9b9460be719cb3f9ac3dc7c2179fa3d7942a85ab Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 27 Sep 2020 11:24:22 -0500 Subject: [PATCH] mixer change and help instructions --- .../user_mailer/welcome_message.html.erb | 2 +- web/app/assets/images/web/saturated-ok.png | Bin 0 -> 30980 bytes .../SessionBackingTrack.js.jsx.coffee | 5 +- .../SessionChatMixer.js.jsx.coffee | 3 +- .../SessionJamTrack.js.jsx.coffee | 5 +- .../SessionJamTrackCategory.js.jsx.coffee | 2 +- .../SessionMasterMyTracks.js.jsx.coffee | 14 ++-- .../SessionMediaTracks.js.jsx.coffee | 13 +++- .../SessionMetronome.js.jsx.coffee | 5 +- .../SessionMyChat.js.jsx.coffee | 5 +- .../SessionMyTrack.js.jsx.coffee | 7 +- .../SessionMyTracks.js.jsx.coffee | 14 ++-- .../SessionNotification.js.jsx.coffee | 2 +- .../SessionOtherTrack.js.jsx.coffee | 5 +- .../SessionOtherTracks.js.jsx.coffee | 28 ++++++-- .../SessionRecordedCategory.js.jsx.coffee | 5 +- .../SessionRecordedTrack.js.jsx.coffee | 2 +- .../SessionScreen.js.jsx.coffee | 1 - .../SessionTrackVolumeHover.js.jsx.coffee | 67 ++++++++++++++---- .../helpers/MixerHelper.js.coffee | 3 +- .../mixins/SessionMyTracksMixin.js.coffee | 2 +- .../javascripts/wizard/gear/gear_wizard.js | 12 ++-- .../wizard/gear/step_configure_tracks.js | 12 +++- .../wizard/gear/step_configure_voice_chat.js | 12 +++- .../wizard/gear/step_direct_monitoring.js | 13 +++- .../wizard/gear/step_select_gear.js | 15 +++- .../wizard/gear/step_understand_gear.js | 13 ++-- web/app/assets/stylesheets/client/help.scss | 4 ++ .../react-components/SessionScreen.scss | 15 +++- web/app/views/clients/_help.html.slim | 37 ++++++++++ web/app/views/clients/index.html.erb | 4 +- .../wizard/gear/_gear_wizard.html.haml | 10 +-- .../dialogs/_sessionMasterMixDialog.html.slim | 2 +- 33 files changed, 254 insertions(+), 85 deletions(-) create mode 100644 web/app/assets/images/web/saturated-ok.png diff --git a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb index ce830d39d..fdffa9dcd 100644 --- a/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb +++ b/ruby/lib/jam_ruby/app/views/jam_ruby/user_mailer/welcome_message.html.erb @@ -19,7 +19,7 @@ co-writing music, or just hopping into open jams with other musicians for fun. - Check out this Getting Started YouTube Video for help setting up + Check out this Getting Started Guide for help setting up.

Learn & Play Along With Your Favorite Music
diff --git a/web/app/assets/images/web/saturated-ok.png b/web/app/assets/images/web/saturated-ok.png new file mode 100644 index 0000000000000000000000000000000000000000..efab0f421fa49e1b02ab3bd0471fdfc73d17036e GIT binary patch literal 30980 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 @@ -76,7 +77,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@mixers()} + {mixers:@mixers(), trackType: 'SessionBackingTracks', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) diff --git a/web/app/assets/javascripts/react-components/SessionChatMixer.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionChatMixer.js.jsx.coffee index 36e047005..8922949a5 100644 --- a/web/app/assets/javascripts/react-components/SessionChatMixer.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionChatMixer.js.jsx.coffee @@ -11,7 +11,8 @@ context = window muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([@props.mixers.mixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([@props.mixers.mixer], muting) render: () -> diff --git a/web/app/assets/javascripts/react-components/SessionJamTrack.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionJamTrack.js.jsx.coffee index e57edee87..f3a4166de 100644 --- a/web/app/assets/javascripts/react-components/SessionJamTrack.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionJamTrack.js.jsx.coffee @@ -21,7 +21,8 @@ MixerActions = @MixerActions muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([@props.mixers['master'].mixer, @props.mixers['personal'].mixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([@props.mixers['master'].mixer, @props.mixers['personal'].mixer], muting) render: () -> @@ -76,7 +77,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@mixers()} + {mixers:@mixers(), trackType: 'SessionJamTracks', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) diff --git a/web/app/assets/javascripts/react-components/SessionJamTrackCategory.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionJamTrackCategory.js.jsx.coffee index 9997b410a..d81a88ada 100644 --- a/web/app/assets/javascripts/react-components/SessionJamTrackCategory.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionJamTrackCategory.js.jsx.coffee @@ -66,7 +66,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@props.mixers} + {mixers:@props.mixers, trackType: 'SessionJamTrackCategory', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) diff --git a/web/app/assets/javascripts/react-components/SessionMasterMyTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMasterMyTracks.js.jsx.coffee index 5fdde3e90..d33703280 100644 --- a/web/app/assets/javascripts/react-components/SessionMasterMyTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMasterMyTracks.js.jsx.coffee @@ -4,7 +4,11 @@ logger = context.JK.logger @SessionMasterMyTracks = React.createClass({ - mixins: [@SessionMyTracksMixin, Reflux.listenTo(@SessionMyTracksStore,"onInputsChanged"), Reflux.listenTo(@AppStore,"onAppInit")] + mixins: [Reflux.listenTo(@SessionMyTracksStore,"onInputsChanged")] + + + onInputsChanged: (update) -> + this.setState(update) render: () -> @@ -13,7 +17,7 @@ logger = context.JK.logger if this.state.tracks.length > 0 for track in this.state.tracks - track.mode = MIX_MODES.MASTER + track.mode = @props.mode tracks.push(``) if @state.chat @@ -24,7 +28,7 @@ logger = context.JK.logger logger.debug("no 'my inputs' for master mix") `

-

my live tracks

+

audio tracks

{content} {tracks} @@ -32,8 +36,6 @@ logger = context.JK.logger
` getInitialState:() -> - {tracks:[], session: null} + {tracks:[], session: null, chat:null} - onAppInit: (app) -> - @app = app }) diff --git a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee index afebb8978..0e5c3924e 100644 --- a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee @@ -188,6 +188,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds render: () -> + content = null scrollerClassData = {'session-tracks-scroller': true} mediaOptions = `
@@ -248,6 +249,8 @@ ChannelGroupIds = context.JK.ChannelGroupIds Close {mediaType} ` + content = null + if this.state.mediaSummary.backingTrackOpen @@ -257,7 +260,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds else if this.state.mediaSummary.recordingOpen - mediaTracks.push(``) + mediaTracks.push(``) for recordedTrack in @state.recordedTracks recordedTrack.mode = @props.mode mediaTracks.push(``) @@ -274,7 +277,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds # The Category mixer # The Metronome # All the JamTracks - mediaTracks.push(``) + mediaTracks.push(``) if @state.metronome? # && @state.jamTrackMixdown.id == null @state.metronome.mode = @props.mode @@ -299,9 +302,10 @@ ChannelGroupIds = context.JK.ChannelGroupIds scrollerClasses = classNames(scrollerClassData) `
-

recorded audio

+

recorded audio ?

{contents}
+ {content} {mediaTracks}
` @@ -326,6 +330,9 @@ ChannelGroupIds = context.JK.ChannelGroupIds componentDidMount: () -> context.JK.HandleBackingTrackSelectedCallback2 = @handleBackingTrackSelectedCallback + $root = $(@getDOMNode()) + context.JK.helpBubble($root.find(".session-tracks-help"), "session-media-tracks-instructions", {}, {offsetParent:$root.closest('.top-parent'), positions: ['right', 'bottom'], width:450}) + componentDidUpdate: () -> diff --git a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee index afd9567da..f9fe8acd6 100644 --- a/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMetronome.js.jsx.coffee @@ -12,7 +12,8 @@ MIX_MODES = context.JK.MIX_MODES muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([@mixer()], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([@mixer()], muting) render: () -> @@ -78,7 +79,7 @@ MIX_MODES = context.JK.MIX_MODES $mute, 'SessionTrackVolumeHover', () => - {mixers:@mixers()} + {mixers:@mixers(), trackType: 'SessionMetronome', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$topParent}) diff --git a/web/app/assets/javascripts/react-components/SessionMyChat.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionMyChat.js.jsx.coffee index 1fad123f2..eaa4f8636 100644 --- a/web/app/assets/javascripts/react-components/SessionMyChat.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMyChat.js.jsx.coffee @@ -17,7 +17,8 @@ MixerActions = @MixerActions muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([mixers.mixer, mixers.oppositeMixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([mixers.mixer, mixers.oppositeMixer], muting) render: () -> @@ -63,7 +64,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@mixers()} + {mixers:@mixers(), trackType: 'SessionMyChat', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) }) 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 a631b41db..4e9e480fb 100644 --- a/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMyTrack.js.jsx.coffee @@ -17,7 +17,7 @@ ConfigureTracksActions = @ConfigureTracksActions else clientStats = null {stats: clientStats} - + handleMute: (e) -> e.preventDefault() @@ -27,7 +27,8 @@ ConfigureTracksActions = @ConfigureTracksActions muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([this.props.mixers.mixer, this.props.mixers.oppositeMixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([this.props.mixers.mixer, this.props.mixers.oppositeMixer], muting) render: () -> @@ -103,7 +104,7 @@ ConfigureTracksActions = @ConfigureTracksActions $mute, 'SessionTrackVolumeHover', () => - {mixers:this.props.mixers} + {mixers:this.props.mixers, trackType: 'SessionMyTrack', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) 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 4a3294724..8995d6450 100644 --- a/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionMyTracks.js.jsx.coffee @@ -11,19 +11,21 @@ SessionActions = context.SessionActions SessionActions.leaveSession.trigger({location: '/client#/account/audio'}) + render: () -> content = null videoTutorialLink = null tracks = [] - if @state.session?.preppingVstEnable + if @state.mySession?.preppingVstEnable delayVstEnable = `
Enabling VSTs ...
` else videoTutorialLink = `` if @state.tracks.length > 0 for track in @state.tracks + track = $.extend({}, track) track.mode = @props.mode tracks.push(``) @@ -31,7 +33,7 @@ SessionActions = context.SessionActions @state.chat.mode = @props.mode tracks.push(``) - else if @state.session? && @state.session.inSession() + else if @state.mySession? && @state.mySession.inSession() content = `

You have not set up any inputs for your instrument or vocals. @@ -41,7 +43,7 @@ SessionActions = context.SessionActions

` `
-

my live tracks

+

audio inputs ?

{videoTutorialLink} @@ -54,7 +56,11 @@ SessionActions = context.SessionActions
` getInitialState:() -> - {tracks:[], session: null, chat:null} + {tracks:[], mySession: null, chat:null} + + componentDidMount:() -> + $root = $(@getDOMNode()) + context.JK.helpBubble($root.find(".session-tracks-help"), "session-audio-inputs-instructions", {}, {offsetParent:$root.closest('.top-parent'), positions: ['right', 'bottom'], width:450}) onAppInit: (app) -> @app = app diff --git a/web/app/assets/javascripts/react-components/SessionNotification.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionNotification.js.jsx.coffee index b1decbf08..2b885972b 100644 --- a/web/app/assets/javascripts/react-components/SessionNotification.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionNotification.js.jsx.coffee @@ -25,5 +25,5 @@ context = window context.JK.popExternalLinks($root) if @props.detail? - context.JK.hoverBubble($root, @props.detail, {offsetParent:$root.closest('.top-parent'), positions: ['left', 'bottom']}) + context.JK.hoverBubble($root, @props.detail, {offsetParent:$root.closest('.screen'), positions: ['left', 'bottom']}) }) \ No newline at end of file diff --git a/web/app/assets/javascripts/react-components/SessionOtherTrack.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionOtherTrack.js.jsx.coffee index 8095b1034..67001d6ef 100644 --- a/web/app/assets/javascripts/react-components/SessionOtherTrack.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionOtherTrack.js.jsx.coffee @@ -28,7 +28,8 @@ MixerActions = @MixerActions mixers = if this.props.tracks.length > 0 then this.props.tracks[0].mixers else {} - MixerActions.mute([mixers.mixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + #MixerActions.mute([mixers.mixer], muting) render: () -> @@ -108,7 +109,7 @@ MixerActions = @MixerActions 'SessionTrackVolumeHover', () => mixers = if this.props.tracks.length > 0 then this.props.tracks[0].mixers else {} - {mixers:mixers} + {mixers:mixers, trackType: 'SessionOtherTrack', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.screen')}) diff --git a/web/app/assets/javascripts/react-components/SessionOtherTracks.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionOtherTracks.js.jsx.coffee index 5566c8595..7f2e095ae 100644 --- a/web/app/assets/javascripts/react-components/SessionOtherTracks.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionOtherTracks.js.jsx.coffee @@ -1,11 +1,12 @@ +$ = jQuery context = window MixerActions = context.MixerActions @SessionOtherTracks = React.createClass({ - mixins: [Reflux.listenTo(@SessionOtherTracksStore,"onInputsChanged"), Reflux.listenTo(@AppStore,"onAppInit")] + mixins: [@SessionMyTracksMixin, Reflux.listenTo(@SessionOtherTracksStore,"onOtherInputsChanged"), Reflux.listenTo(@SessionMyTracksStore,"onInputsChanged"), Reflux.listenTo(@AppStore,"onAppInit")] - onInputsChanged: (sessionMixers) -> + onOtherInputsChanged: (sessionMixers) -> session = sessionMixers.session mixers = sessionMixers.mixers noAudioUsers = mixers.noAudioUsers @@ -95,16 +96,26 @@ MixerActions = context.MixerActions content = null participants = [] - noOthers = `
No other musicians are in your session.
` + if @state.tracks.length > 0 + for track in @state.tracks + track = $.extend({}, track) + track.mode = @props.mode + participants.push(``) + + if @state.chat + chat= $.extend({}, @state.chat) + chat.mode = @props.mode + participants.push(``) if this.state.participants.length > 0 for participant in this.state.participants + participant.mode = @props.mode participants.push(``) else if this.state.session? && this.state.session.inSession() - content = noOthers + content = null `
-

other live tracks

+

personal mix ?

{content} @@ -114,7 +125,12 @@ MixerActions = context.MixerActions
` getInitialState:() -> - {participants:[], session: null} + {participants:[], session: null, mySession: null, tracks:[], chat:null} + + componentDidMount:() -> + $root = $(@getDOMNode()) + context.JK.helpBubble($root.find(".session-tracks-help"), "session-personal-mix-instructions", {}, {offsetParent:$root.closest('.top-parent'), positions: ['right', 'bottom'], width:450}) + onAppInit: (app) -> @app = app diff --git a/web/app/assets/javascripts/react-components/SessionRecordedCategory.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionRecordedCategory.js.jsx.coffee index fff2db3d6..a5f7814d2 100644 --- a/web/app/assets/javascripts/react-components/SessionRecordedCategory.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionRecordedCategory.js.jsx.coffee @@ -13,7 +13,8 @@ MixerActions = @MixerActions muting = $(e.currentTarget).is('.enabled') - MixerActions.mute([this.props.mixers.mixer, this.props.mixers.oppositeMixer], muting) + # this button is annoying. the hover shows mute and it's good to use instead + # MixerActions.mute([this.props.mixers.mixer, this.props.mixers.oppositeMixer], muting) render: () -> @@ -69,7 +70,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@props.mixers} + {mixers:@props.mixers, trackType: 'SessionRecordedCategory', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) diff --git a/web/app/assets/javascripts/react-components/SessionRecordedTrack.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionRecordedTrack.js.jsx.coffee index f8db4915d..c6214e77e 100644 --- a/web/app/assets/javascripts/react-components/SessionRecordedTrack.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionRecordedTrack.js.jsx.coffee @@ -76,7 +76,7 @@ MixerActions = @MixerActions $mute, 'SessionTrackVolumeHover', () => - {mixers:@mixers()} + {mixers:@mixers(), trackType: 'SessionRecordedTrack', mode: @props.mode} , {width:235, positions:['right', 'left'], offsetParent:$root.closest('.top-parent')}) diff --git a/web/app/assets/javascripts/react-components/SessionScreen.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionScreen.js.jsx.coffee index 610fe05e4..2d97cbeff 100644 --- a/web/app/assets/javascripts/react-components/SessionScreen.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionScreen.js.jsx.coffee @@ -30,7 +30,6 @@ SessionActions = @SessionActions {videoBtn} {filesBtn} -
diff --git a/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee b/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee index 8d41f2017..c1b4c923d 100644 --- a/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee +++ b/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee @@ -21,13 +21,13 @@ ptrCount = 0 onInputsChanged: (sessionMixers) -> mixers = sessionMixers.mixers - newMixers = mixers.refreshMixer(@state.mixers) + if mixers? + newMixers = mixers.refreshMixer(@state.mixers) - newMixers = {} unless newMixers? - sessionController = sessionMixers.session.sessionController() - logger.debug("session controller", sessionController) + newMixers = {} unless newMixers? + sessionController = sessionMixers.session.sessionController() - this.setState({mixers: newMixers, sessionController: sessionController}) + this.setState({mixers: newMixers, sessionController: sessionController}) getInitialState: () -> {mixers: this.props.mixers, ptr: "STVH#{ptrCount++}", sessionController: window.SessionStore.helper.sessionController()} @@ -38,10 +38,10 @@ ptrCount = 0 muting = $(e.currentTarget).is('.enabled') # if it's a chat, my input, or media track, or jam track, or media track group, then do both mixers at the same time - if @state.mixers.mixer.group_id == ChannelGroupIds.AudioInputMusicGroup || @state.mixers.mixer.group_id == ChannelGroupIds.AudioInputChatGroup || @state.mixers.mixer.group_id == ChannelGroupIds.MediaTrackGroup || @state.mixers.mixer.group_id == ChannelGroupIds.JamTrackGroup || ((@state.mixers.mixer.group_id == ChannelGroupIds.MonitorCatGroup || @state.mixers.mixer.group_id == ChannelGroupIds.MasterCatGroup) && @state.mixers.mixer.name == CategoryGroupIds.MediaTrack) - MixerActions.mute([this.state.mixers.mixer, this.state.mixers.oppositeMixer], muting) - else - MixerActions.mute(this.state.mixers.mixer, muting) + #if @state.mixers.mixer.group_id == ChannelGroupIds.AudioInputMusicGroup || @state.mixers.mixer.group_id == ChannelGroupIds.AudioInputChatGroup || @state.mixers.mixer.group_id == ChannelGroupIds.MediaTrackGroup || @state.mixers.mixer.group_id == ChannelGroupIds.JamTrackGroup || ((@state.mixers.mixer.group_id == ChannelGroupIds.MonitorCatGroup || @state.mixers.mixer.group_id == ChannelGroupIds.MasterCatGroup) && @state.mixers.mixer.name == CategoryGroupIds.MediaTrack) + # MixerActions.mute([this.state.mixers.mixer, this.state.mixers.oppositeMixer], muting) + #else + # MixerActions.mute(this.state.mixers.mixer, muting) handleMuteCheckbox: (e) -> @@ -76,6 +76,49 @@ ptrCount = 0 'muted' : muteMixer?.mute }) + textualHelp = null + + if (@props.trackType == 'SessionMyTrack' || @props.trackType == 'SessionMyChat') && @props.mode == context.JK.MIX_MODES.MASTER + textualHelp = `
+

Use the gain knobs on your + audio interface or this slider to + adjust your input level up/down.

+ +

Play or sing, and watch where the + meter lights peak.

+ +

These lights should reach the top of + the green lights, and maybe one light + into the orange/red zone.

+
` + else if @props.trackType == 'SessionOtherTrack' || @props.trackType == 'SessionMyTrack' + textualHelp = `
+

Use this slider to adjust this audio + track's volume up or down to get + your mix where you like.

+ +

This only affects what you hear, not + what others hear in your session.

+ +

Your personal mix is what will be + used for recordings and broadcasts + you personally control in sessions.

+
` + else + textualHelp = `
+

Use this slider to adjust this audio + track's volume up or down to get + your mix where you like.

+ +

This only affects what you hear, not + what others hear in your session.

+ +

Your personal mix is what will be + used for recordings and broadcasts + you personally control in sessions.

+
` + + `
@@ -95,11 +138,7 @@ ptrCount = 0
-
-

Use this slider to control the volume of this track in your personal mix.

-

This will not affect the volume of this track for other musicians in the session.

-

To adjust master levels for all musicians for recordings and broadcasts, use Mixer button in the toolbar.

-
+ {textualHelp}
close diff --git a/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee b/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee index a475caad5..ae4a65a7f 100644 --- a/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee +++ b/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee @@ -523,7 +523,7 @@ MIX_MODES = context.JK.MIX_MODES; # supply the master mixer of a media track, and this function will harvest out the rest mediaMixers:(masterMixer, isOpener) -> - personalMixer = if isOpener then @getMixerByResourceId(masterMixer.rid, MIX_MODES.PERSONAL) else null + personalMixer = if isOpener then @getMixerByResourceId(masterMixer.rid, MIX_MODES.PERSONAL) else masterMixer personalVuMixer = if isOpener then personalMixer else masterMixer { isOpener: isOpener @@ -569,6 +569,7 @@ MIX_MODES = context.JK.MIX_MODES; null getMixer: (mixerId, mode) -> + beforeMode = mode mode = @mixMode unless mode? @allMixers[(if mode then 'M' else 'P') + mixerId] 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 6a6430b33..87fe9f0fb 100644 --- a/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee +++ b/web/app/assets/javascripts/react-components/mixins/SessionMyTracksMixin.js.coffee @@ -89,7 +89,7 @@ MIDI_TRACK = context.JK.MIDI_TRACK else logger.warn("SessionMyTracks: unable to find participant") - this.setState(tracks: tracks, session:session, chat: chat) + this.setState(tracks: tracks, mySession:session, chat: chat) } \ No newline at end of file diff --git a/web/app/assets/javascripts/wizard/gear/gear_wizard.js b/web/app/assets/javascripts/wizard/gear/gear_wizard.js index ebf6202dd..5965657dc 100644 --- a/web/app/assets/javascripts/wizard/gear/gear_wizard.js +++ b/web/app/assets/javascripts/wizard/gear/gear_wizard.js @@ -218,11 +218,13 @@ var networkTest = $wizardSteps.filter($('.network-test')) wizard = new context.JK.Wizard(app); - stepUnderstandGear.initialize($wizardSteps.filter($('[layout-wizard-step=0]')), self); - stepSelectGear.initialize($wizardSteps.filter($('[layout-wizard-step=1]')), self); - stepConfigureTracks.initialize($wizardSteps.filter($('[layout-wizard-step=2]')), self); - stepConfigureVoiceChat.initialize($wizardSteps.filter($('[layout-wizard-step=3]')), self); - stepDirectMonitoring.initialize($wizardSteps.filter($('[layout-wizard-step=4]')), self); + + var operatingSystem = context.JK.GetOSAsString(); + stepUnderstandGear.initialize($wizardSteps.filter($('[layout-wizard-step=0]')), self, operatingSystem); + stepSelectGear.initialize($wizardSteps.filter($('[layout-wizard-step=1]')), self, operatingSystem); + stepConfigureTracks.initialize($wizardSteps.filter($('[layout-wizard-step=2]')), self, operatingSystem); + stepConfigureVoiceChat.initialize($wizardSteps.filter($('[layout-wizard-step=3]')), self, operatingSystem); + stepDirectMonitoring.initialize($wizardSteps.filter($('[layout-wizard-step=4]')), self, operatingSystem); stepSuccess.initialize($wizardSteps.filter($('.success')), self); var dynamicStepCount = 5 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 f8aa60839..3d8f5fa11 100644 --- a/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js +++ b/web/app/assets/javascripts/wizard/gear/step_configure_tracks.js @@ -18,10 +18,16 @@ var wizard = null; var firstTime = true; var helpTimeout = null; + var operatingSystem = null; function handleHelp() { - return "https://www.youtube.com/watch?v=SjMeMZpKNR4" + if (operatingSystem == "Win32") { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123618-setup-wizard-windows-step-3-configuring-your-audio-input-tracks" + } + else { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123593-setup-wizard-mac-step-3-configuring-your-audio-input-tracks" + } } function handleNext() { @@ -62,10 +68,12 @@ }, 2000) } } - function initialize(_$step, _wizard) { + function initialize(_$step, _wizard, _operatingSystem) { $step = _$step; wizard = _wizard; + operatingSystem = _operatingSystem; $watchVideoBtn = $step.find('.watch-video') + $watchVideoBtn.attr('href', handleHelp()) configureTracksHelper.initialize($step); } diff --git a/web/app/assets/javascripts/wizard/gear/step_configure_voice_chat.js b/web/app/assets/javascripts/wizard/gear/step_configure_voice_chat.js index b33621450..b3a64241d 100644 --- a/web/app/assets/javascripts/wizard/gear/step_configure_voice_chat.js +++ b/web/app/assets/javascripts/wizard/gear/step_configure_voice_chat.js @@ -22,9 +22,15 @@ var $watchVideoBtn = null; var firstTime = true; var helpTimeout = null; + var operatingSystem = null; function handleHelp() { - return "https://www.youtube.com/watch?v=f7niycdWm7Y"; + if (operatingSystem == "Win32") { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123633-setup-wizard-windows-step-4-setting-up-a-chat-mic" + } + else { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123594-setup-wizard-mac-step-4-setting-up-a-chat-mic" + } } function newSession() { @@ -66,12 +72,14 @@ } } - function initialize(_$step) { + function initialize(_$step, _wizard, _operatingSystem) { $step = _$step; + operatingSystem = _operatingSystem; voiceChatHelper.initialize($step, 'configure_voice_gear_wizard', true, {vuType: "vertical", lightCount: 8, lightWidth: 3, lightHeight: 10}, 101); $watchVideoBtn = $step.find('.watch-video') + $watchVideoBtn.attr('href', handleHelp()) } this.handleHelp = handleHelp; diff --git a/web/app/assets/javascripts/wizard/gear/step_direct_monitoring.js b/web/app/assets/javascripts/wizard/gear/step_direct_monitoring.js index b85464729..ade7a9549 100644 --- a/web/app/assets/javascripts/wizard/gear/step_direct_monitoring.js +++ b/web/app/assets/javascripts/wizard/gear/step_direct_monitoring.js @@ -16,7 +16,7 @@ var $watchVideoBtn = null; var firstTime = true; var helpTimeout = null; - + var operatingSystem = null; function checkIfPlaying() { var currentPositionMs = context.jamClient.SessionCurrrentPlayPosMs(); var atEnd = currentPositionMs == 0 || trackDurationMs == currentPositionMs; @@ -62,7 +62,12 @@ } function handleHelp() { - return "https://www.youtube.com/watch?v=-nC-D3JBHnk"; + if (operatingSystem == "Win32") { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123634-setup-wizard-windows-step-5-turning-off-direct-monitoring" + } + else { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123595-setup-wizard-mac-step-5-turning-off-direct-monitoring" + } } function handleNext() { @@ -126,7 +131,7 @@ } } - function initialize(_$step) { + function initialize(_$step, _wizard, _operatingSystem) { $step = _$step; $directMonitoringBtn = $step.find('.test-direct-monitoring'); @@ -134,6 +139,8 @@ $adjustSettingsDirectMonitor = $step.find('.adjust-settings-direct-monitor'); $adjustSettingsDirectMonitor.on('click', onAdjustGearRequested) $watchVideoBtn = $step.find('.watch-video') + operatingSystem = _operatingSystem + $watchVideoBtn.attr('href', handleHelp()) } this.handleHelp = handleHelp; diff --git a/web/app/assets/javascripts/wizard/gear/step_select_gear.js b/web/app/assets/javascripts/wizard/gear/step_select_gear.js index e3e7b4e44..79ffd0f68 100644 --- a/web/app/assets/javascripts/wizard/gear/step_select_gear.js +++ b/web/app/assets/javascripts/wizard/gear/step_select_gear.js @@ -1095,8 +1095,14 @@ initializeNextButtonState(); } + function handleHelp() { - return "https://www.youtube.com/channel/UC38nc9MMZgExJAd7ca3rkUA/videos" + if (operatingSystem == "Win32") { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123617-setup-wizard-windows-step-2-setting-up-your-audio-interface" + } + else { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123592-setup-wizard-mac-step-2-setting-up-your-audio-interface" + } } function handleNext() { @@ -1303,7 +1309,7 @@ } } - function initialize(_$step, _wizard) { + function initialize(_$step, _wizard, _operatingSystem) { $step = _$step; wizard = _wizard; @@ -1330,7 +1336,10 @@ $resyncStatusText = $step.find('.resynctext'); $latencyScoreBox = $step.find('.latency-score-section') - operatingSystem = context.JK.GetOSAsString(); + operatingSystem = _operatingSystem; + + $watchVideoBtn.attr('href', handleHelp()) + frameBuffers.initialize($knobs); $(frameBuffers) .on(frameBuffers.FRAMESIZE_CHANGED, onFramesizeChanged) diff --git a/web/app/assets/javascripts/wizard/gear/step_understand_gear.js b/web/app/assets/javascripts/wizard/gear/step_understand_gear.js index 2a1de8bb6..e94f12a42 100644 --- a/web/app/assets/javascripts/wizard/gear/step_understand_gear.js +++ b/web/app/assets/javascripts/wizard/gear/step_understand_gear.js @@ -9,7 +9,12 @@ var operatingSystem; function handleHelp() { - return "https://www.youtube.com/watch?v=Z1GxCljtdCY"; + if (operatingSystem == "Win32") { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123616-setup-wizard-windows-step-1-starting-the-setup-wizard" + } + else { + return "https://jamkazam.freshdesk.com/support/solutions/articles/66000123577-setup-wizard-mac-step-1-starting-the-setup-wizard" + } } function beforeShow() { @@ -18,13 +23,13 @@ if (operatingSystem == "Win32") { $watchVideo.attr('href', 'https://www.youtube.com/watch?v=Z1GxCljtdCY'); } - $watchVideo.attr('href', videoUrl); + $watchVideo.attr('href', handleHelp()); } - function initialize(_$step) { + function initialize(_$step, _wizard, _operatingSystem) { $step = _$step; - operatingSystem = context.JK.GetOSAsString(); + operatingSystem = _operatingSystem; } this.handleHelp = handleHelp; diff --git a/web/app/assets/stylesheets/client/help.scss b/web/app/assets/stylesheets/client/help.scss index 10d1afa4b..105cd2a15 100644 --- a/web/app/assets/stylesheets/client/help.scss +++ b/web/app/assets/stylesheets/client/help.scss @@ -74,6 +74,10 @@ html { } } + .session-help { + padding:5px; + } + .big-dark-help { font-size:20px; color: $ColorTextTypical; diff --git a/web/app/assets/stylesheets/client/react-components/SessionScreen.scss b/web/app/assets/stylesheets/client/react-components/SessionScreen.scss index b9797b1c3..97d4fef40 100644 --- a/web/app/assets/stylesheets/client/react-components/SessionScreen.scss +++ b/web/app/assets/stylesheets/client/react-components/SessionScreen.scss @@ -210,6 +210,15 @@ $session-screen-divider: 1190px; color: $ColorTextTypical; overflow: hidden; position: relative; + + .session-tracks-help { + font-size:14px; + text-decoration: none; + cursor: pointer; + color:$ColorLink; + top: -2px; + position: relative; + } } .my-tracks-header { @@ -304,10 +313,12 @@ $session-screen-divider: 1190px; } .when-empty { - margin-top: 25px; - margin-left: 22px; + //margin-top: 25px; + //margin-left: 22px; + margin:5px 0 10px 0; color: $ColorTextTypical; overflow: hidden; + font-size:12px; } .session-track-settings { diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim index 1951c87a4..b4ad3e853 100644 --- a/web/app/views/clients/_help.html.slim +++ b/web/app/views/clients/_help.html.slim @@ -71,6 +71,43 @@ script type="text/template" id="template-help-recording-count" script type="text/template" id="template-help-session-count" | The number of sessions that this {{data.entity_type}} has played in. +script type="text/template" id="template-help-session-audio-inputs-instructions" + .session-audio-inputs-instructions.big-dark-help.session-help + p + | In this Audio Inputs section, set the input level on each of your audio tracks to a healthy level. + br + p + | To do this, hover your mouse over the volume icon on one of your audio tracks. You'll see a slider with meter lights on the sides. Use the gain knobs on your audio interface or the slider in the JamKazam app to adjust your input level up or down. Play and/or sing, and watch where the meter lights peak. These lights should reach the top of the green lights, and maybe one light into the orange/red zone. + br + p + | If your input is set too high, you'll get clipping and distortion. If your input is set too low, your audio may be too soft, or you'll get too much white noise mixed with your audio signal. + +script type="text/template" id="template-help-session-personal-mix-instructions" + .session-personal-mix-instructions.big-dark-help.session-help + p + | In this Personal Mix section, adjust the volume of each audio track in your session to get the mix where you like it. + br + p + | To do this, hover your mouse over the volume icon on any of the audio tracks. You'll see a slider with meter lights on the sides. Pull the slider in the JamKazam app up to make the track louder in the mix, or pull the slider down to make the track softer in the mix. Don't worry, as these changes only affect what you hear - they don't change what others in your sessions hear. + br + p + | Also, please note that your personal mix is the mix that will be used for any recordings that you personally make in the session and also for any broadcast that you personally send from your computer to YouTube, Facebook, etc. If another musician in your session makes a recording or broadcasts your session, that musician's personal mix is the mix that will be used. + + +script type="text/template" id="template-help-session-media-tracks-instructions" + .session-media-tracks-instructions.big-dark-help.session-help + p + | In this Recorded Audio section, you can open recordings you've made in JamKazam sessions, JamTracks (multi-track recordings of popular songs) you've purchased from JamKazam, or audio files (i.e. simple backing tracks). You can also start a metronome that everyone in the session will hear. + br + p + | For any of these features, you can adjust the associated volume of audio in your session to get the mix where you like it. + br + p + | To do this, hover your mouse over the volume icon on any of the audio tracks. You'll see a slider with meter lights on the sides. Pull the slider in the JamKazam app up to make the track louder in your personal mix, or pull the slider down to make the track softer in your mix. Don't worry, as these changes only affect what you hear - they don't change what others in your sessions hear. + br + p + | Also, please note that your personal mix is the mix that will be used for any recordings that you personally make in the session and also for any broadcast that you personally send from your computer to YouTube, Facebook, etc. If another musician in your session makes a recording or broadcasts your session, that musician's personal mix is the mix that will be used. + script type="text/template" id="template-help-musician-score-count" .help-musician-score-count p diff --git a/web/app/views/clients/index.html.erb b/web/app/views/clients/index.html.erb index daa6ae36d..7c0fd678a 100644 --- a/web/app/views/clients/index.html.erb +++ b/web/app/views/clients/index.html.erb @@ -373,8 +373,8 @@ var singlePlayerProfileGuardDialog = new JK.SinglePlayerProfileGuardDialog(JK.app); singlePlayerProfileGuardDialog.initialize(); - var sessionMasterMixDialog = new JK.SessionMasterMixDialog(JK.app); - sessionMasterMixDialog.initialize(); + //var sessionMasterMixDialog = new JK.SessionMasterMixDialog(JK.app); + //sessionMasterMixDialog.initialize(); var signinDialog = new JK.SigninDialog(JK.app); signinDialog.initialize(); 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 cdbd11bd4..de9a2d795 100644 --- a/web/app/views/clients/wizard/gear/_gear_wizard.html.haml +++ b/web/app/views/clients/wizard/gear/_gear_wizard.html.haml @@ -11,7 +11,7 @@ It will take a few minutes, but it will educate you and save you time and trouble. .center.video-button-holder - %a.button-orange.watch-video{href:"#", rel:'external'} WATCH VIDEO + %a.button-orange.watch-video{href:"#", rel:'external'} INSTRUCTIONS .wizard-step{ 'layout-wizard-step' => "1", 'dialog-title' => "Select & Test Audio Gear", 'dialog-purpose' => "SelectAudioGear" } .ftuesteps @@ -27,7 +27,7 @@ %li Configure interface settings. %li View test results. .center - %a.button-orange.watch-video{href:'https://jamkazam.desk.com/customer/en/portal/articles/2400685-using-the-setup-wizard-%E2%80%93-step-2-%E2%80%93-select-and-test-audio-gear', rel:'external'} + %a.button-orange.watch-video{rel:'external'} INSTRUCTIONS .wizard-step-column %h2 Audio Input Device @@ -68,7 +68,7 @@ %li Edit the first audio track using the "update" link to set it up as an instrumental or vocal track as you like. %li If desired, add other audio or MIDI tracks for other instruments or vocals. .center - %a.button-orange.watch-video{href:'https://jamkazam.desk.com/customer/en/portal/articles/2400702-using-the-setup-wizard-%E2%80%93-step-3-%E2%80%93-configure-tracks', rel:'external'} INSTRUCTIONS + %a.button-orange.watch-video{rel:'external'} INSTRUCTIONS .wizard-step-column = react_component 'ConfigureTracks', {} @@ -83,7 +83,7 @@ %p If you have set up a mic in step 2 for your instrument or voice, click Next to move forward. %p Otherwise, follow the instructions to set up a voice chat mic. .center - %a.button-orange.watch-video{href:'https://jamkazam.desk.com/customer/en/portal/articles/2400826-using-the-setup-wizard-%E2%80%93-step-4-%E2%80%93-configure-voice-chat', rel:'external'} INSTRUCTIONS + %a.button-orange.watch-video{rel:'external'} INSTRUCTIONS .wizard-step-column %h2.sub-header Select Voice Chat Option %form.voice @@ -123,7 +123,7 @@ = "If audio is poor try " %a.adjust-settings-direct-monitor{'href'=>'#'}tweaking your settings .center - %a.button-orange.watch-video{href:'https://jamkazam.desk.com/customer/en/portal/articles/2400827-using-the-setup-wizard-%E2%80%93-step-5-%E2%80%93-turn-off-direct-monitoring', rel:'external'} INSTRUCTIONS + %a.button-orange.watch-video{rel:'external'} INSTRUCTIONS .wizard-step-column .help-content When you have fully turned off the direct monitoring control (if any) on your audio interface, diff --git a/web/app/views/dialogs/_sessionMasterMixDialog.html.slim b/web/app/views/dialogs/_sessionMasterMixDialog.html.slim index 15a04c214..95dec3b9b 100644 --- a/web/app/views/dialogs/_sessionMasterMixDialog.html.slim +++ b/web/app/views/dialogs/_sessionMasterMixDialog.html.slim @@ -5,5 +5,5 @@ .dialog-inner p.notice | The master mix is the audio mix used for both recordings and live broadcasts of session audio. Changes to the master mix are global, so there is only one master mix for the session. The master mix does not include controls for the metronome because the metronome is not recorded or broadcast. Any user in the session may use the volume and pan controls below to make adjustments to the master mix for everyone in the session. - = react_component 'SessionMasterMix', {} + //= react_component 'SessionMasterMix', {} a.button-orange.close-button layout-action="close" CLOSE