Module: WSK::Common

Overview

Common methods

Instance Method Summary collapse

Instance Method Details

#accessInputWaveFile(iFileName) ⇒ Object

Access a WAVE file for read access. Give its header information as well as a proxy to access its data. Proxies are used to cache accesses as they might be time consuming.

Parameters
  • iFileName (String): The file name to open

  • CodeBlock: The code block called when accessing the file:

    • iHeader (WSK::Model::Header): The file header information

    • iInputData (WSK::Model::InputData): The file data proxy

    • Return
    • Exception: Error, or nil in case of success

Return
  • Exception: Error, or nil in case of success



37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/WSK/Common.rb', line 37

def accessInputWaveFile(iFileName)
  rError = nil

  File.open(iFileName, 'rb') do |iFile|
    log_info "Access #{iFileName}"
    rError, lHeader, lInputData = getWaveFileAccesses(iFile)
    if (rError == nil)
      rError = yield(lHeader, lInputData)
    end
  end
  
  return rError
end

#accessOutputWaveFile(iFileName, iHeader, iOutputInterface, iNbrOutputDataSamples) ⇒ Object

Access a WAVE file for write access. Give its header information as well as a proxy to access its data. Proxies are used to cache accesses as they might be time consuming.

Parameters
  • iFileName (String): The file name to write

  • iHeader (WSK::Model::Header): The file header information to write

  • iOutputInterface (Object): The output interface

  • iNbrOutputDataSamples (Integer): The number of output data samples

  • CodeBlock: The code block called when accessing the file

    • Return
    • Exception: Error, or nil in case of success

Return
  • Exception: Error, or nil in case of success



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
# File 'lib/WSK/Common.rb', line 90

def accessOutputWaveFile(iFileName, iHeader, iOutputInterface, iNbrOutputDataSamples)
  rError = nil

  File.open(iFileName, 'wb') do |oFile|
    # Initialize the output interface
    rError = iOutputInterface.initInterface(oFile, iHeader, iNbrOutputDataSamples)
    if (rError == nil)
      # Write header
      log_info "Write header in #{iFileName}"
      rError = writeHeader(oFile, iHeader, iNbrOutputDataSamples)
      if (rError == nil)
        # Call client code
        rError = yield
        if (rError == nil)
          # Finalize the output interface
          lNbrSamplesWritten = iOutputInterface.finalize
          # Pad with \x00 if lNbrSamplesWritten is below iNbrOutputDataSamples
          if (lNbrSamplesWritten < iNbrOutputDataSamples)
            log_warn "#{lNbrSamplesWritten} samples written out of #{iNbrOutputDataSamples}: padding with silence."
            oFile.write(iHeader.getEncodedString([0]*(iNbrOutputDataSamples-lNbrSamplesWritten)*iHeader.NbrChannels))
          elsif (lNbrSamplesWritten > iNbrOutputDataSamples)
            log_warn "#{lNbrSamplesWritten} samples written, but #{iNbrOutputDataSamples} only were expected. #{lNbrSamplesWritten - iNbrOutputDataSamples} samples more."
          end
        end
      end
    end
  end

  return rError
end

#getWaveFileAccesses(iFile) ⇒ Object

Give Header and Data access from an opened Wave file

Parameters
  • iFile (IO): The IO handler

Return
  • Exception: An error, or nil in case of success

  • WSK::Model::Header: The header

  • WSK::Model::InputData: The input data



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/WSK/Common.rb', line 59

def getWaveFileAccesses(iFile)
  rError = nil
  rHeader = nil
  rInputData = nil
  
  # Read header
  rError, rHeader = readHeader(iFile)
  log_debug "Header: #{rHeader.inspect}"
  if (rError == nil)
    # Get a data handle
    rInputData = WSK::Model::InputData.new(iFile, rHeader)
    rError = rInputData.init_cursor
  end

  return rError, rHeader, rInputData
end

#parsePluginsObject

Parse plugins



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/WSK/Common.rb', line 12

