diff --git a/ruby/lib/jam_ruby/models/jam_track_mixdown.rb b/ruby/lib/jam_ruby/models/jam_track_mixdown.rb
index f1841e365..3c6a30bc8 100644
--- a/ruby/lib/jam_ruby/models/jam_track_mixdown.rb
+++ b/ruby/lib/jam_ruby/models/jam_track_mixdown.rb
@@ -7,7 +7,7 @@ module JamRuby
belongs_to :user, class_name: "JamRuby::User" # the owner, or purchaser of the jam_track
belongs_to :jam_track, class_name: "JamRuby::JamTrack"
- has_many :jam_track_mixdown_packages, class_name: "JamRuby::JamTrackMixdownPackage"
+ has_many :jam_track_mixdown_packages, class_name: "JamRuby::JamTrackMixdownPackage", order: 'created_at DESC'
has_one :jam_track_right, class_name: 'JamRuby::JamTrackRight', foreign_key: 'last_mixdown_id', inverse_of: :last_mixdown
validates :name, presence: true, length: {maximum: 100}
@@ -19,6 +19,7 @@ module JamRuby
validates_uniqueness_of :name, scope: :user_id
validate :verify_settings
+ validate :verify_max_mixdowns
def self.index(params, user)
jam_track_id = params[:id]
@@ -38,11 +39,19 @@ module JamRuby
end
end
+ def verify_max_mixdowns
+ if self.jam_track && self.user && self.jam_track.mixdowns_for_user(self.user).length >= 5
+ errors.add(:jam_track, 'allowed 5 mixes')
+ end
+ end
+
def verify_settings
# the user has to specify at least at least one tweak to volume, speed, pitch, pan. otherwise there is nothing to do
tweaked = false
+ all_quiet = true
+
parsed = JSON.parse(self.settings)
if parsed["speed"]
tweaked = true
@@ -50,6 +59,8 @@ module JamRuby
if parsed["pitch"]
tweaked = true
end
+
+
if parsed["tracks"]
parsed["tracks"].each do |track|
if track["mute"]
@@ -61,8 +72,17 @@ module JamRuby
if track["pan"] && track["pan"] != 0
tweaked = true
end
+
+ # there is at least one track with volume specified.
+ if !track["mute"] && track["vol"] != 0
+ all_quiet = false
+ end
end
end
+
+ if all_quiet
+ errors.add(:settings, 'are all muted')
+ end
if !tweaked
errors.add(:settings, 'have nothing specified')
end
diff --git a/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb b/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb
index 7cb790360..c52db8f6c 100644
--- a/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb
+++ b/ruby/lib/jam_ruby/resque/jam_track_mixdown_packager.rb
@@ -114,12 +114,14 @@ module JamRuby
vol = 1.0
pan = 0
match = false
+ skipped = false
# is this stem in the altered_tracks list?
altered_tracks.each do |alteration|
if alteration["id"] == stem.id
if alteration["mute"] || alteration["vol"] == 0
- log.debug("leaving out track because muted or 0 volume")
+ log.debug("leaving out track because muted or 0 volume #{alteration.inspect}")
+ skipped = true
next
else
vol = alteration["vol"] || vol
@@ -131,7 +133,8 @@ module JamRuby
end
end
- unless match
+ # if we didn't deliberately skip this one, and if there was no 'match' (meaning user did not specify), then we leave this in unchanged
+ if !skipped && !match
@track_settings << {stem:stem, vol:vol, pan:pan}
end
end
@@ -146,7 +149,7 @@ module JamRuby
# k = f(i) = (i)/(2*MAX_PAN) + 0.5
# so f(MIN_PAN) = -0.5 + 0.5 = 0
- k = ((i * (1.0))/ (2.0 * MAX_PAN )) + 0.5
+ k = ((pan * (1.0))/ (2.0 * MAX_PAN )) + 0.5
l, r = 0
if k == 0
@@ -165,6 +168,7 @@ module JamRuby
puts @settings.inspect
puts @track_count
puts @track_settings
+ puts @track_settings.count
Dir.mktmpdir do |tmp_dir|
@@ -217,6 +221,8 @@ module JamRuby
else
pan_l, pan_r = slider_to_pan(track[:pan])
+ vol = track[:vol]
+
# short
channel_l = pan_l * vol
channel_r = pan_r * vol
@@ -227,7 +233,7 @@ module JamRuby
volumed_file = File.join(tmp_dir, jam_track_track.id + '-volumed.ogg')
- cmd("sox \"#{file}\" \"#{volumed_file}\" remix 1v#{channel_l} 2v#{channel_r}")
+ cmd("sox \"#{file}\" \"#{volumed_file}\" remix 1v#{channel_r} 2v#{channel_l}", 'vol_pan')
track[:volumed_file] = volumed_file
end
@@ -239,21 +245,30 @@ module JamRuby
bump_step(@mixdown_package)
- # sox -m will divide by number of inputs by default. But we purposefully leave out tracks that are mute/no volume (to save downloading/processing time in this job)
- # so we need to tell sox to divide by how many tracks there are as a constant, because this is how the client works today
- #sox -m -v 1/n file1 -v 1/n file2 out
- cmd = "sox -m"
- mix_divide = 1.0/@track_count
- @track_settings.each do |track|
- volumed_file = track[:volumed_file]
- cmd << " -v #{mix_divide} \"#{volumed_file}\""
+ @mix_file = File.join(tmp_dir, "mix.ogg")
+
+ # if there is only one track to mix, we need to skip mixing (sox will barf if you try to mix one file), but still divide by number of tracks
+ if @track_settings.count == 1
+ mix_divide = 1.0/@track_count
+ cmd = "sox -v #{mix_divide} \"#{@track_settings[0][:volumed_file]}\" \"#{@mix_file}\""
+ cmd(cmd, 'volume_adjust')
+ else
+ # sox -m will divide by number of inputs by default. But we purposefully leave out tracks that are mute/no volume (to save downloading/processing time in this job)
+ # so we need to tell sox to divide by how many tracks there are as a constant, because this is how the client works today
+ #sox -m -v 1/n file1 -v 1/n file2 out
+ cmd = "sox -m"
+ mix_divide = 1.0/@track_count
+ @track_settings.each do |track|
+ volumed_file = track[:volumed_file]
+ cmd << " -v #{mix_divide} \"#{volumed_file}\""
+ end
+
+
+ cmd << " \"#{@mix_file}\""
+ cmd(cmd, 'mix_adjust')
end
- @mix_file = File.join(tmp_dir, "mix.ogg")
-
- cmd << " \"#{@mix_file}\""
- cmd(cmd)
end
@@ -335,7 +350,7 @@ module JamRuby
raise 'unknown file_type' if @mixdown_package.file_type != JamTrackMixdownPackage::FILE_TYPE_AAC
- cmd("ffmpeg -i \"#{@speed_mix_file}\" -c:a libfdk_aac -b:a 128k \"#{output}\"")
+ cmd("ffmpeg -i \"#{@speed_mix_file}\" -c:a libfdk_aac -b:a 128k \"#{output}\"", 'convert_aac')
output
end
end
@@ -357,6 +372,25 @@ module JamRuby
py_file = File.join(py_root, "jkcreate.py")
version = @mixdown_package.version
+ right = @mixdown.jam_track.right_for_user(@mixdown.user)
+
+ if @mixdown_package.sample_rate == 48
+ private_key = right.private_key_48
+ else
+ private_key = right.private_key_44
+ end
+
+ unless private_key
+ @error_reason = 'no_private_key'
+ @error_detail = 'user needs to generate JamTrack for given sample rate'
+ raise @error_reason
+ end
+
+ private_key_file = File.join(tmp_dir, 'skey.pem')
+ File.open(private_key_file, 'w') {|f| f.write(private_key) }
+
+ log.debug("PRIVATE KEY")
+ log.debug(private_key)
log.info "Executing python source in #{py_file}, outputting to #{tmp_dir} (#{output})"
cli = "python #{py_file} -D -k #{sku} -p #{Shellwords.escape(tmp_dir)}/pkey.pem -s #{Shellwords.escape(tmp_dir)}/skey.pem #{jam_file_opts} -o #{Shellwords.escape(output)} -t #{Shellwords.escape(title)} -V #{Shellwords.escape(version)}"
@@ -370,12 +404,12 @@ module JamRuby
raise ArgumentError, "Error calling python script: #{err}" if err.present?
raise ArgumentError, "Error calling python script: #{out}" if out && (out.index("No track files specified") || out.index("Cannot find file"))
- private_key = File.read("#{tmp_dir}/skey.pem")
+ private_key = File.read(private_key_file)
end
return output, private_key
end
- def cmd(cmd)
+ def cmd(cmd, type)
log.debug("executing #{cmd}")
@@ -386,6 +420,8 @@ module JamRuby
if result_code == 0
output
else
+ @error_reason = type + "_fail"
+ @error_detail = "#{cmd}, #{output}"
raise "command `#{cmd}` failed."
end
end
diff --git a/web/app/assets/javascripts/download_jamtrack.js.coffee b/web/app/assets/javascripts/download_jamtrack.js.coffee
index 8890e6b87..c4727631d 100644
--- a/web/app/assets/javascripts/download_jamtrack.js.coffee
+++ b/web/app/assets/javascripts/download_jamtrack.js.coffee
@@ -190,7 +190,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
showDownloading: () =>
@logger.debug("showing #{@state.name}")
# while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually
- context.jamClient.JamTrackDownload(@jamTrack.id, context.JK.currentUserId,
+ context.jamClient.JamTrackDownload(@jamTrack.id, null, context.JK.currentUserId,
this.makeDownloadProgressCallback(),
this.makeDownloadSuccessCallback(),
this.makeDownloadFailureCallback())
diff --git a/web/app/assets/javascripts/fakeJamClient.js b/web/app/assets/javascripts/fakeJamClient.js
index 8dfc2ace7..077ad4ced 100644
--- a/web/app/assets/javascripts/fakeJamClient.js
+++ b/web/app/assets/javascripts/fakeJamClient.js
@@ -505,6 +505,9 @@
return 0;
}
+ function GetJamTrackSettings() {
+ return {tracks:[]}
+ }
function SessionGetJamTracksPlayDurationMs() {
return 60000;
}
@@ -1214,6 +1217,7 @@
this.TrackGetChatUsesMusic = TrackGetChatUsesMusic;
this.TrackSetChatUsesMusic = TrackSetChatUsesMusic;
+ this.GetJamTrackSettings = GetJamTrackSettings;
this.JamTrackStopPlay = JamTrackStopPlay;
this.JamTrackPlay = JamTrackPlay;
this.JamTrackIsPlayable = JamTrackIsPlayable;
diff --git a/web/app/assets/javascripts/react-components.js b/web/app/assets/javascripts/react-components.js
index 6b8ef7446..350dce7e9 100644
--- a/web/app/assets/javascripts/react-components.js
+++ b/web/app/assets/javascripts/react-components.js
@@ -1,6 +1,6 @@
//= require react-input-autosize
//= require react-select
-//= require react_rails_img
+// //= require react_rails_img
//= require_directory ./react-components/helpers
//= require_directory ./react-components/actions
//= require ./react-components/stores/AppStore
diff --git a/web/app/assets/javascripts/react-components/MediaControls.js.jsx.coffee b/web/app/assets/javascripts/react-components/MediaControls.js.jsx.coffee
index 34899a6cf..fed32bea6 100644
--- a/web/app/assets/javascripts/react-components/MediaControls.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/MediaControls.js.jsx.coffee
@@ -38,9 +38,11 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
@state.controls.onPlayStopEvent()
else if changes.playbackState == 'play_pause'
@state.controls.onPlayPauseEvent();
- else if changes.positionUpdateChanged
+ if changes.positionUpdateChanged
if @state.controls?
@state.controls.executeMonitor(changes.positionMs, changes.durationMs, changes.isPlaying)
+ if changes.currentTimeChanged
+ @setState({time: changes.time})
onInputsChanged: (sessionMixers) ->
@@ -69,8 +71,8 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
monitorControls: (controls, mediaSummary) ->
- if mediaSummary.mediaOpen
- if mediaSummary.jamTrackOpen
+ if mediaSummary.mediaOpen || mediaSummary.jamTrack?
+ if mediaSummary.jamTrack?
controls.startMonitor(PLAYBACK_MONITOR_MODE.JAMTRACK)
else if mediaSummary.backingTrackOpen
controls.startMonitor(PLAYBACK_MONITOR_MODE.MEDIA_FILE)
@@ -163,7 +165,7 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
-
@@ -313,17 +365,57 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
toggleCustomMixes: (e) ->
e.preventDefault()
+
@setState({showCustomMixes: !@state.showCustomMixes})
mixdownPlay: (mixdown, e) ->
+ @setState({editingMixdownId: null})
+
e.preventDefault()
+
+ if @disableLoading
+ $target = $(e.target)
+ context.JK.prodBubble($target, 'no-change-while-loading', {}, {positions:['left', 'top']})
+ return
+
# make this package the active one
JamTrackMixdownActions.openMixdown(mixdown)
+ jamTrackPlay: (jamtrack, e) ->
+ e.preventDefault()
+ # user wants to select the full track
+
+ if @disableLoading
+ $target = $(e.target)
+ context.JK.prodBubble($target, 'no-change-while-loading', {}, {positions:['left', 'top']})
+ return
+
+ JamTrackActions.activateNoMixdown(jamtrack)
+
+ onEditKeydown: (mixdown, e) ->
+ logger.debug("on edit keydown", e)
+ if e.keyCode == 13 # enter
+ @mixdownSave(mixdown, e)
+ else if e.keyCode == 27 # esc
+ @setState({editingMixdownId: null})
+
mixdownEdit: (mixdown) ->
+ @setState({editingMixdownId: mixdown.id})
+
+ mixdownSave: (mixdown, e) ->
+ e.preventDefault()
+ $input = $(this.getDOMNode()).find('input.edit-name')
+ newValue = $input.val()
+ logger.debug("editing mixdown name to be: " + newValue)
+ JamTrackMixdownActions.editMixdown({id: mixdown.id, name: newValue})
+ @setState({editingMixdownId: null})
mixdownDelete: (mixdown) ->
- JamTrackAction.deleteMixdown(mixdown)
+ if confirm("Delete this custom mix?")
+
+ @setState({editingMixdownId:null})
+ JamTrackMixdownActions.deleteMixdown(mixdown)
+
mixdownError: (mixdown) ->
alert("error")
@@ -339,6 +431,10 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
speed = $root.find('select[name="mix-speed"]').val()
pitch = $root.find('select[name="mix-pitch"]').val()
+ if @state.jamTrackState.jamTrack?.activeMixdown?
+ @setState({createMixdownErrors: {errors: {'Full JamTrack': ['must be selected']}}})
+ return
+
if name == null || name == ''
@setState({createMixdownErrors: {errors: {'Mix Name': ["can't be blank"]}}})
return
@@ -353,7 +449,6 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
else
pitch = parseInt(pitch)
-
mixdown = {jamTrackID: @state.jamTrackState.jamTrack.id, name: name, settings: {speed:speed, pitch: pitch}}
package_settings = {file_type: 'ogg', encrypt_type: 'jkz'}
@@ -419,4 +514,25 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
#offset += 25
window.resizeTo(width, height + offset)
+
+ componentWillUpdate: (nextProps, nextState) ->
+
+ @disableLoading = false
+
+ return unless nextState?
+
+ selectedMixdown = nextState?.jamTrackState?.jamTrack?.activeMixdown
+
+ mixdownDownloading = false
+ if selectedMixdown?
+ switch selectedMixdown.client_state
+ when 'keying'
+ mixdownDownloading = true
+ when 'downloading'
+ mixdownDownloading = true
+
+
+ @disableLoading = SessionStore.downloadingJamTrack || mixdownDownloading
+
+
})
\ No newline at end of file
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 f800302c8..afb9a13f2 100644
--- a/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/SessionMediaTracks.js.jsx.coffee
@@ -15,9 +15,18 @@ ChannelGroupIds = context.JK.ChannelGroupIds
Reflux.listenTo(@JamTrackStore, "onJamTrackStateChanged")]
onJamTrackStateChanged: (jamTrackState) ->
- if jamTrackState.opened
+ if jamTrackState.fullTrackActivated || jamTrackState.opened && jamTrackState.jamTrack.activeMixdown == null
@loadJamTrack(jamTrackState.jamTrack)
else if jamTrackState.closed
+ logger.debug("SessionMediaTracks: jamtrack has been closed")
+
+ if @state.downloadJamTrack?
+ logger.debug("closing DownloadJamTrack widget")
+ @state.downloadJamTrack.root.remove()
+ @state.downloadJamTrack.destroy()
+ SessionActions.downloadingJamTrack(false)
+ @setState({downloadJamTrack: null})
+
SessionActions.closeMedia(true)
#inputsChangedProcessed: (state) ->
@@ -264,8 +273,8 @@ ChannelGroupIds = context.JK.ChannelGroupIds
# All the JamTracks
mediaTracks.push(``)
-
- if @state.metronome?
+ # show metronome only if it's a full jamtrack
+ if @state.metronome? && @state.jamTrackMixdown.id == null
@state.metronome.mode = MIX_MODES.PERSONAL
mediaTracks.push(``)
@@ -338,7 +347,7 @@ ChannelGroupIds = context.JK.ChannelGroupIds
unless @childWindow?
logger.debug("opening media control window")
@childWindow = window.open("/popups/media-controls", 'Media Controls', 'scrollbars=yes,toolbar=no,status=no,height=155,width=350')
- @childWindow.PopupProps = {media: @state, jamTrackState: context.JamTrackStore.getState()}
+ @childWindow.PopupProps = {media: @state, jamTrackState: context.JamTrackStore.getState(), downloadingJamTrack: context.SessionStore.downloadingJamTrack }
else
if @childWindow?
@childWindow.DontAutoCloseMedia = true
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 63c02f9bb..e14db1c14 100644
--- a/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee
+++ b/web/app/assets/javascripts/react-components/SessionTrackVolumeHover.js.jsx.coffee
@@ -113,9 +113,10 @@ ptrCount = 0
context.JK.checkbox($checkbox)
$checkbox.on('ifChanged', this.handleMuteCheckbox);
+
# using iCheck causes a 'ifChanged' event, so we need to swallow this up
@iCheckMaint = true
- if muteMixer.mute
+ if muteMixer?.mute
$checkbox.iCheck('check').attr('checked', true)
else
$checkbox.iCheck('uncheck').attr('checked', false)
@@ -139,7 +140,7 @@ ptrCount = 0
# using iCheck causes a 'ifChanged' event, so we need to swallow this up
@iCheckMaint = true
- if muteMixer.mute
+ if muteMixer?.mute
$checkbox.iCheck('check').attr('checked', true)
else
$checkbox.iCheck('uncheck').attr('checked', false)
diff --git a/web/app/assets/javascripts/react-components/actions/JamTrackActions.js.coffee b/web/app/assets/javascripts/react-components/actions/JamTrackActions.js.coffee
index 0c122c4c6..1b5e6a9ae 100644
--- a/web/app/assets/javascripts/react-components/actions/JamTrackActions.js.coffee
+++ b/web/app/assets/javascripts/react-components/actions/JamTrackActions.js.coffee
@@ -3,6 +3,7 @@ context = window
@JamTrackActions = Reflux.createActions({
open: {}
close: {}
+ activateNoMixdown: {}
requestSearch: {}
requestFilter: {}
})
diff --git a/web/app/assets/javascripts/react-components/actions/SessionActions.js.coffee b/web/app/assets/javascripts/react-components/actions/SessionActions.js.coffee
index 634e7d419..d9d31fada 100644
--- a/web/app/assets/javascripts/react-components/actions/SessionActions.js.coffee
+++ b/web/app/assets/javascripts/react-components/actions/SessionActions.js.coffee
@@ -19,4 +19,5 @@ context = window
broadcastFailure: {}
broadcastSuccess: {}
broadcastStopped: {}
+ mixdownActive: {}
})
\ No newline at end of file
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 e4d46e2b6..c1fe26514 100644
--- a/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee
+++ b/web/app/assets/javascripts/react-components/helpers/MixerHelper.js.coffee
@@ -299,6 +299,7 @@ MIX_MODES = context.JK.MIX_MODES;
jamTrackMixers = @jamTrackMixers.slice();
jamTracks = []
jamTrackName = null;
+ jamTrackMixdown = {id: null}
if @session.isPlayingRecording()
# only return managed mixers for recorded backing tracks
@@ -308,6 +309,7 @@ MIX_MODES = context.JK.MIX_MODES;
# only return un-managed (ad-hoc) mixers for normal backing tracks
jamTracks = @session.jamTracks()
jamTrackName = @session.jamTrackName()
+ jamTrackMixdown = @session.jamTrackMixdown()
# 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
@@ -315,55 +317,90 @@ MIX_MODES = context.JK.MIX_MODES;
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
+ # Are we opening a mixdown, or a full track?
+ if jamTrackMixdown.id?
+ logger.debug("MixerHelper: mixdown is active. id: #{jamTrackMixdown.id}")
+ if jamTrackMixers.length == 0
noCorrespondingTracks = true
- logger.error("could not correlate jam tracks", jamTrackMixers, jamTracks)
+ logger.error("could not correlate mixdown tracks", jamTrackMixers, jamTrackMixdown)
@app.notify({
- title: "Unable to Open JamTrack",
+ title: "Unable to Open Custom Mix",
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
-
- instrumentName = oneOfTheTracks.instrument.description
-
- if part?
- trackName = "#{instrumentName}: #{part}"
+ else if jamTrackMixers.length > 1
+ logger.warn("ignoring wrong amount of mixers for JamTrack in mixdown mode")
+ return _jamTracks
else
- trackName = instrumentName
- data =
- name: jamTrackName
- trackName: trackName
- part: part
- isOpener: isOpener
- instrumentIcon: instrumentIcon
- track: oneOfTheTracks
- mixers: @mediaMixers(mixer, isOpener)
+ instrumentIcon = context.JK.getInstrumentIcon24('other')
+ part = null
+ instrumentName = 'Custom Mix'
+ trackName = 'Custom Mix'
- _jamTracks.push(data)
+ data =
+ name: jamTrackName
+ trackName: trackName
+ part: part
+ isOpener: isOpener
+ instrumentIcon: instrumentIcon
+ track: jamTrackMixdown
+ mixers: @mediaMixers(jamTrackMixers[0], isOpener)
+
+ _jamTracks.push(data)
+ else
+ logger.debug("MixerHelper: full jamtrack is active")
+
+ 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
+
+ instrumentName = oneOfTheTracks.instrument.description
+
+ if part?
+ trackName = "#{instrumentName}: #{part}"
+ else
+ trackName = instrumentName
+
+ data =
+ name: jamTrackName
+ trackName: trackName
+ part: part
+ isOpener: isOpener
+ instrumentIcon: instrumentIcon
+ track: oneOfTheTracks
+ mixers: @mediaMixers(mixer, isOpener)
+
+ _jamTracks.push(data)
_jamTracks
diff --git a/web/app/assets/javascripts/react-components/helpers/SessionHelper.js.coffee b/web/app/assets/javascripts/react-components/helpers/SessionHelper.js.coffee
index 1cb5023c7..e9d88c04a 100644
--- a/web/app/assets/javascripts/react-components/helpers/SessionHelper.js.coffee
+++ b/web/app/assets/javascripts/react-components/helpers/SessionHelper.js.coffee
@@ -75,6 +75,9 @@ context = window
else
null
+ jamTrackMixdown: () ->
+ { id: @session?.jam_track?.mixdown.id }
+
jamTrackName: () ->
@session?.jam_track?.name
diff --git a/web/app/assets/javascripts/react-components/mixins/SessionMediaTracksMixin.js.coffee b/web/app/assets/javascripts/react-components/mixins/SessionMediaTracksMixin.js.coffee
index 92dc025f7..6297c7be0 100644
--- a/web/app/assets/javascripts/react-components/mixins/SessionMediaTracksMixin.js.coffee
+++ b/web/app/assets/javascripts/react-components/mixins/SessionMediaTracksMixin.js.coffee
@@ -31,6 +31,7 @@ logger = context.JK.logger
mediaCategoryMixer: mediaCategoryMixer
recordingName: mixers.recordingName()
jamTrackName: mixers.jamTrackName()
+ jamTrackMixdown: session.jamTrackMixdown()
@inputsChangedProcessed(state) if @inputsChangedProcessed?
diff --git a/web/app/assets/javascripts/react-components/stores/JamTrackStore.js.coffee b/web/app/assets/javascripts/react-components/stores/JamTrackStore.js.coffee
index 997f311d9..c92666e2e 100644
--- a/web/app/assets/javascripts/react-components/stores/JamTrackStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/JamTrackStore.js.coffee
@@ -30,14 +30,12 @@ JamTrackActions = @JamTrackActions
return unless @jamTrack?
- sampleRate = context.jamClient.GetSampleRate()
- sampleRate = if sampleRate == 48 then 48 else 44
for mixdown in @jamTrack.mixdowns
myPackage = null
for mixdown_package in mixdown.packages
- if mixdown_package.file_type == 'ogg' && mixdown_package.encrypt_type == 'jkz' && mixdown_package.sample_rate == sampleRate
+ if mixdown_package.file_type == 'ogg' && mixdown_package.encrypt_type == 'jkz' && mixdown_package.sample_rate == @sampleRate
myPackage = mixdown_package
break
@@ -95,22 +93,162 @@ JamTrackActions = @JamTrackActions
@changed()
break
+ # this drives the state engine required to get a Mixdown from 'available on the server' to
+ manageMixdownSynchronization: () ->
+
+ @jamTrack.activeMixdown = null if @jamTrack
+
+ # let's see if we have a mixdown active?
+
+ if !@jamTrack?.last_mixdown_id?
+ logger.debug("JamTrackStore: no mixdown active")
+ @clearMixdownTimers()
+ return
+
+ for mixdown in @jamTrack.mixdowns
+ if mixdown.id == @jamTrack.last_mixdown_id
+ @jamTrack.activeMixdown = mixdown
+ logger.debug("JamTrackStore: mixdown active:", mixdown)
+ break
+
+ if @jamTrack.activeMixdown?
+
+ # if we don't have this on the server yet, don't engage the rest of this logic...
+ return if @jamTrack.activeMixdown?.myPackage?.signing_state != 'SIGNED'
+
+ fqId = "#{@jamTrack.id}_#{@jamTrack.activeMixdown.id}-#{@sampleRate}"
+ @trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
+
+ logger.debug("JamTrackStore: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail)
+
+ # first check if the version is not the same; if so, invalidate.
+
+ if @trackDetail.version? && @jamTrack.activeMixdown.myPackage?
+ if @jamTrack.activeMixdown.myPackage.version != @trackDetail.version
+ logger.info("JamTrackStore: JamTrack Mixdown on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.activeMixdown.myPackage.version}. Invalidating")
+ context.jamClient.InvalidateJamTrack(fqId)
+ @trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
+
+ if @trackDetail.version?
+ logger.error("after invalidating package, the version is still wrong!")
+ throw "after invalidating package, the version is still wrong!"
+
+ if @jamTrack.activeMixdown.client_state == 'cant_open'
+ logger.debug(" skipping state check because of earlier 'cant_open'. user should hit retry. ")
+ return
+
+ if @jamTrack.activeMixdown.client_state == 'download_fail'
+ logger.debug("skipping state check because of earlier 'download_fail'. user should hit retry. ")
+ return
+
+ if @jamTrack.activeMixdown.client_state == 'downloading'
+ logger.debug("skipping state check because we are downloading")
+
+ switch @trackDetail.key_state
+ when 'pending'
+ @attemptKeying()
+ when 'not authorized'
+ # TODO: if not authorized, do we need to re-initiate a keying attempt?
+ @attemptKeying()
+ when 'ready'
+ if @jamTrack.activeMixdown.client_state != 'ready'
+
+ @clearMixdownTimers()
+ @jamTrack.activeMixdown.client_state = 'ready'
+
+ # now load it:
+ # JamTrackPlay means 'load'
+ logger.debug("JamTrackStore: loading mixdown")
+ context.jamClient.JamTrackStopPlay();
+ result = context.jamClient.JamTrackPlay(fqId);
+ if !result
+ @jamTrack.activeMixdown.client_state = 'cant_open'
+ @app.notify(
+ {
+ title: "Mixdown Can Not Open",
+ text: "Unable to open your JamTrack Mixdown. Please contact support@jamkazam.com"
+ }
+ , null, true)
+
+ when 'unknown'
+ if @jamTrack.activeMixdown.client_state != 'downloading'
+ @jamTrack.activeMixdown.client_state = 'downloading'
+ logger.debug("JamTrackStore: initiating download of mixdown")
+ context.jamClient.JamTrackDownload(@jamTrack.id, @jamTrack.activeMixdown.id, context.JK.currentUserId,
+ this.makeDownloadProgressCallback(),
+ this.makeDownloadSuccessCallback(),
+ this.makeDownloadFailureCallback())
+ else
+ logger.debug("JamTrackStore: already downloading")
+
+ attemptKeying: () ->
+ if @keyCheckTimeout?
+ logger.debug("JamTrackStore: attemptKeying: skipping because already keying")
+ return
+ else if @jamTrack.activeMixdown.client_state == 'keying_timeout'
+ # if we have timed out keying, we shouldn't automatically retry
+ logger.debug("JamTrackStore: attempKeying: skipping because we have timed out before and user hasn't requested RETRY")
+ return
+ else
+ @keyCheckTimeout = setTimeout(@onKeyCheckTimeout, 10000)
+ @keyCheckoutInterval = setInterval(@checkOnKeying, 1000)
+ @jamTrack.activeMixdown.client_state = 'keying'
+ logger.debug("JamTrackStore: initiating keying requested")
+ context.jamClient.JamTrackKeysRequest()
+
+ onKeyCheckTimeout: () ->
+ @keyCheckTimeout = null
+ clearInterval(@keyCheckoutInterval)
+ @keyCheckoutInterval = null
+
+ if @jamTrack?.activeMixdown?
+ @jamTrack.activeMixdown.client_state = 'keying_timeout'
+ @changed()
+
+ checkOnKeying: () ->
+ @manageMixdownSynchronization()
+
+ # if we exit keying state, we can clear our timers and poke state
+ if @jamTrack.activeMixdown.client_state != 'keying'
+ @clearMixdownTimers()
+ @changed()
+
+
+ # clear out any timer/watcher stuff
+ clearMixdownTimers: () ->
+ logger.debug("JamTrackStore: clearing mixdown timers", @keyCheckTimeout, @keyCheckoutInterval)
+ clearTimeout(@keyCheckTimeout) if @keyCheckTimeout?
+ clearInterval(@keyCheckoutInterval) if @keyCheckoutInterval?
+ @keyCheckTimeout = null
+ @keyCheckoutInterval = null
changed: () ->
@pickMyPackage()
@manageWatchedMixdowns()
+ @manageMixdownSynchronization()
- @state = {jamTrack: @jamTrack, opened: @previous == null && @jamTrack != null, closed: @previous != null && @jamTrack == null}
+ @state = {
+ jamTrack: @jamTrack,
+ opened: @previous == null && @jamTrack != null,
+ closed: @previous != null && @jamTrack == null,
+ fullTrackActivated: @previousMixdown != null && @jamTrack?.activeMixdown == null}
@previous = @jamTrack
+ @previousMixdown = @jamTrack?.activeMixdown
this.trigger(@state)
+
onOpen: (jamTrack) ->
if @jamTrack?
@app.notify({text: 'Unable to open JamTrack because another one is already open.'})
return
@jamTrack = jamTrack
+
+ # we can cache this because you can't switch gear while in a session (and possible change sample rate!)
+ sampleRate = context.jamClient.GetSampleRate()
+ @sampleRate = if sampleRate == 48 then 48 else 44
+
@changed()
onClose: () ->
@@ -138,7 +276,18 @@ JamTrackActions = @JamTrackActions
requested
onCreateMixdown: (mixdown, package_settings, done, fail) ->
+
+ volumeSettings = context.jamClient.GetJamTrackSettings();
+
+ track_settings = []
+
+ for track in volumeSettings.tracks
+ track_settings.push({id: track.id, pan: track.pan, vol: track.vol_l, mute: track.mute})
+
+ mixdown.settings.tracks = track_settings
+
logger.debug("creating mixdown", mixdown, package_settings)
+
rest.createMixdown(mixdown)
.done((created) =>
@@ -149,9 +298,7 @@ JamTrackActions = @JamTrackActions
package_settings.id = created.id
# we have to determine sample rate here, in the store, because child windows don't have access to jamClient
- sampleRate = context.jamClient.GetSampleRate()
- sampleRate = if sampleRate == 48 then 48 else 44
- package_settings.sample_rate = sampleRate
+ package_settings.sample_rate = @sampleRate
rest.enqueueMixdown(package_settings)
.done((enqueued) =>
@@ -160,7 +307,7 @@ JamTrackActions = @JamTrackActions
done(enqueued)
)
.fail((jqxhr) =>
- @app.layout.notify({title:'Unable to Package Mixdown', text: 'You can push the RETRY button.'})
+ @app.layout.notify({title:'Unable to Create Custom Mix', text: 'You can push the RETRY button.'})
fail(jqxhr)
)
)
@@ -171,9 +318,27 @@ JamTrackActions = @JamTrackActions
onEditMixdown: (mixdown) ->
logger.debug("editing mixdown", mixdown)
+ rest.editMixdown(mixdown)
+ .done((updatedMixdown) =>
+ logger.debug("edited mixdown")
+ @updateMixdown(updatedMixdown)
+ ).fail((jqxhr) =>
+ @app.layout.notify({title:'Unable to Edit Custom Mix', text: 'The server was unable to edit this mix.'})
+ )
+
onDeleteMixdown: (mixdown) ->
logger.debug("deleting mixdown", mixdown)
+ rest.deleteMixdown(mixdown)
+ .done(() =>
+ logger.debug("deleted mixdown")
+
+ @deleteMixdown(mixdown)
+ )
+ .fail((jqxhr) =>
+ @app.layout.notify({title:'Unable to Deleted Custom Mix', text: 'The server was unable to delete this mix.'})
+ )
+
onOpenMixdown: (mixdown) ->
logger.debug("opening mixdown", mixdown)
@@ -182,12 +347,35 @@ JamTrackActions = @JamTrackActions
.done((edited) =>
logger.debug("marked mixdown as active")
@jamTrack = edited
+
+ # unload any currently loaded JamTrack
+ context.jamClient.JamTrackStopPlay();
+
@changed()
+
+ SessionActions.mixdownActive(mixdown)
)
.fail((jqxhr) =>
@app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
)
+ onActivateNoMixdown: (jamTrack) ->
+ logger.debug("activating no mixdown")
+
+ rest.markMixdownActive({id: @jamTrack.id, mixdown_id: null})
+ .done((edited) =>
+ logger.debug("marked JamTrack as active")
+
+ @jamTrack = edited
+ @changed()
+
+ SessionActions.mixdownActive({id:null})
+ )
+ .fail((jqxhr) =>
+ @app.layout.notify({title:'Unable to Edit Mixdown', text: 'Unable to mark this mixdown as active.'})
+ )
+
+
onCloseMixdown: (mixdown) ->
logger.debug("closing mixdown", mixdown)
@@ -208,6 +396,41 @@ JamTrackActions = @JamTrackActions
else
logger.warn("no jamtrack to add mixdown to in JamTrackStore", mixdown)
+ deleteMixdown: (mixdown) ->
+ if @jamTrack?
+ logger.debug("deleting mixdown from JamTrackStore", mixdown)
+ index = null
+ for matchMixdown, i in @jamTrack.mixdowns
+ if mixdown.id == matchMixdown.id
+ index = i
+ if index?
+ @jamTrack.mixdowns.splice(index, 1)
+
+ if @jamTrack.activeMixdown?.id == mixdown.id
+ @onActivateNoMixdown(@jamTrack)
+
+ @changed()
+ else
+ logger.warn("unable to find mixdown to delete in JamTrackStore", mixdown)
+ else
+ logger.warn("no jamtrack to delete mixdown for in JamTrackStore", mixdown)
+
+ updateMixdown: (mixdown) ->
+ if @jamTrack?
+ logger.debug("editing mixdown from JamTrackStore", mixdown)
+ index = null
+ for matchMixdown, i in @jamTrack.mixdowns
+ if mixdown.id == matchMixdown.id
+ index = i
+ if index?
+ @jamTrack.mixdowns[index] = mixdown
+
+ @changed()
+ else
+ logger.warn("unable to find mixdown to edit in JamTrackStore", mixdown)
+ else
+ logger.warn("no jamtrack to edit mixdown for in JamTrackStore", mixdown)
+
addOrUpdatePackage: (mixdown_package) ->
if @jamTrack?
added = false
@@ -237,5 +460,50 @@ JamTrackActions = @JamTrackActions
else
logger.warn("no mixdown to add package to in JamTrackStore", mixdown_package)
+
+ updateDownloadProgress: () ->
+
+ if @bytesReceived? and @bytesTotal?
+ progress = "#{Math.round(@bytesReceived/@bytesTotal * 100)}%"
+ else
+ progress = '0%'
+
+ #@root.find('.state-downloading .progress').text(progress)
+
+ downloadProgressCallback: (bytesReceived, bytesTotal) ->
+ logger.debug("download #{bytesReceived}/#{bytesTotal}")
+
+ @bytesReceived = Number(bytesReceived)
+ @bytesTotal = Number(bytesTotal)
+
+ # the reason this timeout is set is because, without it,
+ # we observe that the client will hang. So, if you remove this timeout, make sure to test with real client
+ setTimeout(this.updateDownloadProgress, 100)
+
+ downloadSuccessCallback: (updateLocation) ->
+ # is the package loadable yet?
+ logger.debug("JamTrackStore: download complete - on to keying")
+ @attemptKeying()
+ @changed()
+
+ downloadFailureCallback: (errorMsg) ->
+
+ if @jamTrack?.activeMixdown?
+ @jamTrack.activeMixdown.client_state = 'download_fail'
+ @changed()
+
+ # makes a function name for the backend
+ makeDownloadProgressCallback: () ->
+ "JamTrackStore.downloadProgressCallback"
+
+ # makes a function name for the backend
+ makeDownloadSuccessCallback: () ->
+ "JamTrackStore.downloadSuccessCallback"
+
+ # makes a function name for the backend
+ makeDownloadFailureCallback: () ->
+ "JamTrackStore.downloadFailureCallback"
+
+
}
)
\ No newline at end of file
diff --git a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
index f56828030..b0bbb0ac7 100644
--- a/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
+++ b/web/app/assets/javascripts/react-components/stores/SessionStore.js.coffee
@@ -53,6 +53,11 @@ VideoActions = @VideoActions
RecordingActions.initModel(@recordingModel)
@helper = new context.SessionHelper(@app, @currentSession, @participantsEverSeen, @isRecording, @downloadingJamTrack)
+ onMixdownActive: (mixdown) ->
+ if @currentSession?.jam_track?
+ @currentSession.jam_track.mixdown = mixdown
+ @issueChange()
+
onVideoChanged: (@videoState) ->
@@ -241,6 +246,7 @@ VideoActions = @VideoActions
rest.closeJamTrack({id: @currentSessionId})
.done(() =>
+ @downloadingJamTrack = false
@refreshCurrentSession(true)
)
.fail((jqXHR) =>
diff --git a/web/app/assets/stylesheets/minimal/media_controls.css.scss b/web/app/assets/stylesheets/minimal/media_controls.css.scss
index 4e16538c8..960f5b4ab 100644
--- a/web/app/assets/stylesheets/minimal/media_controls.css.scss
+++ b/web/app/assets/stylesheets/minimal/media_controls.css.scss
@@ -55,11 +55,29 @@ body.media-controls-popup.popup {
margin-top:15px;
font-size:12px;
font-weight:normal;
+
+ span {
+ vertical-align:middle;
+ }
+ img {
+ vertical-align:middle;
+ margin-left:5px;
+ height:16px;
+ }
}
h5 {
font-size:12px;
font-weight:normal;
+
+ span {
+ vertical-align:middle;
+ }
+ img {
+ vertical-align:middle;
+ margin-left:5px;
+ height:16px;
+ }
}
}
@@ -105,6 +123,7 @@ body.media-controls-popup.popup {
background-color:#2c2c2c;
@include border_box_sizing;
border-spacing:7px;
+ text-align: left;
&.active {
background-color:#44423f;
diff --git a/web/app/controllers/api_jam_track_mixdowns_controller.rb b/web/app/controllers/api_jam_track_mixdowns_controller.rb
index ca830ef47..2da9c9ff3 100644
--- a/web/app/controllers/api_jam_track_mixdowns_controller.rb
+++ b/web/app/controllers/api_jam_track_mixdowns_controller.rb
@@ -18,22 +18,27 @@ class ApiJamTrackMixdownsController < ApiController
end
def show
- JamTrack.find()
@jam_track_mixdown = JamTrackMixdown.find(params[:id])
end
- def update
+ def delete
@jam_track_mixdown = JamTrackMixdown.find(params[:id])
- @jam_track_mixdown.name = params[:name] if params[:name]
- @jam_track_mixdown.description = params[:description] if params[:description]
- @jam_track_mixdown.save
+ @jam_track_mixdown.destroy
+ render json: {}, status:204
+ end
+
+ def update
+ @mixdown = JamTrackMixdown.find(params[:id])
+ @mixdown.name = params[:name] if params[:name]
+ @mixdown.description = params[:description] if params[:description]
+ @mixdown.save
if params[:active]
- @jam_track_right.last_mixdown = @jam_track_mixdown
+ @jam_track_right.last_mixdown = @mixdown
@jam_track_right.save
end
- if @jam_track_mixdown.errors.any?
- respond_with_model(@jam_track_mixdown)
+ if @mixdown.errors.any?
+ respond_with_model(@mixdown)
return
else
diff --git a/web/app/controllers/api_jam_tracks_controller.rb b/web/app/controllers/api_jam_tracks_controller.rb
index 619ad3459..55fe58ce7 100644
--- a/web/app/controllers/api_jam_tracks_controller.rb
+++ b/web/app/controllers/api_jam_tracks_controller.rb
@@ -153,7 +153,10 @@ class ApiJamTracksController < ApiController
end
def keys
+ puts "Keys"
+ puts "--------------------------"
jamtrack_holder = params[:jamtracks]
+ puts jamtrack_holder.inspect
unless jamtrack_holder.kind_of?(Hash)
render :json => {message: 'jamtracks parameter must be an hash'}, :status => 422
@@ -169,20 +172,49 @@ class ApiJamTracksController < ApiController
# jamtracks come in the form id-44 or id-48, so we need to do a little extra parsing
+ # mixdowns come in the form id_mixid-44 or id_mixid-48, so we also need to handle that
jamtrack_ids = Set.new
jamtracks_fq_ids = Set.new
+ jamtrack_mixdowns = {}
+
jamtracks.each do |jamtrack|
rindex = jamtrack.rindex('-')
if rindex
id = jamtrack[0..(rindex-1)]
- jamtrack_ids << id
+
+ # let's see if a mixid is in this ID
+ rindex = id.rindex('_')
+
+ if rindex
+ # ok, this is id_mixid-44 format; so we need to parse again for the ID
+ just_id = jamtrack[0..(rindex-1)]
+ sample_rate = jamtrack[-2..-1]
+
+ jamtrack_ids << just_id
+
+ simulated_fq_id = "#{just_id}-#{sample_rate}"
+ mixdown_info = jamtrack_mixdowns[simulated_fq_id]
+
+ unless mixdown_info
+ mixdown_info = []
+ jamtrack_mixdowns[simulated_fq_id] = mixdown_info
+ end
+ mixdown_info << id
+
+ else
+ jamtrack_ids << id
+ end
+
+
jamtracks_fq_ids << jamtrack # includes sample rate
end
end
@jam_tracks = JamTrackRight.list_keys(current_user, jamtrack_ids)
@jamtracks_fq_ids = jamtracks_fq_ids
+ @jamtrack_mixdowns = jamtrack_mixdowns
+ puts "jamtrack_mixdowns #{jamtrack_mixdowns}"
end
private
diff --git a/web/app/views/api_jam_track_mixdowns/show_package.rabl b/web/app/views/api_jam_track_mixdowns/show_package.rabl
index 9813b688b..b4899b037 100644
--- a/web/app/views/api_jam_track_mixdowns/show_package.rabl
+++ b/web/app/views/api_jam_track_mixdowns/show_package.rabl
@@ -1,3 +1,3 @@
object @package
-attributes :id, :jam_track_mixdown_id, :file_type, :sample_rate, :encrypt_type, :error_count, :error_reason, :error_detail, :signing_state, :packaging_steps, :current_packaging_step
+attributes :id, :jam_track_mixdown_id, :file_type, :sample_rate, :encrypt_type, :error_count, :error_reason, :error_detail, :signing_state, :packaging_steps, :current_packaging_step, :version
diff --git a/web/app/views/api_jam_tracks/keys.rabl b/web/app/views/api_jam_tracks/keys.rabl
index a5cd9d471..2b482e44a 100644
--- a/web/app/views/api_jam_tracks/keys.rabl
+++ b/web/app/views/api_jam_tracks/keys.rabl
@@ -17,7 +17,35 @@ node do |jam_track|
private: jam_track['private_key_48'],
error: jam_track['private_key_48'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
}
+ end
+
+ # now include mixdown info
+ mixdowns_44 = []
+ mixdown_info = @jamtrack_mixdowns[id]
+ if mixdown_info
+ mixdown_info.each do |mixdown_id|
+ mixdowns_44 << {
+ id: mixdown_id + '-44',
+ private: jam_track['private_key_44'],
+ error: jam_track['private_key_44'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
+ }
end
+ end
+ result['mixdowns_44'] = mixdowns_44
+
+ # now include mixdown info
+ mixdowns_48 = []
+ mixdown_info = @jamtrack_mixdowns[id + '-48']
+ if mixdown_info
+ mixdown_info.each do |mixdown_id|
+ mixdowns_48 << {
+ id: mixdown_id + '-48',
+ private: jam_track['private_key_48'],
+ error: jam_track['private_key_48'] ? nil : ( jam_track['jam_track_right_id'] ? 'no_key' : 'not_purchased' )
+ }
+ end
+ end
+ result['mixdowns_48'] = mixdowns_48
result
end
\ No newline at end of file
diff --git a/web/app/views/api_music_sessions/show.rabl b/web/app/views/api_music_sessions/show.rabl
index 3472f18a3..d5afc2a02 100644
--- a/web/app/views/api_music_sessions/show.rabl
+++ b/web/app/views/api_music_sessions/show.rabl
@@ -81,6 +81,12 @@ else
child({:jam_track => :jam_track}, :if => lambda { |music_session| music_session.users.exists?(current_user) }) {
attributes :id, :name, :description
+ node :mixdown do |jam_track|
+ right = jam_track.right_for_user(User.find(@music_session.jam_track_initiator_id))
+
+ {id: right ? right.last_mixdown_id : nil}
+ end
+
child(:jam_track_tracks => :tracks) {
attributes :id, :part, :instrument, :track_type
}
diff --git a/web/app/views/clients/_help.html.slim b/web/app/views/clients/_help.html.slim
index 721a5f191..6823d0b45 100644
--- a/web/app/views/clients/_help.html.slim
+++ b/web/app/views/clients/_help.html.slim
@@ -349,4 +349,7 @@ script type="text/template" id="template-help-ftue-video-disable"
li If you know you never want to see anyone else's video.
li If you are experiencing technical problems with others send you video.
+script type="text/template" id="template-help-no-change-while-loading"
+ span Certain actions are disabled while a track is being loaded.
+
diff --git a/web/config/routes.rb b/web/config/routes.rb
index 7d08ac47d..cef2252c1 100644
--- a/web/config/routes.rb
+++ b/web/config/routes.rb
@@ -257,6 +257,7 @@ SampleApp::Application.routes.draw do
match '/mixdowns/:id' => 'api_jam_track_mixdowns#show', :via => :get
match '/mixdowns/:id' => 'api_jam_track_mixdowns#update', :via => :post
match '/mixdowns' => 'api_jam_track_mixdowns#create', :via => :post
+ match '/mixdowns/:id' => 'api_jam_track_mixdowns#delete', :via => :delete
match '/mixdown_packages/:id' => 'api_jam_track_mixdowns#show_package', :via => :get