WaveSwissKnife 0.0.1.20101110-x86-cygwin

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.
Files changed (88) hide show
  1. data/AUTHORS +1 -0
  2. data/ChangeLog +5 -0
  3. data/Credits +3 -0
  4. data/LICENSE +31 -0
  5. data/README +18 -0
  6. data/ReleaseInfo +8 -0
  7. data/TODO +2 -0
  8. data/bin/WSK.rb +14 -0
  9. data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
  10. data/ext/WSK/AnalyzeUtils/AnalyzeUtils.o +0 -0
  11. data/ext/WSK/AnalyzeUtils/AnalyzeUtils.so +0 -0
  12. data/ext/WSK/AnalyzeUtils/Makefile +149 -0
  13. data/ext/WSK/AnalyzeUtils/build.rb +18 -0
  14. data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
  15. data/ext/WSK/ArithmUtils/ArithmUtils.o +0 -0
  16. data/ext/WSK/ArithmUtils/ArithmUtils.so +0 -0
  17. data/ext/WSK/ArithmUtils/Makefile +149 -0
  18. data/ext/WSK/ArithmUtils/build.rb +20 -0
  19. data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
  20. data/ext/WSK/FFTUtils/FFTUtils.o +0 -0
  21. data/ext/WSK/FFTUtils/FFTUtils.so +0 -0
  22. data/ext/WSK/FFTUtils/Makefile +149 -0
  23. data/ext/WSK/FFTUtils/build.rb +20 -0
  24. data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
  25. data/ext/WSK/FunctionUtils/FunctionUtils.o +0 -0
  26. data/ext/WSK/FunctionUtils/FunctionUtils.so +0 -0
  27. data/ext/WSK/FunctionUtils/Makefile +149 -0
  28. data/ext/WSK/FunctionUtils/build.rb +20 -0
  29. data/ext/WSK/SilentUtils/Makefile +149 -0
  30. data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
  31. data/ext/WSK/SilentUtils/SilentUtils.o +0 -0
  32. data/ext/WSK/SilentUtils/SilentUtils.so +0 -0
  33. data/ext/WSK/SilentUtils/build.rb +18 -0
  34. data/ext/WSK/VolumeUtils/Makefile +149 -0
  35. data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
  36. data/ext/WSK/VolumeUtils/VolumeUtils.o +0 -0
  37. data/ext/WSK/VolumeUtils/VolumeUtils.so +0 -0
  38. data/ext/WSK/VolumeUtils/build.rb +20 -0
  39. data/lib/WSK/Actions/Analyze.rb +176 -0
  40. data/lib/WSK/Actions/ApplyMap.desc.rb +15 -0
  41. data/lib/WSK/Actions/ApplyMap.rb +57 -0
  42. data/lib/WSK/Actions/ApplyVolumeFct.desc.rb +30 -0
  43. data/lib/WSK/Actions/ApplyVolumeFct.rb +72 -0
  44. data/lib/WSK/Actions/Compare.desc.rb +25 -0
  45. data/lib/WSK/Actions/Compare.rb +238 -0
  46. data/lib/WSK/Actions/ConstantCompare.desc.rb +20 -0
  47. data/lib/WSK/Actions/ConstantCompare.rb +61 -0
  48. data/lib/WSK/Actions/Cut.desc.rb +20 -0
  49. data/lib/WSK/Actions/Cut.rb +60 -0
  50. data/lib/WSK/Actions/CutFirstSignal.desc.rb +25 -0
  51. data/lib/WSK/Actions/CutFirstSignal.rb +72 -0
  52. data/lib/WSK/Actions/DCShifter.desc.rb +15 -0
  53. data/lib/WSK/Actions/DCShifter.rb +67 -0
  54. data/lib/WSK/Actions/DrawFct.desc.rb +20 -0
  55. data/lib/WSK/Actions/DrawFct.rb +59 -0
  56. data/lib/WSK/Actions/FFT.rb +104 -0
  57. data/lib/WSK/Actions/GenAllValues.rb +67 -0
  58. data/lib/WSK/Actions/GenConstant.desc.rb +20 -0
  59. data/lib/WSK/Actions/GenConstant.rb +56 -0
  60. data/lib/WSK/Actions/GenSawtooth.rb +57 -0
  61. data/lib/WSK/Actions/GenSine.desc.rb +20 -0
  62. data/lib/WSK/Actions/GenSine.rb +73 -0
  63. data/lib/WSK/Actions/Identity.rb +43 -0
  64. data/lib/WSK/Actions/Mix.desc.rb +15 -0
  65. data/lib/WSK/Actions/Mix.rb +149 -0
  66. data/lib/WSK/Actions/Multiply.desc.rb +15 -0
  67. data/lib/WSK/Actions/Multiply.rb +73 -0
  68. data/lib/WSK/Actions/NoiseGate.desc.rb +35 -0
  69. data/lib/WSK/Actions/NoiseGate.rb +129 -0
  70. data/lib/WSK/Actions/SilenceInserter.desc.rb +20 -0
  71. data/lib/WSK/Actions/SilenceInserter.rb +87 -0
  72. data/lib/WSK/Actions/SilenceRemover.desc.rb +30 -0
  73. data/lib/WSK/Actions/SilenceRemover.rb +74 -0
  74. data/lib/WSK/Actions/VolumeProfile.desc.rb +35 -0
  75. data/lib/WSK/Actions/VolumeProfile.rb +63 -0
  76. data/lib/WSK/Common.rb +292 -0
  77. data/lib/WSK/FFT.rb +527 -0
  78. data/lib/WSK/Functions.rb +770 -0
  79. data/lib/WSK/Launcher.rb +216 -0
  80. data/lib/WSK/Maps.rb +29 -0
  81. data/lib/WSK/Model/CachedBufferReader.rb +151 -0
  82. data/lib/WSK/Model/Header.rb +133 -0
  83. data/lib/WSK/Model/InputData.rb +193 -0
  84. data/lib/WSK/Model/RawReader.rb +78 -0
  85. data/lib/WSK/Model/WaveReader.rb +91 -0
  86. data/lib/WSK/OutputInterfaces/DirectStream.rb +146 -0
  87. data/lib/WSK/RIFFReader.rb +60 -0
  88. metadata +151 -0
