MusicMaster 0.0.1.20101110 → 1.0.0.20120307

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.
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
@@ -0,0 +1,253 @@
1
+ #--
2
+ # Copyright (c) 2011 - 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ require 'MusicMaster/Hash'
7
+
8
+ module MusicMaster
9
+
10
+ module FilesNamer
11
+
12
+ # Get the directory in which files are recorded
13
+ #
14
+ # Return::
15
+ # * _String_: Directory to record files to
16
+ def getRecordedDir
17
+ return @MusicMasterConf[:Directories][:Record]
18
+ end
19
+
20
+ # Get the directory in which static audio files are stored
21
+ #
22
+ # Return::
23
+ # * _String_: Directory to store static audio files to
24
+ def getWaveDir
25
+ return @MusicMasterConf[:Directories][:Wave]
26
+ end
27
+
28
+ # Get the directory in which recorded files are analyzed
29
+ #
30
+ # Return::
31
+ # * _String_: Directory to store analysis results of recorded files to
32
+ def getAnalyzedRecordedDir
33
+ return @MusicMasterConf[:Directories][:AnalyzeRecord]
34
+ end
35
+
36
+ # Get the directory in which files are cleaned
37
+ #
38
+ # Return::
39
+ # * _String_: Directory to clean files to
40
+ def getCleanedDir
41
+ return @MusicMasterConf[:Directories][:Clean]
42
+ end
43
+
44
+ # Get the directory in which files are calibrated
45
+ #
46
+ # Return::
47
+ # * _String_: Directory to calibrate files to
48
+ def getCalibratedDir
49
+ return @MusicMasterConf[:Directories][:Calibrate]
50
+ end
51
+
52
+ # Get the directory in which Wave files are processed
53
+ #
54
+ # Return::
55
+ # * _String_: Directory to process files to
56
+ def getProcessesWaveDir
57
+ return @MusicMasterConf[:Directories][:ProcessWave]
58
+ end
59
+
60
+ # Get the directory in which recorded files are processed
61
+ #
62
+ # Return::
63
+ # * _String_: Directory to process files to
64
+ def getProcessesRecordDir
65
+ return @MusicMasterConf[:Directories][:ProcessRecord]
66
+ end
67
+
68
+ # Get the directory in which mix files are processed
69
+ #
70
+ # Return::
71
+ # * _String_: Directory to mix files to
72
+ def getMixDir
73
+ return @MusicMasterConf[:Directories][:Mix]
74
+ end
75
+
76
+ # Get the directory in which final mix files are linked
77
+ #
78
+ # Return::
79
+ # * _String_: Directory storing links to final mix files
80
+ def getFinalMixDir
81
+ return @MusicMasterConf[:Directories][:FinalMix]
82
+ end
83
+
84
+ # Get the directory in which files are delivered
85
+ #
86
+ # Return::
87
+ # * _String_: Directory to deliver files to
88
+ def getDeliverDir
89
+ return @MusicMasterConf[:Directories][:Deliver]
90
+ end
91
+
92
+ # Get the recorded file name of a given list of tracks on a given environment
93
+ #
94
+ # Parameters::
95
+ # * *iEnv* (_Symbol_): The environment
96
+ # * *iLstTracks* (<em>list<Integer></em>): The list of tracks being recorded
97
+ # Return::
98
+ # * _String_: Name of the Wave file
99
+ def getRecordedFileName(iEnv, iLstTracks)
100
+ return "#{getRecordedDir}/#{iEnv}.#{iLstTracks.sort.join('.')}.wav"
101
+ end
102
+
103
+ # Get the recorded silence file name on a given recording environment
104
+ #
105
+ # Parameters::
106
+ # * *iEnv* (_Symbol_): The environment
107
+ # Return::
108
+ # * _String_: Name of the Wave file
109
+ def getRecordedSilenceFileName(iEnv)
110
+ return "#{getRecordedDir}/#{iEnv}.Silence.wav"
111
+ end
112
+
113
+ # Get the recorded calibration file name, recording from a recording environment in order to be compared later with a reference environment.
114
+ #
115
+ # Parameters::
116
+ # * *iEnvReference* (_Symbol_): The reference environment
117
+ # * *iEnvRecording* (_Symbol_): The recording environment
118
+ # Return::
119
+ # * _String_: Name of the Wave file
120
+ def getRecordedCalibrationFileName(iEnvReference, iEnvRecording)
121
+ return "#{getRecordedDir}/Calibration.#{iEnvRecording}.#{iEnvReference}.wav"
122
+ end
123
+
124
+ # Get the calibrated recorded file name
125
+ #
126
+ # Parameters::
127
+ # * *iRecordedBaseName* (_String_): Base name of the recorded track
128
+ # Return::
129
+ # * _String_: Name of the Wave file
130
+ def getCalibratedFileName(iRecordedBaseName)
131
+ return "#{getCalibratedDir}/#{iRecordedBaseName}.Calibrated.wav"
132
+ end
133
+
134
+ # Get the name of a source wave file
135
+ #
136
+ # Parameters::
137
+ # * *iFileName* (_String_): Name of the Wave file used to generate this source wave file
138
+ # Return::
139
+ # * _String_: Name of the Wave file
140
+ def getWaveSourceFileName(iFileName)
141
+ if (File.exists?(iFileName))
142
+ # Use the original one
143
+ return iFileName
144
+ else
145
+ # We will generate a new one
146
+ return "#{getWaveDir}/#{File.basename(iFileName)}"
147
+ end
148
+ end
149
+
150
+ # Get the name of an analysis file taken from a recorded file
151
+ #
152
+ # Parameters::
153
+ # * *iBaseName* (_String_): Base name of the recorded file (without extension)
154
+ # Return::
155
+ # * _String_: The analysis file name
156
+ def getRecordedAnalysisFileName(iBaseName)
157
+ return "#{getAnalyzedRecordedDir}/#{iBaseName}.analyze"
158
+ end
159
+
160
+ # Get the name of a FFT profike file taken from a recorded file
161
+ #
162
+ # Parameters::
163
+ # * *iBaseName* (_String_): Base name of the recorded file (without extension)
164
+ # Return::
165
+ # * _String_: The FFT profile file name
166
+ def getRecordedFFTProfileFileName(iBaseName)
167
+ return "#{getAnalyzedRecordedDir}/#{iBaseName}.fftprofile"
168
+ end
169
+
170
+ # Get the name of the file generated after removing silences from it.
171
+ #
172
+ # Parameters::
173
+ # * *iBaseName* (_String_): Base name of the file
174
+ # Return::
175
+ # * _String_: The generated file name
176
+ def getSilenceRemovedFileName(iBaseName)
177
+ return "#{getCleanedDir}/#{iBaseName}.01.SilenceRemover.wav"
178
+ end
179
+
180
+ # Get the name of the file generated after applying a cut from it.
181
+ #
182
+ # Parameters::
183
+ # * *iBaseName* (_String_): Base name of the file
184
+ # * *iCutInfo* (<em>[String,String]</em>): The cut information, used to extract only a part of the file (begin and end markers, in seconds or samples)
185
+ # Return::
186
+ # * _String_: The generated file name
187
+ def getCutFileName(iBaseName, iCutInfo)
188
+ return "#{getCleanedDir}/#{iBaseName}.02.Cut.#{iCutInfo.join('_')}.wav"
189
+ end
190
+
191
+ # Get the name of the file generated after applying a DC remover from it.
192
+ #
193
+ # Parameters::
194
+ # * *iBaseName* (_String_): Base name of the file
195
+ # Return::
196
+ # * _String_: The generated file name
197
+ def getDCRemovedFileName(iBaseName)
198
+ return "#{getCleanedDir}/#{iBaseName}.03.DCShifter.wav"
199
+ end
200
+
201
+ # Get the name of the file generated after applying a noise gate from it.
202
+ #
203
+ # Parameters::
204
+ # * *iBaseName* (_String_): Base name of the file
205
+ # Return::
206
+ # * _String_: The generated file name
207
+ def getNoiseGateFileName(iBaseName)
208
+ return "#{getCleanedDir}/#{iBaseName}.04.NoiseGate.wav"
209
+ end
210
+
211
+ # Get the name of a file to processed
212
+ #
213
+ # Parameters::
214
+ # * *iDir* (_String_): Directory where to store the processed file
215
+ # * *iBaseName* (_String_): Base name of the processed file source
216
+ # * *iIdxProcess* (_Integer_): Index of the process
217
+ # * *iProcessName* (_String_): Name of the process to apply
218
+ # * *iProcessParams* (<em>map<Symbol,Object></em>): Process parameters
219
+ def getProcessedFileName(iDir, iBaseName, iIdxProcess, iProcessName, iProcessParams)
220
+ # If the base name contains already an ID, integrate it in the new ID
221
+ lMatch = iBaseName.match(/^(.*)\.([[:xdigit:]]{32,32})$/)
222
+ if (lMatch == nil)
223
+ return "#{iDir}/#{iBaseName}.#{iIdxProcess}.#{iProcessName}.#{iProcessParams.unique_id}.wav"
224
+ else
225
+ lNewBaseName = lMatch[1]
226
+ lNewProcessParams = {
227
+ :__InheritedID__ => lMatch[2]
228
+ }.merge(iProcessParams)
229
+ return "#{iDir}/#{lNewBaseName}.#{iIdxProcess}.#{iProcessName}.#{lNewProcessParams.unique_id}.wav"
230
+ end
231
+ end
232
+
233
+ # Get the name of a file to be mixed
234
+ #
235
+ # Parameters::
236
+ # * *iDir* (_String_): Directory where to store the mixed file
237
+ # * *iMixName* (_String_): Name of the mix
238
+ # * *iMixTracksConf* (<em>map<Symbol,Object></em>): Mix tracks' parameters
239
+ def getMixFileName(iDir, iMixName, iMixTracksConf)
240
+ return "#{iDir}/#{iMixName}.#{iMixTracksConf.unique_id}.wav"
241
+ end
242
+
243
+ # Get the name of a final mix file (the symbolic link)
244
+ #
245
+ # Parameters::
246
+ # * *iMixName* (_String_): Name of the mix
247
+ def getFinalMixFileName(iMixName)
248
+ return "#{getFinalMixDir}/#{iMixName}.wav"
249
+ end
250
+
251
+ end
252
+
253
+ end
@@ -0,0 +1,50 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module MusicMaster
7
+
8
+ module Formats
9
+
10
+ class MP3
11
+
12
+ # Give the file extension
13
+ #
14
+ # Return::
15
+ # * _String_: The file extension (without .)
16
+ def getFileExt
17
+ return 'mp3'
18
+ end
19
+
20
+ # Deliver a file.
21
+ # The delivered file can be a shortcut to the source one.
22
+ #
23
+ # Parameters::
24
+ # * *iSrcFileName* (_String_): The source file to deliver from
25
+ # * *iDstFileName* (_String_): The destination file to be delivered
26
+ # * *iFormatConf* (<em>map<Symbol,Object></em>): The format configuration
27
+ # * *iMetadata* (<em>map<Symbol,Object></em>): The metadata that can be used while delivering the file
28
+ def deliver(iSrcFileName, iDstFileName, iFormatConf, iMetadata)
29
+ # TODO: Implement it using an external tool, and make regression testing
30
+ lTranslatedParams = []
31
+ iParams.each do |iParam, iValue|
32
+ case iParam
33
+ when :SampleRate
34
+ lTranslatedParams << "Sample rate: #{iValue} Hz"
35
+ when :BitRate
36
+ lTranslatedParams << "Bit rate: #{iValue} kbps"
37
+ else
38
+ log_warn "Unknown MP3 format parameter: #{iParam} (value #{iValue.inspect}). Ignoring it."
39
+ end
40
+ end
41
+ puts "Convert file #{iSrcFileName} into file #{iDstFileName} in MP3 format with following parameters: #{lTranslatedParams.join(', ')}"
42
+ puts 'Press Enter when done.'
43
+ $stdin.gets
44
+ end
45
+
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,44 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module MusicMaster
7
+
8
+ module Formats
9
+
10
+ class Test
11
+
12
+ # Give the file extension
13
+ #
14
+ # Return::
15
+ # * _String_: The file extension (without .)
16
+ def getFileExt
17
+ return 'test.rb'
18
+ end
19
+
20
+ # Deliver a file.
21
+ # The delivered file can be a shortcut to the source one.
22
+ #
23
+ # Parameters::
24
+ # * *iSrcFileName* (_String_): The source file to deliver from
25
+ # * *iDstFileName* (_String_): The destination file to be delivered
26
+ # * *iFormatConf* (<em>map<Symbol,Object></em>): The format configuration
27
+ # * *iMetadata* (<em>map<Symbol,Object></em>): The metadata that can be used while delivering the file
28
+ def deliver(iSrcFileName, iDstFileName, iFormatConf, iMetadata)
29
+ log_debug "Deliver for test purposes file #{iDstFileName}"
30
+ File.open(iDstFileName, 'w') do |oFile|
31
+ oFile.write({
32
+ :SrcFileName => iSrcFileName,
33
+ :DstFileName => iDstFileName,
34
+ :FormatConf => iFormatConf,
35
+ :Metadata => iMetadata
36
+ }.inspect)
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,80 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module MusicMaster
7
+
8
+ module Formats
9
+
10
+ # Wave file format.
11
+ # Take the following parameters:
12
+ # * *:Dither* (_Boolean_): Do we apply dither while converting ?
13
+ # * *:SampleRate* (_Integer_): Sample rate in Hz (ie 44100, 192000 ...)
14
+ # * *:BitDepth* (_Integer_): Number of bits used to encode 1 sample on 1 channel (ie 8, 16, 24...)
15
+ class Wave
16
+
17
+ # Give the file extension
18
+ #
19
+ # Return::
20
+ # * _String_: The file extension (without .)
21
+ def getFileExt
22
+ return 'wav'
23
+ end
24
+
25
+ # Deliver a file.
26
+ # The delivered file can be a shortcut to the source one.
27
+ #
28
+ # Parameters::
29
+ # * *iSrcFileName* (_String_): The source file to deliver from
30
+ # * *iDstFileName* (_String_): The destination file to be delivered
31
+ # * *iFormatConf* (<em>map<Symbol,Object></em>): The format configuration
32
+ # * *iMetadata* (<em>map<Symbol,Object></em>): The metadata that can be used while delivering the file
33
+ def deliver(iSrcFileName, iDstFileName, iFormatConf, iMetadata)
34
+ # Check if we can just make a shortcut
35
+ lShortcut = true
36
+ if (!iFormatConf.empty?)
37
+ if (iFormatConf[:Dither])
38
+ lShortcut = false
39
+ else
40
+ # Need to get the source file attributes (sample rate and bit depth)
41
+ require 'WSK/Common'
42
+ self.class.module_eval('include WSK::Common')
43
+ accessInputWaveFile(iSrcFileName) do |iHeader, iInputData|
44
+ lShortcut = !(((iFormatConf[:SampleRate] != nil) and
45
+ (iFormatConf[:SampleRate] != iHeader.SampleRate)) or
46
+ ((iFormatConf[:BitDepth] != nil) and
47
+ (iFormatConf[:BitDepth] != iHeader.NbrBitsPerSample)))
48
+ next nil
49
+ end
50
+ end
51
+ end
52
+ if (lShortcut)
53
+ # Just create a shortcut
54
+ createShortcut(iSrcFileName, iDstFileName)
55
+ else
56
+ # We need to convert the Wave file: call SSRC
57
+ lTranslatedParams = [ '--profile standard', '--twopass' ]
58
+ iFormatConf.each do |iParam, iValue|
59
+ case iParam
60
+ when :SampleRate
61
+ lTranslatedParams << "--rate #{iValue}"
62
+ when :BitDepth
63
+ lTranslatedParams << "--bits #{iValue}"
64
+ when :Dither
65
+ lTranslatedParams << '--dither 4' if (iValue == true)
66
+ else
67
+ log_warn "Unknown Wave format parameter: #{iParam} (value #{iValue.inspect}). Ignoring it."
68
+ end
69
+ end
70
+ lCmd = "#{@MusicMasterConf[:Formats]['Wave'][:SRCCmdLine]} #{lTranslatedParams.sort.join(' ')} \"#{iSrcFileName}\" \"#{iDstFileName}\""
71
+ log_info "=> #{lCmd}"
72
+ raise "Error while executing SSRC command \"#{lCmd}\": error code #{$?.exitstatus}" if (!system(lCmd)) or ($?.exitstatus != 0)
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+
80
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+ #--
3
+ # Copyright (c) 2012 Muriel Salvan (muriel@x-aeon.com)
4
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
5
+ #++
6
+
7
+ require 'yaml'
8
+ require 'digest/md5'
9
+
10
+ class Hash
11
+
12
+ # Get a unique ID that will always be the same for any Hash having the same content
13
+ #
14
+ # Return::
15
+ # * _String_: The unique ID
16
+ def unique_id
17
+ return Digest::MD5.hexdigest(self.to_a.sort.to_yaml)
18
+ end
19
+
20
+ end
@@ -0,0 +1,241 @@
1
+ #--
2
+ # Copyright (c) 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ require 'fileutils'
7
+ require 'optparse'
8
+ require 'rUtilAnts/Logging'
9
+ RUtilAnts::Logging::install_logger_on_object(:no_dialogs => true)
10
+ require 'MusicMaster/Utils'
11
+ require 'MusicMaster/FilesNamer'
12
+ require 'MusicMaster/RakeProcesses'
13
+
14
+ module MusicMaster
15
+
16
+ class Launcher
17
+
18
+ include MusicMaster::Utils
19
+
20
+ # Constructor
21
+ def initialize
22
+ parsePlugins
23
+ @DisplayHelp = false
24
+ @Debug = false
25
+
26
+ require 'optparse'
27
+ @Options = OptionParser.new
28
+ @Options.banner = "#{$0} [--help] [--debug] #{getOptionsBanner} <ConfigFile>"
29
+ @Options.on( '--help',
30
+ 'Display help') do
31
+ @DisplayHelp = true
32
+ end
33
+ @Options.on( '--debug',
34
+ 'Activate debug logs') do
35
+ @Debug = true
36
+ end
37
+ completeOptionParser(@Options)
38
+ end
39
+
40
+ # Execute the process
41
+ #
42
+ # Parameters::
43
+ # * *iArgs* (<em>list<String></em>): The list of arguments
44
+ # Return::
45
+ # * _Integer_: The error code
46
+ def execute(iArgs)
47
+ rErrorCode = 0
48
+
49
+ lError = nil
50
+ lConfFileName = nil
51
+ begin
52
+ lRemainingArgs = @Options.parse(iArgs)
53
+ if ((lRemainingArgs.size != 1) and
54
+ (!@DisplayHelp))
55
+ lError = RuntimeError.new("Please specify 1 config file (specified: \"#{lRemainingArgs.join(' ')}\")")
56
+ end
57
+ lConfFileName = lRemainingArgs.first
58
+ rescue Exception
59
+ lError = $!
60
+ end
61
+ if (lError == nil)
62
+ if (@DisplayHelp)
63
+ puts @Options
64
+ else
65
+ if (@Debug)
66
+ activate_log_debug(true)
67
+ end
68
+ # Read the MusicMaster configuration
69
+ begin
70
+ @MusicMasterConf = get_musicmaster_conf
71
+ rescue Exception
72
+ lError = $!
73
+ end
74
+ if (lError == nil)
75
+ # Read configuration
76
+ lError, lRecordConf = readConf(lConfFileName)
77
+ if (lError == nil)
78
+ # Check the conf. This is dependent on the process
79
+ lError = checkConf(lRecordConf)
80
+ if (lError == nil)
81
+ @RecordConf = lRecordConf
82
+ initialize_Utils
83
+ begin
84
+ lRakeTarget = getRakeTarget
85
+ rescue
86
+ lError = $!
87
+ end
88
+ if (lError == nil)
89
+ if debug_activated?
90
+ Rake::application.options.trace = true
91
+ displayRakeTasks
92
+ end
93
+ begin
94
+ Rake::Task[lRakeTarget].invoke
95
+ rescue
96
+ lError = $!
97
+ end
98
+ log_info 'Processed finished successfully.' if (lError == nil)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ if (lError != nil)
106
+ log_err "#{lError}#{(debug_activated? and lError.backtrace) ? "\n#{lError.backtrace.join("\n")}" : ''}"
107
+ rErrorCode = 1
108
+ end
109
+
110
+ return rErrorCode
111
+ end
112
+
113
+ protected
114
+
115
+ # Give additional command line options banner
116
+ #
117
+ # Return::
118
+ # * _String_: Options banner
119
+ def getOptionsBanner
120
+ return ''
121
+ end
122
+
123
+ # Complete options with the specific ones of this binary
124
+ #
125
+ # Parameters::
126
+ # * *ioOptionParser* (_OptionParser_): The options parser to complete
127
+ def completeOptionParser(ioOptionParser)
128
+ end
129
+
130
+ # Check configuration.
131
+ #
132
+ # Parameters::
133
+ # * *iConf* (<em>map<Symbol,Object></em>): The configuration
134
+ # Return::
135
+ # * _Exception_: Error, or nil in case of success
136
+ def checkConf(iConf)
137
+ return nil
138
+ end
139
+
140
+ # Initialize Rake processes and return the task to be built
141
+ #
142
+ # Return::
143
+ # * _Symbol_: Rake target to execute
144
+ def getRakeTarget
145
+ return nil
146
+ end
147
+
148
+ private
149
+
150
+ include FilesNamer
151
+ include RakeProcesses
152
+ include Utils
153
+
154
+ # Get the global MusicMaster configuration
155
+ # Read it from:
156
+ # 1. The environment variable MUSICMASTER_CONF_PATH
157
+ # 2. The installed MusicMaster directory
158
+ # 3. The current directory
159
+ #
160
+ # Return::
161
+ # * <em>map<Symbol,Object></em>: The MusicMaster configuration
162
+ def get_musicmaster_conf
163
+ rMusicMasterConf = nil
164
+
165
+ lConfSource = nil
166
+ # 1. Find from the environment
167
+ lConfigFileName = ENV['MUSICMASTER_CONF_PATH']
168
+ if (lConfigFileName == nil)
169
+ # 2. Find from the MusicMaster directory
170
+ lConfigFileName = "#{File.dirname(__FILE__)}/musicmaster.conf.rb"
171
+ if (File.exists?(lConfigFileName))
172
+ lConfSource = 'MusicMaster package local libraries'
173
+ else
174
+ # 3. Find from the current directory
175
+ lConfigFileName = "musicmaster.conf.rb"
176
+ if (File.exists?(lConfigFileName))
177
+ lConfSource = 'current directory'
178
+ else
179
+ # 4. Failure
180
+ end
181
+ end
182
+ else
183
+ lConfSource = 'MUSICMASTER_CONF_PATH environment variable'
184
+ end
185
+
186
+ # Check the configuration
187
+ if (lConfSource == nil)
188
+ raise "No MusicMaster configuration file could be found. You can set it by setting MUSICMASTER_CONF_PATH environment variable, or create a musicmaster.conf.rb file either in #{File.dirname(__FILE__)} or the current directory."
189
+ else
190
+ if (File.exists?(lConfigFileName))
191
+ File.open(lConfigFileName, 'r') do |iFile|
192
+ begin
193
+ rMusicMasterConf = eval(iFile.read)
194
+ rescue Exception
195
+ raise "Invalid configuration file #{lConfigFileName} specified in #{lConfSource}: #{$!}"
196
+ rMusicMasterConf = nil
197
+ end
198
+ end
199
+ else
200
+ raise "Missing file #{lConfigFileName}, specified in #{lConfSource}"
201
+ end
202
+ end
203
+
204
+ return rMusicMasterConf
205
+ end
206
+
207
+ # Parse plugins
208
+ def parsePlugins
209
+ require 'rUtilAnts/Plugins'
210
+ RUtilAnts::Plugins::install_plugins_on_object
211
+ lLibDir = File.expand_path(File.dirname(__FILE__))
212
+ parse_plugins_from_dir('Processes', "#{lLibDir}/Processes", 'MusicMaster::Processes')
213
+ parse_plugins_from_dir('Formats', "#{lLibDir}/Formats", 'MusicMaster::Formats')
214
+ end
215
+
216
+ # Read configuration.
217
+ # Perform basic checks on it, independent of the process reading it.
218
+ #
219
+ # Parameters::
220
+ # * *iConfFile* (_String_): Configuration file
221
+ # Return::
222
+ # * _Exception_: Error, or nil in case of success
223
+ # * <em>map<Symbol,Object></em>: The configuration
224
+ def readConf(iConfFile)
225
+ rError = nil
226
+ rConf = nil
227
+
228
+ if (!File.exists?(iConfFile))
229
+ rError = RuntimeError.new("Missing configuration file: #{iConfFile}")
230
+ else
231
+ File.open(iConfFile, 'r') do |iFile|
232
+ rConf = eval(iFile.read)
233
+ end
234
+ end
235
+
236
+ return rError, rConf
237
+ end
238
+
239
+ end
240
+
241
+ end