Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/wavesync.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Wavesync
end

require 'wavesync/acid_chunk'
require 'wavesync/audio_format'
require 'wavesync/audio'
require 'wavesync/config'
require 'wavesync/device'
Expand Down
10 changes: 9 additions & 1 deletion lib/wavesync/audio.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def initialize(file_path)
end

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

def bit_depth
Expand All @@ -32,6 +32,14 @@ def bit_depth

attr_reader :bpm

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

def write_bpm(bpm)
case @file_ext
when '.m4a'
Expand Down
13 changes: 13 additions & 0 deletions lib/wavesync/audio_format.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

module Wavesync
AudioFormat = Data.define(:file_type, :sample_rate, :bit_depth) do
def merge(other)
with(
file_type: other.file_type || file_type,
sample_rate: other.sample_rate || sample_rate,
bit_depth: other.bit_depth || bit_depth
)
end
end
end
8 changes: 8 additions & 0 deletions lib/wavesync/device.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ def self.load_from_yaml
end
end

def target_format(source_format, source_file_path)
AudioFormat.new(
file_type: target_file_type(source_file_path),
sample_rate: target_sample_rate(source_format.sample_rate),
bit_depth: target_bit_depth(source_format.bit_depth)
)
end

def target_file_type(source_file_path)
file_extension = File.extname(source_file_path).downcase[1..]
return nil if file_types.include?(file_extension)
Expand Down
17 changes: 8 additions & 9 deletions lib/wavesync/file_converter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@

module Wavesync
class FileConverter
def convert(audio, source_file_path, path_resolver, target_file_type, _source_sample_rate,
target_sample_rate, source_bit_depth, target_bit_depth, &before_transcode)
return false unless target_file_type || target_sample_rate || target_bit_depth
def convert(audio, source_file_path, path_resolver, source_format, target_format, &before_transcode)
return false unless target_format.file_type || target_format.sample_rate || target_format.bit_depth

target_path = path_resolver.resolve(source_file_path, audio, target_file_type: target_file_type)
target_path = path_resolver.resolve(source_file_path, audio, target_file_type: target_format.file_type)

files_to_cleanup = path_resolver.find_files_to_cleanup(target_path, audio)
files_to_cleanup.each { |file| FileUtils.rm_f(file) }

if target_file_type
source_converted_path = Pathname(source_file_path).sub_ext(".#{target_file_type}")
if target_format.file_type
source_converted_path = Pathname(source_file_path).sub_ext(".#{target_format.file_type}")
return false if source_converted_path.exist?
end