@@ -0,0 +1,176 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module WSK
7
+
8
+ module Actions
9
+
10
+ class Analyze
11
+
12
+ include WSK::Common
13
+
14
+ # Get the number of samples that will be written.
15
+ # This is called before execute, as it is needed to write the output file.
16
+ # It is possible to give a majoration: it will be padded with silence.
17
+ #
18
+ # Parameters:
19
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
20
+ # Return:
21
+ # * _Integer_: The number of samples to be written
22
+ def getNbrSamples(iInputData)
23
+ return 0
24
+ end
25
+
26
+ # Execute
27
+ #
28
+ # Parameters:
29
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
30
+ # * *oOutputData* (_Object_): The output data to fill
31
+ # Return:
32
+ # * _Exception_: An error, or nil if success
33
+ def execute(iInputData, oOutputData)
34
+ lMaxValue = 2**(iInputData.Header.NbrBitsPerSample-1)-1
35
+ lMinValue = 2**(iInputData.Header.NbrBitsPerSample-1)
36
+
37
+ # Require C extension
38
+ require 'WSK/AnalyzeUtils/AnalyzeUtils'
39
+ lAnalyzeUtils = AnalyzeUtils::AnalyzeUtils.new
40
+ # Initialize computing arrays
41
+ lCMaxValues = lAnalyzeUtils.init64bitsArray(iInputData.Header.NbrChannels, 0);
42
+ lCMinValues = lAnalyzeUtils.init64bitsArray(iInputData.Header.NbrChannels, lMinValue);
43
+ lCSumValues = lAnalyzeUtils.init64bitsArray(iInputData.Header.NbrChannels, 0);
44
+ lCAbsSumValues = lAnalyzeUtils.init64bitsArray(iInputData.Header.NbrChannels, 0);
45
+ lCSquareSumValues = lAnalyzeUtils.init128bitsArray(iInputData.Header.NbrChannels);
46
+ # Gather data
47
+ lNbrSamplesProcessed = 0
48
+ iInputData.eachRawBuffer do |iRawBuffer, iNbrSamples, iNbrChannels|
49
+ lAnalyzeUtils.completeAnalyze(iRawBuffer, iInputData.Header.NbrBitsPerSample, iNbrSamples, iNbrChannels, lCMaxValues, lCMinValues, lCSumValues, lCAbsSumValues, lCSquareSumValues)
50
+ lNbrSamplesProcessed += iNbrSamples
51
+ $stdout.write("#{(lNbrSamplesProcessed*100)/iInputData.NbrSamples} %\015")
52
+ $stdout.flush
53
+ end
54
+ # Get the Ruby arrays from the C ones
55
+ lMaxValues = lAnalyzeUtils.getRuby64bitsArray(lCMaxValues, iInputData.Header.NbrChannels);
56
+ lMinValues = lAnalyzeUtils.getRuby64bitsArray(lCMinValues, iInputData.Header.NbrChannels);
57
+ lSumValues = lAnalyzeUtils.getRuby64bitsArray(lCSumValues, iInputData.Header.NbrChannels);
58
+ lAbsSumValues = lAnalyzeUtils.getRuby64bitsArray(lCAbsSumValues, iInputData.Header.NbrChannels);
59
+ lSquareSumValues = lAnalyzeUtils.getRuby128bitsArray(lCSquareSumValues, iInputData.Header.NbrChannels);
60
+ # Compute values in DB scale also
61
+ lDBMinValues = []
62
+ lMinValues.each do |iValue|
63
+ lDBMinValues << val2db(iValue, lMinValue)[0]
64
+ end
65
+ lDBMaxValues = []
66
+ lMaxValues.each do |iValue|
67
+ lDBMaxValues << val2db(iValue, lMaxValue)[0]
68
+ end
69
+ lMoyValues = []
70
+ lDBMoyValues = []
71
+ lSumValues.each do |iValue|
72
+ lMoyValue = Float(iValue)/Float(iInputData.NbrSamples)
73
+ lMoyValues << lMoyValue
74
+ lDBMoyValues << val2db(lMoyValue, lMinValue)[0]
75
+ end
76
+ lAbsMoyValues = []
77
+ lDBAbsMoyValues = []
78
+ lAbsSumValues.each do |iValue|
79
+ lAbsMoyValue = Float(iValue)/Float(iInputData.NbrSamples)
80
+ lAbsMoyValues << lAbsMoyValue
81
+ lDBAbsMoyValues << val2db(lAbsMoyValue, lMinValue)[0]
82
+ end
83
+ lAbsMaxValues = []
84
+ lDBAbsMaxValues = []
85
+ lMinValues.each_with_index do |iValue, iIdx|
86
+ lAbsMinValue = iValue.abs
87
+ lAbsMaxValue = lMaxValues[iIdx].abs
88
+ lAbsMax = nil
89
+ if (lAbsMinValue > lAbsMaxValue)
90
+ lAbsMax = lAbsMinValue
91
+ else
92
+ lAbsMax = lAbsMaxValue
93
+ end
94
+ lAbsMaxValues << lAbsMax
95
+ lDBAbsMaxValues << val2db(lAbsMax, lMinValue)[0]
96
+ end
97
+ lAbsMaxValue = lAbsMaxValues.sort[-1]
98
+ lAbsMaxValueDB, lAbsMaxValuePC = val2db(lAbsMaxValue, lMinValue)
99
+ lAbsMoyValue = 0
100
+ lAbsMoyValues.each do |iValue|
101
+ lAbsMoyValue += iValue
102
+ end
103
+ lAbsMoyValue /= lAbsMoyValues.size
104
+ lAbsMoyValueDB, lAbsMoyValuePC = val2db(lAbsMoyValue, lMinValue)
105
+ lRMSValues = []
106
+ lDBRMSValues = []
107
+ lSquareSumValues.each do |iValue|
108
+ lRMSValue = Math.sqrt(iValue/iInputData.NbrSamples).round
109
+ lRMSValues << lRMSValue
110
+ lDBRMSValues << val2db(lRMSValue, lMinValue)[0]
111
+ end
112
+ lResult = {
113
+ :MinValues => lMinValues,
114
+ :MaxValues => lMaxValues,
115
+ :MoyValues => lMoyValues,
116
+ :DBMinValues => lDBMinValues,
117
+ :DBMaxValues => lDBMaxValues,
118
+ :DBMoyValues => lDBMoyValues,
119
+ :AbsMaxValues => lAbsMaxValues,
120
+ :AbsMoyValues => lAbsMoyValues,
121
+ :DBAbsMaxValues => lDBAbsMaxValues,
122
+ :DBAbsMoyValues => lDBAbsMoyValues,
123
+ :SampleRate => iInputData.Header.SampleRate,
124
+ :SampleSize => iInputData.Header.NbrBitsPerSample,
125
+ :NbrChannels => iInputData.Header.NbrChannels,
126
+ :DataRate => ((iInputData.Header.NbrChannels*iInputData.Header.NbrBitsPerSample)/8)*iInputData.Header.SampleRate,
127
+ :NbrDataSamples => iInputData.NbrSamples,
128
+ :DataLength => Float(iInputData.NbrSamples)/Float(iInputData.Header.SampleRate),
129
+ :AbsMaxValue => lAbsMaxValue,
130
+ :DBAbsMaxValue => lAbsMaxValueDB,
131
+ :PCAbsMaxValue => lAbsMaxValuePC,
132
+ :AbsMoyValue => lAbsMoyValue,
133
+ :DBAbsMoyValue => lAbsMoyValueDB,
134
+ :PCAbsMoyValue => lAbsMoyValuePC,
135
+ :MaxPossibleValue => lMaxValue,
136
+ :MinPossibleValue => lMinValue,
137
+ :RMSValues => lRMSValues,
138
+ :DBRMSValues => lDBRMSValues
139
+ }
140
+ # Display
141
+ logInfo "Min values: #{lResult[:MinValues].join(', ')}"
142
+ logInfo "Min values (db): #{lResult[:DBMinValues].join(', ')}"
143
+ logInfo "Max values: #{lResult[:MaxValues].join(', ')}"
144
+ logInfo "Max values (db): #{lResult[:DBMaxValues].join(', ')}"
145
+ logInfo "Moy values (DC offset): #{lResult[:MoyValues].join(', ')}"
146
+ logInfo "Moy values (DC offset) (db): #{lResult[:DBMoyValues].join(', ')}"
147
+ logInfo "RMS values: #{lResult[:RMSValues].join(', ')}"
148
+ logInfo "RMS values (db): #{lResult[:DBRMSValues].join(', ')}"
149
+ logInfo "Abs Max values: #{lResult[:AbsMaxValues].join(', ')}"
150
+ logInfo "Abs Max values (db): #{lResult[:DBAbsMaxValues].join(', ')}"
151
+ logInfo "Abs Moy values: #{lResult[:AbsMoyValues].join(', ')}"
152
+ logInfo "Abs Moy values (db): #{lResult[:DBAbsMoyValues].join(', ')}"
153
+ logInfo ''
154
+ logInfo 'Header:'
155
+ logInfo "Sample rate: #{lResult[:SampleRate]}"
156
+ logInfo "Sample size (bits): #{lResult[:SampleSize]}"
157
+ logInfo "Number of channels: #{lResult[:NbrChannels]}"
158
+ logInfo "Data rate: #{lResult[:DataRate]} bytes/sec"
159
+ logInfo ''
160
+ logInfo 'Data:'
161
+ logInfo "Number of data samples: #{lResult[:NbrDataSamples]} (#{lResult[:DataLength]} secs)"
162
+ logInfo "Maximal absolute value: #{lResult[:AbsMaxValue]} (#{lResult[:DBAbsMaxValue]} db) (#{lResult[:PCAbsMaxValue]} %)"
163
+ logInfo "Mean absolute value: #{lResult[:AbsMoyValue]} (#{lResult[:DBAbsMoyValue]} db) (#{lResult[:PCAbsMoyValue]} %)"
164
+ # Write a result file
165
+ File.open('analyze.result', 'wb') do |oFile|
166
+ oFile.write(Marshal.dump(lResult))
167
+ end
168
+
169
+ return nil
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+
176
+ end
@@ -0,0 +1,15 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ {
7
+ :OutputInterface => 'DirectStream',
8
+ :Options => {
9
+ :MapFileName => [
10
+ '--transformmap <MapFileName>', String,
11
+ '<MapFileName>: Name of the map file corresponding to the transform',
12
+ 'Specify the file to take the transformation from.'
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,57 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module WSK
7
+
8
+ module Actions
9
+
10
+ class ApplyMap
11
+
12
+ include WSK::Common
13
+
14
+ # Get the number of samples that will be written.
15
+ # This is called before execute, as it is needed to write the output file.
16
+ # It is possible to give a majoration: it will be padded with silence.
17
+ #
18
+ # Parameters:
19
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
20
+ # Return:
21
+ # * _Integer_: The number of samples to be written
22
+ def getNbrSamples(iInputData)
23
+ return iInputData.NbrSamples
24
+ end
25
+
26
+ # Execute
27
+ #
28
+ # Parameters:
29
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
30
+ # * *oOutputData* (_Object_): The output data to fill
31
+ # Return:
32
+ # * _Exception_: An error, or nil if success
33
+ def execute(iInputData, oOutputData)
34
+ lTransformMap = nil
35
+ File.open(@MapFileName, 'rb') do |iFile|
36
+ lTransformMap = Marshal.load(iFile.read)
37
+ end
38
+ iInputData.eachBuffer do |iBuffer, iNbrSamples, iNbrChannels|
39
+ lTransformedBuffer = iBuffer.map do |iValue|
40
+ if (lTransformMap[iValue] == nil)
41
+ logWarn "Unknown value from the transform map: #{iValue}. Keeping it."
42
+ next iValue
43
+ else
44
+ next lTransformMap[iValue]
45
+ end
46
+ end
47
+ oOutputData.pushBuffer(lTransformedBuffer)
48
+ end
49
+
50
+ return nil
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,30 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ {
7
+ :OutputInterface => 'DirectStream',
8
+ :Options => {
9
+ :FctFileName => [
10
+ '--function <FunctionFileName>', String,
11
+ '<FunctionFileName>: File containing the function definition',
12
+ 'Specify the function to apply'
13
+ ],
14
+ :Begin => [
15
+ '--begin <BeginPos>', String,
16
+ '<BeginPos>: Position to apply volume transformation from. Can be specified as a sample number or a float seconds (ie. 12.3s).',
17
+ 'Specify the first sample that will have the function applied'
18
+ ],
19
+ :End => [
20
+ '--end <EndPos>', String,
21
+ '<EndPos>: Position to apply volume transformation to. Can be specified as a sample number or a float seconds (ie. 12.3s). -1 means to the end of file.',
22
+ 'Specify the last sample that will have the function applied'
23
+ ],
24
+ :UnitDB => [
25
+ '--unitdb <Switch>', Integer,
26
+ '<Switch>: 0 means that units used in the function are ratios. 1 means that units used in the functions are db.',
27
+ 'Specify the unit used in the function'
28
+ ]
29
+ }
30
+ }
@@ -0,0 +1,72 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module WSK
7
+
8
+ module Actions
9
+
10
+ class ApplyVolumeFct
11
+
12
+ include WSK::Common
13
+ include WSK::Functions
14
+
15
+ # Get the number of samples that will be written.
16
+ # This is called before execute, as it is needed to write the output file.
17
+ # It is possible to give a majoration: it will be padded with silence.
18
+ #
19
+ # Parameters:
20
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
21
+ # Return:
22
+ # * _Integer_: The number of samples to be written
23
+ def getNbrSamples(iInputData)
24
+ return iInputData.NbrSamples
25
+ end
26
+
27
+ # Execute
28
+ #
29
+ # Parameters:
30
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
31
+ # * *oOutputData* (_Object_): The output data to fill
32
+ # Return:
33
+ # * _Exception_: An error, or nil if success
34
+ def execute(iInputData, oOutputData)
35
+ rError = nil
36
+
37
+ lIdxBegin = readDuration(@Begin, iInputData.Header.SampleRate)
38
+ lIdxEnd = readDuration(@End, iInputData.Header.SampleRate)
39
+ if (lIdxEnd == -1)
40
+ lIdxEnd = iInputData.NbrSamples - 1
41
+ end
42
+ if (lIdxEnd >= iInputData.NbrSamples)
43
+ rError = RuntimeError.new("Transformation ends at #{lIdxEnd}, superceeding last sample (#{iInputData.NbrSamples-1})")
44
+ else
45
+ lFunction = WSK::Functions::Function.new
46
+ begin
47
+ lFunction.readFromFile(@FctFileName)
48
+ rescue Exception
49
+ rError = $!
50
+ end
51
+ if (rError == nil)
52
+ # First, write samples before
53
+ iInputData.eachRawBuffer(0, lIdxBegin-1) do |iInputRawBuffer, iNbrSamples, iNbrChannels|
54
+ oOutputData.pushRawBuffer(iInputRawBuffer)
55
+ end
56
+ # Then apply volume transformation
57
+ lFunction.applyOnVolume(iInputData, oOutputData, lIdxBegin, lIdxEnd, (@UnitDB == 1))
58
+ # Last, write samples after
59
+ iInputData.eachRawBuffer(lIdxEnd+1) do |iInputRawBuffer, iNbrSamples, iNbrChannels|
60
+ oOutputData.pushRawBuffer(iInputRawBuffer)
61
+ end
62
+ end
63
+ end
64
+
65
+ return rError
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -0,0 +1,25 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ {
7
+ :OutputInterface => 'DirectStream',
8
+ :Options => {
9
+ :InputFileName2 => [
10
+ '--inputfile2 <FileName>', String,
11
+ '<FileName>: Second file name to compare with.',
12
+ 'Specify the file to compare with. The resulting file will be (inputfile - inputfile2)*Coefficient.'
13
+ ],
14
+ :Coeff => [
15
+ '--coeff <Coefficient>', Integer,
16
+ '<Coefficient>: Coefficient to multiply the differences [default = 1]',
17
+ 'Specify the multiplying coefficient.'
18
+ ],
19
+ :GenMap => [
20
+ '--genmap <Switch>', Integer,
21
+ '<Switch>: 0 or 1, turning off or on the map generation [default = 0]',
22
+ 'If 1, a file (named Output.map) will be created, storing the distortion for each encountered value.'
23
+ ]
24
+ }
25
+ }
@@ -0,0 +1,238 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module WSK
7
+
8
+ module Actions
9
+
10
+ class Compare
11
+
12
+ include WSK::Common
13
+ include WSK::Maps
14
+
15
+ # Get the number of samples that will be written.
16
+ # This is called before execute, as it is needed to write the output file.
17
+ # It is possible to give a majoration: it will be padded with silence.
18
+ #
19
+ # Parameters:
20
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
21
+ # Return:
22
+ # * _Integer_: The number of samples to be written
23
+ def getNbrSamples(iInputData)
24
+ rNbrSamples = iInputData.NbrSamples
25
+
26
+ # Get the second input file
27
+ lError = accessInputWaveFile(@InputFileName2) do |iInputHeader2, iInputData2|
28
+ rSubError = nil
29
+ # First check that headers are the same
30
+ if (iInputHeader2 != iInputData.Header)
31
+ rSubError = RuntimeError.new("Mismatch headers: First input file: #{iInputData.Header.inspect} Second input file: #{iInputHeader2.inspect}")
32
+ end
33
+ # Then we will return the maximal samples
34
+ if (iInputData2.NbrSamples > iInputData.NbrSamples)
35
+ logWarn "Second file has more samples (#{iInputData2.NbrSamples} > #{iInputData.NbrSamples})."
36
+ rNbrSamples = iInputData2.NbrSamples
37
+ elsif (iInputData2.NbrSamples < iInputData.NbrSamples)
38
+ logWarn "Second file has less samples (#{iInputData2.NbrSamples} < #{iInputData.NbrSamples})."
39
+ else
40
+ logInfo 'Files have the same number of samples.'
41
+ end
42
+ next rSubError
43
+ end
44
+ if (lError != nil)
45
+ raise lError
46
+ end
47
+ @TotalNbrSamples = rNbrSamples
48
+
49
+ return rNbrSamples
50
+ end
51
+
52
+ # Execute
53
+ #
54
+ # Parameters:
55
+ # * *iInputData* (<em>WSK::Model::InputData</em>): The input data
56
+ # * *oOutputData* (_Object_): The output data to fill
57
+ # Return:
58
+ # * _Exception_: An error, or nil if success
59
+ def execute(iInputData, oOutputData)
60
+ @NbrBitsPerSample = iInputData.Header.NbrBitsPerSample
61
+ @NbrChannels = iInputData.Header.NbrChannels
62
+ if (@GenMap == 1)
63
+ # We want to generate the map
64
+ @DistortionMap = [nil]*(2**@NbrBitsPerSample)
65
+ else
66
+ @DistortionMap = nil
67
+ end
68
+ # Measure the cumulative errors
69
+ @CumulativeErrors = 0
70
+ @MaxValue = 2**(@NbrBitsPerSample-1)-1
71
+ @MinValue = -2**(@NbrBitsPerSample-1)
72
+ # Get the second input file
73
+ rError = accessInputWaveFile(@InputFileName2) do |iInputHeader2, iInputData2|
74
+ # Loop on both files.
75
+ # !!! We count on the same buffer size for both files.
76
+ require 'WSK/ArithmUtils/ArithmUtils'
77
+ @ArithmUtils = WSK::ArithmUtils::ArithmUtils.new
78
+ # Initialize buffers
79
+ lNbrSamplesProcessed = 0
80
+ iInputData.eachRawBuffer do |iRawBuffer, iNbrSamples, iNbrChannels|
81
+ break
82
+ end
83
+ lRawBuffer1, lNbrSamples1, lNbrChannels = iInputData.getCurrentRawBuffer
84
+ iInputData2.eachRawBuffer do |iRawBuffer, iNbrSamples, iNbrChannels|
85
+ break
86
+ end
87
+ lRawBuffer2, lNbrSamples2, lNbrChannels = iInputData2.getCurrentRawBuffer
88
+ while ((lRawBuffer1 != nil) or
89
+ (lRawBuffer2 != nil))
90
+ if (lRawBuffer1 == nil)
91
+ oOutputData.pushRawBuffer(lRawBuffer2)
92
+ lNbrSamplesProcessed += lNbrSamples2
93
+ if (lNbrSamplesProcessed == @TotalNbrSamples)
94
+ lRawBuffer2 = nil
95
+ end
96
+ elsif (lRawBuffer2 == nil)
97
+ computeInverseMap
98
+ oOutputData.pushRawBuffer(@ArithmUtils.applyMap(@InverseMap, lRawBuffer1, @NbrBitsPerSample, lNbrSamples1))
99
+ lNbrSamplesProcessed += lNbrSamples1
100
+ if (lNbrSamplesProcessed == @TotalNbrSamples)
101
+ lRawBuffer1 = nil
102
+ end
103
+ elsif (lNbrSamples1 == lNbrSamples2)
104
+ lOutputBuffer, lCumulativeErrors = @ArithmUtils.compareBuffers(
105
+ lRawBuffer1,
106
+ lRawBuffer2,
107
+ @NbrBitsPerSample,
108
+ @NbrChannels,
109
+ lNbrSamples1,
110
+ @Coeff,
111
+ @DistortionMap
112
+ )
113
+ oOutputData.pushRawBuffer(lOutputBuffer)
114
+ @CumulativeErrors += lCumulativeErrors
115
+ lNbrSamplesProcessed += lNbrSamples1
116
+ if (lNbrSamplesProcessed == @TotalNbrSamples)
117
+ lRawBuffer1 = nil
118
+ lRawBuffer2 = nil
119
+ end
120
+ elsif (lNbrSamples1 > lNbrSamples2)
121
+ lOutputBuffer, lCumulativeErrors = @ArithmUtils.compareBuffers(
122
+ lRawBuffer1[0..lRawBuffer2.size-1],
123
+ lRawBuffer2,
124
+ @NbrBitsPerSample,
125
+ @NbrChannels,
126
+ lNbrSamples1,
127
+ @Coeff,
128
+ @DistortionMap
129
+ )
130
+ oOutputData.pushRawBuffer(lOutputBuffer)
131
+ @CumulativeErrors += lCumulativeErrors
132
+ # Write remaining buffer (-Buffer1)
133
+ computeInverseMap
134
+ oOutputData.pushRawBuffer(@ArithmUtils.applyMap(@InverseMap, lRawBuffer1[lRawBuffer2.size..-1], @NbrBitsPerSample, lNbrSamples2 - lNbrSamples1))
135
+ # Buffer2 is finished
136
+ lRawBuffer2 = nil
137
+ lNbrSamplesProcessed += lNbrSamples1
138
+ else
139
+ lOutputBuffer, lCumulativeErrors = @ArithmUtils.compareBuffers(
140
+ lRawBuffer1,
141
+ lRawBuffer2[0..lRawBuffer1.size-1],
142
+ @NbrBitsPerSample,
143
+ @NbrChannels,
144
+ lNbrSamples1,
145
+ @Coeff,
146
+ @DistortionMap
147
+ )
148
+ oOutputData.pushRawBuffer(lOutputBuffer)
149
+ @CumulativeErrors += lCumulativeErrors
150
+ # Write remaining buffer (Buffer2)
151
+ oOutputData.pushRawBuffer(lRawBuffer2[lRawBuffer1.size..-1])
152
+ # Buffer1 is finished
153
+ lRawBuffer1 = nil
154
+ lNbrSamplesProcessed += lNbrSamples2
155
+ end
156
+ # Read next buffers if they are not finished
157
+ if (lRawBuffer1 != nil)
158
+ iInputData.eachRawBuffer(lNbrSamplesProcessed) do |iRawBuffer, iNbrSamples, iNbrChannels|
159
+ break
160
+ end
161
+ lRawBuffer1, lNbrSamples1, lNbrChannels = iInputData.getCurrentRawBuffer
162
+ end
163
+ if (lRawBuffer2 != nil)
164
+ iInputData2.eachRawBuffer(lNbrSamplesProcessed) do |iRawBuffer, iNbrSamples, iNbrChannels|
165
+ break
166
+ end
167
+ lRawBuffer2, lNbrSamples2, lNbrChannels = iInputData2.getCurrentRawBuffer
168
+ end
169
+ end
170
+ end
171
+ if (@DistortionMap != nil)
172
+ # Write the distortion map
173
+ logInfo 'Generate distortion map in distortion.diffmap'
174
+ File.open('distortion.diffmap', 'wb') do |oFile|
175
+ oFile.write(Marshal.dump(@DistortionMap))
176
+ end
177
+ logInfo 'Generate invert map in invert.map'
178
+ # We want to spot the values that are missing, and the duplicate values
179
+ lInvertMap = [nil]*(2**@NbrBitsPerSample)
180
+ (@MinValue .. @MaxValue).each do |iValue|
181
+ if (@DistortionMap[iValue] == nil)
182
+ logWarn "Value #{iValue} was not part of the input file"
183
+ else
184
+ lRecordedValue = iValue + @DistortionMap[iValue]
185
+ if (lInvertMap[lRecordedValue] == nil)
186
+ lInvertMap[lRecordedValue] = iValue
187
+ else
188
+ if (iValue.abs < lInvertMap[lRecordedValue].abs)
189
+ logWarn "Recorded value #{lRecordedValue} is used for both input values #{iValue} and #{lInvertMap[lRecordedValue]}. Setting it to #{iValue}."
190
+ lInvertMap[lRecordedValue] = iValue
191
+ else
192
+ logWarn "Recorded value #{lRecordedValue} is used for both input values #{iValue} and #{lInvertMap[lRecordedValue]}. Keeping it to #{lInvertMap[lRecordedValue]}."
193
+ end
194
+ end
195
+ end
196
+ end
197
+ (@MinValue .. @MaxValue).each do |iValue|
198
+ if (lInvertMap[iValue] == nil)
199
+ logWarn "Missing value that has never been recorded: #{iValue}"
200
+ end
201
+ end
202
+ File.open('invert.map', 'wb') do |oFile|
203
+ oFile.write(Marshal.dump(lInvertMap))
204
+ end
205
+ end
206
+ puts "Cumulative errors: #{@CumulativeErrors} (#{Float(@CumulativeErrors*100)/Float(iInputData.NbrSamples*(2**@NbrBitsPerSample))} %)"
207
+
208
+ return rError
209
+ end
210
+
211
+ private
212
+
213
+ # Compute the inverse map
214
+ def computeInverseMap
215
+ if (defined?(@InverseMap) == nil)
216
+ # Compute the function that will perform inversion
217
+ lMaxValue = 2**(@NbrBitsPerSample-1) - 1
218
+ lMinValue = -2**(@NbrBitsPerSample-1)
219
+ @InverseMap = @ArithmUtils.createMapFromFunctions(
220
+ @NbrBitsPerSample,
221
+ [ {
222
+ :FunctionType => WSK::Functions::FCTTYPE_PIECEWISE_LINEAR,
223
+ :MinValue => lMinValue,
224
+ :MaxValue => lMaxValue,
225
+ :Points => {
226
+ lMinValue => -lMinValue,
227
+ lMaxValue => -lMaxValue
228
+ }
229
+ } ] * @NbrChannels
230
+ )
231
+ end
232
+ end
233
+
234
+ end
235
+
236
+ end
237
+
238
+ end
@@ -0,0 +1,20 @@
1
+ #--
2
+ # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ {
7
+ :OutputInterface => 'DirectStream',
8
+ :Options => {
9
+ :Value => [
10
+ '--value <Value>', Integer,
11
+ '<Value>: Constant value to compare with',
12
+ 'Specify the value to compare with.'
13
+ ],
14
+ :NbrSamples => [
15
+ '--nbrsamples <NbrSamples>', Integer,
16
+ '<NbrSamples>: Number of samples used to compare with',
17
+ 'Specify the number of samples the file should have.'
18
+ ]
19
+ }
20
+ }