From d3d2fbb210dd0d61310be0590331d88849374220 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Wed, 18 Nov 2015 15:22:06 -0600 Subject: [PATCH] * generate jmep automatically --- admin/config/initializers/jam_tracks.rb | 23 --- ruby/lib/jam_ruby/jam_track_importer.rb | 198 ++++++++++++++++++------ ruby/lib/jam_ruby/models/jam_track.rb | 28 ++++ web/lib/tasks/jam_tracks.rake | 5 + 4 files changed, 186 insertions(+), 68 deletions(-) diff --git a/admin/config/initializers/jam_tracks.rb b/admin/config/initializers/jam_tracks.rb index 33efd995c..60537c467 100644 --- a/admin/config/initializers/jam_tracks.rb +++ b/admin/config/initializers/jam_tracks.rb @@ -2,28 +2,5 @@ class JamRuby::JamTrack # add a custom validation - attr_accessor :preview_generate_error - before_save :jmep_json_generate - validate :jmep_text_validate - - def jmep_text_validate - begin - JmepManager.execute(self.jmep_text) - rescue ArgumentError => err - errors.add(:jmep_text, err.to_s) - end - end - - def jmep_json_generate - self.licensor_id = nil if self.licensor_id == '' - self.jmep_json = nil if self.jmep_json == '' - self.time_signature = nil if self.time_signature == '' - - begin - self[:jmep_json] = JmepManager.execute(self.jmep_text) - rescue ArgumentError => err - #errors.add(:jmep_text, err.to_s) - end - end end diff --git a/ruby/lib/jam_ruby/jam_track_importer.rb b/ruby/lib/jam_ruby/jam_track_importer.rb index a92aca61b..4fe6d3d5a 100644 --- a/ruby/lib/jam_ruby/jam_track_importer.rb +++ b/ruby/lib/jam_ruby/jam_track_importer.rb @@ -33,6 +33,123 @@ module JamRuby self.detail = detail end + def generate_jmep(jam_track) + if jam_track.jmep_text + finish('success', 'jmep already exists') + return + else + # we need to download the click track, if it exists. + Dir.mktmpdir do |tmp_dir| + + master_track = jam_track.master_track + + click_track = jam_track.click_track + + if master_track.nil? + finish('no_master_track', nil) + return + end + + master_track_file = File.join(tmp_dir, File.basename(master_track[:url_48])) + begin + JamTrackImporter.private_s3_manager.download(master_track.url_by_sample_rate(44), master_track_file) + rescue Exception => e + @@log.error("unable to download master track") + finish("no-download-master", master_track.url_by_sample_rate(44)) + return + end + + if click_track + click_track_file = File.join(tmp_dir, File.basename(click_track[:url])) + JamTrackImporter.song_storage_manager.download(click_track[:url], click_track_file) + else + # we'll use the master for click analysis. not ideal, but would work + click_track_file = master_track_file + end + + start_time = determine_start_time(master_track_file, tmp_dir, master_track[:url]) + + # bpm comes from git clone http://www.pogo.org.uk/~mark/bpm-tools.git + + sox="sox #{Shellwords.escape(click_track_file)} -t raw -r 44100 -e float -c 1 - | bpm" + cmd = "bash -c #{Shellwords.escape(sox)}" + @@log.debug("executing cmd #{cmd}") + output=`#{cmd}` + + result_code = $?.to_i + + if result_code == 0 + bpm = output.to_f + + @@log.debug("bpm: #{bpm} start_time: #{start_time}") + + metro_fin = "#{Time.at(start_time).utc.strftime("%H:%M:%S")}:#{((start_time - start_time.to_i) * 1000).round}" + + jmep = "" + jmep << "# created via code using bpm/silence detection (bpm:#{bpm})\r\n" + jmep << "prelude@10.0 #number of seconds before music starts\r\n" + jmep << "metro_fin@#{metro_fin} bpm=#{bpm.round}, ticks=4, pmode=stream, name=Beep, play=mono" + + @@log.info("jmep generated: #{jmep}") + + jam_track.jmep_text = jmep + if jam_track.save + + else + @@log.error("jamtrack did not save. #{jam_track.errors.inspect}") + finish("no-save", "jamtrack did not save. #{jam_track.errors.inspect}") + return + end + else + finish("bpm-fail", "failed to run bpm: #{output}") + return + end + end + end + end + + + + def determine_start_time(audio_file, tmp_dir, original_filename) + burp_gaps = ['0.3', '0.2', '0.1', '0.05'] + + out_wav = File.join(tmp_dir, 'stripped.wav') + total_time_command = "soxi -D \"#{audio_file}\"" + total_time = `#{total_time_command}`.to_f + + result_code = -20 + stripped_time = total_time # default to the case where we just start the preview at the beginning + + burp_gaps.each do |gap| + command_strip_lead_silence = "sox \"#{audio_file}\" \"#{out_wav}\" silence 1 #{gap} 1%" + + @@log.debug("stripping silence: " + command_strip_lead_silence) + + output = `#{command_strip_lead_silence}` + + result_code = $?.to_i + + if result_code == 0 + stripped_time_command = "soxi -D \"#{out_wav}\"" + stripped_time_test = `#{stripped_time_command}`.to_f + + if stripped_time_test < 1 # meaning a very short duration + @@log.warn("could not determine the start of non-silence. assuming beginning") + stripped_time = total_time # default to the case where we just start the preview at the beginning + else + stripped_time = stripped_time_test # accept the measured time of the stripped file and move on by using break + break + end + else + @@log.warn("unable to determine silence for jam_track #{original_filename}, #{output}") + stripped_time = total_time # default to the case where we just start the preview at the beginning + end + end + + preview_start_time = total_time - stripped_time + + preview_start_time + end def synchronize_preview_dev(jam_track) jam_track.jam_track_tracks.each do |track| @@ -1341,58 +1458,15 @@ module JamRuby def synchronize_track_preview(track, tmp_dir, ogg_44100) - out_wav = File.join(tmp_dir, 'stripped.wav') - - burp_gaps = ['0.3', '0.2', '0.1', '0.05'] - - total_time_command = "soxi -D \"#{ogg_44100}\"" - total_time = `#{total_time_command}`.to_f - - result_code = -20 - stripped_time = total_time # default to the case where we just start the preview at the beginning - - burp_gaps.each do |gap| - command_strip_lead_silence = "sox \"#{ogg_44100}\" \"#{out_wav}\" silence 1 #{gap} 1%" - - @@log.debug("stripping silence: " + command_strip_lead_silence) - - output = `#{command_strip_lead_silence}` - - result_code = $?.to_i - - if result_code == 0 - stripped_time_command = "soxi -D \"#{out_wav}\"" - stripped_time_test = `#{stripped_time_command}`.to_f - - if stripped_time_test < 1 # meaning a very short duration - @@log.warn("could not determine the start of non-silencea. assuming beginning") - stripped_time = total_time # default to the case where we just start the preview at the beginning - else - stripped_time = stripped_time_test # accept the measured time of the stripped file and move on by using break - break - end - else - @@log.warn("unable to determine silence for jam_track #{track.original_filename}, #{output}") - stripped_time = total_time # default to the case where we just start the preview at the beginning - end - - end - - preview_start_time = total_time - stripped_time + preview_start_time = determine_start_time(ogg_44100, tmp_dir, track.original_filename) # this is in seconds; convert to integer milliseconds preview_start_time = (preview_start_time * 1000).to_i - preview_start_time = nil if preview_start_time < 0 + preview_start_time = 0 if preview_start_time < 0 track.preview_start_time = preview_start_time - if track.preview_start_time - @@log.debug("determined track start time to be #{track.preview_start_time}") - else - @@log.debug("determined track start time to be #{track.preview_start_time}") - end - track.process_preview(ogg_44100, tmp_dir) if track.preview_start_time if track.preview_generate_error @@ -1915,6 +1989,39 @@ module JamRuby end end + def generate_jmep(jam_track) + importer = JamTrackImporter.new + importer.name = jam_track.name + importer.generate_jmep(jam_track) + + importer + end + def generate_jmeps + importers = [] + + JamTrack.all.each do |jam_track| + importers << generate_jmep(jam_track) + end + + @@log.info("SUMMARY") + @@log.info("-------") + importers.each do |importer| + if importer + if importer.reason == "success" + @@log.info("#{importer.name} #{importer.reason}") + else + @@log.error("#{importer.name} failed to generate jmep.") + @@log.error("#{importer.name} reason=#{importer.reason}") + @@log.error("#{importer.name} detail=#{importer.detail}") + end + else + @@log.error("NULL IMPORTER") + end + + end + end + + def synchronize_previews importers = [] @@ -2395,3 +2502,4 @@ module JamRuby end end end + diff --git a/ruby/lib/jam_ruby/models/jam_track.rb b/ruby/lib/jam_ruby/models/jam_track.rb index b361d3fe5..611cdc029 100644 --- a/ruby/lib/jam_ruby/models/jam_track.rb +++ b/ruby/lib/jam_ruby/models/jam_track.rb @@ -433,6 +433,10 @@ module JamRuby end + def click_track + JamTrackFile.where(jam_track_id: self.id).where(file_type: 'ClickWav').first + end + def master_track JamTrackTrack.where(jam_track_id: self.id).where(track_type: 'Master').first end @@ -471,5 +475,29 @@ module JamRuby "#{self.name} (#{self.original_artist})" end + attr_accessor :preview_generate_error + + before_save :jmep_json_generate + validate :jmep_text_validate + + def jmep_text_validate + begin + JmepManager.execute(self.jmep_text) + rescue ArgumentError => err + errors.add(:jmep_text, err.to_s) + end + end + + def jmep_json_generate + self.licensor_id = nil if self.licensor_id == '' + self.jmep_json = nil if self.jmep_json == '' + self.time_signature = nil if self.time_signature == '' + + begin + self[:jmep_json] = JmepManager.execute(self.jmep_text) + rescue ArgumentError => err + #errors.add(:jmep_text, err.to_s) + end + end end end diff --git a/web/lib/tasks/jam_tracks.rake b/web/lib/tasks/jam_tracks.rake index bbabe08e5..68fcf835d 100644 --- a/web/lib/tasks/jam_tracks.rake +++ b/web/lib/tasks/jam_tracks.rake @@ -1,5 +1,10 @@ namespace :jam_tracks do + task generate_jmep: :environment do |task, args| + JamTrackImporter.storage_format = 'Tency' + JamTrackImporter.generate_jmeps + end + task dry_run: :environment do |task, args| JamTrackImporter.dry_run end