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
@@ -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