MusicMaster 0.0.1.20101110 → 1.0.0.20120307

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/AUTHORS +4 -1
  2. data/ChangeLog +28 -0
  3. data/LICENSE +1 -1
  4. data/README +2 -5
  5. data/ReleaseInfo +8 -8
  6. data/bin/Calibrate.rb +55 -0
  7. data/bin/Clean.rb +55 -0
  8. data/bin/DBConvert.rb +3 -1
  9. data/bin/Deliver.rb +73 -42
  10. data/bin/Mix.rb +39 -78
  11. data/bin/Process.rb +55 -0
  12. data/bin/Record.rb +63 -116
  13. data/bin/{Album.rb → old/Album.rb} +18 -18
  14. data/bin/{AnalyzeAlbum.rb → old/AnalyzeAlbum.rb} +11 -11
  15. data/bin/{DeliverAlbum.rb → old/DeliverAlbum.rb} +12 -12
  16. data/bin/{Fct2Wave.rb → old/Fct2Wave.rb} +11 -11
  17. data/{album.conf.rb.example → bin/old/album.conf.rb.example} +0 -0
  18. data/lib/MusicMaster/FilesNamer.rb +253 -0
  19. data/lib/MusicMaster/Formats/MP3.rb +50 -0
  20. data/lib/MusicMaster/Formats/Test.rb +44 -0
  21. data/lib/MusicMaster/Formats/Wave.rb +80 -0
  22. data/lib/MusicMaster/Hash.rb +20 -0
  23. data/lib/MusicMaster/Launcher.rb +241 -0
  24. data/lib/MusicMaster/Processes/ApplyVolumeFct.rb +4 -8
  25. data/lib/MusicMaster/Processes/Compressor.rb +50 -47
  26. data/lib/MusicMaster/Processes/Custom.rb +3 -3
  27. data/lib/MusicMaster/Processes/{AddSilence.rb → Cut.rb} +8 -4
  28. data/lib/MusicMaster/Processes/CutFirstSignal.rb +6 -3
  29. data/lib/MusicMaster/Processes/DCShifter.rb +30 -0
  30. data/lib/MusicMaster/Processes/GVerb.rb +3 -2
  31. data/lib/MusicMaster/Processes/Normalize.rb +7 -6
  32. data/lib/MusicMaster/Processes/SilenceInserter.rb +31 -0
  33. data/lib/MusicMaster/Processes/Test.rb +39 -0
  34. data/lib/MusicMaster/Processes/VolCorrection.rb +3 -3
  35. data/lib/MusicMaster/RakeProcesses.rb +1014 -0
  36. data/lib/MusicMaster/Symbol.rb +12 -0
  37. data/lib/MusicMaster/Task.rb +29 -0
  38. data/lib/MusicMaster/Utils.rb +467 -0
  39. data/lib/MusicMaster/old/Common.rb +101 -0
  40. data/musicmaster.conf.rb.example +42 -59
  41. data/record.conf.rb.example +374 -30
  42. metadata +91 -41
  43. data/TODO +0 -3
  44. data/bin/Master.rb +0 -60
  45. data/bin/PrepareMix.rb +0 -422
  46. data/lib/MusicMaster/Common.rb +0 -197
  47. data/lib/MusicMaster/ConfLoader.rb +0 -56
  48. data/lib/MusicMaster/musicmaster.conf.rb +0 -96
  49. data/master.conf.rb.example +0 -13
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: MusicMaster
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.20101110
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ - 20120307
10
+ version: 1.0.0.20120307
5
11
  platform: ruby
6
12
  authors:
7
13
  - Muriel Salvan
@@ -9,69 +15,109 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-11-10 00:00:00 +01:00
18
+ date: 2012-03-07 00:00:00 +01:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
- name: WaveSwissKnife
22
+ name: rake
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
31
+ - 9
32
+ version: "0.9"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rUtilAnts
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 0
46
+ version: "1.0"
17
47
  type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: WaveSwissKnife
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
20
54
  requirements:
21
55
  - - ">="
22
56
  - !ruby/object:Gem::Version
57
+ segments:
58
+ - 0
59
+ - 0
60
+ - 1
23
61
  version: 0.0.1
24
- version:
62
+ type: :runtime
63
+ version_requirements: *id003
25
64
  description: Command line tool handling steps to deliver music album masters from recordings. Handle Track Mixing, Track Mastering, Track Master Delivery, Album Mastering and Album Master Delivery. Easy-to-use configuration files drive the complete processes.
