diff --git a/db/manifest b/db/manifest index 9188feab3..93be92198 100755 --- a/db/manifest +++ b/db/manifest @@ -269,4 +269,5 @@ jam_track_playable_plays.sql shopping_cart_anonymous.sql user_reuse_card_and_reedem.sql jam_track_id_to_varchar.sql -drop_position_unique_jam_track.sql \ No newline at end of file +drop_position_unique_jam_track.sql +recording_client_metadata.sql \ No newline at end of file diff --git a/db/up/recording_client_metadata.sql b/db/up/recording_client_metadata.sql new file mode 100644 index 000000000..f800f234a --- /dev/null +++ b/db/up/recording_client_metadata.sql @@ -0,0 +1 @@ +ALTER TABLE recordings ADD COLUMN timeline JSON; \ No newline at end of file diff --git a/ruby/lib/jam_ruby/models/mix.rb b/ruby/lib/jam_ruby/models/mix.rb index be833326c..d5c7bd364 100644 --- a/ruby/lib/jam_ruby/models/mix.rb +++ b/ruby/lib/jam_ruby/models/mix.rb @@ -136,23 +136,43 @@ module JamRuby def manifest one_day = 60 * 60 * 24 + jam_track_offset = 0 + + if recording.timeline + recording_timeline_data = JSON.parse(recording.timeline) + + recording_start_time = recording_timeline_data["recording_start_time"] + jam_track_play_start_time = recording_timeline_data["jam_track_play_start_time"] + jam_track_recording_start_play_offset = recording_timeline_data["jam_track_recording_start_play_offset"] + + jam_track_offset = -jam_track_recording_start_play_offset + end + manifest = { "files" => [], "timeline" => [] } mix_params = [] + + # this 'pick limiter' logic will ensure that we set a limiter on the 1st recorded_track we come across. + pick_limiter = false + if recording.is_jamtrack_recording? + # we only use the limiter feature if this is a JamTrack recording + # by setting this to true, the 1st recorded_track in the database will be the limiter + pick_limiter = true + end + recording.recorded_tracks.each do |recorded_track| - manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 } - mix_params << { "level" => 100, "balance" => 0 } - # change to 1.0 when ready to deploy new audiomixer + manifest["files"] << { "filename" => recorded_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0, limiter:pick_limiter } + pick_limiter = false + mix_params << { "level" => 1.0, "balance" => 0 } end recording.recorded_backing_tracks.each do |recorded_backing_track| manifest["files"] << { "filename" => recorded_backing_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 } - mix_params << { "level" => 100, "balance" => 0 } - # change to 1.0 when ready to deploy new audiomixer + mix_params << { "level" => 1.0, "balance" => 0 } end recording.recorded_jam_track_tracks.each do |recorded_jam_track_track| - manifest["files"] << { "filename" => recorded_jam_track_track.jam_track_track.sign_url(one_day), "codec" => "vorbis", "offset" => 0 } + manifest["files"] << { "filename" => recorded_jam_track_track.jam_track_track.sign_url(one_day), "codec" => "vorbis", "offset" => jam_track_offset } # let's look for level info from the client level = 1.0 # default value - means no effect if recorded_jam_track_track.timeline diff --git a/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb b/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb index f77615beb..53bad104c 100644 --- a/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb +++ b/ruby/lib/jam_ruby/models/recorded_jam_track_track.rb @@ -9,10 +9,11 @@ module JamRuby validates :user, presence: true validates :jam_track_track, presence:true - def self.create_from_jam_track_track(jam_track_track, recording) + def self.create_from_jam_track_track(jam_track_track, recording, user) recorded_jam_track_track = self.new recorded_jam_track_track.recording = recording recorded_jam_track_track.jam_track_track = jam_track_track + recorded_jam_track_track.user = user recorded_jam_track_track.save recorded_jam_track_track end diff --git a/ruby/lib/jam_ruby/models/recording.rb b/ruby/lib/jam_ruby/models/recording.rb index c4537c94d..cdb72816a 100644 --- a/ruby/lib/jam_ruby/models/recording.rb +++ b/ruby/lib/jam_ruby/models/recording.rb @@ -49,6 +49,10 @@ module JamRuby self.comments.size end + def is_jamtrack_recording? + !jam_track_id.nil? + end + def high_quality_mix? has_final_mix end @@ -229,11 +233,13 @@ module JamRuby if music_session.jam_track music_session.jam_track.jam_track_tracks.each do |jam_track_track| - recording.recorded_jam_track_tracks << RecordedJamTrackTrack.create_from_jam_track_track(jam_track_track, recording) + recording.recorded_jam_track_tracks << RecordedJamTrackTrack.create_from_jam_track_track(jam_track_track, recording, owner) if jam_track_track.track_type == 'Track' end recording.jam_track = music_session.jam_track recording.jam_track_initiator = music_session.jam_track_initiator end + + recording.save end end @@ -690,19 +696,17 @@ module JamRuby end def add_timeline(timeline) - tracks = timeline["tracks"] + global = timeline["global"] + raise JamArgumentError, "global must be specified" unless global + tracks = timeline["tracks"] raise JamArgumentError, "tracks must be specified" unless tracks + Recording.where(id: self.id).update_all(timeline: global.to_json) + jam_tracks = tracks.select {|track| track["type"] == "jam_track"} jam_tracks.each do |client_jam_track| - recorded_jam_track_track = RecordedJamTrackTrack.find_by_jam_track_track_id(client_jam_track["id"]) - if recorded_jam_track_track - recorded_jam_track_track.timeline = client_jam_track["timeline"].to_json - recorded_jam_track_track.save! - else - @@log.error("unable to find JamTrackTrack with id #{recorded_jam_track_track.id}") - end + RecordedJamTrackTrack.where(recording_id: id, jam_track_track_id: client_jam_track["id"]).update_all(timeline: client_jam_track["timeline"].to_json) end end diff --git a/ruby/lib/jam_ruby/resque/audiomixer.rb b/ruby/lib/jam_ruby/resque/audiomixer.rb index e0a3b065e..fa987b69f 100644 --- a/ruby/lib/jam_ruby/resque/audiomixer.rb +++ b/ruby/lib/jam_ruby/resque/audiomixer.rb @@ -260,6 +260,10 @@ module JamRuby end @manifest = symbolize_keys(mix.manifest) + @@log.debug("manifest") + @@log.debug("--------") + @@log.debug(JSON.pretty_generate(@manifest)) + @manifest[:mix_id] = mix_id # slip in the mix_id so that the job can add it to the ogg comments # sanity check the manifest diff --git a/ruby/spec/jam_ruby/models/recording_spec.rb b/ruby/spec/jam_ruby/models/recording_spec.rb index 3d8515f29..7b64b2144 100644 --- a/ruby/spec/jam_ruby/models/recording_spec.rb +++ b/ruby/spec/jam_ruby/models/recording_spec.rb @@ -1080,6 +1080,7 @@ describe Recording do let(:recording) {recorded_jam_track_track.recording} let(:timeline_data) {{"sample" => "data"}} let(:good_timeline) { { + "global" => {"recording_start_time" => 0, "jam_track_play_start_time" => 0, "jam_track_recording_start_play_offset" => 0}, "tracks" => [ { "id" => recorded_jam_track_track.jam_track_track.id, diff --git a/web/app/assets/javascripts/playbackControls.js b/web/app/assets/javascripts/playbackControls.js index ce7d74075..d56a1e214 100644 --- a/web/app/assets/javascripts/playbackControls.js +++ b/web/app/assets/javascripts/playbackControls.js @@ -104,10 +104,10 @@ $playButton.on('click', function(e) { var sessionModel = context.JK.CurrentSessionModel || null; - if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') { - context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton}) - return false; - } + //if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') { + // context.JK.prodBubble($fader, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $playButton}) + // return false; + //} startPlay(); return false; @@ -115,10 +115,10 @@ $pauseButton.on('click', function(e) { var sessionModel = context.JK.CurrentSessionModel || null; - if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') { - context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton}) - return false; - } + //if(sessionModel && sessionModel.areControlsLockedForJamTrackRecording() && $parentElement.closest('.session-track').data('track_data').type == 'jam_track') { + // context.JK.prodBubble($pauseButton, 'jamtrack-controls-disabled', {}, {positions:['top'], offsetParent: $pauseButton}) + // return false; + //} stopPlay(); return false; diff --git a/web/app/assets/javascripts/session.js b/web/app/assets/javascripts/session.js index 96ebee955..11cd94cd3 100644 --- a/web/app/assets/javascripts/session.js +++ b/web/app/assets/javascripts/session.js @@ -481,7 +481,7 @@ function checkMetronomeTransition() { // trust backend over server - if(sessionModel.jamTracks() !== null) { + if(sessionModel.jamTracks() !== null || sessionModel.recordedJamTracks() !== null) { // ignore all metronome events when jamtracks are open, because backend opens metronome mixer to play jamtrack tap-ins logger.debug("ignore checkMetronomeTransition because JamTrack is open") return; @@ -956,6 +956,8 @@ var recordedBackingTracks = sessionModel.recordedBackingTracks(); var backingTracks = sessionModel.backingTracks(); + logger.debug("localMediaMixers", localMediaMixers) + // 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. @@ -1041,7 +1043,7 @@ if(jamTrackMixers.length > 0) { renderJamTracks(jamTrackMixers); } - if(metronomeTrackMixers.length > 0 && sessionModel.jamTracks() === null) { + if(metronomeTrackMixers.length > 0 && sessionModel.jamTracks() === null && sessionModel.recordedJamTracks() == null) { renderMetronomeTracks(metronomeTrackMixers); } if(adhocTrackMixers.length > 0) { @@ -1178,7 +1180,20 @@ function renderJamTracks(jamTrackMixers) { logger.debug("rendering jam tracks") - var jamTracks = sessionModel.jamTracks(); + + var jamTracks = [] + var jamTrackName = 'JamTrack'; + if(sessionModel.isPlayingRecording()) { + // only return managed mixers for recorded backing tracks + jamTracks = sessionModel.recordedJamTracks(); + jamTrackName = sessionModel.recordedJamTrackName(); + } + else { + // only return un-managed (ad-hoc) mixers for normal backing tracks + jamTracks = sessionModel.jamTracks(); + jamTrackName = sessionModel.jamTrackName(); + } + // pluck the 1st mixer, and assume that all other mixers in this group are of the same type (between JamTrack vs Peer) @@ -1187,7 +1202,7 @@ // using the server's info in conjuction with the client's, draw the recording tracks if(jamTracks) { - $('.session-recording-name').text(sessionModel.getCurrentSession().jam_track.name); + $('.session-recording-name').text(jamTrackName); var noCorrespondingTracks = false; $.each(jamTrackMixers, function(index, mixer) { @@ -2843,7 +2858,7 @@ function startStopRecording() { // check first if a jamtrack is loaded, and playing; if so, tell user to stop the play - if(sessionModel.jamTracks() && context.jamClient.isSessionTrackPlaying()) { + /**if(sessionModel.jamTracks() && context.jamClient.isSessionTrackPlaying()) { app.notify( { title: "Can't Recording a Play JamTrack", text: "Stop the JamTrack before trying to recording." }, @@ -2851,7 +2866,7 @@ true); return; - } + }*/ if(sessionModel.recordingModel.isRecording()) { sessionModel.recordingModel.stopRecording(); diff --git a/web/app/assets/javascripts/sessionModel.js b/web/app/assets/javascripts/sessionModel.js index c09f4e878..05f726557 100644 --- a/web/app/assets/javascripts/sessionModel.js +++ b/web/app/assets/javascripts/sessionModel.js @@ -127,6 +127,32 @@ } } + function recordedJamTracks() { + if(currentSession && currentSession.claimed_recording) { + return currentSession.claimed_recording.recording.recorded_jam_track_tracks + } + else { + return null; + } + } + + function jamTrackName() { + if (currentSession && currentSession.jam_track) { + return currentSession.jam_track.name; + } + else { + return null; + } + } + + function recordedJamTrackName() { + if(currentSession && currentSession.claimed_recording && currentSession.claimed_recording.recording.jam_track) { + return currentSession.claimed_recording.recording.jam_track.name; + } + else { + return null; + } + } // did I open up the current JamTrack? function selfOpenedJamTracks() { return currentSession && (currentSession.jam_track_initiator_id == context.JK.currentUserId) @@ -843,8 +869,11 @@ this.backingTrack = backingTrack; this.backingTracks = backingTracks; this.recordedBackingTracks = recordedBackingTracks; + this.recordedJamTracks = recordedJamTracks; this.setUserTracks = setUserTracks; this.recordedTracks = recordedTracks; + this.jamTrackName = jamTrackName; + this.recordedJamTrackName = recordedJamTrackName; this.jamTracks = jamTracks; this.participants = participants; this.joinSession = joinSession; diff --git a/web/app/controllers/api_recordings_controller.rb b/web/app/controllers/api_recordings_controller.rb index b6f246e72..27eb6c856 100644 --- a/web/app/controllers/api_recordings_controller.rb +++ b/web/app/controllers/api_recordings_controller.rb @@ -1,7 +1,7 @@ class ApiRecordingsController < ApiController before_filter :api_signed_in_user, :except => [ :add_like ] - before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim, :add_timeline_data ] + before_filter :lookup_recording, :only => [ :show, :stop, :claim, :discard, :keep, :delete_claim, :add_timeline ] before_filter :lookup_recorded_track, :only => [ :download, :upload_next_part, :upload_sign, :upload_part_complete, :upload_complete ] before_filter :lookup_recorded_backing_track, :only => [ :backing_track_download, :backing_track_upload_next_part, :backing_track_upload_sign, :backing_track_upload_part_complete, :backing_track_upload_complete ] before_filter :lookup_recorded_video, :only => [ :video_upload_sign, :video_upload_start, :video_upload_complete ] @@ -379,7 +379,7 @@ class ApiRecordingsController < ApiController # metadata def add_timeline - @recording.add_timeline(params[:metadata]) + @recording.add_timeline(params) render :json => {}, :status => 200 end diff --git a/web/app/views/api_claimed_recordings/show.rabl b/web/app/views/api_claimed_recordings/show.rabl index 91174f87b..c22a49ad3 100644 --- a/web/app/views/api_claimed_recordings/show.rabl +++ b/web/app/views/api_claimed_recordings/show.rabl @@ -22,6 +22,10 @@ end child(:recording => :recording) { attributes :id, :created_at, :duration, :comment_count, :like_count, :play_count, :jam_track_id, :jam_track_initiator_id + node :timeline do |recording| + recording.timeline ? JSON.parse(recording.timeline) : {} + end + child(:jam_track => :jam_track) { attributes :id diff --git a/web/app/views/api_music_sessions/show.rabl b/web/app/views/api_music_sessions/show.rabl index 8149352d0..093e47077 100644 --- a/web/app/views/api_music_sessions/show.rabl +++ b/web/app/views/api_music_sessions/show.rabl @@ -79,10 +79,6 @@ else child(:jam_track_tracks => :tracks) { attributes :id, :part, :instrument, :track_type } - - child(:jam_track_tap_ins => :tap_ins) { - attributes :offset_time, :bpm, :tap_in_count - } } # only show currently playing recording data if the current_user is in the session @@ -107,6 +103,10 @@ else end } + child({:jam_track => :jam_track}) { + attributes :id, :name, :description + } + child(:recorded_tracks => :recorded_tracks) { attributes :id, :fully_uploaded, :client_track_id, :client_id, :instrument_id @@ -126,6 +126,19 @@ else attributes :id, :first_name, :last_name, :city, :state, :country, :photo_url } } + + child(:recorded_jam_track_tracks => :recorded_jam_track_tracks) { + node do |recorded_jam_track_track| + { + id: recorded_jam_track_track.jam_track_track.id, + user_id: recorded_jam_track_track.user_id, + part: recorded_jam_track_track.jam_track_track.part, + instrument: recorded_jam_track_track.jam_track_track.instrument, + track_type: recorded_jam_track_track.jam_track_track.track_type, + timeline: recorded_jam_track_track.timeline ? JSON.parse(recorded_jam_track_track.timeline) : [] + } + end + } } } diff --git a/web/app/views/api_recordings/show.rabl b/web/app/views/api_recordings/show.rabl index a717a6bfb..330f12f7b 100644 --- a/web/app/views/api_recordings/show.rabl +++ b/web/app/views/api_recordings/show.rabl @@ -12,6 +12,10 @@ node :mix do |recording| end end +node :timeline do |recording| + recording.timeline ? JSON.parse(recording.timeline) : {} +end + child(:jam_track => :jam_track) { attributes :id