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,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
|
+
}
|