def parsePlugins
  # Protect from re-entrance to avoid useless error messages in regression
  if (defined?($WSK_PluginsParsed) == nil)
    lLibDir = File.expand_path(File.dirname(__FILE__))
    require 'rUtilAnts/Plugins'
    RUtilAnts::Plugins::install_plugins_on_object
    parse_plugins_from_dir('Actions', "#{lLibDir}/Actions", 'WSK::Actions')
    parse_plugins_from_dir('OutputInterfaces', "#{lLibDir}/OutputInterfaces", 'WSK::OutputInterfaces')
    $WSK_PluginsParsed = true
  end
end

#readDuration(iStrDuration, iSampleRate) ⇒ Object

Read a duration and give its corresponding value in samples Throws an exception in case of bad format.

Parameters
  • iStrDuration (String): The duration to read

  • iSampleRate (Integer): Sample rate of the file for which this duration applies

Return
  • Integer: The number of samples corresponding to this duration



129
130
131
132
133
134
135
136
137
138
139
# File 'lib/WSK/Common.rb', line 129

def readDuration(iStrDuration, iSampleRate)
  rNbrSamples = nil

  if (iStrDuration[-1..-1] == 's')
    rNbrSamples = ((iStrDuration[0..-2].to_f)*iSampleRate).round
  else
    rNbrSamples = iStrDuration.to_i
  end

  return rNbrSamples
end

#readFFTProfile(iFileName) ⇒ Object

Read an FFT profile file

Parameters
  • iFileName (String): Name of the FFT profile file, or ‘none’ if none.

Return
  • Integer: Maximal FFT distance beyond which we consider being too far from the FFT profile

  • [Integer,Integer,list<list<Integer>>]: The FFT profile



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/WSK/Common.rb', line 178

def readFFTProfile(iFileName)
  rFFTMaxDistance = nil
  rFFTProfile = nil

  if (iFileName != 'none')
    if (File.exists?(iFileName))
      # Load the reference FFT profile
      File.open(iFileName, 'rb') do |iFile|
        rFFTMaxDistance, rFFTProfile = Marshal.load(iFile.read)
      end
      # We add an arbitrary percentage to the average distance.
      rFFTMaxDistance = (rFFTMaxDistance*1.01).to_i
    else
      log_err "Missing file #{iFileName}. Ignoring FFT."
    end
  end

  return rFFTMaxDistance, rFFTProfile
end

#readThresholds(iStrThresholds, iNbrChannels) ⇒ Object

Read a given threshold indication on the command line.

Parameters
  • iStrThresholds (String): The thresholds to read

  • iNbrChannels (Integer): Number of channels for the file being decoded

Return
  • list< [Integer,Integer] >: The list of min and max values, per channel



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/WSK/Common.rb', line 148

def readThresholds(iStrThresholds, iNbrChannels)
  rThresholds = nil

  if (iStrThresholds.split('|').size == 1)
    if (iStrThresholds.split(',').size == 1)
      rThresholds = [ [ -iStrThresholds.to_i, iStrThresholds.to_i ] ] * iNbrChannels
    else
      rThresholds = [iStrThresholds.split(',').map { |iStrValue| iStrValue.to_i }] * iNbrChannels
    end
  else
    rThresholds = []
    iStrThresholds.split('|').each do |iThresholdInfo|
      if (iThresholdInfo.split(',').size == 1)
        rThresholds << [ -iThresholdInfo.to_i, iThresholdInfo.to_i ]
      else
        rThresholds << iThresholdInfo.split(',').map { |iStrValue| iStrValue.to_i }
      end
    end
  end

  return rThresholds
end

#val2db(iValue, iMaxValue) ⇒ Object

Convert a value to its db notation and % notation

Parameters
  • iValue (Integer): The value

  • iMaxValue (Integer): The maximal possible value

Return
  • Float: Its corresponding db

  • Float: Its corresponding percentage



206
207
208
209
210
211
212
213
214
215
# File 'lib/WSK/Common.rb', line 206

def val2db(iValue, iMaxValue)
  if (iValue == 0)
    return -1.0/0, 0.0
  else
    if (defined?(@Log2) == nil)
      @Log2 = Math.log(2.0)
    end
    return -6*(Math.log(Float(iMaxValue))-Math.log(Float(iValue.abs)))/@Log2, (Float(iValue.abs)*100)/Float(iMaxValue)
  end
end