lib/scissor/chunk.rb in youpy-scissor-0.0.16 vs lib/scissor/chunk.rb in youpy-scissor-0.0.17

- old
+ new

@@ -1,25 +1,30 @@ require 'digest/md5' require 'pathname' require 'open4' require 'logger' +require 'bigdecimal' module Scissor class Chunk + @logger = Logger.new(STDOUT) + @logger.level = Logger::INFO + + class << self + attr_accessor :logger + end + class Error < StandardError; end class FileExists < Error; end class EmptyFragment < Error; end class OutOfDuration < Error; end class CommandFailed < Error; end attr_reader :fragments - attr_accessor :logger def initialize(filename = nil) @fragments = [] - @logger = Logger.new(STDOUT) - @logger.level = Logger::INFO if filename @fragments << Fragment.new( filename, 0, @@ -29,16 +34,23 @@ def add_fragment(fragment) @fragments << fragment end - def duration - @fragments.inject(0) do |memo, fragment| - memo += fragment.duration + def add_fragments(fragments) + fragments.each do |fragment| + add_fragment(fragment) end end + def duration + BigDecimal( + @fragments.inject(0) do |memo, fragment| + memo += fragment.duration + end.to_s).round(3).to_f + end + def slice(start, length) if start + length > duration raise OutOfDuration end @@ -63,36 +75,28 @@ end alias [] slice def concat(other) - other.fragments.each do |fragment| - add_fragment(fragment) - end + add_fragments(other.fragments) self end alias << concat def +(other) new_instance = Scissor() - - (@fragments + other.fragments).each do |fragment| - new_instance.add_fragment(fragment) - end - + new_instance.add_fragments(@fragments + other.fragments) new_instance end def loop(count) orig_fragments = @fragments.clone (count - 1).times do - orig_fragments.each do |fragment| - add_fragment(fragment) - end + add_fragments(orig_fragments) end self end @@ -131,24 +135,24 @@ end new_instance end - def replace(start, duration, replaced) + def replace(start, length, replaced) new_instance = self.class.new - offset = start + duration + offset = start + length - if offset > self.duration + if offset > duration raise OutOfDuration end if start > 0 new_instance += slice(0, start) end new_instance += replaced - new_instance += slice(offset, self.duration - offset) + new_instance += slice(offset, duration - offset) new_instance end def reverse @@ -195,40 +199,41 @@ tmpfile = tmpdir + 'tmp.wav' cmd = %w/ecasound/ begin @fragments.each_with_index do |fragment, index| + fragment_filename = fragment.filename + fragment_duration = fragment.duration + if !index.zero? && (index % 80).zero? run_command(cmd.join(' ')) cmd = %w/ecasound/ end fragment_tmpfile = - fragment.filename.extname.downcase == '.wav' ? fragment.filename : - tmpdir + (Digest::MD5.hexdigest(fragment.filename) + '.wav') + fragment_filename.extname.downcase == '.wav' ? fragment_filename : + tmpdir + (Digest::MD5.hexdigest(fragment_filename) + '.wav') unless fragment_tmpfile.exist? - run_command("ffmpeg -i \"#{fragment.filename}\" \"#{fragment_tmpfile}\"") + run_command("ffmpeg -i \"#{fragment_filename}\" \"#{fragment_tmpfile}\"") end cmd << "-a:#{index} " + "-i:" + (fragment.reversed? ? 'reverse,' : '') + - "select,#{fragment.start},#{fragment.duration},\"#{fragment_tmpfile}\" " + + "select,#{fragment.start},#{fragment_duration},\"#{fragment_tmpfile}\" " + "-o:#{tmpfile} " + "-y:#{position}" - position += fragment.duration + position += fragment_duration end run_command(cmd.join(' ')) if filename.extname == '.wav' - open(filename, 'w') do |file| - file.write(tmpfile.read) - end + File.rename(tmpfile, filename) else run_command("ffmpeg -i \"#{tmpfile}\" \"#{filename}\"") end ensure tmpdir.rmtree @@ -246,21 +251,25 @@ def which(command) run_command("which #{command}") end def run_command(cmd) - @logger.debug("run_command: #{cmd}") + logger.debug("run_command: #{cmd}") result = '' status = Open4.popen4(cmd) do |pid, stdin, stdout, stderr| - @logger.debug(stderr.read) + logger.debug(stderr.read) result = stdout.read end if status.exitstatus != 0 raise CommandFailed.new(cmd) end return result + end + + def logger + self.class.logger end end end