WaveSwissKnife 0.2.0.20120302

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/AUTHORS +4 -0
  2. data/ChangeLog +31 -0
  3. data/Credits +3 -0
  4. data/LICENSE +31 -0
  5. data/README +15 -0
  6. data/ReleaseInfo +8 -0
  7. data/bin/WSK.rb +14 -0
  8. data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
  9. data/ext/WSK/AnalyzeUtils/extconf.rb +7 -0
  10. data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
  11. data/ext/WSK/ArithmUtils/extconf.rb +15 -0
  12. data/ext/WSK/CommonBuild.rb +29 -0
  13. data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
  14. data/ext/WSK/FFTUtils/extconf.rb +15 -0
  15. data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
  16. data/ext/WSK/FunctionUtils/extconf.rb +15 -0
  17. data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
  18. data/ext/WSK/SilentUtils/extconf.rb +7 -0
  19. data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
  20. data/ext/WSK/VolumeUtils/extconf.rb +15 -0
  21. data/external/CommonUtils/build.rb +28 -0
  22. data/external/CommonUtils/include/CommonUtils.h +177 -0
  23. data/external/CommonUtils/src/CommonUtils.c +639 -0
  24. data/lib/WSK/Actions/Analyze.rb +176 -0
  25. data/lib/WSK/Actions/ApplyMap.desc.rb +15 -0
  26. data/lib/WSK/Actions/ApplyMap.rb +57 -0
  27. data/lib/WSK/Actions/ApplyVolumeFct.desc.rb +30 -0
  28. data/lib/WSK/Actions/ApplyVolumeFct.rb +72 -0
  29. data/lib/WSK/Actions/Compare.desc.rb +25 -0
  30. data/lib/WSK/Actions/Compare.rb +238 -0
  31. data/lib/WSK/Actions/ConstantCompare.desc.rb +20 -0
  32. data/lib/WSK/Actions/ConstantCompare.rb +61 -0
  33. data/lib/WSK/Actions/Cut.desc.rb +20 -0
  34. data/lib/WSK/Actions/Cut.rb +60 -0
  35. data/lib/WSK/Actions/CutFirstSignal.desc.rb +25 -0
  36. data/lib/WSK/Actions/CutFirstSignal.rb +72 -0
  37. data/lib/WSK/Actions/DCShifter.desc.rb +15 -0
  38. data/lib/WSK/Actions/DCShifter.rb +67 -0
  39. data/lib/WSK/Actions/DrawFct.desc.rb +20 -0
  40. data/lib/WSK/Actions/DrawFct.rb +59 -0
  41. data/lib/WSK/Actions/FFT.rb +104 -0
  42. data/lib/WSK/Actions/GenAllValues.rb +67 -0
  43. data/lib/WSK/Actions/GenConstant.desc.rb +20 -0
  44. data/lib/WSK/Actions/GenConstant.rb +56 -0
  45. data/lib/WSK/Actions/GenSawtooth.rb +57 -0
  46. data/lib/WSK/Actions/GenSine.desc.rb +20 -0
  47. data/lib/WSK/Actions/GenSine.rb +73 -0
  48. data/lib/WSK/Actions/Identity.rb +43 -0
  49. data/lib/WSK/Actions/Mix.desc.rb +15 -0
  50. data/lib/WSK/Actions/Mix.rb +149 -0
  51. data/lib/WSK/Actions/Multiply.desc.rb +15 -0
  52. data/lib/WSK/Actions/Multiply.rb +73 -0
  53. data/lib/WSK/Actions/NoiseGate.desc.rb +35 -0
  54. data/lib/WSK/Actions/NoiseGate.rb +129 -0
  55. data/lib/WSK/Actions/SilenceInserter.desc.rb +20 -0
  56. data/lib/WSK/Actions/SilenceInserter.rb +87 -0
  57. data/lib/WSK/Actions/SilenceRemover.desc.rb +30 -0
  58. data/lib/WSK/Actions/SilenceRemover.rb +74 -0
  59. data/lib/WSK/Actions/VolumeProfile.desc.rb +35 -0
  60. data/lib/WSK/Actions/VolumeProfile.rb +63 -0
  61. data/lib/WSK/Common.rb +292 -0
  62. data/lib/WSK/FFT.rb +527 -0
  63. data/lib/WSK/Functions.rb +770 -0
  64. data/lib/WSK/Launcher.rb +216 -0
  65. data/lib/WSK/Maps.rb +29 -0
  66. data/lib/WSK/Model/CachedBufferReader.rb +151 -0
  67. data/lib/WSK/Model/Header.rb +133 -0
  68. data/lib/WSK/Model/InputData.rb +193 -0
  69. data/lib/WSK/Model/RawReader.rb +78 -0
  70. data/lib/WSK/Model/WaveReader.rb +91 -0
  71. data/lib/WSK/OutputInterfaces/DirectStream.rb +146 -0
  72. data/lib/WSK/RIFFReader.rb +60 -0
  73. metadata +155 -0