Expand All @@ -21,9 +20,9 @@ def convert(audio, source_file_path, path_resolver, target_file_type, _source_sa
target_path.dirname.mkpath
before_transcode&.call

audio.transcode(target_path.to_s, target_sample_rate: target_sample_rate,
target_file_type: target_file_type,
target_bit_depth: target_bit_depth || source_bit_depth)
audio.transcode(target_path.to_s, target_sample_rate: target_format.sample_rate,
target_file_type: target_format.file_type,
target_bit_depth: target_format.bit_depth || source_format.bit_depth)

true
end
Expand Down
21 changes: 7 additions & 14 deletions lib/wavesync/scanner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,19 @@ def sync(target_library_path, device)
audio = Audio.new(file)
@ui.bpm(audio.bpm)

file_type = device.target_file_type(file)
source_sample_rate = audio.sample_rate
source_bit_depth = audio.bit_depth
target_sample_rate = device.target_sample_rate(source_sample_rate)
target_bit_depth = device.target_bit_depth(source_bit_depth)
source_format = audio.format
target_format = device.target_format(source_format, file)

@ui.file_progress(file)

if file_type || target_sample_rate || target_bit_depth
converted = @converter.convert(audio, file, path_resolver, file_type, source_sample_rate,
target_sample_rate, source_bit_depth, target_bit_depth) do
source_file_type = File.extname(file).delete_prefix('.')
@ui.conversion_progress(source_sample_rate, target_sample_rate, source_bit_depth,
source_file_type, file_type, target_bit_depth)
if target_format.file_type || target_format.sample_rate || target_format.bit_depth
converted = @converter.convert(audio, file, path_resolver, source_format, target_format) do
@ui.conversion_progress(source_format, target_format)
end
target_path = path_resolver.resolve(file, audio, target_file_type: file_type)
target_path = path_resolver.resolve(file, audio, target_file_type: target_format.file_type)
else
copied = copy_file(audio, file, path_resolver)
source_file_type = File.extname(file).delete_prefix('.')
@ui.copy(source_sample_rate, source_bit_depth, source_file_type)
@ui.copy(source_format)
target_path = path_resolver.resolve(file, audio)
end

Expand Down
19 changes: 8 additions & 11 deletions lib/wavesync/ui.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,22 @@ def sync_progress(index, total_count, device)
sticky(parts.join(' '), 0)
end

def conversion_progress(source_sample_rate, target_sample_rate, source_bit_depth, source_file_type,
target_file_type, target_bit_depth = nil)
target_sample_rate = source_sample_rate if target_sample_rate.nil?
target_file_type = source_file_type if target_file_type.nil?
target_bit_depth = source_bit_depth if target_bit_depth.nil?
def conversion_progress(source_format, target_format)
effective = source_format.merge(target_format)

source_info = audio_info(source_sample_rate, source_bit_depth)
target_info = audio_info(target_sample_rate, target_bit_depth)
source_info = audio_info(source_format.sample_rate, source_format.bit_depth)
target_info = audio_info(effective.sample_rate, effective.bit_depth)

formatted_line = in_color(
"Converting #{source_file_type} (#{source_info}) ⇢ #{target_file_type} (#{target_info})", :highlight
"Converting #{source_format.file_type} (#{source_info}) ⇢ #{effective.file_type} (#{target_info})", :highlight
)
sticky(formatted_line, 3)
end

def copy(source_sample_rate, source_bit_depth, source_file_type)
info = audio_info(source_sample_rate, source_bit_depth)
def copy(source_format)
info = audio_info(source_format.sample_rate, source_format.bit_depth)

sticky(in_color("Copying #{source_file_type} (#{info})", :highlight), 3)
sticky(in_color("Copying #{source_format.file_type} (#{info})", :highlight), 3)
end

def skip
Expand Down
9 changes: 9 additions & 0 deletions test/wavesync/audio_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'tempfile'
require 'fileutils'
require_relative 'test_case'
require_relative '../../lib/wavesync/audio_format'
require_relative '../../lib/wavesync/audio'
require_relative '../../lib/wavesync/acid_chunk'

Expand Down Expand Up @@ -87,6 +88,14 @@ class AudioTest < Wavesync::TestCase
end
end

test '#format returns an AudioFormat with file type, sample rate, and bit depth' do
format = audio('44100_16.wav').format
assert_instance_of AudioFormat, format
assert_equal 'wav', format.file_type
assert_equal 44_100, format.sample_rate
assert_equal 16, format.bit_depth
end

test 'find_all returns files for all supported extensions' do
files = Audio.find_all(FIXTURES_PATH)
exts = files.map { |f| File.extname(f).downcase }.uniq.sort
Expand Down
19 changes: 19 additions & 0 deletions test/wavesync/device_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require 'yaml'
require_relative 'test_case'
require_relative '../../lib/wavesync/audio_format'
require_relative '../../lib/wavesync/device'

module Wavesync
Expand Down Expand Up @@ -95,6 +96,24 @@ class DeviceTest < Wavesync::TestCase
assert_nil tp7.target_bit_depth(24)
end

test '.target_format returns all nils when source format is fully supported' do
tp7 = Device.find_by(name: 'TP-7')
source_format = AudioFormat.new(file_type: 'wav', sample_rate: 44_100, bit_depth: 24)
target_format = tp7.target_format(source_format, 'song.wav')
assert_nil target_format.file_type
assert_nil target_format.sample_rate
assert_nil target_format.bit_depth
end

test '.target_format returns converted values when source format is unsupported' do
octatrack = Device.find_by(name: 'Octatrack')
source_format = AudioFormat.new(file_type: 'mp3', sample_rate: 96_000, bit_depth: 32)
target_format = octatrack.target_format(source_format, 'song.mp3')
assert_equal 'wav', target_format.file_type
assert_equal 44_100, target_format.sample_rate
assert_equal 24, target_format.bit_depth
end

test '.target_bit_depth returns closest supported bit depth' do
tp7 = Device.find_by(name: 'TP-7')
assert_equal 16, tp7.target_bit_depth(8)
Expand Down
13 changes: 10 additions & 3 deletions test/wavesync/file_converter_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require_relative 'test_case'
require_relative '../../lib/wavesync/audio_format'
require_relative '../../lib/wavesync/file_converter'
require_relative '../../lib/wavesync/path_resolver'
require_relative '../../lib/wavesync/device'
Expand All @@ -27,7 +28,9 @@ def teardown
FileUtils.touch(File.join(@source_dir, 'track.mp3'))

audio = stub(bpm: nil)
result = @converter.convert(audio, source_aiff, @path_resolver, 'mp3', 44_100, nil, 16, nil)
source_format = AudioFormat.new(file_type: 'aiff', sample_rate: 44_100, bit_depth: 16)
target_format = AudioFormat.new(file_type: 'mp3', sample_rate: nil, bit_depth: nil)
result = @converter.convert(audio, source_aiff, @path_resolver, source_format, target_format)

assert_equal false, result
end
Expand All @@ -39,7 +42,9 @@ def teardown
audio = stub(bpm: nil)
audio.stubs(:transcode)

result = @converter.convert(audio, source_aiff, @path_resolver, 'mp3', 44_100, nil, 16, nil)
source_format = AudioFormat.new(file_type: 'aiff', sample_rate: 44_100, bit_depth: 16)
target_format = AudioFormat.new(file_type: 'mp3', sample_rate: nil, bit_depth: nil)
result = @converter.convert(audio, source_aiff, @path_resolver, source_format, target_format)

assert_equal true, result
end
Expand All @@ -50,7 +55,9 @@ def teardown
FileUtils.touch(File.join(@target_dir, 'track.mp3'))

audio = stub(bpm: nil)
result = @converter.convert(audio, source_aiff, @path_resolver, 'mp3', 44_100, nil, 16, nil)
source_format = AudioFormat.new(file_type: 'aiff', sample_rate: 44_100, bit_depth: 16)
target_format = AudioFormat.new(file_type: 'mp3', sample_rate: nil, bit_depth: nil)
result = @converter.convert(audio, source_aiff, @path_resolver, source_format, target_format)

assert_equal false, result
end
Expand Down