* fix bugs

This commit is contained in:
Seth Call 2015-09-17 17:31:00 -05:00
parent 3538e7b0ae
commit b107df2478
24 changed files with 712 additions and 113 deletions

View File

@ -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

View File

@ -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

View File

@ -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())

View File

@ -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;

View File

@ -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

View File

@ -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'))
</div>
</div>
<div className="recording-time start-time">0:00</div>
<div className="recording-time start-time">{this.state.time}</div>
<div className="recording-playback">
<div className="recording-slider"><img src="/assets/content/slider_playcontrols.png" height="16" width="5" /></div>
</div>
@ -179,7 +181,7 @@ mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
getInitialState: () ->
{controls: null, mediaSummary: {}, initializedMetronomeControls: false}
{controls: null, mediaSummary: {}, initializedMetronomeControls: false, time: '0:00'}
tryPrepareMetronome: (metro) ->
if @state.mediaSummary.metronomeOpen && !@state.initializedMetronomeControls

View File

@ -17,17 +17,16 @@ if window.opener?
if accessOpener
SessionActions = window.opener.SessionActions
MediaPlaybackStore = window.opener.MediaPlaybackStore
MixerActions = window.opener.MixerActions
JamTrackActions = window.opener.JamTrackActions
JamTrackMixdownActions = window.opener.JamTrackMixdownActions
#JamTrackMixdownStore = window.opener.JamTrackMixdownStore
JamTrackMixdown = window.opener.JamTrackMixdown
JamTrackStore = window.opener.JamTrackStore
MixerStore = window.opener.MixerStore
SessionStore = window.opener.SessionStore
mixins.push(Reflux.listenTo(MixerStore, 'onMixersChanged'))
mixins.push(Reflux.listenTo(MediaPlaybackStore, 'onMediaStateChanged'))
#mixins.push(Reflux.listenTo(JamTrackMixdownStore, 'onJamTrackMixdownChanged'))
mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
@PopupMediaControls = React.createClass({
@ -51,7 +50,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
recordingName: mixers.recordingName()
jamTrackName: mixers.jamTrackName()
@setState(media: state)
@setState(media: state, downloadingJamTrack: session.downloadingJamTrack)
onMediaStateChanged: (changes) ->
if changes.currentTimeChanged && @root?
@ -70,7 +69,15 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
SessionActions.showNativeMetronomeGui()
getInitialState: () ->
{media: @props.media, time: '0:00', mixdown: @props.mixdown, jamTrackState: @props.jamTrackState, creatingMixdown: false, createMixdownErrors: null}
{
media: @props.media,
mixdown: @props.mixdown,
jamTrackState: @props.jamTrackState,
creatingMixdown: false,
createMixdownErrors: null,
editingMixdownId: null,
downloadingJamTrack: @props.downloadingJamTrack
}
close: () ->
window.close()
@ -87,7 +94,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
mediaType = "Recording"
mediaName = @state.media.recordedTracks[0].recordingName
closeLinkText = 'close recording'
header = `<h3>{mediaType}: {mediaName} ({this.state.time})</h3>`
header = `<h3>{mediaType}: {mediaName}</h3>`
else if @state.jamTrackState.jamTrack?
jamTrack = @state.jamTrackState.jamTrack
mediaType = "JamTrack"
@ -95,20 +102,41 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
closeLinkText = 'CLOSE JAMTRACK'
selectedMixdown = null
if jamTrack.last_mixdown_id
selectedMixdowns = jamTrack.mixdowns.filter((mixdown) -> jamTrack.last_mixdown_id == mixdown.id)
selectedMixdown = selectedMixdowns[0] if selectedMixdowns.length > 0
selectedMixdown = jamTrack.activeMixdown
if selectedMixdown?
jamTrackTypeHeader = 'Custom Mix'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = true
if selectedMixdown.client_state?
switch selectedMixdown.client_state
when 'cant_open'
customMixName = `<h5>L: {selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying_timeout'
customMixName = `<h5>K: {selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'download_fail'
customMixName = `<h5>D: {selectedMixdown.name}<img src="/assets/content/icon-mix-fail@2X.png" /></h5>`
when 'keying'
customMixName = `<h5>K: Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'downloading'
customMixName = `<h5>D: Loading selected mix... <img src="/assets/shared/spinner.gif" /></h5>`
when 'ready'
customMixName = `<h5>{selectedMixdown.name}</h5>`
disabled = false
else
customMixName = `<h5>Creating mixdown... <img src="/assets/shared/spinner.gif" /></h5>`
else
jamTrackTypeHeader = 'Full JamTrack'
logger.debug("STATE!", @state.downloadingJamTrack)
if SessionStore.downloadingJamTrack
downloader = `<img src="/assets/shared/spinner.gif" />`
jamTrackTypeHeader = `<span>Full JamTrack {downloader}</span>`
header = `
<div className="header">
<h3>{mediaType}: {mediaName} ({this.state.time})</h3>
<h3>{mediaType}: {mediaName}</h3>
<h4>{jamTrackTypeHeader}</h4>
{customMixName}
</div>`
@ -116,19 +144,37 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
myMixes = null
if @state.showMyMixes
myMixdowns = []
boundPlayClick = this.jamTrackPlay.bind(this, jamTrack);
active = jamTrack.last_mixdown_id == null
myMixdowns.push `
<div key="full-track" className={classNames({'full-track': true, 'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
Full JamTrack
</div>
<div className="mixdown-actions">
<img src="/assets/content/icon_open@2X.png" className="mixdown-play" onClick={boundPlayClick}/>
</div>
</div>`
for mixdown in jamTrack.mixdowns
boundPlayClick = this.mixdownPlay.bind(this, mixdown);
boundEditClick = this.mixdownEdit.bind(this, mixdown);
boundSaveClick = this.mixdownSave.bind(this, mixdown);
boundDeleteClick = this.mixdownDelete.bind(this, mixdown);
boundErrorClick = this.mixdownError.bind(this, mixdown);
boundEditKeydown = this.onEditKeydown.bind(this, mixdown);
mixdown_package = mixdown.myPackage
active = mixdown.id == jamTrack.last_mixdown_id
editing = mixdown.id == @state.editingMixdownId
# if there is a package, check it's state; otherwise let the user enqueue it
if mixdown_package
logger.debug("MY PACKAGE STATE", mixdown_package.signing_state)
switch mixdown_package.signing_state
when 'QUIET_TIMEOUT'
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
@ -149,22 +195,28 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
else
action = `<img src="/assets/content/icon-mix-fail@2X.png" className="mixdown-play" onClick={boundErrorClick}/>`
if editing
mixdownName = `<input className="edit-name" type="text" defaultValue={mixdown.name} onKeyDown={boundEditKeydown} />`
editIcon = `<img src="/assets/content/icon-save@2X.png" className="mixdown-edit" onClick={boundSaveClick}/>`
else
mixdownName = mixdown.name
editIcon = `<img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>`
myMixdowns.push `
<div key={mixdown.id} className={classNames({'mixdown-display': true, 'active' : active})}>
<div className="mixdown-name">
{mixdown.name}
{mixdownName}
</div>
<div className="mixdown-actions">
{action}
<Img src="/assets/content/icon-edit@2X.png" className="mixdown-edit" onClick={boundEditClick}/>
{editIcon}
<Img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
<img src ="/assets/content/icon-delete@2X.png" className="mixdown-delete" onClick={boundDeleteClick} />
</div>
</div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
myMixes = `<div key="my-mixes" className="my-mixes">{myMixdowns}</div>`
mixControls = null
if @state.showCustomMixes
@ -172,7 +224,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
nameClassData = {field: true}
if @state.createMixdownErrors?
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings'})
errorHtml = context.JK.reactErrors(@state.createMixdownErrors, {name: 'Mix Name', settings: 'Settings', jam_track: 'JamTrack'})
createMixClasses = classNames({'button-orange' : true, 'create-mix-btn' : true, 'disabled' : @state.creatingMixdown})
mixControls = `
@ -278,7 +330,7 @@ mixins.push(Reflux.listenTo(JamTrackStore, 'onJamTrackChanged'))
mediaType = "Audio File"
mediaName = context.JK.getNameOfFile(@state.media.backingTracks[0].shortFilename)
closeLinkText = 'CLOSE AUDIO FILE'
header = `<h3>{mediaType}: {mediaName} ({this.state.time})</h3>`
header = `<h3>{mediaType}: {mediaName}</h3>`
extraControls =
`<div>
<div className="field">
@ -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
})

View File

@ -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(`<SessionJamTrackCategory key="JamTrackCategory" jamTrackName={this.state.jamTrackName} mixers={this.state.mediaCategoryMixer} mode={MIX_MODES.PERSONAL} />`)
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(`<SessionMetronome key="JamTrackMetronome" {...this.state.metronome} location="jam-track" />`)
@ -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

View File

@ -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)

View File

@ -3,6 +3,7 @@ context = window
@JamTrackActions = Reflux.createActions({
open: {}
close: {}
activateNoMixdown: {}
requestSearch: {}
requestFilter: {}
})

View File

@ -19,4 +19,5 @@ context = window
broadcastFailure: {}
broadcastSuccess: {}
broadcastStopped: {}
mixdownActive: {}
})

View File

@ -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

View File

@ -75,6 +75,9 @@ context = window
else
null
jamTrackMixdown: () ->
{ id: @session?.jam_track?.mixdown.id }
jamTrackName: () ->
@session?.jam_track?.name

View File

@ -31,6 +31,7 @@ logger = context.JK.logger
mediaCategoryMixer: mediaCategoryMixer
recordingName: mixers.recordingName()
jamTrackName: mixers.jamTrackName()
jamTrackMixdown: session.jamTrackMixdown()
@inputsChangedProcessed(state) if @inputsChangedProcessed?

View File

@ -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"
}
)

View File

@ -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) =>

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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.

View File

@ -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