Class: WSK::Actions::Mix

Inherits:
Object
  • Object
show all
Includes:
Common
Defined in:
lib/WSK/Actions/Mix.rb

Instance Method Summary collapse

Methods included from Common

#accessInputWaveFile, #accessOutputWaveFile, #getWaveFileAccesses, #parsePlugins, #readDuration, #readFFTProfile, #readThresholds, #val2db

Instance Method Details

#execute(iInputData, oOutputData) ⇒ Object

Execute

Parameters
  • iInputData (WSK::Model::InputData): The input data

  • oOutputData (Object): The output data to fill

Return
  • Exception: An error, or nil if success



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/WSK/Actions/Mix.rb', line 74

def execute(iInputData, oOutputData)
  rError = nil
  
  # Store the list of opened files, and initialize it with the input data (first file)
  # list< [ IO, InputData, Coeff, Buffer, NbrSamplesInBuffer ] >
  lLstOpenedFiles = [ [ nil, iInputData, 1.0, nil, nil ] ]
  @LstFiles.each do |iFileInfo|
    iFileName, iCoeff = iFileInfo
    lFileHandle = File.open(iFileName, 'rb')
    rError, lHeader, lInputData = getWaveFileAccesses(lFileHandle)
    if (rError == nil)
      lLstOpenedFiles << [ lFileHandle, lInputData, iCoeff, nil, nil ]
    else
      break
    end
  end
  if (rError == nil)
    require 'WSK/ArithmUtils/ArithmUtils'
    lArithmUtils = WSK::ArithmUtils::ArithmUtils.new
    # Loop until we meet the maximal number of samples
    # !!! We assume that buffers have the same size when read
    # Initialize buffers
    lLstOpenedFiles.each do |ioFileInfo|
      lFileHandle, lInputData, lCoeff, lBuffer = ioFileInfo
      lInputData.each_raw_buffer do |iRawBuffer, iNbrSamples, iNbrChannels|
        break
      end
      lRawBuffer, lNbrSamples, lNbrChannels2 = lInputData.get_current_raw_buffer
      ioFileInfo[3] = lRawBuffer
      ioFileInfo[4] = lNbrSamples
    end
    # Sort the list based on the number of samples of each file.
    # This is a prerequisite of the C function mixing.
    lLstOpenedFiles.sort! do |iOF1, iOF2|
      next (iOF2[1].NbrSamples <=> iOF1[1].NbrSamples)
    end
    lLstRemainingOpenedFiles = lLstOpenedFiles.clone
    lNbrSamplesProcessed = 0
    while (!lLstRemainingOpenedFiles.empty?)
      # Mix all buffers
      lMixRawBuffer, lNbrSamplesWritten = lArithmUtils.mixBuffers(lLstRemainingOpenedFiles, iInputData.Header.NbrBitsPerSample, iInputData.Header.NbrChannels)
      # Remove the ones that don't have data anymore
      lLstRemainingOpenedFiles.delete_if do |ioFileInfo|
        lFileHandle, lInputData, lCoeff, lRawBuffer = ioFileInfo
        rToBeDeleted = false
        # Set the next buffer of this file
        if (lNbrSamplesProcessed + lNbrSamplesWritten >= lInputData.NbrSamples)
          # Close the handle if it is not the main input
          if (lFileHandle != nil)
            lFileHandle.close
          end
          rToBeDeleted = true
        else
          # Read next Buffer
          lInputData.each_raw_buffer(lNbrSamplesProcessed + lNbrSamplesWritten) do |iRawBuffer, iNbrSamples, iNbrChannels|
            break
          end
          lRawBuffer, lNbrSamples, lNbrChannels2 = lInputData.get_current_raw_buffer
          ioFileInfo[3] = lRawBuffer
          ioFileInfo[4] = lNbrSamples
        end
        next rToBeDeleted
      end
      oOutputData.pushRawBuffer(lMixRawBuffer)
      lNbrSamplesProcessed += lNbrSamplesWritten
    end
  end
  
  return rError
end

#get_nbr_samples(iInputData) ⇒ Object

Get the number of samples that will be written. This is called before execute, as it is needed to write the output file. It is possible to give a majoration: it will be padded with silence.

Parameters
  • iInputData (WSK::Model::InputData): The input data

Return
  • Integer: The number of samples to be written



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/WSK/Actions/Mix.rb', line 22

def get_nbr_samples(iInputData)
  @NbrSamples = iInputData.NbrSamples
  
  # Decode the files list
  # list< [ String, Float ] >
  @LstFiles = []
  lLstParams = @MixFiles.split('|')
  if (lLstParams.size % 2 != 0)
    raise RuntimeError, 'Invalid mix parameters. Example: File1.wav|1|File2.wav|0.4'
  else
    (lLstParams.size/2).times do |iIdxFile|
      lFileName = lLstParams[iIdxFile*2]
      lCoeff = lLstParams[iIdxFile*2+1].to_f
      if (lCoeff == 0)
        log_warn "File #{lFileName} has a null coefficient. It won't be part of the mix."
      else
        # Check if the file exists
        if (File.exists?(lFileName))
          # Check the file's header
          lError = accessInputWaveFile(lFileName) do |iInputHeader2, iInputData2|
            rSubError = nil
            # Check that headers are the same
            if (iInputHeader2 != iInputData.Header)
              rSubError = RuntimeError.new("Mismatch headers with file #{lFileName}: First input file: #{iInputData.Header.inspect} Mix file: #{iInputHeader2.inspect}")
            end
            # OK, keep this file
            @LstFiles << [ lFileName, lCoeff ]
            if (iInputData2.NbrSamples > @NbrSamples)
              @NbrSamples = iInputData2.NbrSamples
            end
            next rSubError
          end
          if (lError != nil)
            raise lError
          end
        else
          raise RuntimeError, "Missing file: #{lFileName}"
        end
      end
    end
  end
  
  return @NbrSamples
end