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.
- data/AUTHORS +4 -1
- data/ChangeLog +28 -0
- data/LICENSE +1 -1
- data/README +2 -5
- data/ReleaseInfo +8 -8
- data/bin/Calibrate.rb +55 -0
- data/bin/Clean.rb +55 -0
- data/bin/DBConvert.rb +3 -1
- data/bin/Deliver.rb +73 -42
- data/bin/Mix.rb +39 -78
- data/bin/Process.rb +55 -0
- data/bin/Record.rb +63 -116
- data/bin/{Album.rb → old/Album.rb} +18 -18
- data/bin/{AnalyzeAlbum.rb → old/AnalyzeAlbum.rb} +11 -11
- data/bin/{DeliverAlbum.rb → old/DeliverAlbum.rb} +12 -12
- data/bin/{Fct2Wave.rb → old/Fct2Wave.rb} +11 -11
- data/{album.conf.rb.example → bin/old/album.conf.rb.example} +0 -0
- data/lib/MusicMaster/FilesNamer.rb +253 -0
- data/lib/MusicMaster/Formats/MP3.rb +50 -0
- data/lib/MusicMaster/Formats/Test.rb +44 -0
- data/lib/MusicMaster/Formats/Wave.rb +80 -0
- data/lib/MusicMaster/Hash.rb +20 -0
- data/lib/MusicMaster/Launcher.rb +241 -0
- data/lib/MusicMaster/Processes/ApplyVolumeFct.rb +4 -8
- data/lib/MusicMaster/Processes/Compressor.rb +50 -47
- data/lib/MusicMaster/Processes/Custom.rb +3 -3
- data/lib/MusicMaster/Processes/{AddSilence.rb → Cut.rb} +8 -4
- data/lib/MusicMaster/Processes/CutFirstSignal.rb +6 -3
- data/lib/MusicMaster/Processes/DCShifter.rb +30 -0
- data/lib/MusicMaster/Processes/GVerb.rb +3 -2
- data/lib/MusicMaster/Processes/Normalize.rb +7 -6
- data/lib/MusicMaster/Processes/SilenceInserter.rb +31 -0
- data/lib/MusicMaster/Processes/Test.rb +39 -0
- data/lib/MusicMaster/Processes/VolCorrection.rb +3 -3
- data/lib/MusicMaster/RakeProcesses.rb +1014 -0
- data/lib/MusicMaster/Symbol.rb +12 -0
- data/lib/MusicMaster/Task.rb +29 -0
- data/lib/MusicMaster/Utils.rb +467 -0
- data/lib/MusicMaster/old/Common.rb +101 -0
- data/musicmaster.conf.rb.example +42 -59
- data/record.conf.rb.example +374 -30
- metadata +91 -41
- data/TODO +0 -3
- data/bin/Master.rb +0 -60
- data/bin/PrepareMix.rb +0 -422
- data/lib/MusicMaster/Common.rb +0 -197
- data/lib/MusicMaster/ConfLoader.rb +0 -56
- data/lib/MusicMaster/musicmaster.conf.rb +0 -96
- 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
|