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,862 @@
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
+ #include "ruby.h"
7
+ #include <math.h>
8
+ #include <stdio.h>
9
+ #include <CommonUtils.h>
10
+ #include <gmp.h>
11
+
12
+ // Struct used to store a map
13
+ typedef struct {
14
+ // Number of channels
15
+ int nbrChannels;
16
+ // Are there some values that can exceed the values range ? 0 = No 1 = Yes.
17
+ int possibleExceedValues;
18
+ // The map
19
+ tSampleValue** map;
20
+ } tMap;
21
+
22
+ // Struct used to convey data among iterators in the applyMap method
23
+ typedef struct {
24
+ unsigned int offsetIdxMap;
25
+ tSampleValue** map;
26
+ } tApplyMapStruct;
27
+
28
+ // Struct used to store info about a buffer
29
+ typedef struct {
30
+ // All buffers point on the same data at the beginning of the iterations
31
+ unsigned char* buffer_8bits;
32
+ signed short int* buffer_16bits;
33
+ t24bits* buffer_24bits;
34
+ tSampleIndex nbrBufferSamples;
35
+ long double coeff;
36
+ } tBufferInfo;
37
+
38
+ // Struct used to convey data among iterators in the Mix method
39
+ typedef struct {
40
+ tBufferInfo* lstBuffers;
41
+ int nbrActiveBuffers;
42
+ long double mainCoeff;
43
+ // Temporary attributes
44
+ long double tmpValue;
45
+ int idxBuffer;
46
+ } tMixStruct;
47
+
48
+ // Struct used to convey data among iterators in the Compare method
49
+ typedef struct {
50
+ unsigned char* buffer2_8bits;
51
+ signed short int* buffer2_16bits;
52
+ t24bits* buffer2_24bits;
53
+ long double coeffDiff;
54
+ tSampleValue* map;
55
+ tSampleValue mapOffset;
56
+ VALUE self;
57
+ mpz_t cumulativeErrors;
58
+ } tCompareStruct;
59
+
60
+ /**
61
+ * Free a map.
62
+ * This method is called by Ruby GC.
63
+ *
64
+ * Parameters:
65
+ * * *iPtrMap* (<em>void*</em>): The trigo cache to free (in fact a <em>tMap*</em>)
66
+ */
67
+ static void arithmutils_freeMap(void* iPtrMap) {
68
+ tMap* lPtrMap = (tMap*)iPtrMap;
69
+
70
+ int lIdxChannel;
71
+ for (lIdxChannel = 0; lIdxChannel < lPtrMap->nbrChannels; ++lIdxChannel) {
72
+ // Free it
73
+ free(lPtrMap->map[lIdxChannel]);
74
+ }
75
+ free(lPtrMap->map);
76
+ }
77
+
78
+ /**
79
+ * Fill a channel map with a given function of type Piecewise Linear
80
+ *
81
+ * Parameters:
82
+ * * *iNbrBitsPerSample* (<em>const int</em>): Number of bits per sample
83
+ * * *oPtrChannelMap* (<em>int*</em>): The channel map to fill
84
+ * * *iValFunction* (<em>map<Symbol,Object></em>): The function to apply
85
+ * Return:
86
+ * * _int_: Result code:
87
+ * ** *0*: The map never exceeds limits
88
+ * ** *1*: The map can exceed limits
89
+ * ** *2*: An error occurred
90
+ */
91
+ static int arithmutils_fillMap_PiecewiseLinear(
92
+ const int iNbrBitsPerSample,
93
+ int* oPtrChannelMap,
94
+ VALUE iValFunction) {
95
+ int rResultCode = 0;
96
+
97
+ // Read points in a sorted list of couples [x,y]
98
+ VALUE lValSortedPoints = rb_funcall(rb_funcall(rb_hash_aref(iValFunction, ID2SYM(rb_intern("Points"))), rb_intern("to_a"), 0), rb_intern("sort"), 0);
99
+ int lNbrPoints = RARRAY(lValSortedPoints)->len;
100
+ // Read the scale min and max values
101
+ long long int lMinScale = FIX2INT(rb_hash_aref(iValFunction, ID2SYM(rb_intern("MinValue"))));
102
+ long long int lMaxScale = FIX2INT(rb_hash_aref(iValFunction, ID2SYM(rb_intern("MaxValue"))));
103
+ long long int lDiffScale = lMaxScale - lMinScale;
104
+
105
+ // Compute the limits
106
+ long long int lMaxValue = (1 << (iNbrBitsPerSample-1)) - 1;
107
+ long long int lMinValue = -(1 << (iNbrBitsPerSample-1));
108
+ long long int lDiffValue = lMaxValue - lMinValue;
109
+ int lIdxMapOffset = 1 << (iNbrBitsPerSample-1);
110
+
111
+ // Variables to be used in loops
112
+ int lIdxPoint;
113
+ VALUE lValPreviousPoint;
114
+ long double lPreviousPointX;
115
+ long double lPreviousPointY;
116
+ VALUE lValNextPoint;
117
+ long double lNextPointX;
118
+ long double lNextPointY;
119
+ long double lDiffX;
120
+ long double lDiffY;
121
+ int lIdxValue;
122
+ long long int lNewValue;
123
+
124
+ // Loop on each points pair
125
+ for (lIdxPoint = 0; lIdxPoint < lNbrPoints-1; ++lIdxPoint) {
126
+ // Compute coordinates at the scale
127
+ lValPreviousPoint = rb_ary_entry(lValSortedPoints, lIdxPoint);
128
+ lPreviousPointX = lMinValue + (lDiffValue*(FIX2LONG(rb_ary_entry(lValPreviousPoint, 0)) - lMinScale))/lDiffScale;
129
+ lPreviousPointY = lMinValue + (lDiffValue*(FIX2LONG(rb_ary_entry(lValPreviousPoint, 1)) - lMinScale))/lDiffScale;
130
+ lValNextPoint = rb_ary_entry(lValSortedPoints, lIdxPoint+1);
131
+ lNextPointX = lMinValue + (lDiffValue*(FIX2LONG(rb_ary_entry(lValNextPoint, 0)) - lMinScale))/lDiffScale;
132
+ lNextPointY = lMinValue + (lDiffValue*(FIX2LONG(rb_ary_entry(lValNextPoint, 1)) - lMinScale))/lDiffScale;
133
+ lDiffX = lNextPointX - lPreviousPointX;
134
+ lDiffY = lNextPointY - lPreviousPointY;
135
+ /*
136
+ printf("NOSCALE lPreviousPoint=%ld,%ld lNextPoint=%ld,%ld\n", FIX2LONG(rb_ary_entry(lValPreviousPoint, 0)), FIX2LONG(rb_ary_entry(lValPreviousPoint, 1)), FIX2LONG(rb_ary_entry(lValNextPoint, 0)), FIX2LONG(rb_ary_entry(lValNextPoint, 1)));
137
+ printf("NOSCALE lMinScale=%lld lDiffScale=%lld\n", lMinScale, lDiffScale);
138
+ printf("lPreviousPoint=%Lf,%Lf lNextPoint=%Lf,%Lf\n", lPreviousPointX, lPreviousPointY, lNextPointX, lNextPointY);
139
+ printf("lMinValue=%lld lDiffValue=%lld\n", lMinValue, lDiffValue);
140
+ */
141
+ // Fill the part of the channel map between these 2 points
142
+ for (lIdxValue = lPreviousPointX; lIdxValue <= lNextPointX; ++lIdxValue) {
143
+ lNewValue = lPreviousPointY + round((lDiffY*(((long double)lIdxValue) - lPreviousPointX))/lDiffX);
144
+ /*
145
+ if (abs(lIdxValue) <= 10) {
146
+ printf("lIdxValue=%d lNewValue=%lld\n", lIdxValue, lNewValue);
147
+ }
148
+ */
149
+ if ((lNewValue > lMaxValue) ||
150
+ (lNewValue < lMinValue)) {
151
+ rResultCode = 1;
152
+ }
153
+ oPtrChannelMap[lIdxValue+lIdxMapOffset] = lNewValue;
154
+ }
155
+ }
156
+
157
+ return rResultCode;
158
+ }
159
+
160
+ /**
161
+ * Fill a channel map with a given function
162
+ *
163
+ * Parameters:
164
+ * * *iSelf* (_Object_): Calling object
165
+ * * *iNbrBitsPerSample* (<em>const int</em>): Number of bits per sample
166
+ * * *oPtrChannelMap* (<em>int*</em>): The channel map to fill
167
+ * * *iValFunction* (<em>map<Symbol,Object></em>): The function to apply
168
+ * Return:
169
+ * * _int_: Result code:
170
+ * ** *0*: The map never exceeds limits
171
+ * ** *1*: The map can exceed limits
172
+ * ** *2*: An error occurred
173
+ */
174
+ static int arithmutils_fillMapWithFunction(
175
+ VALUE iSelf,
176
+ const int iNbrBitsPerSample,
177
+ int* oPtrChannelMap,
178
+ VALUE iValFunction) {
179
+ int rResultCode = 0;
180
+
181
+ // Retrieve the function type
182
+ int lFunctionType = FIX2INT(rb_hash_aref(iValFunction, ID2SYM(rb_intern("FunctionType"))));
183
+ // Call the relevant method based on the type
184
+ switch (lFunctionType) {
185
+ case FCTTYPE_PIECEWISE_LINEAR:
186
+ rResultCode = arithmutils_fillMap_PiecewiseLinear(iNbrBitsPerSample, oPtrChannelMap, iValFunction);
187
+ break;
188
+ default: ; // The ; is here to make gcc compile: variables declarations are forbidden after a label.
189
+ char lLogMessage[256];
190
+ sprintf(lLogMessage, "Unknown function type %d", lFunctionType);
191
+ rb_funcall(iSelf, rb_intern("logWarn"), 1, rb_str_new2(lLogMessage));
192
+ rResultCode = 2;
193
+ break;
194
+ }
195
+
196
+ return rResultCode;
197
+ }
198
+
199
+ /**
200
+ * Create a map from a list of functions.
201
+ *
202
+ * Parameters:
203
+ * * *iSelf* (_FFT_): Self
204
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
205
+ * * *iValFunctions* (<em>list<map<Symbol,Object>></em>): List of functions, per channel
206
+ * Return:
207
+ * * _Object_: Container of the map
208
+ **/
209
+ static VALUE arithmutils_createMapFromFunctions(
210
+ VALUE iSelf,
211
+ VALUE iValNbrBitsPerSample,
212
+ VALUE iValFunctions) {
213
+ // Translate Ruby objects
214
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
215
+ int lNbrChannels = RARRAY(iValFunctions)->len;
216
+
217
+ int lIdxChannel;
218
+ int* lPtrChannelMap;
219
+ int lNbrDifferentValues = 1 << iNbrBitsPerSample;
220
+ // The map
221
+ tMap* lPtrMap = ALLOC(tMap);
222
+ lPtrMap->nbrChannels = lNbrChannels;
223
+ lPtrMap->possibleExceedValues = 0;
224
+ lPtrMap->map = ALLOC_N(int*, lNbrChannels);
225
+ for (lIdxChannel = 0; lIdxChannel < lNbrChannels; ++lIdxChannel) {
226
+ lPtrChannelMap = ALLOC_N(int, lNbrDifferentValues);
227
+ if (arithmutils_fillMapWithFunction(iSelf, iNbrBitsPerSample, lPtrChannelMap, rb_ary_entry(iValFunctions, lIdxChannel)) == 1) {
228
+ lPtrMap->possibleExceedValues = 1;
229
+ }
230
+ lPtrMap->map[lIdxChannel] = lPtrChannelMap;
231
+ }
232
+
233
+ return Data_Wrap_Struct(rb_cObject, NULL, arithmutils_freeMap, lPtrMap);
234
+ }
235
+
236
+ /**
237
+ * Process a value read from an input buffer for the applyMap function.
238
+ *
239
+ * Parameters:
240
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
241
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
242
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
243
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tApplyMapStruct*</em>.
244
+ * Return:
245
+ * * _int_: The return code:
246
+ * ** 0: Continue iteration
247
+ * ** 1: Break all iterations
248
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
249
+ */
250
+ int arithmutils_processValue_applyMap(
251
+ const tSampleValue iValue,
252
+ tSampleValue* oPtrValue,
253
+ const tSampleIndex iIdxSample,
254
+ const int iIdxChannel,
255
+ void* iPtrArgs) {
256
+
257
+ (*oPtrValue) = ((tApplyMapStruct*)iPtrArgs)->map[iIdxChannel][iValue + ((tApplyMapStruct*)iPtrArgs)->offsetIdxMap];
258
+
259
+ return 0;
260
+ }
261
+
262
+ /**
263
+ * Apply a map on an input buffer, and outputs a result buffer.
264
+ *
265
+ * Parameters:
266
+ * * *iSelf* (_FFT_): Self
267
+ * * *iValMap* (_Object_): The container of the map
268
+ * * *iValInputBuffer* (_String_): The input buffer
269
+ * * *iValNbrSamples* (_Integer_): Number of samples from the buffer
270
+ * Return:
271
+ * * _String_: Output buffer
272
+ **/
273
+ static VALUE arithmutils_applyMap(
274
+ VALUE iSelf,
275
+ VALUE iValMap,
276
+ VALUE iValInputBuffer,
277
+ VALUE iValNbrBitsPerSample,
278
+ VALUE iValNbrSamples) {
279
+ // Translate Ruby objects
280
+ tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
281
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
282
+ // Get the map
283
+ tMap* lPtrMap;
284
+ Data_Get_Struct(iValMap, tMap, lPtrMap);
285
+
286
+ // Get the input buffer
287
+ char* lPtrRawBuffer = RSTRING(iValInputBuffer)->ptr;
288
+ int lBufferCharSize = RSTRING(iValInputBuffer)->len;
289
+ // Allocate the output buffer
290
+ char* lPtrOutputBuffer = ALLOC_N(char, lBufferCharSize);
291
+
292
+ // Create parameters to give the process
293
+ tApplyMapStruct lProcessParams;
294
+ lProcessParams.offsetIdxMap = 1 << (iNbrBitsPerSample-1);
295
+ lProcessParams.map = lPtrMap->map;
296
+
297
+ // Iterate through the raw buffer
298
+ commonutils_iterateThroughRawBufferOutput(
299
+ iSelf,
300
+ lPtrRawBuffer,
301
+ lPtrOutputBuffer,
302
+ iNbrBitsPerSample,
303
+ lPtrMap->nbrChannels,
304
+ iNbrSamples,
305
+ 0,
306
+ lPtrMap->possibleExceedValues,
307
+ &arithmutils_processValue_applyMap,
308
+ &lProcessParams
309
+ );
310
+
311
+ VALUE rValOutputBuffer = rb_str_new(lPtrOutputBuffer, lBufferCharSize);
312
+
313
+ free(lPtrOutputBuffer);
314
+
315
+ return rValOutputBuffer;
316
+ }
317
+
318
+ /**
319
+ * Process a value read from an input buffer for the mix function.
320
+ * Optimized for 8 bits samples.
321
+ *
322
+ * Parameters:
323
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
324
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
325
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
326
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
327
+ * Return:
328
+ * * _int_: The return code:
329
+ * ** 0: Continue iteration
330
+ * ** 1: Break all iterations
331
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
332
+ */
333
+ int arithmutils_processValue_mix_8bits(
334
+ const tSampleValue iValue,
335
+ tSampleValue* oPtrValue,
336
+ const tSampleIndex iIdxSample,
337
+ const int iIdxChannel,
338
+ void* iPtrArgs) {
339
+ tMixStruct* lPtrParams = (tMixStruct*)iPtrArgs;
340
+
341
+ if (lPtrParams->nbrActiveBuffers > 0) {
342
+ // Check if we hit the limit of the last active buffer (the one having the least samples)
343
+ if (iIdxSample == lPtrParams->lstBuffers[lPtrParams->nbrActiveBuffers-1].nbrBufferSamples) {
344
+ // We have to check the buffers that are to be removed
345
+ lPtrParams->idxBuffer = lPtrParams->nbrActiveBuffers-1;
346
+ while ((lPtrParams->idxBuffer >= 0) &&
347
+ (lPtrParams->lstBuffers[lPtrParams->idxBuffer].nbrBufferSamples == iIdxSample )) {
348
+ --lPtrParams->nbrActiveBuffers;
349
+ --lPtrParams->idxBuffer;
350
+ }
351
+ }
352
+ // We have to mix several buffers
353
+ lPtrParams->tmpValue = ((long double)iValue)*lPtrParams->mainCoeff;
354
+ for (lPtrParams->idxBuffer = 0; lPtrParams->idxBuffer < lPtrParams->nbrActiveBuffers; ++lPtrParams->idxBuffer) {
355
+ lPtrParams->tmpValue += (((long double)*(lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_8bits))-128)*lPtrParams->lstBuffers[lPtrParams->idxBuffer].coeff;
356
+ ++lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_8bits;
357
+ }
358
+ // Export the result
359
+ (*oPtrValue) = round(lPtrParams->tmpValue);
360
+ } else {
361
+ // There is only the main buffer remaining
362
+ (*oPtrValue) = round(((long double)iValue)*lPtrParams->mainCoeff);
363
+ }
364
+
365
+ return 0;
366
+ }
367
+
368
+ /**
369
+ * Process a value read from an input buffer for the mix function.
370
+ * Optimized for 16 bits samples.
371
+ *
372
+ * Parameters:
373
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
374
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
375
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
376
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
377
+ * Return:
378
+ * * _int_: The return code:
379
+ * ** 0: Continue iteration
380
+ * ** 1: Break all iterations
381
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
382
+ */
383
+ int arithmutils_processValue_mix_16bits(
384
+ const tSampleValue iValue,
385
+ tSampleValue* oPtrValue,
386
+ const tSampleIndex iIdxSample,
387
+ const int iIdxChannel,
388
+ void* iPtrArgs) {
389
+ tMixStruct* lPtrParams = (tMixStruct*)iPtrArgs;
390
+
391
+ if (lPtrParams->nbrActiveBuffers > 0) {
392
+ // Check if we hit the limit of the last active buffer (the one having the least samples)
393
+ if (iIdxSample == lPtrParams->lstBuffers[lPtrParams->nbrActiveBuffers-1].nbrBufferSamples) {
394
+ // We have to check the buffers that are to be removed
395
+ lPtrParams->idxBuffer = lPtrParams->nbrActiveBuffers-1;
396
+ while ((lPtrParams->idxBuffer >= 0) &&
397
+ (lPtrParams->lstBuffers[lPtrParams->idxBuffer].nbrBufferSamples == iIdxSample )) {
398
+ --lPtrParams->nbrActiveBuffers;
399
+ --lPtrParams->idxBuffer;
400
+ }
401
+ }
402
+ // We have to mix several buffers
403
+ lPtrParams->tmpValue = ((long double)iValue)*lPtrParams->mainCoeff;
404
+ for (lPtrParams->idxBuffer = 0; lPtrParams->idxBuffer < lPtrParams->nbrActiveBuffers; ++lPtrParams->idxBuffer) {
405
+ lPtrParams->tmpValue += ((long double)*(lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_16bits))*lPtrParams->lstBuffers[lPtrParams->idxBuffer].coeff;
406
+ ++lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_16bits;
407
+ }
408
+ // Export the result
409
+ (*oPtrValue) = round(lPtrParams->tmpValue);
410
+ } else {
411
+ // There is only the main buffer remaining
412
+ (*oPtrValue) = round(((long double)iValue)*lPtrParams->mainCoeff);
413
+ }
414
+
415
+ return 0;
416
+ }
417
+
418
+ /**
419
+ * Process a value read from an input buffer for the mix function.
420
+ * Optimized for 8 bits samples.
421
+ *
422
+ * Parameters:
423
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
424
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
425
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
426
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
427
+ * Return:
428
+ * * _int_: The return code:
429
+ * ** 0: Continue iteration
430
+ * ** 1: Break all iterations
431
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
432
+ */
433
+ int arithmutils_processValue_mix_24bits(
434
+ const tSampleValue iValue,
435
+ tSampleValue* oPtrValue,
436
+ const tSampleIndex iIdxSample,
437
+ const int iIdxChannel,
438
+ void* iPtrArgs) {
439
+ tMixStruct* lPtrParams = (tMixStruct*)iPtrArgs;
440
+
441
+ if (lPtrParams->nbrActiveBuffers > 0) {
442
+ // Check if we hit the limit of the last active buffer (the one having the least samples)
443
+ if (iIdxSample == lPtrParams->lstBuffers[lPtrParams->nbrActiveBuffers-1].nbrBufferSamples) {
444
+ // We have to check the buffers that are to be removed
445
+ lPtrParams->idxBuffer = lPtrParams->nbrActiveBuffers-1;
446
+ while ((lPtrParams->idxBuffer >= 0) &&
447
+ (lPtrParams->lstBuffers[lPtrParams->idxBuffer].nbrBufferSamples == iIdxSample )) {
448
+ --lPtrParams->nbrActiveBuffers;
449
+ --lPtrParams->idxBuffer;
450
+ }
451
+ }
452
+ // We have to mix several buffers
453
+ lPtrParams->tmpValue = ((long double)iValue)*lPtrParams->mainCoeff;
454
+ for (lPtrParams->idxBuffer = 0; lPtrParams->idxBuffer < lPtrParams->nbrActiveBuffers; ++lPtrParams->idxBuffer) {
455
+ lPtrParams->tmpValue += ((long double)(lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_24bits->value))*lPtrParams->lstBuffers[lPtrParams->idxBuffer].coeff;
456
+ lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_24bits = (t24bits*)(((int)lPtrParams->lstBuffers[lPtrParams->idxBuffer].buffer_24bits)+3);
457
+ }
458
+ // Export the result
459
+ (*oPtrValue) = round(lPtrParams->tmpValue);
460
+ } else {
461
+ // There is only the main buffer remaining
462
+ (*oPtrValue) = round(((long double)iValue)*lPtrParams->mainCoeff);
463
+ }
464
+
465
+ return 0;
466
+ }
467
+
468
+ /**
469
+ * Mix a list of buffers.
470
+ * Prerequisite: The list of buffers have to be sorted, from the one having the more samples to the one having the less.
471
+ *
472
+ * Parameters:
473
+ * * *iSelf* (_FFT_): Self
474
+ * * *iValBuffers* (<em>list<list<Object>></em>): The list of buffers and their associated info (see Mix.rb for details)
475
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
476
+ * * *iValNbrChannels* (_Integer_): Number of channels
477
+ * Return:
478
+ * * _String_: Output buffer
479
+ * * _Integer_: Number of samples written
480
+ **/
481
+ static VALUE arithmutils_mixBuffers(
482
+ VALUE iSelf,
483
+ VALUE iValBuffers,
484
+ VALUE iValNbrBitsPerSample,
485
+ VALUE iValNbrChannels) {
486
+ // Translate Ruby objects
487
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
488
+ int iNbrChannels = FIX2INT(iValNbrChannels);
489
+
490
+ // Create the list of additional buffers to consider
491
+ // This list is sorted from the one having the most samples to the one having the least samples
492
+ int lNbrBuffers = RARRAY(iValBuffers)->len;
493
+ tBufferInfo lPtrAdditionalBuffers[lNbrBuffers-1];
494
+ int lIdxBuffer;
495
+ VALUE lValBufferInfo;
496
+ char* lPtrBuffer;
497
+ for (lIdxBuffer = 0; lIdxBuffer < lNbrBuffers-1 ; ++lIdxBuffer) {
498
+ lValBufferInfo = rb_ary_entry(iValBuffers, lIdxBuffer+1);
499
+ lPtrBuffer = RSTRING(rb_ary_entry(lValBufferInfo, 3))->ptr;
500
+ lPtrAdditionalBuffers[lIdxBuffer].coeff = NUM2DBL(rb_ary_entry(lValBufferInfo, 2));
501
+ lPtrAdditionalBuffers[lIdxBuffer].buffer_8bits = (unsigned char*)lPtrBuffer;
502
+ lPtrAdditionalBuffers[lIdxBuffer].buffer_16bits = (signed short int*)lPtrBuffer;
503
+ lPtrAdditionalBuffers[lIdxBuffer].buffer_24bits = (t24bits*)lPtrBuffer;
504
+ lPtrAdditionalBuffers[lIdxBuffer].nbrBufferSamples = FIX2INT(rb_ary_entry(lValBufferInfo, 4));
505
+ }
506
+
507
+ // Get the first buffer: the one that has the most samples
508
+ VALUE lValFirstBufferInfo = rb_ary_entry(iValBuffers, 0);
509
+ VALUE lValFirstBuffer = rb_ary_entry(lValFirstBufferInfo, 3);
510
+ char* lPtrFirstBuffer = RSTRING(lValFirstBuffer)->ptr;
511
+ int lBufferCharSize = RSTRING(lValFirstBuffer)->len;
512
+ tSampleIndex lNbrSamples = FIX2INT(rb_ary_entry(lValFirstBufferInfo, 4));
513
+
514
+ // Allocate the output buffer
515
+ char* lPtrOutputBuffer = ALLOC_N(char, lBufferCharSize);
516
+
517
+ // Create variables to give to the iteration
518
+ tMixStruct lProcessParams;
519
+ lProcessParams.lstBuffers = lPtrAdditionalBuffers;
520
+ lProcessParams.nbrActiveBuffers = lNbrBuffers - 1;
521
+ lProcessParams.mainCoeff = NUM2DBL(rb_ary_entry(lValFirstBufferInfo, 2));
522
+
523
+ // Iterate through the raw buffer
524
+ if (iNbrBitsPerSample == 8) {
525
+ commonutils_iterateThroughRawBufferOutput(
526
+ iSelf,
527
+ lPtrFirstBuffer,
528
+ lPtrOutputBuffer,
529
+ iNbrBitsPerSample,
530
+ iNbrChannels,
531
+ lNbrSamples,
532
+ 0,
533
+ 1,
534
+ &arithmutils_processValue_mix_8bits,
535
+ &lProcessParams
536
+ );
537
+ } else if (iNbrBitsPerSample == 16) {
538
+ commonutils_iterateThroughRawBufferOutput(
539
+ iSelf,
540
+ lPtrFirstBuffer,
541
+ lPtrOutputBuffer,
542
+ iNbrBitsPerSample,
543
+ iNbrChannels,
544
+ lNbrSamples,
545
+ 0,
546
+ 1,
547
+ &arithmutils_processValue_mix_16bits,
548
+ &lProcessParams
549
+ );
550
+ } else {
551
+ // If it is not 24 bits, the method will throw an exception. So we are safe.
552
+ commonutils_iterateThroughRawBufferOutput(
553
+ iSelf,
554
+ lPtrFirstBuffer,
555
+ lPtrOutputBuffer,
556
+ iNbrBitsPerSample,
557
+ iNbrChannels,
558
+ lNbrSamples,
559
+ 0,
560
+ 1,
561
+ &arithmutils_processValue_mix_24bits,
562
+ &lProcessParams
563
+ );
564
+ }
565
+
566
+ VALUE rValOutputBuffer = rb_str_new(lPtrOutputBuffer, lBufferCharSize);
567
+
568
+ free(lPtrOutputBuffer);
569
+
570
+ return rb_ary_new3(2, rValOutputBuffer, LONG2FIX(lNbrSamples));
571
+ }
572
+
573
+ // The value that represents nil in the maps
574
+ static tSampleValue gImpossibleValue;
575
+ static ID gID_logWarn;
576
+
577
+ /**
578
+ * Process a value read from an input buffer for the compare function.
579
+ * Optimized for 8 bits samples.
580
+ *
581
+ * Parameters:
582
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
583
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
584
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
585
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
586
+ * Return:
587
+ * * _int_: The return code:
588
+ * ** 0: Continue iteration
589
+ * ** 1: Break all iterations
590
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
591
+ */
592
+ int arithmutils_processValue_compare_8bits(
593
+ const tSampleValue iValue,
594
+ tSampleValue* oPtrValue,
595
+ const tSampleIndex iIdxSample,
596
+ const int iIdxChannel,
597
+ void* iPtrArgs) {
598
+ tCompareStruct* lPtrParams = (tCompareStruct*)iPtrArgs;
599
+
600
+ tSampleValue lValue2 = (*lPtrParams->buffer2_8bits)-128;
601
+ if (lPtrParams->map != NULL) {
602
+ // Complete the map
603
+ if (lPtrParams->map[lPtrParams->mapOffset+iValue] == gImpossibleValue) {
604
+ lPtrParams->map[lPtrParams->mapOffset+iValue] = lValue2;
605
+ } else if (lPtrParams->map[lPtrParams->mapOffset+iValue] != lValue2) {
606
+ char lMessage[256];
607
+ sprintf(lMessage, "Distortion for input value %d was found both %d and %d", iValue, lPtrParams->map[lPtrParams->mapOffset+iValue], lValue2);
608
+ rb_funcall(lPtrParams->self, gID_logWarn, 1, rb_str_new2(lMessage));
609
+ }
610
+ }
611
+ *oPtrValue = (tSampleValue)(((long double)(lValue2-iValue))*lPtrParams->coeffDiff);
612
+ mpz_add_ui(lPtrParams->cumulativeErrors, lPtrParams->cumulativeErrors, abs(lValue2-iValue));
613
+ ++lPtrParams->buffer2_8bits;
614
+
615
+ return 0;
616
+ }
617
+
618
+ /**
619
+ * Process a value read from an input buffer for the compare function.
620
+ * Optimized for 16 bits samples.
621
+ *
622
+ * Parameters:
623
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
624
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
625
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
626
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
627
+ * Return:
628
+ * * _int_: The return code:
629
+ * ** 0: Continue iteration
630
+ * ** 1: Break all iterations
631
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
632
+ */
633
+ int arithmutils_processValue_compare_16bits(
634
+ const tSampleValue iValue,
635
+ tSampleValue* oPtrValue,
636
+ const tSampleIndex iIdxSample,
637
+ const int iIdxChannel,
638
+ void* iPtrArgs) {
639
+ tCompareStruct* lPtrParams = (tCompareStruct*)iPtrArgs;
640
+
641
+ tSampleValue lValue2 = *lPtrParams->buffer2_16bits;
642
+ if (lPtrParams->map != NULL) {
643
+ // Complete the map
644
+ if (lPtrParams->map[lPtrParams->mapOffset+iValue] == gImpossibleValue) {
645
+ lPtrParams->map[lPtrParams->mapOffset+iValue] = lValue2;
646
+ } else if (lPtrParams->map[lPtrParams->mapOffset+iValue] != lValue2) {
647
+ char lMessage[256];
648
+ sprintf(lMessage, "Distortion for input value %d was found both %d and %d", iValue, lPtrParams->map[lPtrParams->mapOffset+iValue], lValue2);
649
+ rb_funcall(lPtrParams->self, gID_logWarn, 1, rb_str_new2(lMessage));
650
+ }
651
+ }
652
+ *oPtrValue = (tSampleValue)(((long double)(lValue2-iValue))*lPtrParams->coeffDiff);
653
+ mpz_add_ui(lPtrParams->cumulativeErrors, lPtrParams->cumulativeErrors, abs(lValue2-iValue));
654
+ ++lPtrParams->buffer2_16bits;
655
+
656
+ return 0;
657
+ }
658
+
659
+ /**
660
+ * Process a value read from an input buffer for the compare function.
661
+ * Optimized for 8 bits samples.
662
+ *
663
+ * Parameters:
664
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
665
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
666
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
667
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMixStruct*</em>.
668
+ * Return:
669
+ * * _int_: The return code:
670
+ * ** 0: Continue iteration
671
+ * ** 1: Break all iterations
672
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
673
+ */
674
+ int arithmutils_processValue_compare_24bits(
675
+ const tSampleValue iValue,
676
+ tSampleValue* oPtrValue,
677
+ const tSampleIndex iIdxSample,
678
+ const int iIdxChannel,
679
+ void* iPtrArgs) {
680
+ tCompareStruct* lPtrParams = (tCompareStruct*)iPtrArgs;
681
+
682
+ tSampleValue lValue2 = lPtrParams->buffer2_24bits->value;
683
+ if (lPtrParams->map != NULL) {
684
+ // Complete the map
685
+ if (lPtrParams->map[lPtrParams->mapOffset+iValue] == gImpossibleValue) {
686
+ lPtrParams->map[lPtrParams->mapOffset+iValue] = lValue2;
687
+ } else if (lPtrParams->map[lPtrParams->mapOffset+iValue] != lValue2) {
688
+ char lMessage[256];
689
+ sprintf(lMessage, "Distortion for input value %d was found both %d and %d", iValue, lPtrParams->map[lPtrParams->mapOffset+iValue], lValue2);
690
+ rb_funcall(lPtrParams->self, gID_logWarn, 1, rb_str_new2(lMessage));
691
+ }
692
+ }
693
+ *oPtrValue = (tSampleValue)(((long double)(lValue2-iValue))*lPtrParams->coeffDiff);
694
+ mpz_add_ui(lPtrParams->cumulativeErrors, lPtrParams->cumulativeErrors, abs(lValue2-iValue));
695
+ lPtrParams->buffer2_24bits = (t24bits*)(((int)lPtrParams->buffer2_24bits)+3);
696
+
697
+ return 0;
698
+ }
699
+
700
+ /**
701
+ * Get a Ruby integer based on an MPZ storing an integer value.
702
+ *
703
+ * Parameters:
704
+ * * *iMPZ* (<em>mpz_t</em>): The mpz to read
705
+ * Return:
706
+ * * _Integer_: The Ruby integer
707
+ */
708
+ #define MAX_NUMBER_DIGITS 256
709
+ VALUE mpz2RubyInt(
710
+ mpz_t iMPZ) {
711
+ // The buffer where it will be written
712
+ char lStrNumber[MAX_NUMBER_DIGITS];
713
+ mpz_get_str(lStrNumber, 16, iMPZ);
714
+
715
+ return rb_cstr2inum(lStrNumber, 16);
716
+ }
717
+
718
+ /**
719
+ * Compare 2 buffers.
720
+ * Write the difference in an output buffer (Buffer2 - Buffer1).
721
+ * Buffers must have the same size.
722
+ *
723
+ * Parameters:
724
+ * * *iSelf* (_FFT_): Self
725
+ * * *iValBuffer1* (<em>_String_</em>): First buffer
726
+ * * *iValBuffer2* (<em>_String_</em>): Second buffer
727
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
728
+ * * *iValNbrChannels* (_Integer_): Number of channels
729
+ * * *iValNbrSamples* (_Integer_): Number of samples in buffers
730
+ * * *iValCoeffDiff* (_Float_): The coefficient to apply on the differences written to the output
731
+ * * *ioValMap* (</em>list<Integer></em>): Map of differences in sample values (can be nil if we don't want to compute it)
732
+ * Return:
733
+ * * _String_: Output buffer
734
+ * * _Integer_: Cumulative errors in this buffer
735
+ **/
736
+ static VALUE arithmutils_compareBuffers(
737
+ VALUE iSelf,
738
+ VALUE iValBuffer1,
739
+ VALUE iValBuffer2,
740
+ VALUE iValNbrBitsPerSample,
741
+ VALUE iValNbrChannels,
742
+ VALUE iValNbrSamples,
743
+ VALUE iValCoeffDiff,
744
+ VALUE ioValMap) {
745
+ // Translate Ruby objects
746
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
747
+ int iNbrChannels = FIX2INT(iValNbrChannels);
748
+ int iNbrSamples = FIX2INT(iValNbrSamples);
749
+ long double iCoeffDiff = NUM2DBL(iValCoeffDiff);
750
+ char* lPtrBuffer1 = RSTRING(iValBuffer1)->ptr;
751
+ char* lPtrBuffer2 = RSTRING(iValBuffer2)->ptr;
752
+ int lBufferCharSize = RSTRING(iValBuffer1)->len;
753
+ int lNbrSampleValues = 0;
754
+ // Allocate the output buffer
755
+ char* lPtrOutputBuffer = ALLOC_N(char, lBufferCharSize);
756
+
757
+ // Create variables to give to the iteration
758
+ tCompareStruct lProcessParams;
759
+ lProcessParams.coeffDiff = iCoeffDiff;
760
+ lProcessParams.self = iSelf;
761
+ if (ioValMap == Qnil) {
762
+ lProcessParams.map = NULL;
763
+ } else {
764
+ // Create the internal map
765
+ // Define the impossible value
766
+ gImpossibleValue = pow(2, iNbrBitsPerSample-1) + 1;
767
+ lNbrSampleValues = RARRAY(ioValMap)->len;
768
+ tSampleValue lMap[lNbrSampleValues];
769
+ VALUE lValMapValue;
770
+ int lIdxSampleValue;
771
+ for (lIdxSampleValue = 0; lIdxSampleValue < lNbrSampleValues; ++lIdxSampleValue) {
772
+ lValMapValue = rb_ary_entry(ioValMap, lIdxSampleValue);
773
+ if (lValMapValue == Qnil) {
774
+ lMap[lIdxSampleValue] = gImpossibleValue;
775
+ } else {
776
+ lMap[lIdxSampleValue] = FIX2LONG(lValMapValue);
777
+ }
778
+ }
779
+ lProcessParams.map = lMap;
780
+ lProcessParams.mapOffset = pow(2, iNbrBitsPerSample-1);
781
+ }
782
+ lProcessParams.buffer2_8bits = (unsigned char*)lPtrBuffer2;
783
+ lProcessParams.buffer2_16bits = (signed short int*)lPtrBuffer2;
784
+ lProcessParams.buffer2_24bits = (t24bits*)lPtrBuffer2;
785
+ mpz_init(lProcessParams.cumulativeErrors);
786
+
787
+ // Iterate through the raw buffer
788
+ if (iNbrBitsPerSample == 8) {
789
+ commonutils_iterateThroughRawBufferOutput(
790
+ iSelf,
791
+ lPtrBuffer1,
792
+ lPtrOutputBuffer,
793
+ iNbrBitsPerSample,
794
+ iNbrChannels,
795
+ iNbrSamples,
796
+ 0,
797
+ 1,
798
+ &arithmutils_processValue_compare_8bits,
799
+ &lProcessParams
800
+ );
801
+ } else if (iNbrBitsPerSample == 16) {
802
+ commonutils_iterateThroughRawBufferOutput(
803
+ iSelf,
804
+ lPtrBuffer1,
805
+ lPtrOutputBuffer,
806
+ iNbrBitsPerSample,
807
+ iNbrChannels,
808
+ iNbrSamples,
809
+ 0,
810
+ 1,
811
+ &arithmutils_processValue_compare_16bits,
812
+ &lProcessParams
813
+ );
814
+ } else {
815
+ // If it is not 24 bits, the method will throw an exception. So we are safe.
816
+ commonutils_iterateThroughRawBufferOutput(
817
+ iSelf,
818
+ lPtrBuffer1,
819
+ lPtrOutputBuffer,
820
+ iNbrBitsPerSample,
821
+ iNbrChannels,
822
+ iNbrSamples,
823
+ 0,
824
+ 1,
825
+ &arithmutils_processValue_compare_24bits,
826
+ &lProcessParams
827
+ );
828
+ }
829
+
830
+ if (lProcessParams.map != NULL) {
831
+ // Modify the array in parameter
832
+ int lIdxSampleValue;
833
+ for (lIdxSampleValue = 0; lIdxSampleValue < lNbrSampleValues; ++lIdxSampleValue) {
834
+ if (lProcessParams.map[lIdxSampleValue] == gImpossibleValue) {
835
+ rb_ary_store(ioValMap, lIdxSampleValue, Qnil);
836
+ } else {
837
+ rb_ary_store(ioValMap, lIdxSampleValue, LONG2FIX(lProcessParams.map[lIdxSampleValue]));
838
+ }
839
+ }
840
+ }
841
+ VALUE rValCumulativeErrors = mpz2RubyInt(lProcessParams.cumulativeErrors);
842
+ mpz_clear(lProcessParams.cumulativeErrors);
843
+
844
+ VALUE rValOutputBuffer = rb_str_new(lPtrOutputBuffer, lBufferCharSize);
845
+
846
+ free(lPtrOutputBuffer);
847
+
848
+ return rb_ary_new3(2, rValOutputBuffer, rValCumulativeErrors);
849
+ }
850
+
851
+ // Initialize the module
852
+ void Init_ArithmUtils() {
853
+ VALUE lWSKModule = rb_define_module("WSK");
854
+ VALUE lArithmUtilsModule = rb_define_module_under(lWSKModule, "ArithmUtils");
855
+ VALUE lArithmUtilsClass = rb_define_class_under(lArithmUtilsModule, "ArithmUtils", rb_cObject);
856
+
857
+ rb_define_method(lArithmUtilsClass, "createMapFromFunctions", arithmutils_createMapFromFunctions, 2);
858
+ rb_define_method(lArithmUtilsClass, "applyMap", arithmutils_applyMap, 4);
859
+ rb_define_method(lArithmUtilsClass, "mixBuffers", arithmutils_mixBuffers, 3);
860
+ rb_define_method(lArithmUtilsClass, "compareBuffers", arithmutils_compareBuffers, 7);
861
+ gID_logWarn = rb_intern("logWarn");
862
+ }