26
- email: murielsalvan@users.sourceforge.net
65
+ email: muriel@x-aeon.com
27
66
  executables:
28
- - Album.rb
29
- - AnalyzeAlbum.rb
67
+ - Calibrate.rb
68
+ - Clean.rb
30
69
  - DBConvert.rb
31
70
  - Deliver.rb
32
- - DeliverAlbum.rb
33
- - Fct2Wave.rb
34
- - Master.rb
35
71
  - Mix.rb
36
- - PrepareMix.rb
72
+ - Process.rb
37
73
  - Record.rb
38
74
  extensions: []
39
75
 
40
76
  extra_rdoc_files: []
41
77
 
42
78
  files:
43
- - lib/MusicMaster/Common.rb
44
- - lib/MusicMaster/ConfLoader.rb
45
- - lib/MusicMaster/musicmaster.conf.rb
46
- - lib/MusicMaster/Processes/GVerb.rb
47
- - lib/MusicMaster/Processes/CutFirstSignal.rb
48
- - lib/MusicMaster/Processes/Normalize.rb
49
- - lib/MusicMaster/Processes/VolCorrection.rb
50
- - lib/MusicMaster/Processes/Custom.rb
51
- - lib/MusicMaster/Processes/AddSilence.rb
52
- - lib/MusicMaster/Processes/ApplyVolumeFct.rb
53
- - lib/MusicMaster/Processes/Compressor.rb
79
+ - AUTHORS
80
+ - bin/Calibrate.rb
81
+ - bin/Clean.rb
54
82
  - bin/DBConvert.rb
55
83
  - bin/Deliver.rb
56
- - bin/DeliverAlbum.rb
57
84
  - bin/Mix.rb
58
- - bin/PrepareMix.rb
85
+ - bin/old/album.conf.rb.example
86
+ - bin/old/Album.rb
87
+ - bin/old/AnalyzeAlbum.rb
88
+ - bin/old/DeliverAlbum.rb
89
+ - bin/old/Fct2Wave.rb
90
+ - bin/Process.rb
59
91
  - bin/Record.rb
60
- - bin/AnalyzeAlbum.rb
61
- - bin/Master.rb
62
- - bin/Fct2Wave.rb
63
- - bin/Album.rb
64
- - ReleaseInfo
65
- - README
66
- - LICENSE
67
- - AUTHORS
68
- - Credits
69
- - TODO
70
92
  - ChangeLog
71
- - album.conf.rb.example
72
- - master.conf.rb.example
93
+ - Credits
94
+ - lib/MusicMaster/FilesNamer.rb
95
+ - lib/MusicMaster/Formats/MP3.rb
96
+ - lib/MusicMaster/Formats/Test.rb
97
+ - lib/MusicMaster/Formats/Wave.rb
98
+ - lib/MusicMaster/Hash.rb
99
+ - lib/MusicMaster/Launcher.rb
100
+ - lib/MusicMaster/old/Common.rb
101
+ - lib/MusicMaster/Processes/ApplyVolumeFct.rb
102
+ - lib/MusicMaster/Processes/Compressor.rb
103
+ - lib/MusicMaster/Processes/Custom.rb
104
+ - lib/MusicMaster/Processes/Cut.rb
105
+ - lib/MusicMaster/Processes/CutFirstSignal.rb
106
+ - lib/MusicMaster/Processes/DCShifter.rb
107
+ - lib/MusicMaster/Processes/GVerb.rb
108
+ - lib/MusicMaster/Processes/Normalize.rb
109
+ - lib/MusicMaster/Processes/SilenceInserter.rb
110
+ - lib/MusicMaster/Processes/Test.rb
111
+ - lib/MusicMaster/Processes/VolCorrection.rb
112
+ - lib/MusicMaster/RakeProcesses.rb
113
+ - lib/MusicMaster/Symbol.rb
114
+ - lib/MusicMaster/Task.rb
115
+ - lib/MusicMaster/Utils.rb
116
+ - LICENSE
73
117
  - musicmaster.conf.rb.example
118
+ - README
74
119
  - record.conf.rb.example
120
+ - ReleaseInfo
75
121
  has_rdoc: true
76
122
  homepage: http://musicmaster.sourceforge.net/
