826 lines
29 KiB
CoffeeScript
826 lines
29 KiB
CoffeeScript
context = window
|
|
|
|
ChannelGroupIds = context.JK.ChannelGroupIds
|
|
CategoryGroupIds = context.JK.CategoryGroupIds
|
|
MIX_MODES = context.JK.MIX_MODES;
|
|
|
|
|
|
@MixerHelper = class MixerHelper
|
|
|
|
constructor: (@session, @masterMixers, @personalMixers, @metro, @noAudioUsers, @mixMode) ->
|
|
@mixMode = MIX_MODES.PERSONAL # TODO - remove mixMode from MixerHelper? Or at least stop using it in most functions
|
|
@app = @session.app
|
|
@mixersByResourceId = {}
|
|
@mixersByTrackId = {}
|
|
@allMixers = {}
|
|
@currentMixerRangeMin = null
|
|
@currentMixerRangeMax = null
|
|
@mediaSummary = {}
|
|
@mediaTrackGroups = [ChannelGroupIds.MediaTrackGroup, ChannelGroupIds.JamTrackGroup,
|
|
ChannelGroupIds.MetronomeGroup]
|
|
@muteBothMasterAndPersonalGroups = [ChannelGroupIds.AudioInputMusicGroup, ChannelGroupIds.MediaTrackGroup,
|
|
ChannelGroupIds.JamTrackGroup, ChannelGroupIds.MetronomeGroup]
|
|
@organize()
|
|
|
|
organize: () ->
|
|
for masterMixer in @masterMixers
|
|
@allMixers['M' + masterMixer.id] = masterMixer; # populate allMixers by mixer.id
|
|
|
|
# populate mixer pair
|
|
mixerPair = {}
|
|
@mixersByResourceId[masterMixer.rid] = mixerPair
|
|
@mixersByTrackId[masterMixer.id] = mixerPair
|
|
mixerPair.master = masterMixer;
|
|
|
|
for personalMixer in @personalMixers
|
|
|
|
@allMixers['P' + personalMixer.id] = personalMixer
|
|
|
|
# populate other side of mixer pair
|
|
|
|
mixerPair = @mixersByResourceId[personalMixer.rid]
|
|
unless mixerPair
|
|
if personalMixer.group_id != ChannelGroupIds.MonitorGroup
|
|
logger.warn("there is no master version of ", personalMixer)
|
|
|
|
mixerPair = {}
|
|
@mixersByResourceId[personalMixer.rid] = mixerPair
|
|
|
|
@mixersByTrackId[personalMixer.id] = mixerPair;
|
|
mixerPair.personal = personalMixer;
|
|
|
|
@groupTypes()
|
|
@chatMixer = @resolveChatMixer()
|
|
|
|
groupTypes: () ->
|
|
localMediaMixers = @mixersForGroupIds(@mediaTrackGroups, MIX_MODES.MASTER)
|
|
peerLocalMediaMixers = @mixersForGroupId(ChannelGroupIds.PeerMediaTrackGroup, MIX_MODES.MASTER)
|
|
|
|
#logger.debug("localMediaMixers", localMediaMixers)
|
|
#logger.debug("peerLocalMediaMixers", peerLocalMediaMixers)
|
|
|
|
# get the server data regarding various media tracks
|
|
recordedBackingTracks = @session.recordedBackingTracks()
|
|
backingTracks = @session.backingTracks()
|
|
recordedJamTracks = @session.recordedJamTracks()
|
|
jamTracks = @session.jamTracks()
|
|
|
|
###
|
|
with mixer info, we use these to decide what kind of tracks are open in the backend
|
|
|
|
each mixer has a media_type field, which describes the type of media track it is.
|
|
* JamTrack
|
|
* BackingTrack
|
|
* RecordingTrack
|
|
* MetronomeTrack
|
|
* "" - adhoc track (not supported visually)
|
|
|
|
it is supposed to be the case that there are only one type of track open at a time, however, that's a business policy/logic
|
|
constraint; and may be buggy. **So, we should render whatever we have, so that it's obvious what's really going on.**
|
|
|
|
so, let's group up all mixers by type, and then ask them to be rendered
|
|
###
|
|
|
|
@recordingTrackMixers = []
|
|
@backingTrackMixers = []
|
|
@jamTrackMixers = []
|
|
@metronomeTrackMixers = []
|
|
@adhocTrackMixers = []
|
|
|
|
groupByType = (mixers, isLocalMixer) =>
|
|
for mixer in mixers
|
|
mediaType = mixer.media_type
|
|
groupId = mixer.group_id
|
|
|
|
if mediaType == 'MetronomeTrack' || groupId == ChannelGroupIds.MetronomeGroup
|
|
# Metronomes come across with a blank media type, so check group_id:
|
|
@metronomeTrackMixers.push(mixer)
|
|
else if mediaType == null || mediaType == "" || mediaType == 'RecordingTrack'
|
|
# additional check; if we can match an id in backing tracks or recorded backing track,
|
|
# we need to remove it from the recorded track set, but move it to the backing track set
|
|
|
|
isJamTrack = false;
|
|
|
|
if jamTracks
|
|
# check if the ID matches that of an open jam track
|
|
for jamTrack in jamTracks
|
|
if mixer.id == jamTrack.id
|
|
isJamTrack = true;
|
|
break
|
|
|
|
if !isJamTrack && recordedJamTracks
|
|
# then check if the ID matches that of a open, recorded jam track
|
|
for recordedJamTrack in recordedJamTracks
|
|
if mixer.id == recordedJamTrack.id
|
|
isJamTrack = true
|
|
break
|
|
|
|
if isJamTrack
|
|
@jamTrackMixers.push(mixer)
|
|
else
|
|
isBackingTrack = false
|
|
if recordedBackingTracks
|
|
for recordedBackingTrack in recordedBackingTracks
|
|
if mixer.id == 'L' + recordedBackingTrack.client_track_id
|
|
isBackingTrack = true
|
|
break
|
|
|
|
if backingTracks
|
|
for backingTrack in backingTracks
|
|
if mixer.id == 'L' + backingTrack.client_track_id
|
|
isBackingTrack = true
|
|
break
|
|
|
|
if isBackingTrack
|
|
@backingTrackMixers.push(mixer)
|
|
else
|
|
# couldn't resolve this as a JamTrack or Backing track, must be a normal recorded file
|
|
@recordingTrackMixers.push(mixer)
|
|
|
|
else if mediaType == 'PeerMediaTrack' || mediaType == 'BackingTrack'
|
|
@backingTrackMixers.push(mixer)
|
|
else if mediaType == 'JamTrack'
|
|
@jamTrackMixers.push(mixer);
|
|
else if mediaType == null || mediaType == "" || mediaType == 'RecordingTrack'
|
|
# mediaType == null is for backwards compat with older clients. Can be removed soon
|
|
@recordingTrackMixers.push(mixer)
|
|
else
|
|
logger.warn("Unknown track type: " + mediaType)
|
|
@adhocTrackMixers.push(mixer)
|
|
|
|
groupByType(localMediaMixers, true);
|
|
groupByType(peerLocalMediaMixers, false);
|
|
|
|
###
|
|
if recordingTrackMixers.length > 0
|
|
renderRecordingTracks(recordingTrackMixers)
|
|
|
|
if backingTrackMixers.length > 0
|
|
renderBackingTracks(backingTrackMixers)
|
|
|
|
if jamTrackMixers.length > 0
|
|
renderJamTracks(jamTrackMixers);
|
|
|
|
if metronomeTrackMixers.length > 0 && @session.jamTracks() == null && @session.recordedJamTracks() == null
|
|
renderMetronomeTracks(metronomeTrackMixers);
|
|
|
|
checkMetronomeTransition();
|
|
###
|
|
|
|
@backingTracks = @resolveBackingTracks()
|
|
@jamTracks = @resolveJamTracks()
|
|
@recordedTracks = @resolveRecordedTracks()
|
|
@metronome = @resolveMetronome()
|
|
|
|
|
|
if @adhocTrackMixers.length > 0
|
|
logger.warn("some tracks are open that we don't know how to show")
|
|
|
|
@mediaSummary =
|
|
recordingOpen: @recordedTracks.length > 0
|
|
jamTrackOpen: @jamTracks.length > 0
|
|
backingTrackOpen: @backingTracks.length > 0
|
|
metronomeOpen: @metronome?
|
|
|
|
# figure out if any media is open
|
|
mediaOpenSummary = false
|
|
for mediaType, mediaOpen of @mediaSummary
|
|
mediaOpenSummary = true if mediaOpen
|
|
|
|
@mediaSummary.mediaOpen = mediaOpenSummary
|
|
|
|
# this method is pretty complicated because it forks on a key bit of state:
|
|
# sessionModel.isPlayingRecording()
|
|
# a backing track opened as part of a recording has a different behavior and presence on the server (recording.recorded_backing_tracks)
|
|
# than a backing track opend ad-hoc (connection.backing_tracks)
|
|
|
|
resolveBackingTracks: () ->
|
|
backingTracks = []
|
|
|
|
return backingTracks unless @backingTrackMixers.length > 0
|
|
|
|
# find both client and server representation of the backing track
|
|
serverBackingTracks = []
|
|
backingTrackMixers = @backingTrackMixers
|
|
|
|
if @session.isPlayingRecording()
|
|
backingTrackMixers = context._.filter(backingTrackMixers, (mixer) -> return mixer.managed || !mixer.managed?)
|
|
serverBackingTracks = @session.recordedBackingTracks()
|
|
else
|
|
serverBackingTracks = @session.backingTracks();
|
|
backingTrackMixers = context._.filter(backingTrackMixers, (mixer) -> return !mixer.managed)
|
|
if backingTrackMixers.length > 1
|
|
logger.error("multiple, managed backing track mixers encountered", backingTrackMixers)
|
|
@app.notify({
|
|
title: "Multiple Backing Tracks Encountered",
|
|
text: "Only one backing track can be open a time.",
|
|
icon_url: "/assets/content/icon_alert_big.png"
|
|
});
|
|
return backingTracks;
|
|
|
|
# we don't render backing tracks unless we have server data to accompany
|
|
if !serverBackingTracks? || serverBackingTracks.length == 0
|
|
return backingTracks
|
|
|
|
noCorrespondingTracks = false
|
|
for mixer in backingTrackMixers
|
|
# find the track or tracks that correspond to the mixer
|
|
correspondingTracks = []
|
|
noCorrespondingTracks = false
|
|
if @session.isPlayingRecording()
|
|
for backingTrack in serverBackingTracks
|
|
# occurs if this client is the one that opened the track, # occurs if this client is a remote participant
|
|
if mixer.persisted_track_id == backingTrack.client_track_id || mixer.id == 'L' + backingTrack.client_track_id
|
|
correspondingTracks.push(backingTrack)
|
|
else
|
|
# if this is just an open backing track, then we can assume that the 1st backingTrackMixer is ours
|
|
correspondingTracks.push(serverBackingTracks[0])
|
|
|
|
if correspondingTracks.length == 0
|
|
noCorrespondingTracks = true
|
|
logger.debug("renderBackingTracks: could not map backing tracks")
|
|
@app.notify({
|
|
title: "Unable to Open Backing Track",
|
|
text: "Could not correlate server and client tracks",
|
|
icon_url: "/assets/content/icon_alert_big.png"
|
|
});
|
|
break
|
|
|
|
# now we have backing track and mixer in hand; we can render
|
|
serverBackingTrack = correspondingTracks[0]
|
|
|
|
oppositeMixer = @getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
|
|
|
|
isOpener = mixer.group_id == ChannelGroupIds.MediaTrackGroup
|
|
data =
|
|
isOpener: isOpener
|
|
shortFilename: context.JK.getNameOfFile(serverBackingTrack.filename)
|
|
instrumentIcon: context.JK.getInstrumentIcon45(serverBackingTrack.instrument_id)
|
|
photoUrl: "/assets/content/icon_recording.png"
|
|
showLoop: isOpener && !@session.isPlayingRecording()
|
|
track: serverBackingTrack
|
|
mixers: @mediaMixers(mixer, isOpener)
|
|
|
|
backingTracks.push(data)
|
|
|
|
backingTracks
|
|
|
|
resolveJamTracks: () ->
|
|
_jamTracks = []
|
|
|
|
return _jamTracks unless @jamTrackMixers.length > 0
|
|
|
|
|
|
jamTrackMixers = @jamTrackMixers.slice();
|
|
jamTracks = []
|
|
jamTrackName = null;
|
|
|
|
if @session.isPlayingRecording()
|
|
# only return managed mixers for recorded backing tracks
|
|
jamTracks = @session.recordedJamTracks()
|
|
jamTrackName = @session.recordedJamTrackName()
|
|
else
|
|
# only return un-managed (ad-hoc) mixers for normal backing tracks
|
|
jamTracks = @session.jamTracks()
|
|
jamTrackName = @session.jamTrackName()
|
|
|
|
# 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 (JamTrackGroup), then we can say this person is the opener
|
|
isOpener = jamTrackMixers[0].group_id == ChannelGroupIds.JamTrackGroup;
|
|
|
|
if jamTracks
|
|
noCorrespondingTracks = false
|
|
for jamTrack in jamTracks
|
|
mixer = null
|
|
preMasteredClass = ""
|
|
# find the track or tracks that correspond to the mixer
|
|
correspondingTracks = []
|
|
|
|
for matchMixer in @jamTrackMixers
|
|
if matchMixer.id == jamTrack.id
|
|
correspondingTracks.push(jamTrack)
|
|
mixer = matchMixer
|
|
|
|
if correspondingTracks.length == 0
|
|
noCorrespondingTracks = true
|
|
logger.error("could not correlate jam tracks", jamTrackMixers, jamTracks)
|
|
@app.notify({
|
|
title: "Unable to Open JamTrack",
|
|
text: "Could not correlate server and client tracks",
|
|
icon_url: "/assets/content/icon_alert_big.png"})
|
|
return _jamTracks
|
|
|
|
#jamTracks = $.grep(jamTracks, (value) =>
|
|
# $.inArray(value, correspondingTracks) < 0
|
|
#)
|
|
|
|
# prune found mixers
|
|
jamTrackMixers.splice(mixer);
|
|
|
|
oneOfTheTracks = correspondingTracks[0];
|
|
instrumentIcon = context.JK.getInstrumentIcon24(oneOfTheTracks.instrument.id);
|
|
|
|
part = oneOfTheTracks.part
|
|
part = '' unless name?
|
|
|
|
data =
|
|
name: jamTrackName
|
|
part: part
|
|
isOpener: isOpener
|
|
instrumentIcon: instrumentIcon
|
|
track: oneOfTheTracks
|
|
mixers: @mediaMixers(mixer, isOpener)
|
|
|
|
_jamTracks.push(data)
|
|
|
|
_jamTracks
|
|
|
|
resolveRecordedTracks: () ->
|
|
recordedTracks = []
|
|
|
|
return recordedTracks unless @recordingTrackMixers.length > 0
|
|
|
|
serverRecordedTracks = @session.recordedTracks()
|
|
|
|
isOpener = @recordingTrackMixers[0].group_id == ChannelGroupIds.MediaTrackGroup
|
|
|
|
# using the server's info in conjuction with the client's, draw the recording tracks
|
|
if serverRecordedTracks
|
|
recordingName = @session.recordingName()
|
|
noCorrespondingTracks = false
|
|
for mixer in @recordingTrackMixers
|
|
preMasteredClass = ""
|
|
correspondingTracks = []
|
|
for recordedTrack in serverRecordedTracks
|
|
if mixer.id.indexOf("L") == 0
|
|
if mixer.id.substring(1) == recordedTrack.client_track_id
|
|
correspondingTracks.push(recordedTrack)
|
|
else if mixer.id.indexOf("C") == 0
|
|
if mixer.id.substring(1) == recordedTrack.client_id
|
|
correspondingTracks.push(recordedTrack)
|
|
preMasteredClass = "pre-mastered-track"
|
|
else
|
|
# this should not be possible
|
|
alert("Invalid state: the recorded track had neither persisted_track_id or persisted_client_id")
|
|
|
|
if correspondingTracks.length == 0
|
|
noCorrespondingTracks = true
|
|
logger.debug("unable to correlate all recorded tracks", recordingMixers, serverRecordedTracks)
|
|
@app.notify({
|
|
title: "Unable to Open Recording",
|
|
text: "Could not correlate server and client tracks",
|
|
icon_url: "/assets/content/icon_alert_big.png"});
|
|
return recordedTracks
|
|
|
|
serverRecordedTracks = $.grep(serverRecordedTracks,
|
|
(value) =>
|
|
$.inArray(value, correspondingTracks) < 0
|
|
)
|
|
|
|
oneOfTheTracks = correspondingTracks[0]
|
|
instrumentIcon = context.JK.getInstrumentIcon24(oneOfTheTracks.instrument_id)
|
|
userName = oneOfTheTracks.user.name
|
|
userName = oneOfTheTracks.user.first_name + ' ' + oneOfTheTracks.user.last_name unless userName?
|
|
|
|
data =
|
|
recordingName: recordingName
|
|
isOpener: isOpener
|
|
userName: userName
|
|
instrumentIcon: instrumentIcon
|
|
track: oneOfTheTracks
|
|
mixers: @mediaMixers(mixer, isOpener)
|
|
|
|
recordedTracks.push(data)
|
|
|
|
recordedTracks
|
|
|
|
resolveMetronome: () ->
|
|
metronome = null
|
|
|
|
return metronome if @metronomeTrackMixers.length == 0
|
|
|
|
mixer = @metronomeTrackMixers[0]
|
|
|
|
instrumentIcon = "/assets/content/icon_metronome.png"
|
|
|
|
oppositeMixer = @getMixerByResourceId(mixer.rid, MIX_MODES.PERSONAL);
|
|
|
|
metronome =
|
|
instrumentIcon: instrumentIcon
|
|
mixers: {mixer: mixer, oppositeMixer: oppositeMixer, vuMixer: mixer, muteMixer: mixer}
|
|
|
|
metronome
|
|
|
|
resolveChatMixer: () ->
|
|
masterChatMixers = @mixersForGroupId(ChannelGroupIds.AudioInputChatGroup, MIX_MODES.MASTER);
|
|
|
|
return null if masterChatMixers.length == 0
|
|
|
|
personalChatMixers = @mixersForGroupId(ChannelGroupIds.AudioInputChatGroup, MIX_MODES.PERSONAL);
|
|
|
|
if personalChatMixers.length == 0
|
|
logger.warn("unable to find personal mixer for voice chat");
|
|
return null
|
|
|
|
|
|
masterChatMixer = masterChatMixers[0];
|
|
personalChatMixer = personalChatMixers[0];
|
|
|
|
{
|
|
master: {
|
|
mixer: masterChatMixer
|
|
muteMixer: masterChatMixer
|
|
vuMixer: masterChatMixer
|
|
oppositeMixer: personalChatMixer
|
|
}
|
|
personal: {
|
|
mixer: personalChatMixer
|
|
muteMixer: personalChatMixer
|
|
vuMixer: personalChatMixer
|
|
oppositeMixer: masterChatMixer
|
|
}
|
|
}
|
|
|
|
# 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
|
|
personalVuMixer = if isOpener then personalMixer else masterMixer
|
|
{
|
|
isOpener: isOpener
|
|
|
|
master: {
|
|
mixer: masterMixer
|
|
muteMixer: masterMixer
|
|
vuMixer: masterMixer
|
|
}
|
|
personal: {
|
|
mixer: personalMixer
|
|
muteMixer: personalMixer
|
|
vuMixer: personalVuMixer
|
|
}
|
|
}
|
|
|
|
|
|
mixersForGroupIds: (groupIds, mixMode) ->
|
|
foundMixers = []
|
|
mixers = if mixMode == MIX_MODES.MASTER then @masterMixers else @personalMixers;
|
|
|
|
for mixer in mixers
|
|
for groupId in groupIds
|
|
if mixer.group_id == groupId
|
|
foundMixers.push(mixer)
|
|
|
|
foundMixers
|
|
|
|
mixersForGroupId: (groupId, mixMode) ->
|
|
foundMixers = [];
|
|
mixers = if mixMode == MIX_MODES.MASTER then @masterMixers else @personalMixers;
|
|
for mixer in mixers
|
|
if mixer.group_id == groupId
|
|
foundMixers.push(mixer)
|
|
|
|
foundMixers
|
|
|
|
getMixer: (mixerId, mode) ->
|
|
mode = @mixMode unless mode?
|
|
@allMixers[(if mode then 'M' else 'P') + mixerId]
|
|
|
|
getMixerByTrackId: (trackId, mode) ->
|
|
mixerPair = @mixersByTrackId[trackId]
|
|
|
|
return null unless mixerPair
|
|
|
|
if mode == undefined
|
|
return mixerPair
|
|
|
|
else
|
|
if mode == MIX_MODES.MASTER
|
|
return mixerPair.master
|
|
else
|
|
return mixerPair.personal
|
|
|
|
|
|
groupedMixersForClientId: (clientId, groupIds, usedMixers, mixMode) ->
|
|
foundMixers = {};
|
|
mixers = if mixMode == MIX_MODES.MASTER then @masterMixers else @personalMixers;
|
|
|
|
for mixer in mixers
|
|
if mixer.client_id == clientId
|
|
for groupId in groupIds
|
|
if mixer.group_id == groupId
|
|
if (mixer.groupId != ChannelGroupIds.UserMusicInputGroup) && !(mixer.id of usedMixers)
|
|
mixers = foundMixers[mixer.group_id]
|
|
if !mixers
|
|
mixers = []
|
|
foundMixers[mixer.group_id] = mixers
|
|
mixers.push(mixer)
|
|
|
|
foundMixers
|
|
|
|
getMixerByResourceId:(resourceId, mode) ->
|
|
mixerPair = @mixersByResourceId[resourceId];
|
|
|
|
return null if(!mixerPair)
|
|
|
|
if !mode?
|
|
return mixerPair;
|
|
else
|
|
if mode == MIX_MODES.MASTER
|
|
return mixerPair.master
|
|
else
|
|
return mixerPair.personal
|
|
|
|
|
|
findMixerForTrack: (client_id, track, myTrack, mode = MIX_MODES.PERSONAL) ->
|
|
mixer = null # what is the best mixer for this track/client ID?
|
|
oppositeMixer = null # what is the corresponding mixer in the opposite mode?
|
|
vuMixer = null
|
|
muteMixer = null
|
|
|
|
|
|
if myTrack
|
|
# when it's your track, look it up by the backend resource ID
|
|
mixer = @getMixerByTrackId(track.client_track_id, mode)
|
|
vuMixer = mixer
|
|
muteMixer = mixer
|
|
|
|
# sanity checks
|
|
if mixer && mixer.group_id != ChannelGroupIds.AudioInputMusicGroup
|
|
logger.error("found local mixer that was not of groupID: AudioInputMusicGroup", mixer)
|
|
|
|
if mixer
|
|
# find the matching AudioInputMusicGroup for the opposite mode
|
|
oppositeMixer = @getMixerByTrackId(track.client_track_id, !mode)
|
|
|
|
if mode == MIX_MODES.PERSONAL
|
|
muteMixer = oppositeMixer; # make the master mixer the mute mixer
|
|
|
|
# sanity checks
|
|
if !oppositeMixer
|
|
logger.error("unable to find opposite mixer for local mixer", mixer)
|
|
else if oppositeMixer.group_id != ChannelGroupIds.AudioInputMusicGroup
|
|
logger.error("found local mixer in opposite mode that was not of groupID: AudioInputMusicGroup", mixer, oppositeMixer)
|
|
else
|
|
logger.debug("local track is not present: ", track, @allMixers)
|
|
else
|
|
switch mode
|
|
when MIX_MODES.MASTER
|
|
|
|
# when it's a remote track and in master mode, we should find the PeerAudioInputMusicGroup
|
|
mixer = @getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER)
|
|
|
|
# sanity check
|
|
if mixer && mixer.group_id != ChannelGroupIds.PeerAudioInputMusicGroup
|
|
logger.error("found remote mixer that was not of groupID: PeerAudioInputMusicGroup", mixer)
|
|
|
|
vuMixer = mixer
|
|
muteMixer = mixer
|
|
|
|
if mixer
|
|
# we should be able to find a UserMusicInputGroup for this clientId in personal mode
|
|
oppositeMixers = @groupedMixersForClientId(client_id, [ ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL)
|
|
if oppositeMixers[ChannelGroupIds.UserMusicInputGroup]
|
|
oppositeMixer = oppositeMixers[ChannelGroupIds.UserMusicInputGroup][0]
|
|
|
|
if !oppositeMixer
|
|
logger.error("unable to find UserMusicInputGroup corresponding to PeerAudioInputMusicGroup mixer", mixer )
|
|
|
|
when MIX_MODES.PERSONAL
|
|
mixers = @groupedMixersForClientId(client_id, [ ChannelGroupIds.UserMusicInputGroup], {}, MIX_MODES.PERSONAL)
|
|
if mixers[ChannelGroupIds.UserMusicInputGroup]
|
|
mixer = mixers[ChannelGroupIds.UserMusicInputGroup][0]
|
|
|
|
vuMixer = mixer
|
|
muteMixer = mixer
|
|
|
|
if mixer
|
|
# now grab the PeerAudioInputMusicGroup in master mode to satisfy the 'opposite' mixer
|
|
oppositeMixer = @getMixerByTrackId(track.client_track_id, MIX_MODES.MASTER)
|
|
if !oppositeMixer
|
|
logger.debug("unable to find a PeerAudioInputMusicGroup master mixer matching a UserMusicInput", client_id, track.client_track_id)
|
|
else if oppositeMixer.group_id != ChannelGroupIds.PeerAudioInputMusicGroup
|
|
logger.error("found remote mixer that was not of groupID: PeerAudioInputMusicGroup", mixer)
|
|
|
|
#vuMixer = oppositeMixer; # for personal mode, use the PeerAudioInputMusicGroup's VUs
|
|
|
|
{
|
|
mixer: mixer,
|
|
oppositeMixer: oppositeMixer,
|
|
vuMixer: vuMixer,
|
|
muteMixer: muteMixer
|
|
}
|
|
|
|
mute: (mixerId, mode, muting) ->
|
|
|
|
mode = @mixMode unless mode?
|
|
|
|
@fillTrackVolumeObject(mixerId, mode)
|
|
|
|
context.trackVolumeObject.mute = muting
|
|
|
|
context.jamClient.SessionSetControlState(mixerId, mode)
|
|
|
|
# keep state of mixer in sync with backend
|
|
mixer = @getMixer(mixerId, mode)
|
|
mixer.mute = muting
|
|
|
|
faderChanged: (data, mixers, groupId) ->
|
|
for mixer in mixers
|
|
broadcast = !(data.dragging) # If fader is still dragging, don't broadcast
|
|
mixer = @fillTrackVolumeObject(mixer.id, mixer.mode, broadcast)
|
|
|
|
@setMixerVolume(mixer, data.percentage)
|
|
|
|
# keep state of mixer in sync with backend
|
|
mixer = @getMixer(mixer.id, mixer.mode)
|
|
mixer.volume_left = context.trackVolumeObject.volL
|
|
|
|
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
|
|
context.JK.FaderHelpers.setFaderValue(mixerId, data.percentage)
|
|
|
|
initGain: (mixer) ->
|
|
gainPercent = context.JK.FaderHelpers.convertAudioTaperToPercent(mixer.volume_left)
|
|
context.JK.FaderHelpers.setFaderValue(mixer.id, gainPercent)
|
|
context.JK.FaderHelpers.showFader(mixer.id)
|
|
|
|
panChanged: (data, mixers, groupId) ->
|
|
# media tracks are the only controls that sometimes set two mixers right now
|
|
for mixer in mixers
|
|
broadcast = !(data.dragging) # If fader is still dragging, don't broadcast
|
|
mixer = @fillTrackVolumeObject(mixer.id, mixer.mode, broadcast)
|
|
|
|
@setMixerPan(mixer, data.percentage)
|
|
|
|
# keep state of mixer in sync with backend
|
|
mixer = @getMixer(mixer.id, mixer.mode)
|
|
mixer.pan = context.trackVolumeObject.pan
|
|
|
|
initPan: (mixer) ->
|
|
panPercent= context.JK.PanHelpers.convertPanToPercent(mixer.pan)
|
|
context.JK.FaderHelpers.setFaderValue(mixer.id, panPercent, Math.abs(mixer.pan))
|
|
context.JK.FaderHelpers.showFader(mixer.id)
|
|
|
|
setMixerPan: (mixer, panPercent) ->
|
|
|
|
context.trackVolumeObject.pan = context.JK.PanHelpers.convertPercentToPan(panPercent);
|
|
context.jamClient.SessionSetControlState(mixer.id, mixer.mode);
|
|
|
|
loopChanged: (mixer, shouldLoop) ->
|
|
|
|
@fillTrackVolumeObject(mixer.id, mixer.mode)
|
|
context.trackVolumeObject.loop = shouldLoop
|
|
context.jamClient.SessionSetControlState(mixer.id, mixer.mode)
|
|
|
|
# keep state of mixer in sync with backend
|
|
mixer = @getMixer(mixer.id, mixer.mode)
|
|
mixer.loop = context.trackVolumeObject.loop
|
|
|
|
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.
|
|
// All that needs doing is to translate the incoming percent
|
|
// into the real value ont the sliders range. Set Left/Right
|
|
// volumes on trackVolumeObject, and call SetControlState to stick.
|
|
###
|
|
|
|
context.trackVolumeObject.volL = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
|
|
context.trackVolumeObject.volR = context.JK.FaderHelpers.convertPercentToAudioTaper(volumePercent);
|
|
|
|
context.jamClient.SessionSetControlState(mixer.id, mixer.mode);
|
|
|
|
percentFromMixerValue: (min, max, value) ->
|
|
try
|
|
range = Math.abs(max - min)
|
|
magnitude = value - min
|
|
percent = Math.round(100*(magnitude/range))
|
|
percent
|
|
catch err
|
|
0
|
|
|
|
|
|
percentToMixerValue:(min, max, percent) ->
|
|
range = Math.abs(max - min);
|
|
multiplier = percent/100; # Change 85 into 0.85
|
|
value = min + (multiplier * range);
|
|
|
|
# Protect against percents < 0 and > 100
|
|
if value < min
|
|
value = min;
|
|
|
|
if value > max
|
|
value = max;
|
|
|
|
return value;
|
|
|
|
fillTrackVolumeObject: (mixerId, mode, broadcast) ->
|
|
_broadcast = true
|
|
if broadcast?
|
|
_broadcast = broadcast
|
|
|
|
mixer = @getMixer(mixerId, mode)
|
|
context.trackVolumeObject.clientID = mixer.client_id
|
|
context.trackVolumeObject.broadcast = _broadcast
|
|
context.trackVolumeObject.master = mixer.master
|
|
context.trackVolumeObject.monitor = mixer.monitor
|
|
context.trackVolumeObject.mute = mixer.mute
|
|
context.trackVolumeObject.name = mixer.name
|
|
context.trackVolumeObject.record = mixer.record
|
|
context.trackVolumeObject.volL = mixer.volume_left
|
|
context.trackVolumeObject.pan = mixer.pan
|
|
|
|
# today we treat all tracks as mono, but this is required to make a stereo track happy
|
|
# context.trackVolumeObject.volR = mixer.volume_right;
|
|
context.trackVolumeObject.volR = mixer.volume_left;
|
|
|
|
context.trackVolumeObject.loop = mixer.loop;
|
|
# trackVolumeObject doesn't have a place for range min/max
|
|
@currentMixerRangeMin = mixer.range_low;
|
|
@currentMixerRangeMax = mixer.range_high;
|
|
mixer
|
|
|
|
updateVU: (mixerId, mode, leftValue, leftClipping, rightValue, rightClipping) ->
|
|
mixer = @getMixer(mixerId, mode)
|
|
|
|
if mixer?
|
|
context.JK.VuHelpers.updateVU3(mixer, leftValue, leftClipping, rightValue, rightClipping)
|
|
###
|
|
if mixer
|
|
if mixer.stereo # // stereo track
|
|
if mixerId.substr(-4) == "_vul"
|
|
context.JK.VuHelpers.updateVU2('vul', mixer, value)
|
|
else
|
|
context.JK.VuHelpers.updateVU2('vur', mixer, value)
|
|
else
|
|
if mixerId.substr(-4) == "_vul"
|
|
# Do the left
|
|
context.JK.VuHelpers.updateVU2('vul', mixer, value)
|
|
# Do the right
|
|
context.JK.VuHelpers.updateVU2('vur', mixer, value)
|
|
###
|
|
getTrackInfo: () ->
|
|
context.JK.TrackHelpers.getTrackInfo(context.jamClient, @masterMixers)
|
|
|
|
getGroupMixer: (categoryId, mode) ->
|
|
groupId = if mode == MIX_MODES.MASTER then ChannelGroupIds.MasterCatGroup else ChannelGroupIds.MonitorCatGroup
|
|
mixers = @mixersForGroupId(groupId, mode)
|
|
|
|
if mixers.length == 0
|
|
logger.warn("could not find mixer with group ID: " + groupId + ', mode:' + mode)
|
|
return null
|
|
|
|
found = null
|
|
for mixer in mixers
|
|
if mixer.name == categoryId
|
|
found = mixer
|
|
break
|
|
|
|
unless found?
|
|
logger.warn("could not find mixer with categoryId: " + categoryId)
|
|
return null
|
|
else
|
|
{
|
|
mixer: found,
|
|
muteMixer : found,
|
|
vuMixer: found,
|
|
oppositeMixer: found
|
|
}
|
|
|
|
getAudioInputCategoryMixer: (mode) ->
|
|
@getGroupMixer(CategoryGroupIds.AudioInputMusic, mode)
|
|
|
|
getChatCategoryMixer: (mode) ->
|
|
@getGroupMixer(CategoryGroupIds.AudioInputChat, mode)
|
|
|
|
getMediaCategoryMixer: (mode) ->
|
|
@getGroupMixer(CategoryGroupIds.MediaTrack, mode)
|
|
|
|
getUserMediaCategoryMixer: (mode) ->
|
|
@getGroupMixer(CategoryGroupIds.UserMedia, mode)
|
|
|
|
|
|
refreshMixer: (mixers) ->
|
|
return null unless mixers? && mixers.mixer?
|
|
|
|
mixer = @getMixer(mixers.mixer.id, mixers.mixer.mode)
|
|
|
|
if mixer?
|
|
oppositeMixer = if mixers.oppositeMixer then @getMixer(mixers.oppositeMixer.id, mixers.oppositeMixer.mode) else null
|
|
{
|
|
mixer: mixer
|
|
vuMixer: @getMixer(mixers.vuMixer.id, mixers.vuMixer.mode)
|
|
muteMixer: @getMixer(mixers.muteMixer.id, mixers.muteMixer.mode)
|
|
oppositeMixer: oppositeMixer
|
|
}
|
|
else
|
|
return null
|
|
|
|
|
|
recordingName: () ->
|
|
@session.recordingName()
|
|
|
|
jamTrackName: () ->
|
|
@session.jamTrackName()
|