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.
- data/AUTHORS +1 -0
- data/ChangeLog +5 -0
- data/Credits +3 -0
- data/LICENSE +31 -0
- data/README +18 -0
- data/ReleaseInfo +8 -0
- data/TODO +2 -0
- data/bin/WSK.rb +14 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.o +0 -0
- data/ext/WSK/AnalyzeUtils/AnalyzeUtils.so +0 -0
- data/ext/WSK/AnalyzeUtils/Makefile +149 -0
- data/ext/WSK/AnalyzeUtils/build.rb +18 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.o +0 -0
- data/ext/WSK/ArithmUtils/ArithmUtils.so +0 -0
- data/ext/WSK/ArithmUtils/Makefile +149 -0
- data/ext/WSK/ArithmUtils/build.rb +20 -0
- data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
- data/ext/WSK/FFTUtils/FFTUtils.o +0 -0
- data/ext/WSK/FFTUtils/FFTUtils.so +0 -0
- data/ext/WSK/FFTUtils/Makefile +149 -0
- data/ext/WSK/FFTUtils/build.rb +20 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.o +0 -0
- data/ext/WSK/FunctionUtils/FunctionUtils.so +0 -0
- data/ext/WSK/FunctionUtils/Makefile +149 -0
- data/ext/WSK/FunctionUtils/build.rb +20 -0
- data/ext/WSK/SilentUtils/Makefile +149 -0
- data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
- data/ext/WSK/SilentUtils/SilentUtils.o +0 -0
- data/ext/WSK/SilentUtils/SilentUtils.so +0 -0
- data/ext/WSK/SilentUtils/build.rb +18 -0
- data/ext/WSK/VolumeUtils/Makefile +149 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.o +0 -0
- data/ext/WSK/VolumeUtils/VolumeUtils.so +0 -0
- data/ext/WSK/VolumeUtils/build.rb +20 -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 +151 -0
@@ -0,0 +1,494 @@
|
|
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 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(iValInputBuffer)->ptr;
|
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("logErr"), 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("logErr"), 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(iValInputRawBuffer)->ptr;
|
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
|
+
}
|
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
|
3
|
+
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
4
|
+
#++
|
5
|
+
|
6
|
+
lAdditionalLocalLibs = [
|
7
|
+
'CommonUtils'
|
8
|
+
]
|
9
|
+
|
10
|
+
require 'mkmf'
|
11
|
+
$CFLAGS += ' -Wall '
|
12
|
+
# TODO (Cygwin): Adding -L/usr/local/lib is due to some Cygwin installs that do not include it with gcc
|
13
|
+
$LDFLAGS += ' -L/usr/local/lib -lgmp '
|
14
|
+
lAdditionalLocalLibs.each do |iLibName|
|
15
|
+
lLibDir = File.expand_path("#{File.dirname(__FILE__)}/../../../external/#{iLibName}")
|
16
|
+
$CFLAGS += " -I#{lLibDir}/include "
|
17
|
+
$LDFLAGS += " -L#{lLibDir}/lib -l#{iLibName} "
|
18
|
+
end
|
19
|
+
create_makefile('VolumeUtils')
|
20
|
+
system('make')
|