77
123
  licenses: []
@@ -82,21 +128,25 @@ rdoc_options: []
82
128
  require_paths:
83
129
  - lib
84
130
  required_ruby_version: !ruby/object:Gem::Requirement
131
+ none: false
85
132
  requirements:
86
133
  - - ">="
87
134
  - !ruby/object:Gem::Version
135
+ segments:
136
+ - 0
88
137
  version: "0"
89
- version:
90
138
  required_rubygems_version: !ruby/object:Gem::Requirement
139
+ none: false
91
140
  requirements:
92
141
  - - ">="
93
142
  - !ruby/object:Gem::Version
143
+ segments:
144
+ - 0
94
145
  version: "0"
95
- version:
96
146
  requirements: []
97
147
 
98
148
  rubyforge_project: musicmaster
99
- rubygems_version: 1.3.5
149
+ rubygems_version: 1.3.7
100
150
  signing_key:
101
151
  specification_version: 3
102
152
  summary: Command line tool helping recording, mixing and mastering music tracks and albums.
data/TODO DELETED
@@ -1,3 +0,0 @@
1
- * Add a Makefile generation procedure to ensure that modifying files will regenerate correct albums.
2
- * Implement Functions with inheritance for specialization.
3
- * Implement a Multiband compressor.
data/bin/Master.rb DELETED
@@ -1,60 +0,0 @@
1
- #!env ruby
2
- #--
3
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
4
- # Licensed under the terms specified in LICENSE file. No warranty is provided.
5
- #++
6
-
7
- require 'fileutils'
8
- require 'MusicMaster/Common'
9
- require 'rUtilAnts/Logging'
10
- RUtilAnts::Logging::initializeLogging('', '')
11
- require 'MusicMaster/ConfLoader'
12
-
13
- module MusicMaster
14
-
15
- # Execute the mastering
16
- #
17
- # Parameters:
18
- # * *iConf* (<em>map<Symbol,Object></em>): Configuration of the master
19
- # * *iWaveFile* (_String_): Wave file to master
20
- # Return:
21
- # * _String_: Name of the Wave file containing the result
22
- def self.execute(iConf, iWaveFile)
23
- rWaveFileToProcess = "#{$MusicMasterConf[:Master][:Dir]}/#{File.basename(iWaveFile)}"
24
-
25
- logInfo 'Copying Master file ...'
26
- FileUtils::cp(iWaveFile, rWaveFileToProcess)
27
- # Execute each step of the mastering to the wave file
28
- if (iConf[:Mastering] != nil)
29
- self.applyProcesses(iConf[:Mastering], rWaveFileToProcess, $MusicMasterConf[:Master][:Dir])
30
- end
31
-
32
- return rWaveFileToProcess
33
- end
34
-
35
- end
36
-
37
- rErrorCode = 0
38
- lConfFile, lWaveFile = ARGV[0..1]
39
- if ((lConfFile == nil) or
40
- (lWaveFile == nil))
41
- logErr 'Usage: Master <ConfFile> <WaveFile>'
42
- rErrorCode = 1
43
- elsif (!File.exists?(lConfFile))
44
- logErr "File #{lConfFile} does not exist."
45
- rErrorCode = 2
46
- elsif (!File.exists?(lWaveFile))
47
- logErr "File #{lWaveFile} does not exist."
48
- rErrorCode = 3
49
- else
50
- MusicMaster::parsePlugins
51
- FileUtils::mkdir_p($MusicMasterConf[:Master][:Dir])
52
- lConf = nil
53
- File.open(lConfFile, 'r') do |iFile|
54
- lConf = eval(iFile.read)
55
- end
56
- lFinalWave = MusicMaster::execute(lConf, lWaveFile)
57
- logInfo "===== Mastering finished in #{lFinalWave}"
58
- end
59
-
60
- exit rErrorCode
data/bin/PrepareMix.rb DELETED
@@ -1,422 +0,0 @@
1
- #!env ruby
2
- #--
3
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
4
- # Licensed under the terms specified in LICENSE file. No warranty is provided.
5
- #++
6
-
7
- require 'MusicMaster/Common'
8
- require 'rUtilAnts/Plugins'
9
- RUtilAnts::Plugins::initializePlugins
10
- require 'rUtilAnts/Logging'
11
- RUtilAnts::Logging::initializeLogging('', '')
12
- require 'MusicMaster/ConfLoader'
13
-
14
- module MusicMaster
15
-
16
- # Get the configuration
17
- #
18
- # Parameters:
19
- # * *iRecordConf* (<em>map<Symbol,Object></em>): The record configuration
20
- # Return:
21
- # * <em>map<Symbol,Object></em>: The configuration
22
- def self.getConfig(iRecordConf)
23
- rConfig = {
24
- :MixFiles => []
25
- }
26
-
27
- # Check all needed files are present
28
- lError = false
29
- if (iRecordConf[:Patches] != nil)
30
- iRecordConf[:Patches].each do |iIdxTrack, iTrackConf|
31
- if (!File.exists?("Patch.#{iIdxTrack}.wav"))
32
- logErr "Missing file Patch.#{iIdxTrack}.wav"
33
- lError = true
34
- end
35
- if (!File.exists?("Patch.#{iIdxTrack}.Silence.wav"))
36
- logErr "Missing file Patch.#{iIdxTrack}.Silence.wav"
37
- lError = true
38
- end
39
- if (iTrackConf[:VolCorrection] == nil)
40
- if (!File.exists?("Patch.#{iIdxTrack}.VolOriginal.wav"))
41
- logErr "Missing file Patch.#{iIdxTrack}.VolOriginal.wav"
42
- lError = true
43
- end
44
- if (!File.exists?("Patch.#{iIdxTrack}.VolReference.wav"))
45
- logErr "Missing file Patch.#{iIdxTrack}.VolReference.wav"
46
- lError = true
47
- end
48
- end
49
- end
50
- end
51
- if (iRecordConf[:Performs] != nil)
52
- iRecordConf[:Performs].each do |iLstPerform|
53
- if (!File.exists?("Perform.#{iLstPerform.join(' ')}.wav"))
54
- logErr "Missing file Perform.#{iLstPerform.join(' ')}.wav"
55
- lError = true
56
- end
57
- end
58
- end
59
- if (!File.exists?('Perform.Silence.wav'))
60
- logErr 'Missing file Perform.Silence.wav'
61
- lError = true
62
- end
63
-
64
- if (lError)
65
- logErr 'Some errors were found during files parsing. Aborting.'
66
- else
67
- # Generate the configuration
68
- lPerformSilenceThresholds = getSilenceThresholds('Perform')
69
- lLstStrPerformSilenceThresholds = []
70
- lPerformSilenceThresholds.each do |iSilenceThresholdInfo|
71
- lLstStrPerformSilenceThresholds << iSilenceThresholdInfo.join(',')
72
- end
73
- lPerformFFTProfile = genSilenceFFTProfile('Perform')
74
- # Perform files
75
- if (iRecordConf[:Performs] != nil)
76
- iRecordConf[:Performs].each do |iLstPerform|
77
- lFileName = "Perform.#{iLstPerform.join(' ')}.wav"
78
- # Check if there is a DC offset to apply first
79
- lAnalyze = analyzeFile(lFileName)
80
- lDCOffsets = []
81
- lOffset = false
82
- lAnalyze[:MoyValues].each do |iMoyValue|
83
- lDCOffset = iMoyValue.round
84
- lDCOffsets << lDCOffset
85
- if (lDCOffset != 0)
86
- lOffset = true
87
- end
88
- end
89
- lSilenceThresholdsWithDC = getDCThresholds(lDCOffsets, lPerformSilenceThresholds)
90
- # Build the list of parameters to give to wsk
91
- lLstStrSilenceThresholdsWithDC = []
92
- lSilenceThresholdsWithDC.each do |iSilenceThresholdInfo|
93
- lLstStrSilenceThresholdsWithDC << iSilenceThresholdInfo.join(',')
94
- end
95
- # The list of operations to perform
96
- # list< [ String, String ] >
97
- lOperations = [
98
- [ 'SilenceRemover', "--silencethreshold \"#{lLstStrSilenceThresholdsWithDC.join('|')}\" --attack 0 --release #{$MusicMasterConf[:NoiseGate][:SilenceMin]} --noisefft \"#{lPerformFFTProfile}\"" ]
99
- ]
100
- if (lOffset)
101
- logInfo "DC offset to correct: #{lDCOffsets.join(', ')}"
102
- lOperations << [ 'DCShifter', "--offset \"#{lDCOffsets.map { |iValue| -iValue }.join('|')}\"" ]
103
- else
104
- logInfo 'No DC offset to correct'
105
- end
106
- lOperations << [ 'NoiseGate', "--silencethreshold \"#{lLstStrPerformSilenceThresholds.join('|')}\" --attack #{$MusicMasterConf[:NoiseGate][:Attack]} --release #{$MusicMasterConf[:NoiseGate][:Release]} --silencemin #{$MusicMasterConf[:NoiseGate][:SilenceMin]} --noisefft \"#{lPerformFFTProfile}\"" ]
107
- # Register this file
108
- rConfig[:MixFiles] << {
109
- :FileName => lFileName,
110
- :Operations => lOperations
111
- }
112
- end
113
- end
114
- # Patch files
115
- if (iRecordConf[:Patches] != nil)
116
- iRecordConf[:Patches].each do |iIdxTrack, iTrackConf|
117
- # Measure the volume differences between Perform and Patch
118
- lPatchSilenceThresholds = getSilenceThresholds("Patch.#{iIdxTrack}")
119
- lLstStrPatchSilenceThresholds = []
120
- lPatchSilenceThresholds.each do |iSilenceThresholdInfo|
121
- lLstStrPatchSilenceThresholds << iSilenceThresholdInfo.join(',')
122
- end
123
- lPatchFFTProfile = genSilenceFFTProfile("Patch.#{iIdxTrack}")
124
- # Check if there is a DC offset to apply first
125
- lFileName = "Patch.#{iIdxTrack}.wav"
126
- lAnalyze = analyzeFile(lFileName)
127
- lDCOffsets = []
128
- lOffset = false
129
- lAnalyze[:MoyValues].each do |iMoyValue|
130
- lDCOffset = iMoyValue.round
131
- lDCOffsets << lDCOffset
132
- if (lDCOffset != 0)
133
- lOffset = true
134
- end
135
- end
136
- lSilenceThresholdsWithDC = getDCThresholds(lDCOffsets, lPatchSilenceThresholds)
137
- # Build the list of parameters to give to wsk
138
- lLstStrSilenceThresholdsWithDC = []
139
- lSilenceThresholdsWithDC.each do |iSilenceThresholdInfo|
140
- lLstStrSilenceThresholdsWithDC << iSilenceThresholdInfo.join(',')
141
- end
142
- lVolCorrection = nil
143
- if (iTrackConf[:VolCorrection] == nil)
144
- # We use recorded previews to indicate volume corrections
145
- lVolReference_Framed = genFramedWave("Patch.#{iIdxTrack}.VolReference.wav", lLstStrPerformSilenceThresholds, iTrackConf[:VolCompareCuts][0], iTrackConf[:VolCompareCuts][1], lPerformFFTProfile)
146
- lVolOriginal_Framed = genFramedWave("Patch.#{iIdxTrack}.VolOriginal.wav", lLstStrPatchSilenceThresholds, iTrackConf[:VolCompareCuts][0], iTrackConf[:VolCompareCuts][1], lPatchFFTProfile)
147
- lVolReference_Analyze = analyzeFile(lVolReference_Framed)
148
- lVolOriginal_Analyze = analyzeFile(lVolOriginal_Framed)
149
- lRMSReference = 0
150
- lVolReference_Analyze[:RMSValues].each do |iValue|
151
- lRMSReference += iValue
152
- end
153
- lRMSReference = lRMSReference / lVolReference_Analyze[:RMSValues].size
154
- lRMSOriginal = 0
155
- lVolOriginal_Analyze[:RMSValues].each do |iValue|
156
- lRMSOriginal += iValue
157
- end
158
- lRMSOriginal = lRMSOriginal / lVolOriginal_Analyze[:RMSValues].size
159
- # Show RMS difference
160
- logInfo "Track #{iIdxTrack} - Reference sample RMS: #{lRMSReference} (#{lVolReference_Analyze[:RMSValues].join(', ')})"
161
- logInfo "Track #{iIdxTrack} - Patch sample RMS: #{lRMSOriginal} (#{lVolOriginal_Analyze[:RMSValues].join(', ')})"
162
- # If the Patch is louder, apply a volume reduction
163
- if (lRMSOriginal != lRMSReference)
164
- if (lRMSOriginal < lRMSReference)
165
- # Here we are loosing quality: we need to increase the volume
166
- lDBValue, lPCValue = val2db(lRMSReference-lRMSOriginal, lAnalyze[:MinPossibleValue].abs)
167
- logWarn "Patch Track #{iIdxTrack} should be recorded louder (at least #{lDBValue} db <=> #{lPCValue} %)."
168
- end
169
- lVolCorrection = "#{lRMSReference}/#{lRMSOriginal}"
170
- end
171
- else
172
- lVolCorrection = iTrackConf[:VolCorrection]
173
- end
174
- # The list of operations to perform
175
- # list< [ String, String ] >
176
- lOperations = [
177
- [ 'SilenceRemover', "--silencethreshold \"#{lLstStrSilenceThresholdsWithDC.join('|')}\" --attack 0 --release #{$MusicMasterConf[:NoiseGate][:SilenceMin]} --noisefft \"#{lPatchFFTProfile}\"" ]
178
- ]
179
- if (lOffset)
180
- logInfo "DC offset to correct: #{lDCOffsets.join(', ')}"
181
- lOperations << [ 'DCShifter', "--offset \"#{lDCOffsets.map { |iValue| -iValue }.join('|')}\"" ]
182
- else
183
- logInfo 'No DC offset to correct'
184
- end
185
- lOperations << [ 'NoiseGate', "--silencethreshold \"#{lLstStrPatchSilenceThresholds.join('|')}\" --attack #{$MusicMasterConf[:NoiseGate][:Attack]} --release #{$MusicMasterConf[:NoiseGate][:Release]} --silencemin #{$MusicMasterConf[:NoiseGate][:SilenceMin]} --noisefft \"#{lPatchFFTProfile}\"" ]
186
- if (lVolCorrection != nil)
187
- lOperations << [ 'Multiply', "--coeff \"#{lVolCorrection}\"" ]
188
- end
189
- # Register this file
190
- rConfig[:MixFiles] << {
191
- :FileName => lFileName,
192
- :Operations => lOperations
193
- }
194
- end
195
- end
196
- # Now treat additional WAV files
197
- if (iRecordConf[:WaveFiles])
198
- lLstWaveFiles = Dir.glob('Wave.*.wav')
199
- if (lLstWaveFiles.empty?)
200
- logWarn 'Record conf indicated some Wave files were present, but none was found.'
201
- else
202
- lLstWaveFiles.each do |iFileName|
203
- rConfig[:MixFiles] << {
204
- :FileName => iFileName,
205
- :Operations => []
206
- }
207
- end
208
- end
209
- end
210
- end
211
-
212
- return rConfig
213
- end
214
-
215
- # Convert a value to its db notation and % notation
216
- #
217
- # Parameters:
218
- # * *iValue* (_Integer_): The value
219
- # * *iMaxValue* (_Integer_): The maximal possible value
220
- # Return:
221
- # * _Float_: Its corresponding db
222
- # * _Float_: Its corresponding percentage
223
- def self.val2db(iValue, iMaxValue)
224
- if (iValue == 0)
225
- return -1.0/0, 0.0
226
- else
227
- if (defined?(@Log2) == nil)
228
- @Log2 = Math.log(2.0)
229
- end
230
- return -6*(Math.log(Float(iMaxValue))-Math.log(Float(iValue.abs)))/@Log2, (Float(iValue.abs)*100)/Float(iMaxValue)
231
- end
232
- end
233
-
234
- # Get thresholds shifted by a DC offset.
235
- #
236
- # Parameters:
237
- # * *iDCOffsets* (<em>list<Integer></em>): The DC offsets
238
- # * *iThresholds* (<em>list<[Integer,Integer]></em>): The thresholds to shift
239
- # Return:
240
- # * <em>list<[Integer,Integer]></em>: The shifted thresholds
241
- # * _Boolean_: Has an offset really been applied ?
242
- def self.getDCThresholds(iDCOffsets, iThresholds)
243
- rCorrectedSilenceThresholds = []
244
-
245
- # Compute the silence thresholds with DC offset applied
246
- iThresholds.each do |iThresholdInfo|
247
- lCorrectedThresholdInfo = []
248
- iThresholdInfo.each_with_index do |iValue, iIdxChannel|
249
- lCorrectedThresholdInfo << iValue + iDCOffsets[iIdxChannel]
250
- end
251
- rCorrectedSilenceThresholds << lCorrectedThresholdInfo
252
- end
253
-
254
- return rCorrectedSilenceThresholds
255
- end
256
-
257
- # Analyze a given wav file
258
- #
259
- # Parameters:
260
- # * *iWaveFile* (_String_): The wav file to analyze
261
- # Return:
262
- # * <em>map<Symbol,Object></em>: The analyze result
263
- def self.analyzeFile(iWaveFile)
264
- rResult = nil
265
-
266
- lAnalyzeFile = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{File.basename(iWaveFile)}.analyze"
267
- if (!File.exists?(lAnalyzeFile))
268
- lDummyFile = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/Dummy.wav"
269
- wsk(iWaveFile, lDummyFile, 'Analyze')
270
- File.unlink(lDummyFile)
271
- FileUtils::mv('analyze.result', lAnalyzeFile)
272
- end
273
- File.open(lAnalyzeFile, 'rb') do |iFile|
274
- rResult = Marshal.load(iFile.read)
275
- end
276
-
277
- return rResult
278
- end
279
-
280
- # Get the silence threshold of a given record type.
281
- # Remove the DC offset in the returned thresholds.
282
- #
283
- # Parameters:
284
- # * *iRecordType* (_String_): The record type
285
- # Return:
286
- # * <em>list<[Integer,Integer]></em>: Silence thresholds, per channel
287
- def self.getSilenceThresholds(iRecordType)
288
- rSilenceThresholds = []
289
-
290
- # Read the silence file
291
- lSilenceThresholdFile = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{iRecordType}.Silence.threshold"
292
- if (!File.exists?(lSilenceThresholdFile))
293
- lResult = analyzeFile("#{iRecordType}.Silence.wav")
294
- # Compute the DC offsets
295
- lDCOffsets = lResult[:MoyValues].map { |iValue| iValue.round }
296
- lSilenceThresholds = []
297
- lResult[:MaxValues].each_with_index do |iMaxValue, iIdxChannel|
298
- # Remove DC Offset
299
- lCorrectedMinValue = lResult[:MinValues][iIdxChannel] - lDCOffsets[iIdxChannel]
300
- lCorrectedMaxValue = iMaxValue - lDCOffsets[iIdxChannel]
301
- # Compute the silence threshold by adding the margin
302
- lSilenceThresholds << [(lCorrectedMinValue-lCorrectedMinValue.abs*$MusicMasterConf[:PrepareMix][:MarginSilenceThresholds]).to_i, (lCorrectedMaxValue+lCorrectedMaxValue.abs*$MusicMasterConf[:PrepareMix][:MarginSilenceThresholds]).to_i]
303
- end
304
- # Write them
305
- File.open(lSilenceThresholdFile, 'wb') do |oFile|
306
- oFile.write(Marshal.dump(lSilenceThresholds))
307
- end
308
- end
309
- File.open(lSilenceThresholdFile, 'rb') do |iFile|
310
- rSilenceThresholds = Marshal.load(iFile.read)
311
- end
312
- logInfo "#{iRecordType} silence thresholds: #{rSilenceThresholds.join(', ')}"
313
-
314
- return rSilenceThresholds
315
- end
316
-
317
- # Generate the silence FFT profile of a record type.
318
- #
319
- # Parameters:
320
- # * *iRecordType* (_String_): The record type
321
- # Return:
322
- # * _String_: Name of the file containing the FFT profile
323
- def self.genSilenceFFTProfile(iRecordType)
324
- rFFTProfileFileName = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{iRecordType}.Silence.fftprofile"
325
-
326
- if (!File.exists?(rFFTProfileFileName))
327
- lDummyFile = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/Dummy.wav"
328
- wsk("#{iRecordType}.Silence.wav", lDummyFile, 'FFT')
329
- File.unlink(lDummyFile)
330
- FileUtils::mv('fft.result', rFFTProfileFileName)
331
- end
332
-
333
- return rFFTProfileFileName
334
- end
335
-
336
- # Generate the framed wave file corresponding to a specified wave file.
337
- # Framed wave removes silence at the beginning and end of the file, and then cut a specific section of the file
338
- # If the framed file already exists, it does nothing.
339
- #
340
- # Parameters:
341
- # * *iInputFile* (_String_): The file we want to frame
342
- # * *iStrSilenceThresholds* (_String_): The silence thresholds parameter
343
- # * *iBeginCut* (_String_): The begin marker to cut
344
- # * *iEndCut* (_String_): The end marker to cut
345
- # * *iSilenceFFTProfile* (_String_): Name of the file containing the silence FFT profile
346
- # Return:
347
- # * _String_: Name of the framed file
348
- def self.genFramedWave(iInputFile, iStrSilenceThresholds, iBeginCut, iEndCut, iSilenceFFTProfile)
349
- lBaseName = File.basename(iInputFile)[0..-5]
350
- lFileName_Framed = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{lBaseName}_Framed.wav"
351
- if (File.exists?(lFileName_Framed))
352
- logInfo "File #{lFileName_Framed} already exists. Skipping its generation."
353
- else
354
- wsk(iInputFile, lFileName_Framed, 'SilenceRemover', "--silencethreshold \"#{iStrSilenceThresholds}\" --attack 0 --release 0 --noisefft \"#{iSilenceFFTProfile}\"")
355
- end
356
- # Cut the specific region
357
- lFileName_Cut = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{lBaseName}_Cut.wav"
358
- if (File.exists?(lFileName_Cut))
359
- logInfo "File #{lFileName_Cut} already exists. Skipping its generation."
360
- else
361
- wsk(lFileName_Framed, lFileName_Cut, 'Cut', "--begin \"#{iBeginCut}\" --end \"#{iEndCut}\"")
362
- end
363
- # Remove its DC offset if needed
364
- lAnalyze = analyzeFile(lFileName_Cut)
365
- lDCOffsets = []
366
- lOffset = false
367
- lAnalyze[:MoyValues].each do |iValue|
368
- lDCOffset = iValue.round
369
- lDCOffsets << lDCOffset
370
- if (lDCOffset != 0)
371
- lOffset = true
372
- end
373
- end
374
- lFileName_DCOffset = nil
375
- if (lOffset)
376
- lFileName_DCOffset = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{lBaseName}_DCOffset.wav"
377
- if (File.exists?(lFileName_DCOffset))
378
- logInfo "File #{lFileName_DCOffset} already exists. Skipping its generation."
379
- else
380
- wsk(lFileName_Cut, lFileName_DCOffset, 'DCShifter', "--offset \"#{lDCOffsets.map { |iValue| -iValue }.join('|')}\"")
381
- end
382
- else
383
- lFileName_DCOffset = lFileName_Cut
384
- end
385
- rFileName_NoiseGate = "#{$MusicMasterConf[:PrepareMix][:TempDir]}/#{lBaseName}_NoiseGate.wav"
386
- if (File.exists?(rFileName_NoiseGate))
387
- logInfo "File #{rFileName_NoiseGate} already exists. Skipping its generation."
388
- else
389
- wsk(lFileName_DCOffset, rFileName_NoiseGate, 'NoiseGate', "--silencethreshold \"#{iStrSilenceThresholds}\" --attack #{$MusicMasterConf[:NoiseGate][:Attack]} --release #{$MusicMasterConf[:NoiseGate][:Release]} --silencemin #{$MusicMasterConf[:NoiseGate][:SilenceMin]} --noisefft \"#{iSilenceFFTProfile}\"")
390
- end
391
-
392
- return rFileName_NoiseGate
393
- end
394
-
395
- end
396
-
397
- rErrorCode = 0
398
- lRecordConfFile, lConfigFile = ARGV[0..1]
399
- if ((lRecordConfFile == nil) or
400
- (lConfigFile == nil))
401
- puts 'Usage: PrepareMix <RecordConfFile> <MixConfFile>'
402
- rErrorCode = 1
403
- elsif (File.exists?(lConfigFile))
404
- logErr "File #{lConfigFile} already exist."
405
- rErrorCode = 2
406
- else
407
- lError, lRecordConf = MusicMaster::readRecordConf(lRecordConfFile)
408
- if (lError == nil)
409
- FileUtils::mkdir_p($MusicMasterConf[:PrepareMix][:TempDir])
410
- lConfig = MusicMaster::getConfig(lRecordConf)
411
- require 'pp'
412
- File.open(lConfigFile, 'w') do |oFile|
413
- oFile.write(lConfig.pretty_inspect)
414
- end
415
- logInfo "===== config saved in #{lConfigFile}"
416
- else
417
- logErr "Error: #{lError}"
418
- rErrorCode = 3
419
- end
420
- end
421
-
422
- exit rErrorCode