mp3gain 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2a58ef2ba5e808b606ae88b2d25ea56f3542fb4be85b93fddef2388262e8850c
4
+ data.tar.gz: fc19bc89f6c31b3cd9911d3b2cd917665f04661ea503d8ba7092ef31872f96c4
5
+ SHA512:
6
+ metadata.gz: 503b57473afbb6b74a336a5435d3ed7e6b3ad31e1655a1c6054b52fb263b7ec5cad31690ce624944380276483e337f094af4cc9313884b64dd824a728d74b9ff
7
+ data.tar.gz: 15f99a78ae1cd832e3baa70dccd628864ff0fbe49b4d7c382676a11473161852594677002002062faecff1edaa2839db0069f4365c5cbd940ad1e88a824a3803
data/.gitignore ADDED
@@ -0,0 +1,56 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /spec/examples.txt
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+
13
+ # Used by dotenv library to load environment variables.
14
+ # .env
15
+
16
+ # Ignore Byebug command history file.
17
+ .byebug_history
18
+
19
+ ## Specific to RubyMotion:
20
+ .dat*
21
+ .repl_history
22
+ build/
23
+ *.bridgesupport
24
+ build-iPhoneOS/
25
+ build-iPhoneSimulator/
26
+
27
+ ## Specific to RubyMotion (use of CocoaPods):
28
+ #
29
+ # We recommend against adding the Pods directory to your .gitignore. However
30
+ # you should judge for yourself, the pros and cons are mentioned at:
31
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
32
+ #
33
+ # vendor/Pods/
34
+
35
+ ## Documentation cache and generated files:
36
+ /.yardoc/
37
+ /_yardoc/
38
+ /doc/
39
+ /rdoc/
40
+
41
+ ## Environment normalization:
42
+ /.bundle/
43
+ /vendor/bundle
44
+ /lib/bundler/man/
45
+
46
+ # for a library or gem, you might want to ignore these files since the code is
47
+ # intended to run in multiple environments; otherwise, check them in:
48
+ Gemfile.lock
49
+ # .ruby-version
50
+ # .ruby-gemset
51
+
52
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
53
+ .rvmrc
54
+
55
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
56
+ # .rubocop-https?--*
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ Metrics/ParameterLists:
2
+ Enabled: false
3
+ Layout/EmptyLinesAroundClassBody:
4
+ Enabled: false
5
+ Metrics/ClassLength:
6
+ Enabled: false
7
+ Metrics/AbcSize:
8
+ Enabled: false
9
+ Metrics/CyclomaticComplexity:
10
+ Enabled: false
11
+ Metrics/MethodLength:
12
+ Enabled: false
13
+ Metrics/PerceivedComplexity:
14
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in mp3gain.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+
10
+ gem 'minitest', '~> 5.0'
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Christian Feier
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # RubyMp3gain
2
+
3
+ RubyMP3Gain is an [Mp3Gain](http://mp3gain.sourceforge.net/) wrapper written in Ruby.
4
+
5
+ ## Installation
6
+
7
+ ```shell
8
+ gem build mp3gain.gemspec
9
+ ```
10
+ And then execute:
11
+ ```shell
12
+ $ gem install mp3gain-1.0.0.gem
13
+ ```
14
+ Or from ruby gems using
15
+ or
16
+ ```shell
17
+ gem install mp3gain
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```ruby
23
+ require 'mp3gain'
24
+ mp3gain = Mp3gain.init("path/to/MP3Gain/binary")
25
+ ## optional target db and preserve timestamps
26
+ mp3gain = Mp3gain.init("aacgain", 100, preserve_timestamp: false)
27
+
28
+ # print current version
29
+ mp3gain.version
30
+ # analyze the gain of the given files
31
+ mp3gain.analyze_gain(['path/to/file1', 'path/to/file2'])
32
+ # delete stored tag infos of the given files
33
+ mp3gain.delete_stored_tag_info(['path/to/file1', 'path/to/file2'])
34
+ # apply track gain depending on the provided target DB
35
+ mp3gain.apply_track_gain(['path/to/file1', 'path/to/file2'])
36
+ # apply album gain depending on the provided target DB
37
+ mp3gain.apply_album_gain(['path/to/file1', 'path/to/file2'])
38
+ # apply the given gain
39
+ mp3gain.add_gain(['path/to/file1', 'path/to/file2'], 5)
40
+ ```
41
+
42
+ ## License
43
+
44
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ task default: :test
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mp3gain
4
+ # data Object when gain is added
5
+ class AddGainChange
6
+
7
+ def initialize(file_path, gain_change)
8
+ @file_path = file_path
9
+ @gain_change = gain_change
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mp3gain
4
+ # data object when gain is applied
5
+ class ApplyGainChange
6
+
7
+ attr_reader :file_path, :mp3_gain, :db_gain, :max_amplitude, :max_global_gain, :min_global_gain
8
+
9
+ def initialize(file_path, mp3_gain, db_gain, max_amplitude, max_global_gain, min_global_gain)
10
+ @file_path = file_path
11
+ @mp3_gain = mp3_gain
12
+ @db_gain = db_gain
13
+ @max_amplitude = max_amplitude
14
+ @max_global_gain = max_global_gain
15
+ @min_global_gain = min_global_gain
16
+ end
17
+
18
+ def clipping?
19
+ # if > 31000 -> clipping
20
+ @max_amplitude > 31_000
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mp3gain
4
+ # data object for the recommended gain change
5
+ class RecommendedGainChange
6
+
7
+ attr_reader :file_path, :track_mp3_gain, :track_db_gain, :max_amplitude, :max_global_gain
8
+ attr_accessor :album_changes
9
+
10
+ def initialize(file_path, track_mp3_gain, track_db_gain, max_amplitude, max_global_gain, min_global_gain)
11
+ @file_path = file_path
12
+ @track_mp3_gain = track_mp3_gain
13
+ @track_db_gain = track_db_gain
14
+ @max_amplitude = max_amplitude
15
+ @max_global_gain = max_global_gain
16
+ @min_global_gain = min_global_gain
17
+ @album_changes = nil
18
+ end
19
+
20
+ def clipping?
21
+ # if > 31000 -> clipping
22
+ @max_amplitude > 31_000
23
+ end
24
+ end
25
+ end
data/lib/mp3gain.rb ADDED
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+
5
+ require 'mp3gain/add_gain_change'
6
+ require 'mp3gain/apply_gain_change'
7
+ require 'mp3gain/recommended_gain_change'
8
+
9
+ # wrapper for mp3gain http://mp3gain.sourceforge.net/
10
+ module Mp3gain
11
+
12
+ def self.init(mp3gain_path,
13
+ target_db = 89,
14
+ preserve_timestamp: true)
15
+ Mp3gain.new(mp3gain_path, target_db, preserve_timestamp)
16
+ end
17
+
18
+ # Mp3gain entity to analyze and apply gain
19
+ class Mp3gain
20
+
21
+ MAX_FILES = 15
22
+
23
+ # constructor
24
+ #
25
+ # @param [String] mp3gain_path - path to mp3gain binary
26
+ # @param [Integer] target_db - the target db, default is 89 for mp3gain
27
+ # @param [Boolean] preserve_timestamp - keeps the existing timestamps when changing gain
28
+ def initialize(mp3gain_path,
29
+ target_db = 89,
30
+ preserve_timestamp = true)
31
+ @mp3gain_path = mp3gain_path
32
+ @target_db = target_db
33
+ @preserve_timestamp = preserve_timestamp
34
+ end
35
+
36
+ # returns the version of mp3gain
37
+ #
38
+ # @return the version as a String, e.g. 1.4.7
39
+ def version
40
+ cmd = [@mp3gain_path, '-v']
41
+
42
+ status, result = nil
43
+ Open3.popen3(*cmd) do |_, _, stderr, thread|
44
+ while (line = stderr.gets)
45
+ result = line.split.last
46
+ end
47
+
48
+ status = thread.value
49
+ end
50
+
51
+ throw RuntimeError.new('Could not determine version.') if status != 0 || result.nil?
52
+
53
+ result
54
+ end
55
+
56
+ # deletes the stored tag infos of the given files
57
+ #
58
+ # @param [Array<String>] files - given files
59
+ #
60
+ # @return [Boolean] true if deleted, else false
61
+ def delete_stored_tag_info(files)
62
+ file_size?(files)
63
+
64
+ cmd = [@mp3gain_path, '-s', 'd']
65
+ cmd << '-p' if @preserve_timestamp
66
+ cmd += files
67
+
68
+ status = nil
69
+ Open3.popen3(*cmd) do |_, _, _, thread|
70
+ status = thread.value
71
+ end
72
+
73
+ # rubocop:disable Style/NumericPredicate
74
+ status == 0
75
+ # rubocop:enable Style/NumericPredicate
76
+ end
77
+
78
+ # applies the track gain to the given files
79
+ #
80
+ # @param [Array<String>] files - the given files
81
+ # @param [Boolean] until_no_clipping - ignores clipping warnings if false, otherwise stops if clipping occurred
82
+ #
83
+ # @return [Array<ApplyGainChange>] list of ApplyGainChange items
84
+ def apply_track_gain(files, until_no_clipping: false)
85
+ file_size?(files)
86
+
87
+ cmd = [@mp3gain_path, '-r', '-o', '-c']
88
+ cmd << '-p' if @preserve_timestamp
89
+ cmd << '-k' if until_no_clipping
90
+ cmd << '-d' << (@target_db - 89).to_s if !until_no_clipping && @target_db != 89
91
+ cmd += files
92
+
93
+ apply_gain(cmd)
94
+ end
95
+
96
+ # applies the album gain to the given files
97
+ #
98
+ # @param [Array<String>] files - the given files
99
+ # @param [Boolean] until_no_clipping - ignores clipping warnings if false, otherwise stops if clipping occurred
100
+ #
101
+ # @return [Array<ApplyGainChange>] list of ApplyGainChange items
102
+ def apply_album_gain(files, until_no_clipping: false)
103
+ file_size?(files)
104
+
105
+ cmd = [@mp3gain_path, '-a', '-o', '-c']
106
+ cmd << '-p' if @preserve_timestamp
107
+ cmd << '-k' if until_no_clipping
108
+ cmd << '-d' << (@target_db - 89).to_s if !until_no_clipping && @target_db != 89
109
+ cmd += files
110
+
111
+ apply_gain(cmd)
112
+ end
113
+
114
+ # analyzes the given files and recommends the gain changes that should be applied
115
+ #
116
+ # @param [Array<String>] files - the given files to analyze
117
+ #
118
+ # @return [Array<RecommendGainChange>] a list oaf RecommendedGainChange items
119
+ def analyze_gain(files)
120
+ file_size?(files)
121
+
122
+ cmd = [@mp3gain_path, '-s', 'r', '-o']
123
+ cmd << '-p' if @preserve_timestamp
124
+ cmd << '-d' << (@target_db - 89).to_s if @target_db != 89
125
+ cmd += files
126
+
127
+ status = nil
128
+ result = []
129
+ album_changes = nil
130
+ Open3.popen3(*cmd) do |_, stdout, _, thread|
131
+ while (line = stdout.gets)
132
+ entries = line.strip.split("\t")
133
+ next if entries.length != 6 || entries[0] == 'File'
134
+
135
+ if entries[0] == '"Album"'
136
+ album_changes = RecommendedGainChange.new(nil, entries[1].to_i, entries[2].to_f, entries[3].to_f,
137
+ entries[4].to_i, entries[5].to_i)
138
+ next
139
+ end
140
+
141
+ result << RecommendedGainChange.new(entries[0], entries[1].to_i, entries[2].to_f, entries[3].to_f,
142
+ entries[4].to_i, entries[5].to_i)
143
+ end
144
+
145
+ status = thread.value
146
+ end
147
+
148
+ throw RuntimeError.new('Could not analyze gain.') if status != 0
149
+
150
+ # apply album changes
151
+ result.each { |it| it.album_changes = album_changes }
152
+
153
+ result
154
+ end
155
+
156
+ # adds the specified gain to the given files
157
+ #
158
+ # @param [Array<String>] files - the given files
159
+ # @param [Integer] gain - the gain to add to each file
160
+ #
161
+ # @return [Array<AddGainChange>] a list of AddGain items
162
+ def add_gain(files, gain)
163
+ cmd = [@mp3gain_path, '-g', gain.to_s]
164
+ cmd << '-p' if @preserve_timestamp
165
+ cmd += files
166
+
167
+ status = nil
168
+ Open3.popen3(*cmd) do |_, _, _, thread|
169
+ status = thread.value
170
+ end
171
+
172
+ throw RuntimeError.new('Could not apply gain.') if status != 0
173
+
174
+ files.map { |file| AddGainChange.new(file, gain) }
175
+ end
176
+
177
+ # helper method to apply gain changes by executing the given command and parsing the output
178
+ #
179
+ # @param [Array<String>] cmd - the command to execute
180
+ #
181
+ # @return [Array<ApplyGainChange>] a list of ApplyGainChange items containing the change for each file
182
+ def apply_gain(cmd)
183
+ status = nil
184
+ result = []
185
+ Open3.popen3(*cmd) do |_, stdout, _, thread|
186
+ while (line = stdout.gets)
187
+ entries = line.strip.split("\t")
188
+ next if entries.length != 6 || entries[0] == 'File' || entries[0] == '"Album"'
189
+
190
+ result << ApplyGainChange.new(entries[0], entries[1].to_i, entries[2].to_f, entries[3].to_f,
191
+ entries[4].to_i, entries[5].to_i)
192
+ end
193
+
194
+ status = thread.value
195
+ end
196
+
197
+ throw RuntimeError.new('Could not apply gain.') if status != 0
198
+
199
+ result
200
+ end
201
+
202
+ # checks if the given list of files has less than 15 elements
203
+ #
204
+ # @param [Array<String>] files - given files
205
+ #
206
+ # @return [Boolean] true if size is ok, else false
207
+ def file_size?(files)
208
+ # rubocop:disable Style/GuardClause
209
+ if MAX_FILES < files.length
210
+ throw ArgumentError.new("Only max #{MAX_FILES} can be processed at once. Found #{files.length}")
211
+ end
212
+ # rubocop:enable Style/GuardClause
213
+ end
214
+
215
+ private :apply_gain, :file_size?
216
+ end
217
+ end
data/mp3gain.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'mp3gain'
5
+ spec.version = '1.0.0'
6
+ spec.authors = ['Christian Feier']
7
+ spec.email = ['christian.feier@gmail.com']
8
+
9
+ spec.summary = 'Simple wrapper for some common mp3gain console commands.'
10
+ spec.description = 'Takes mp3gain/aacgain binary path as an argument and offers methods to analyze and modify the'\
11
+ ' track/album gain of mp3 files.'
12
+ spec.homepage = 'https://github.com/cfe86/RubyMp3gain'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = '>= 2.5.0'
15
+
16
+ spec.metadata['homepage_uri'] = 'https://github.com/cfe86/RubyMp3gain'
17
+ spec.metadata['source_code_uri'] = 'https://github.com/cfe86/RubyMp3gain'
18
+ spec.metadata['changelog_uri'] = 'https://github.com/cfe86/RubyMp3gain'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ # Uncomment to register a new dependency of your gem
30
+ # spec.add_dependency "example-gem", "~> 1.0"
31
+
32
+ # For more information and examples about making a new gem, checkout our
33
+ # guide at: https://bundler.io/guides/creating_gem.html
34
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mp3gain
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Christian Feier
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-11-13 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Takes mp3gain/aacgain binary path as an argument and offers methods to
14
+ analyze and modify the track/album gain of mp3 files.
15
+ email:
16
+ - christian.feier@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".gitignore"
22
+ - ".rubocop.yml"
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - lib/.DS_Store
28
+ - lib/mp3gain.rb
29
+ - lib/mp3gain/add_gain_change.rb
30
+ - lib/mp3gain/apply_gain_change.rb
31
+ - lib/mp3gain/recommended_gain_change.rb
32
+ - mp3gain.gemspec
33
+ homepage: https://github.com/cfe86/RubyMp3gain
34
+ licenses:
35
+ - MIT
36
+ metadata:
37
+ homepage_uri: https://github.com/cfe86/RubyMp3gain
38
+ source_code_uri: https://github.com/cfe86/RubyMp3gain
39
+ changelog_uri: https://github.com/cfe86/RubyMp3gain
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: 2.5.0
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubygems_version: 3.2.22
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: Simple wrapper for some common mp3gain console commands.
59
+ test_files: []