def initialize (cls,
                    aacCommandLine, audioProcessorMap,
                    ffmpegCommand, midiToWavCommandLine,
                    soundStyleNameToEffectsMap, intermediateFilesAreKept):
        """Sets some global processing data like e.g. the command
           paths."""

        Logging.trace(">>: aac = %r, audioProcessor = %r,"
                      + " ffmpeg = %r, midiToWavCommand = %r,"
                      + " soundStyleNameToEffectsMap = %r,"
                      + " debugging = %r",
                      aacCommandLine, audioProcessorMap,
                      ffmpegCommand, midiToWavCommandLine,
                      soundStyleNameToEffectsMap,
                      intermediateFilesAreKept)

        cls._aacCommandLine                = aacCommandLine
        cls._audioProcessorMap             = audioProcessorMap
        cls._intermediateFilesAreKept      = intermediateFilesAreKept
        cls._ffmpegCommand                 = ffmpegCommand
        cls._midiToWavRenderingCommandList = tokenize(midiToWavCommandLine)
        cls._soundStyleNameToEffectsMap    = soundStyleNameToEffectsMap

        # check whether sox is used as audio processor
        commandList = tokenize(cls._audioProcessorMap["refinementCommandLine"])
        command = commandList[0].lower()
        cls._audioProcessorIsSox = (command.endswith("sox")
                                    or command.endswith("sox.exe"))

        Logging.trace("<<")
    def _compressAudio (self, audioFilePath, songTitle, targetFilePath):
        """Compresses audio file with <songTitle> in path with
          <audioFilePath> to AAC file at <targetFilePath>"""

        Logging.trace(">>: audioFile = %r, title = %r,"
                      + " targetFile = %r",
                      audioFilePath, songTitle, targetFilePath)

        cls = self.__class__

        OperatingSystem.showMessageOnConsole("== convert to AAC: "
                                             + songTitle)

        commandLine = iif(cls._aacCommandLine != "", cls._aacCommandLine,
                          ("%s -loglevel %s -aac_tns 0"
                           + " -i ${infile} -y ${outfile}")
                           % (cls._ffmpegCommand, _ffmpegLogLevel))
        variableMap = { "infile"  : audioFilePath,
                        "outfile" : targetFilePath }
        command = cls._replaceVariablesByValues(tokenize(commandLine),
                                                variableMap)

        OperatingSystem.executeCommand(command, True)

        Logging.trace("<<")
    def _shiftAudioFileExternally (cls, commandLine, audioFilePath,
                                   shiftedFilePath, shiftOffset):
        """Shifts audio file in <audioFilePath> to shifted audio in
           <shiftedFilePath> with silence prefix of length
           <shiftOffset> using external command with <commandLine>"""

        Logging.trace(">>: commandLine = %r,"
                      + " infile = %r, outfile = %r,"
                      + " shiftOffset = %7.3f",
                      commandLine, audioFilePath,
                      shiftedFilePath, shiftOffset)

        variableMap = { "infile"   : audioFilePath,
                        "outfile"  : shiftedFilePath,
                        "duration" : "%7.3f" % shiftOffset }
        command = cls._replaceVariablesByValues(tokenize(commandLine),
                                                variableMap)
        OperatingSystem.executeCommand(command, True,
                                       stdout=OperatingSystem.nullDevice)

        Logging.trace("<<")
    def _mixdownToWavFileExternally (self, sourceFilePathList,
                                     volumeFactorList, masteringEffectList,
                                     amplificationLevel, targetFilePath):
        """Mixes WAV audio files given in <sourceFilePathList> to target WAV
           file with <targetFilePath> with volumes given by
           <volumeFactorList> with loudness amplification given by
           <amplificationLevel> using external command;
           <masteringEffectList> gives the refinement effects for this
           track (if any) to be applied after mixdown"""

        Logging.trace(">>: sourceFiles = %r, volumeFactors = %r,"
                      + " masteringEffects = %r, level = %4.3f,"
                      + " targetFile = %r",
                      sourceFilePathList, volumeFactorList,
                      masteringEffectList, amplificationLevel,
                      targetFilePath)

        cls = self.__class__

        # some shorthands
        audioProcMap     = cls._audioProcessorMap
        replaceVariables = cls._replaceVariablesByValues

        # check whether mastering is done after mixdown
        masteringPassIsRequired = (amplificationLevel != 0
                                   or masteringEffectList > "")
        intermediateFilePath = self._audioDirectoryPath + "/result-mix.wav"
        intermediateFilePath = iif(masteringPassIsRequired,
                                   intermediateFilePath, targetFilePath)

        Logging.trace("--: masteringPass = %r, intermediateFile = %r",
                      masteringPassIsRequired, intermediateFilePath)

        # do the mixdown of the audio sources
        commandRegexp = re.compile(r"([^\[]*)\[([^\]]+)\](.*)")
        mixingCommandLine = audioProcMap["mixingCommandLine"]
        match = commandRegexp.search(mixingCommandLine)

        if match is None:
            Logging.trace("--: bad command line format for mix - %r",
                          mixingCommandLine)
        else:
            commandPrefix        = tokenize(match.group(1))
            commandRepeatingPart = tokenize(match.group(2))
            commandSuffix        = tokenize(match.group(3))

            elementCount = len(sourceFilePathList)
            command = []

            for i in range(elementCount):
                volumeFactor = volumeFactorList[i]
                filePath     = sourceFilePathList[i]
                variableMap  = { "factor" : volumeFactor,
                                 "infile" : filePath }
                part = replaceVariables(commandRepeatingPart, variableMap)
                command.extend(part)

            Logging.trace("--: repeating part = %r", command)

            commandList = commandPrefix + command + commandSuffix
            variableMap = { "outfile" : intermediateFilePath }
            command = replaceVariables(commandList, variableMap)
            OperatingSystem.executeCommand(command, True,
                                           stdout=OperatingSystem.nullDevice)

        if masteringPassIsRequired:
            # do mastering and amplification
            amplificationEffect = audioProcMap["amplificationEffect"]
            amplificationEffectTokenList = tokenize(amplificationEffect)
            variableMap  = { "amplificationLevel" : amplificationLevel }
            nmEffectPartList = replaceVariables(amplificationEffectTokenList,
                                                variableMap)
            effectList = (tokenize(masteringEffectList)
                          + nmEffectPartList)

            refinementCommandLine = audioProcMap["refinementCommandLine"]
            refinementCommandList = tokenize(refinementCommandLine)
            variableMap = { "infile"  : intermediateFilePath,
                            "outfile" : targetFilePath,
                            "effects" : effectList }
            command = replaceVariables(refinementCommandList, variableMap)
            OperatingSystem.executeCommand(command, True)
            OperatingSystem.removeFile(intermediateFilePath,
                                       cls._intermediateFilesAreKept)

        Logging.trace("<<")
    def _processAudioRefinement (self, voiceName, audioProcessingEffects):
        """Handles audio processing given by <audioProcessingEffects>"""

        Logging.trace(">>: voice = %s, effects = %r",
                      voiceName, audioProcessingEffects)

        cls = self.__class__

        debugFileCount = 0
        separator = cls._audioProcessorMap["chainSeparator"]
        chainCommandList = splitAndStrip(audioProcessingEffects, separator)
        chainCommandCount = len(chainCommandList)
        commandList = tokenize(cls._audioProcessorMap["refinementCommandLine"])

        for chainIndex, chainProcessingEffects in enumerate(chainCommandList):
            Logging.trace("--: chain[%d] = %r",
                          chainIndex, chainProcessingEffects)
            chainPosition = iif3(chainCommandCount == 1, "SINGLE",
                                 chainIndex == 0, "FIRST",
                                 chainIndex == chainCommandCount - 1, "LAST",
                                 "OTHER")
            chainPartCommandList = splitAndStrip(chainProcessingEffects,
                                                 "tee ")
            partCount = len(chainPartCommandList)

            for partIndex, partProcessingEffects \
                in enumerate(chainPartCommandList):

                partPosition = iif3(partCount == 1, "SINGLE",
                                    partIndex == 0, "FIRST",
                                    partIndex == partCount - 1, "LAST",
                                    "OTHER")
                partCommandTokenList = tokenize(partProcessingEffects)
                sourceList, currentTarget, debugFileCount = \
                    self._extractEffectListSrcAndTgt(voiceName, chainPosition,
                                                     partPosition,
                                                     debugFileCount,
                                                     partCommandTokenList)

                if (len(partCommandTokenList) == 0
                    or partCommandTokenList[0] != "mix"):
                    currentSource = sourceList[0]
                    variableMap = { "infile"   : currentSource,
                                    "outfile"  : currentTarget,
                                    "effects"  : partCommandTokenList }
                    command = cls._replaceVariablesByValues(commandList,
                                                            variableMap)
                    OperatingSystem.executeCommand(command, True)
                else:
                    volumeList = partCommandTokenList[1:]

                    if len(volumeList) < len(sourceList):
                        Logging.trace("--: bad argument pairing for mix")
                    else:
                        for i in range(len(sourceList)):
                            volume = volumeList[i]
                            valueName = "value %d in mix" % (i+1)
                            ValidityChecker.isNumberString(volume,
                                                           valueName, True)
                            volumeList[i] = float(volume)

                        self._mixdownToWavFile(sourceList, volumeList,
                                               "", 0.0, currentTarget)

        Logging.trace("<<")