Class: Wavesync::Audio

Inherits:
Object
  • Object
show all
Defined in:
lib/wavesync/audio.rb

Constant Summary collapse

SUPPORTED_FORMATS =
%w[.m4a .mp3 .wav .aif .aiff].freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path) ⇒ Audio

: (String file_path) -> void



21
22
23
24
25
# File 'lib/wavesync/audio.rb', line 21

def initialize(file_path)
  @file_path = file_path #: String
  @file_ext = File.extname(@file_path).downcase #: String
  @audio = FFMPEG::Movie.new(file_path) #: untyped
end

Class Method Details

.find_all(library_path) ⇒ Object

: (String library_path) -> Array



15
16
17
18
# File 'lib/wavesync/audio.rb', line 15

def self.find_all(library_path)
  Dir.glob(File.join(library_path, '**', '*'))
     .select { |f| SUPPORTED_FORMATS.include?(File.extname(f).downcase) }
end

Instance Method Details

#bit_depthObject

: () -> Integer?



38
39
40
# File 'lib/wavesync/audio.rb', line 38

def bit_depth
  @bit_depth ||= calculate_bit_depth
end

#bpmObject

: () -> (String | Integer)?



43
44
45
46
47
# File 'lib/wavesync/audio.rb', line 43

def bpm
  return @bpm if defined?(@bpm)

  @bpm = bpm_from_file
end

#cue_pointsObject

: () -> Array[Integer, sample_offset: Integer, label: String?]



59
60
61
62
63
# File 'lib/wavesync/audio.rb', line 59

def cue_points
  return [] unless @file_ext == '.wav'

  CueChunk.read(@file_path)
end

#durationObject

: () -> Float



28
29
30
# File 'lib/wavesync/audio.rb', line 28

def duration
  @audio.duration
end

#formatObject

: () -> AudioFormat



50
51
52
53
54
55
56
# File 'lib/wavesync/audio.rb', line 50

def format
  AudioFormat.new(
    file_type: @file_ext.delete_prefix('.'),
    sample_rate: sample_rate,
    bit_depth: bit_depth
  )
end

#sample_rateObject

: () -> Integer?



33
34
35
# File 'lib/wavesync/audio.rb', line 33

def sample_rate
  @sample_rate ||= @audio.audio_sample_rate
end

#transcode(target_path, target_sample_rate: nil, target_file_type: nil, target_bit_depth: nil, padding_seconds: nil) ⇒ Object

: (String target_path, ?target_sample_rate: Integer?, ?target_file_type: String?, ?target_bit_depth: Integer?, ?padding_seconds: Numeric?) -> bool



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/wavesync/audio.rb', line 88

def transcode(target_path, target_sample_rate: nil, target_file_type: nil, target_bit_depth: nil, padding_seconds: nil)
  options = build_transcode_options(target_sample_rate, target_bit_depth, padding_seconds)
  ext = target_file_type || @file_ext.delete_prefix('.')
  temp_path = File.join(
    Dir.tmpdir,
    "wavesync_transcode_#{SecureRandom.hex}.#{ext}"
  )

  begin
    @audio.transcode(temp_path, options)
    FileUtils.install(temp_path, target_path)
    true
  rescue Errno::ENOENT
    puts 'Errno::ENOENT'
    false
  ensure
    FileUtils.rm_f(temp_path)
  end
end

#write_bpm(bpm) ⇒ Object

: (String | Integer | Float bpm) -> void



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/wavesync/audio.rb', line 73

def write_bpm(bpm)
  case @file_ext
  when '.m4a'
    write_bpm_to_m4a(bpm)
  when '.mp3'
    write_bpm_to_mp3(bpm)
  when '.wav'
    write_bpm_to_wav(bpm)
  when '.aif', '.aiff'
    write_bpm_to_aiff(bpm)
  end
  @bpm = bpm
end

#write_cue_points(cue_points) ⇒ Object

: (Array[Integer, sample_offset: Integer, label: String?] cue_points) -> void



66
67
68
69
70
# File 'lib/wavesync/audio.rb', line 66

def write_cue_points(cue_points)
  temp_path = "#{@file_path}.tmp"
  CueChunk.write(@file_path, temp_path, cue_points)
  FileUtils.mv(temp_path, @file_path)
end