WaveSwissKnife 0.2.0.20120302
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +4 -0
- data/ChangeLog +31 -0
- data/Credits +3 -0
- data/LICENSE +31 -0
- data/README +15 -0
- data/ReleaseInfo +8 -0
- data/bin/WSK.rb +14 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
- data/ext/WSK/AnalyzeUtils/extconf.rb +7 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
- data/ext/WSK/ArithmUtils/extconf.rb +15 -0
- data/ext/WSK/CommonBuild.rb +29 -0
- data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
- data/ext/WSK/FFTUtils/extconf.rb +15 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
- data/ext/WSK/FunctionUtils/extconf.rb +15 -0
- data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
- data/ext/WSK/SilentUtils/extconf.rb +7 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
- data/ext/WSK/VolumeUtils/extconf.rb +15 -0
- data/external/CommonUtils/build.rb +28 -0
- data/external/CommonUtils/include/CommonUtils.h +177 -0
- data/external/CommonUtils/src/CommonUtils.c +639 -0
- data/lib/WSK/Actions/Analyze.rb +176 -0
- data/lib/WSK/Actions/ApplyMap.desc.rb +15 -0
- data/lib/WSK/Actions/ApplyMap.rb +57 -0
- data/lib/WSK/Actions/ApplyVolumeFct.desc.rb +30 -0
- data/lib/WSK/Actions/ApplyVolumeFct.rb +72 -0
- data/lib/WSK/Actions/Compare.desc.rb +25 -0
- data/lib/WSK/Actions/Compare.rb +238 -0
- data/lib/WSK/Actions/ConstantCompare.desc.rb +20 -0
- data/lib/WSK/Actions/ConstantCompare.rb +61 -0
- data/lib/WSK/Actions/Cut.desc.rb +20 -0
- data/lib/WSK/Actions/Cut.rb +60 -0
- data/lib/WSK/Actions/CutFirstSignal.desc.rb +25 -0
- data/lib/WSK/Actions/CutFirstSignal.rb +72 -0
- data/lib/WSK/Actions/DCShifter.desc.rb +15 -0
- data/lib/WSK/Actions/DCShifter.rb +67 -0
- data/lib/WSK/Actions/DrawFct.desc.rb +20 -0
- data/lib/WSK/Actions/DrawFct.rb +59 -0
- data/lib/WSK/Actions/FFT.rb +104 -0
- data/lib/WSK/Actions/GenAllValues.rb +67 -0
- data/lib/WSK/Actions/GenConstant.desc.rb +20 -0
- data/lib/WSK/Actions/GenConstant.rb +56 -0
- data/lib/WSK/Actions/GenSawtooth.rb +57 -0
- data/lib/WSK/Actions/GenSine.desc.rb +20 -0
- data/lib/WSK/Actions/GenSine.rb +73 -0
- data/lib/WSK/Actions/Identity.rb +43 -0
- data/lib/WSK/Actions/Mix.desc.rb +15 -0
- data/lib/WSK/Actions/Mix.rb +149 -0
- data/lib/WSK/Actions/Multiply.desc.rb +15 -0
- data/lib/WSK/Actions/Multiply.rb +73 -0
- data/lib/WSK/Actions/NoiseGate.desc.rb +35 -0
- data/lib/WSK/Actions/NoiseGate.rb +129 -0
- data/lib/WSK/Actions/SilenceInserter.desc.rb +20 -0
- data/lib/WSK/Actions/SilenceInserter.rb +87 -0
- data/lib/WSK/Actions/SilenceRemover.desc.rb +30 -0
- data/lib/WSK/Actions/SilenceRemover.rb +74 -0
- data/lib/WSK/Actions/VolumeProfile.desc.rb +35 -0
- data/lib/WSK/Actions/VolumeProfile.rb +63 -0
- data/lib/WSK/Common.rb +292 -0
- data/lib/WSK/FFT.rb +527 -0
- data/lib/WSK/Functions.rb +770 -0
- data/lib/WSK/Launcher.rb +216 -0
- data/lib/WSK/Maps.rb +29 -0
- data/lib/WSK/Model/CachedBufferReader.rb +151 -0
- data/lib/WSK/Model/Header.rb +133 -0
- data/lib/WSK/Model/InputData.rb +193 -0
- data/lib/WSK/Model/RawReader.rb +78 -0
- data/lib/WSK/Model/WaveReader.rb +91 -0
- data/lib/WSK/OutputInterfaces/DirectStream.rb +146 -0
- data/lib/WSK/RIFFReader.rb +60 -0
- 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
|