@@ -0,0 +1,494 @@
1
+ /**
2
+ * Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
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 convey data among iterators in the applyVolumeFct method for piecewise linear functions
13
+ typedef struct {
14
+ tFunction_PiecewiseLinear* fctData;
15
+ int unitDB;
16
+ int idxPreviousPoint;
17
+ int idxNextPoint;
18
+ int idxLastPoint;
19
+ // Values used to cache segment computations
20
+ // These must be refreshed each time idxPreviousPoint or idxNextPoint is set/changed.
21
+ tSampleIndex idxPreviousPointX;
22
+ tSampleIndex distWithNextX;
23
+ long double idxPreviousPointY;
24
+ long double distWithNextY;
25
+ tSampleIndex idxNextSegmentX;
26
+ // Values used to cache sample computations
27
+ // These must be refreshed each time we change the current sample. They are the same for all the channels of the current sample.
28
+ long double currentRatio;
29
+ } tApplyVolumeFctStruct_PiecewiseLinear;
30
+
31
+ // Struct used to convey data among iterators in the drawVolumeFct method for piecewise linear functions
32
+ typedef struct {
33
+ tFunction_PiecewiseLinear* fctData;
34
+ int unitDB;
35
+ int idxPreviousPoint;
36
+ int idxNextPoint;
37
+ int idxLastPoint;
38
+ tSampleValue medianValue;
39
+ // Values used to cache segment computations
40
+ // These must be refreshed each time idxPreviousPoint or idxNextPoint is set/changed.
41
+ tSampleIndex idxPreviousPointX;
42
+ tSampleIndex distWithNextX;
43
+ long double idxPreviousPointY;
44
+ long double distWithNextY;
45
+ tSampleIndex idxNextSegmentX;
46
+ // Values used to cache sample computations
47
+ // These must be refreshed each time we change the current sample. They are the same for all the channels of the current sample.
48
+ long double currentRatio;
49
+ } tDrawVolumeFctStruct_PiecewiseLinear;
50
+
51
+ // Struct used to convey data among iterators in the MeasureLevel method
52
+ typedef struct {
53
+ mpz_t* squareSums;
54
+ tSampleValue* maxAbsValue;
55
+ mpz_t tmpInt;
56
+ } tMeasureLevelStruct;
57
+
58
+ /**
59
+ * Process a value read from an input buffer for the applyVolumeFct function in case of piecewise linear function.
60
+ *
61
+ * Parameters::
62
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
63
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
64
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
65
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tApplyVolumeFctStruct_PiecewiseLinear*</em>.
66
+ * Return::
67
+ * * _int_: The return code:
68
+ * ** 0: Continue iteration
69
+ * ** 1: Break all iterations
70
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
71
+ */
72
+ int volumeutils_processValue_applyVolumeFct_PiecewiseLinear(
73
+ const tSampleValue iValue,
74
+ tSampleValue* oPtrValue,
75
+ const tSampleIndex iIdxSample,
76
+ const int iIdxChannel,
77
+ void* iPtrArgs) {
78
+ tApplyVolumeFctStruct_PiecewiseLinear* lPtrArgs = (tApplyVolumeFctStruct_PiecewiseLinear*)iPtrArgs;
79
+
80
+ // Change caches if needed
81
+ if (iIdxChannel == 0) {
82
+ // Switch to the next segment if we arrived at the end and it is the last one
83
+ if ((iIdxSample == lPtrArgs->idxNextSegmentX) &&
84
+ (lPtrArgs->idxNextPoint != lPtrArgs->idxLastPoint)) {
85
+ /*
86
+ printf("[%lld] Changing segment (%lld reached) to [%d - %d] ([%lld - %lld])\n", iIdxSample, lPtrArgs->idxNextSegmentX, lPtrArgs->idxPreviousPoint+1, lPtrArgs->idxNextPoint+1, lPtrArgs->fctData->pointsX[lPtrArgs->idxPreviousPoint+1], lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint+1]);
87
+ */
88
+ ++lPtrArgs->idxNextPoint;
89
+ ++lPtrArgs->idxPreviousPoint;
90
+ // Compute next cache values
91
+ lPtrArgs->idxPreviousPointX = lPtrArgs->fctData->pointsX[lPtrArgs->idxPreviousPoint];
92
+ lPtrArgs->distWithNextX = lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint]-lPtrArgs->idxPreviousPointX;
93
+ lPtrArgs->idxPreviousPointY = lPtrArgs->fctData->pointsY[lPtrArgs->idxPreviousPoint];
94
+ lPtrArgs->distWithNextY = lPtrArgs->fctData->pointsY[lPtrArgs->idxNextPoint]-lPtrArgs->idxPreviousPointY;
95
+ lPtrArgs->idxNextSegmentX = lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint]+1;
96
+ }
97
+ // Compute the ratio to apply
98
+ if (lPtrArgs->unitDB == 1) {
99
+ lPtrArgs->currentRatio = pow(2, (lPtrArgs->idxPreviousPointY+((iIdxSample-lPtrArgs->idxPreviousPointX)*lPtrArgs->distWithNextY)/lPtrArgs->distWithNextX)/6);
100
+ } else {
101
+ lPtrArgs->currentRatio = lPtrArgs->idxPreviousPointY+((iIdxSample-lPtrArgs->idxPreviousPointX)*lPtrArgs->distWithNextY)/lPtrArgs->distWithNextX;
102
+ }
103
+ /*
104
+ if ((iIdxSample > 26563930) && (iIdxSample < 26563940)) {
105
+ printf("[%lld] idxPreviousPoint=%d idxPreviousPointX=%lld idxPreviousPointY=%Lf idxNextPoint=%d distWithNextX=%lld distWithNextY=%Lf idxNextSegmentX=%lld currentRatio=%Lf\n", iIdxSample, lPtrArgs->idxPreviousPoint, lPtrArgs->idxPreviousPointX, lPtrArgs->idxPreviousPointY, lPtrArgs->idxNextPoint, lPtrArgs->distWithNextX, lPtrArgs->distWithNextY, lPtrArgs->idxNextSegmentX, lPtrArgs->currentRatio);
106
+ }
107
+ */
108
+ }
109
+
110
+ // Write the correct value
111
+ (*oPtrValue) = iValue*lPtrArgs->currentRatio;
112
+
113
+ return 0;
114
+ }
115
+
116
+ /**
117
+ * Apply a function on the volume of an input buffer, and outputs a result buffer.
118
+ *
119
+ * Parameters::
120
+ * * *iSelf* (_FFT_): Self
121
+ * * *iValCFunction* (_Object_): The container of the C function (created with createCFunction)
122
+ * * *iValInputBuffer* (_String_): The input buffer
123
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
124
+ * * *iValNbrChannels* (_Integer_): Number of channels
125
+ * * *iValNbrSamples* (_Integer_): Number of samples
126
+ * * *iValIdxBufferFirstSample* (_Integer_): Index of the first buffer's sample in the input data
127
+ * * *iValUnitDB* (_Boolean_): Are the units in DB scale ?
128
+ * Return::
129
+ * * _String_: Output buffer
130
+ **/
131
+ static VALUE volumeutils_applyVolumeFct(
132
+ VALUE iSelf,
133
+ VALUE iValCFunction,
134
+ VALUE iValInputBuffer,
135
+ VALUE iValNbrBitsPerSample,
136
+ VALUE iValNbrChannels,
137
+ VALUE iValNbrSamples,
138
+ VALUE iValIdxBufferFirstSample,
139
+ VALUE iValUnitDB) {
140
+ // Translate Ruby objects
141
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
142
+ int iNbrChannels = FIX2INT(iValNbrChannels);
143
+ tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
144
+ tSampleIndex iIdxBufferFirstSample = FIX2LONG(iValIdxBufferFirstSample);
145
+ int iUnitDB = (iValUnitDB == Qtrue ? 1 : 0);
146
+ // Get the C function
147
+ tFunction* lPtrFct;
148
+ Data_Get_Struct(iValCFunction, tFunction, lPtrFct);
149
+ // Get the input buffer
150
+ char* lPtrRawBuffer = RSTRING_PTR(iValInputBuffer);
151
+ int lBufferCharSize = RSTRING(iValInputBuffer)->len;
152
+ // Allocate the output buffer
153
+ char* lPtrOutputBuffer = ALLOC_N(char, lBufferCharSize);
154
+
155
+ // Call the relevant method based on the type
156
+ switch (lPtrFct->fctType) {
157
+ case FCTTYPE_PIECEWISE_LINEAR: ;
158
+ // Create parameters to give the process
159
+ tApplyVolumeFctStruct_PiecewiseLinear lProcessParams;
160
+ lProcessParams.fctData = lPtrFct->fctData;
161
+ lProcessParams.idxLastPoint = lProcessParams.fctData->nbrPoints-1;
162
+ lProcessParams.unitDB = iUnitDB;
163
+ // Find the segment containing iIdxBufferFirstSample
164
+ lProcessParams.idxNextPoint = 0;
165
+ while (lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint] <= iIdxBufferFirstSample) {
166
+ ++lProcessParams.idxNextPoint;
167
+ }
168
+ lProcessParams.idxPreviousPoint = lProcessParams.idxNextPoint - 1;
169
+ // Special case for the last segment
170
+ if (lProcessParams.idxNextPoint == lProcessParams.idxLastPoint + 1) {
171
+ --lProcessParams.idxNextPoint;
172
+ }
173
+ /*
174
+ printf("Apply on volume starts on sample %lld at segment [%d - %d] (%lld - %lld]).\n", iIdxBufferFirstSample, lProcessParams.idxPreviousPoint, lProcessParams.idxNextPoint, lProcessParams.fctData->pointsX[lProcessParams.idxPreviousPoint], lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint]);
175
+ */
176
+ // Compute first cache values
177
+ lProcessParams.idxPreviousPointX = lProcessParams.fctData->pointsX[lProcessParams.idxPreviousPoint];
178
+ lProcessParams.distWithNextX = lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint]-lProcessParams.idxPreviousPointX;
179
+ lProcessParams.idxPreviousPointY = lProcessParams.fctData->pointsY[lProcessParams.idxPreviousPoint];
180
+ lProcessParams.distWithNextY = lProcessParams.fctData->pointsY[lProcessParams.idxNextPoint]-lProcessParams.idxPreviousPointY;
181
+ lProcessParams.idxNextSegmentX = lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint]+1;
182
+ // Iterate through the raw buffer
183
+ commonutils_iterateThroughRawBufferOutput(
184
+ iSelf,
185
+ lPtrRawBuffer,
186
+ lPtrOutputBuffer,
187
+ iNbrBitsPerSample,
188
+ iNbrChannels,
189
+ iNbrSamples,
190
+ iIdxBufferFirstSample,
191
+ 1,
192
+ &volumeutils_processValue_applyVolumeFct_PiecewiseLinear,
193
+ &lProcessParams
194
+ );
195
+ break;
196
+ default: ; // The ; is here to make gcc compile: variables declarations are forbidden after a label.
197
+ char lLogMessage[256];
198
+ sprintf(lLogMessage, "Unknown function type %d", lPtrFct->fctType);
199
+ rb_funcall(iSelf, rb_intern("log_err"), 1, rb_str_new2(lLogMessage));
200
+ break;
201
+ }
202
+
203
+ VALUE rValOutputBuffer = rb_str_new(lPtrOutputBuffer, lBufferCharSize);
204
+
205
+ free(lPtrOutputBuffer);
206
+
207
+ return rValOutputBuffer;
208
+ }
209
+
210
+ /**
211
+ * Process a value read from an input buffer for the drawVolumeFct function in case of piecewise linear function.
212
+ *
213
+ * Parameters::
214
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
215
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
216
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tApplyVolumeFctStruct_PiecewiseLinear*</em>.
217
+ * Return::
218
+ * * _int_: The return code:
219
+ * ** 0: Continue iteration
220
+ * ** 1: Break all iterations
221
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
222
+ */
223
+ int volumeutils_processValue_drawVolumeFct_PiecewiseLinear(
224
+ tSampleValue* oPtrValue,
225
+ const tSampleIndex iIdxSample,
226
+ const int iIdxChannel,
227
+ void* iPtrArgs) {
228
+ tDrawVolumeFctStruct_PiecewiseLinear* lPtrArgs = (tDrawVolumeFctStruct_PiecewiseLinear*)iPtrArgs;
229
+
230
+ // Change caches if needed
231
+ if (iIdxChannel == 0) {
232
+ // Switch to the next segment if we arrived at the end and it is the last one
233
+ if ((iIdxSample == lPtrArgs->idxNextSegmentX) &&
234
+ (lPtrArgs->idxNextPoint != lPtrArgs->idxLastPoint)) {
235
+ /*
236
+ printf("[%lld] Changing segment (%lld reached) to [%d - %d] ([%lld - %lld])\n", iIdxSample, lPtrArgs->idxNextSegmentX, lPtrArgs->idxPreviousPoint+1, lPtrArgs->idxNextPoint+1, lPtrArgs->fctData->pointsX[lPtrArgs->idxPreviousPoint+1], lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint+1]);
237
+ */
238
+ ++lPtrArgs->idxNextPoint;
239
+ ++lPtrArgs->idxPreviousPoint;
240
+ // Compute next cache values
241
+ lPtrArgs->idxPreviousPointX = lPtrArgs->fctData->pointsX[lPtrArgs->idxPreviousPoint];
242
+ lPtrArgs->distWithNextX = lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint]-lPtrArgs->idxPreviousPointX;
243
+ lPtrArgs->idxPreviousPointY = lPtrArgs->fctData->pointsY[lPtrArgs->idxPreviousPoint];
244
+ lPtrArgs->distWithNextY = lPtrArgs->fctData->pointsY[lPtrArgs->idxNextPoint]-lPtrArgs->idxPreviousPointY;
245
+ lPtrArgs->idxNextSegmentX = lPtrArgs->fctData->pointsX[lPtrArgs->idxNextPoint]+1;
246
+ }
247
+ // Compute the ratio to apply
248
+ if (lPtrArgs->unitDB == 1) {
249
+ lPtrArgs->currentRatio = pow(2, (lPtrArgs->idxPreviousPointY+((iIdxSample-lPtrArgs->idxPreviousPointX)*lPtrArgs->distWithNextY)/lPtrArgs->distWithNextX)/6);
250
+ } else {
251
+ lPtrArgs->currentRatio = lPtrArgs->idxPreviousPointY+((iIdxSample-lPtrArgs->idxPreviousPointX)*lPtrArgs->distWithNextY)/lPtrArgs->distWithNextX;
252
+ }
253
+ /*
254
+ if ((iIdxSample > 15) && (iIdxSample < 25)) {
255
+ printf("[%lld] idxPreviousPoint=%d idxPreviousPointX=%lld idxPreviousPointY=%Lf idxNextPoint=%d distWithNextX=%lld distWithNextY=%Lf idxNextSegmentX=%lld idxLastPoint=%d currentRatio=%Lf\n", iIdxSample, lPtrArgs->idxPreviousPoint, lPtrArgs->idxPreviousPointX, lPtrArgs->idxPreviousPointY, lPtrArgs->idxNextPoint, lPtrArgs->distWithNextX, lPtrArgs->distWithNextY, lPtrArgs->idxNextSegmentX, lPtrArgs->idxLastPoint, lPtrArgs->currentRatio);
256
+ }
257
+ */
258
+ }
259
+
260
+ // Write the correct value
261
+ (*oPtrValue) = (lPtrArgs->medianValue)*(lPtrArgs->currentRatio);
262
+
263
+ return 0;
264
+ }
265
+
266
+ /**
267
+ * Draw a function on an output buffer.
268
+ *
269
+ * Parameters::
270
+ * * *iSelf* (_FFT_): Self
271
+ * * *iValCFunction* (_Object_): The container of the C function (created with createCFunction)
272
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
273
+ * * *iValNbrChannels* (_Integer_): Number of channels
274
+ * * *iValNbrSamples* (_Integer_): Number of samples
275
+ * * *iValIdxBufferFirstSample* (_Integer_): Index of the first buffer's sample in the input data
276
+ * * *iValUnitDB* (_Boolean_): Are the units in DB scale ?
277
+ * * *iValMedianValue* (_Integer_): Sample value to take as the reference to draw the function
278
+ * Return::
279
+ * * _String_: Output buffer
280
+ **/
281
+ static VALUE volumeutils_drawVolumeFct(
282
+ VALUE iSelf,
283
+ VALUE iValCFunction,
284
+ VALUE iValNbrBitsPerSample,
285
+ VALUE iValNbrChannels,
286
+ VALUE iValNbrSamples,
287
+ VALUE iValIdxBufferFirstSample,
288
+ VALUE iValUnitDB,
289
+ VALUE iValMedianValue) {
290
+ // Translate Ruby objects
291
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
292
+ int iNbrChannels = FIX2INT(iValNbrChannels);
293
+ tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
294
+ tSampleIndex iIdxBufferFirstSample = FIX2LONG(iValIdxBufferFirstSample);
295
+ int iUnitDB = (iValUnitDB == Qtrue ? 1 : 0);
296
+ tSampleValue iMedianValue = FIX2LONG(iValMedianValue);
297
+ // Get the C function
298
+ tFunction* lPtrFct;
299
+ Data_Get_Struct(iValCFunction, tFunction, lPtrFct);
300
+ int lBufferCharSize = (iNbrSamples*iNbrChannels*iNbrBitsPerSample)/8;
301
+ // Allocate the output buffer
302
+ char* lPtrOutputBuffer = ALLOC_N(char, lBufferCharSize);
303
+
304
+ // Call the relevant method based on the type
305
+ switch (lPtrFct->fctType) {
306
+ case FCTTYPE_PIECEWISE_LINEAR: ;
307
+ // Create parameters to give the process
308
+ tDrawVolumeFctStruct_PiecewiseLinear lProcessParams;
309
+ lProcessParams.fctData = lPtrFct->fctData;
310
+ lProcessParams.medianValue = iMedianValue;
311
+ lProcessParams.idxLastPoint = lProcessParams.fctData->nbrPoints-1;
312
+ lProcessParams.unitDB = iUnitDB;
313
+ // Find the segment containing iIdxBufferFirstSample
314
+ lProcessParams.idxNextPoint = 0;
315
+ while (lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint] <= iIdxBufferFirstSample) {
316
+ ++lProcessParams.idxNextPoint;
317
+ }
318
+ // Special case for the last segment
319
+ if (lProcessParams.idxNextPoint == lProcessParams.idxLastPoint + 1) {
320
+ --lProcessParams.idxNextPoint;
321
+ }
322
+ lProcessParams.idxPreviousPoint = lProcessParams.idxNextPoint - 1;
323
+ // Compute first cache values
324
+ lProcessParams.idxPreviousPointX = lProcessParams.fctData->pointsX[lProcessParams.idxPreviousPoint];
325
+ lProcessParams.distWithNextX = lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint]-lProcessParams.idxPreviousPointX;
326
+ lProcessParams.idxPreviousPointY = lProcessParams.fctData->pointsY[lProcessParams.idxPreviousPoint];
327
+ lProcessParams.distWithNextY = lProcessParams.fctData->pointsY[lProcessParams.idxNextPoint]-lProcessParams.idxPreviousPointY;
328
+ lProcessParams.idxNextSegmentX = lProcessParams.fctData->pointsX[lProcessParams.idxNextPoint]+1;
329
+ // Iterate through the raw buffer
330
+ commonutils_iterateThroughRawBufferOutputOnly(
331
+ iSelf,
332
+ lPtrOutputBuffer,
333
+ iNbrBitsPerSample,
334
+ iNbrChannels,
335
+ iNbrSamples,
336
+ iIdxBufferFirstSample,
337
+ 1,
338
+ &volumeutils_processValue_drawVolumeFct_PiecewiseLinear,
339
+ &lProcessParams
340
+ );
341
+ break;
342
+ default: ; // The ; is here to make gcc compile: variables declarations are forbidden after a label.
343
+ char lLogMessage[256];
344
+ sprintf(lLogMessage, "Unknown function type %d", lPtrFct->fctType);
345
+ rb_funcall(iSelf, rb_intern("log_err"), 1, rb_str_new2(lLogMessage));
346
+ break;
347
+ }
348
+
349
+ VALUE rValOutputBuffer = rb_str_new(lPtrOutputBuffer, lBufferCharSize);
350
+
351
+ free(lPtrOutputBuffer);
352
+
353
+ return rValOutputBuffer;
354
+ }
355
+
356
+ /**
357
+ * Process a value read from an input buffer for the MeasureLevel function.
358
+ * Use the trigo cache.
359
+ *
360
+ * Parameters::
361
+ * * *iValue* (<em>const tSampleValue</em>): The value being read
362
+ * * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
363
+ * * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
364
+ * * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tMeasureLevelStruct*</em>.
365
+ * Return::
366
+ * * _int_: The return code:
367
+ * ** 0: Continue iteration
368
+ * ** 1: Break all iterations
369
+ * ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
370
+ */
371
+ int volumeutils_processValue_MeasureLevel(
372
+ const tSampleValue iValue,
373
+ const tSampleIndex iIdxSample,
374
+ const int iIdxChannel,
375
+ void* iPtrArgs) {
376
+ // Interpret parameters
377
+ tMeasureLevelStruct* lPtrParams = (tMeasureLevelStruct*)iPtrArgs;
378
+
379
+ // RMS computation
380
+ mpz_set_si(lPtrParams->tmpInt, iValue);
381
+ mpz_addmul(lPtrParams->squareSums[iIdxChannel], lPtrParams->tmpInt, lPtrParams->tmpInt);
382
+ // Peak computation
383
+ if (abs(iValue) > lPtrParams->maxAbsValue[iIdxChannel]) {
384
+ lPtrParams->maxAbsValue[iIdxChannel] = abs(iValue);
385
+ }
386
+
387
+
388
+ return 0;
389
+ }
390
+
391
+ /**
392
+ * Measure the Level values of a given raw buffer.
393
+ *
394
+ * Parameters::
395
+ * * *iSelf* (_FFT_): Self
396
+ * * *iValInputRawBuffer* (_String_): The input raw buffer
397
+ * * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
398
+ * * *iValNbrChannels* (_Integer_): Number of channels
399
+ * * *iValNbrSamples* (_Integer_): Number of samples
400
+ * * *iValRMSRatio* (_Float_): Ratio of RMS measure vs Peak level measure
401
+ * Return::
402
+ * * <em>list<Integer></em>: List of integer values
403
+ **/
404
+ static VALUE volumeutils_measureLevel(
405
+ VALUE iSelf,
406
+ VALUE iValInputRawBuffer,
407
+ VALUE iValNbrBitsPerSample,
408
+ VALUE iValNbrChannels,
409
+ VALUE iValNbrSamples,
410
+ VALUE iValRMSRatio) {
411
+ // Translate Ruby objects
412
+ int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
413
+ int iNbrChannels = FIX2INT(iValNbrChannels);
414
+ tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
415
+ double iRMSRatio = NUM2DBL(iValRMSRatio);
416
+ // Get the input buffer
417
+ char* lPtrRawBuffer = RSTRING_PTR(iValInputRawBuffer);
418
+
419
+ // Allocate the array that will store the square sums
420
+ mpz_t lSquareSums[iNbrChannels];
421
+ // The array that will store the maximal absolute values
422
+ tSampleValue lMaxAbsValues[iNbrChannels];
423
+ // Initialize everything
424
+ int lIdxChannel;
425
+ for (lIdxChannel = 0; lIdxChannel < iNbrChannels; ++lIdxChannel) {
426
+ mpz_init(lSquareSums[lIdxChannel]);
427
+ lMaxAbsValues[lIdxChannel] = 0;
428
+ }
429
+
430
+ // Parse the data
431
+ tMeasureLevelStruct lParams;
432
+ lParams.squareSums = lSquareSums;
433
+ lParams.maxAbsValue = lMaxAbsValues;
434
+ mpz_init(lParams.tmpInt);
435
+ commonutils_iterateThroughRawBuffer(
436
+ lPtrRawBuffer,
437
+ iNbrBitsPerSample,
438
+ iNbrChannels,
439
+ iNbrSamples,
440
+ 0,
441
+ &volumeutils_processValue_MeasureLevel,
442
+ &lParams
443
+ );
444
+ mpz_clear(lParams.tmpInt);
445
+
446
+ // Build the resulting array
447
+ VALUE lLevelValues[iNbrChannels];
448
+ // Buffer that stores string representation of mpz_t for Ruby RBigNum
449
+ char lStrValue[128];
450
+ // Temporary variables needed
451
+ mpf_t lRMSCoeff;
452
+ mpf_t lPeakCoeff;
453
+ mpf_t lRMSRatio;
454
+ mpf_t lPeakRatio;
455
+ mpz_t lLevel;
456
+ mpf_init(lRMSCoeff);
457
+ mpf_init(lPeakCoeff);
458
+ mpf_init_set_d(lRMSRatio, iRMSRatio);
459
+ mpf_init_set_d(lPeakRatio, 1.0-iRMSRatio);
460
+ mpz_init(lLevel);
461
+ for (lIdxChannel = 0; lIdxChannel < iNbrChannels; ++lIdxChannel) {
462
+ // Finalize computing the RMS value using a float
463
+ mpf_set_z(lRMSCoeff, lSquareSums[lIdxChannel]);
464
+ mpf_div_ui(lRMSCoeff, lRMSCoeff, iNbrSamples);
465
+ mpf_sqrt(lRMSCoeff, lRMSCoeff);
466
+ // Mix RMS and Peak levels according to the ratio
467
+ mpf_mul(lRMSCoeff, lRMSCoeff, lRMSRatio);
468
+ mpf_set_ui(lPeakCoeff, lMaxAbsValues[lIdxChannel]);
469
+ mpf_mul(lPeakCoeff, lPeakCoeff, lPeakRatio);
470
+ // Use lRMSCoeff to contain the result
471
+ mpf_add(lRMSCoeff, lRMSCoeff, lPeakCoeff);
472
+ mpz_set_f(lLevel, lRMSCoeff);
473
+ lLevelValues[lIdxChannel] = rb_cstr2inum(mpz_get_str(lStrValue, 16, lLevel), 16);
474
+ mpz_clear(lSquareSums[lIdxChannel]);
475
+ }
476
+ mpz_clear(lLevel);
477
+ mpf_clear(lPeakRatio);
478
+ mpf_clear(lRMSRatio);
479
+ mpf_clear(lPeakCoeff);
480
+ mpf_clear(lRMSCoeff);
481
+
482
+ return rb_ary_new4(iNbrChannels, lLevelValues);
483
+ }
484
+
485
+ // Initialize the module
486
+ void Init_VolumeUtils() {
487
+ VALUE lWSKModule = rb_define_module("WSK");
488
+ VALUE lVolumeUtilsModule = rb_define_module_under(lWSKModule, "VolumeUtils");
489
+ VALUE lVolumeUtilsClass = rb_define_class_under(lVolumeUtilsModule, "VolumeUtils", rb_cObject);
490
+
491
+ rb_define_method(lVolumeUtilsClass, "applyVolumeFct", volumeutils_applyVolumeFct, 7);
492
+ rb_define_method(lVolumeUtilsClass, "drawVolumeFct", volumeutils_drawVolumeFct, 7);
493
+ rb_define_method(lVolumeUtilsClass, "measureLevel", volumeutils_measureLevel, 5);
494
+ }
@@ -0,0 +1,15 @@
1
+ #--
2
+ # Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ require "#{File.dirname(__FILE__)}/../CommonBuild"
7
+ # TODO (Cygwin): Adding -L/usr/local/lib is due to some Cygwin installs that do not include it with gcc
8
+ $LDFLAGS += ' -L/usr/local/lib '
9
+ begin
10
+ have_library('gmp')
11
+ rescue Exception
12
+ puts "\n\n!!! Missing library gmp in this system. Please install it from http://gmplib.org/\n\n"
13
+ raise
14
+ end
15
+ create_makefile('VolumeUtils')
@@ -0,0 +1,28 @@
1
+ #--
2
+ # Copyright (c) 2009 - 2012 Muriel Salvan (muriel@x-aeon.com)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ lLibName = 'CommonUtils'
7
+
8
+ if (!File.exists?("lib/lib#{lLibName}.a"))
9
+ puts "Building external library #{lLibName} ..."
10
+ require 'mkmf'
11
+ require 'fileutils'
12
+ # Create it as static, as Ruby does not seem to be able to require libraries linking to external shared libraries (at least on cygwin), even when LD_LIBRARY_PATH is set correctly. The only workaround (unacceptable) is to put the shared library in the exact same directory as the Ruby library.
13
+ $static = true
14
+ $CFLAGS += ' -Wall -Iinclude'
15
+ create_makefile(lLibName, 'src')
16
+ if (!system('make static'))
17
+ raise RuntimeError.new("Error while running 'make static': #{$?}")
18
+ end
19
+ FileUtils::mkdir_p('lib')
20
+ FileUtils::mkdir_p('obj')
21
+ Dir.glob('*.o').each do |iObjectFile|
22
+ FileUtils::mv(iObjectFile, "obj/#{File.basename(iObjectFile)}")
23
+ end
24
+ Dir.glob('*.a').each do |iLibFile|
25
+ # Create the file for ld to link with
26
+ FileUtils::mv(iLibFile, "lib/lib#{File.basename(iLibFile)}")
27
+ end
28
+ end