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,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('FFTUtils')
|
@@ -0,0 +1,182 @@
|
|
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
|
+
/**
|
13
|
+
* Free a C function.
|
14
|
+
* This method is called by Ruby GC.
|
15
|
+
*
|
16
|
+
* Parameters::
|
17
|
+
* * *iPtrCFct* (<em>void*</em>): The C function to free (in fact a <em>tFunction*</em>)
|
18
|
+
*/
|
19
|
+
static void volumeutils_freeCFct(void* iPtrCFct) {
|
20
|
+
tFunction* lPtrCFct = (tFunction*)iPtrCFct;
|
21
|
+
|
22
|
+
if (lPtrCFct->freeFct != NULL) {
|
23
|
+
(lPtrCFct->freeFct)(lPtrCFct->fctData);
|
24
|
+
}
|
25
|
+
free(lPtrCFct->fctData);
|
26
|
+
}
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Free a C function of type Piecewiese Linear.
|
30
|
+
*
|
31
|
+
* Parameters::
|
32
|
+
* * *iPtrCFct* (<em>void*</em>): The C function to free (in fact a <em>tFunction_PiecewiseLinear*</em>)
|
33
|
+
*/
|
34
|
+
static void functionutils_freeCFct_PiecewiseLinear(void* iPtrCFct) {
|
35
|
+
tFunction_PiecewiseLinear* lPtrCFct = (tFunction_PiecewiseLinear*)iPtrCFct;
|
36
|
+
|
37
|
+
free(lPtrCFct->pointsX);
|
38
|
+
free(lPtrCFct->pointsY);
|
39
|
+
}
|
40
|
+
|
41
|
+
static int gID_to_s;
|
42
|
+
static int gID_numerator;
|
43
|
+
static int gID_denominator;
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Convert a Ruby function value into a long double
|
47
|
+
*
|
48
|
+
* Parameters::
|
49
|
+
* * *iValBD* (_Rational_): The value to convert
|
50
|
+
* Return::
|
51
|
+
* * <em>long double</em>: The equivalent long double
|
52
|
+
*/
|
53
|
+
inline long double value2ld(
|
54
|
+
VALUE iValBD) {
|
55
|
+
long double rResult;
|
56
|
+
|
57
|
+
mpf_t lDenominator;
|
58
|
+
mpf_init_set_str(lDenominator, RSTRING_PTR(rb_funcall(rb_funcall(iValBD, gID_denominator, 0), gID_to_s, 0)), 10);
|
59
|
+
mpf_t lDivResult;
|
60
|
+
mpf_init_set_str(lDivResult, RSTRING_PTR(rb_funcall(rb_funcall(iValBD, gID_numerator, 0), gID_to_s, 0)), 10);
|
61
|
+
mpf_div(lDivResult, lDivResult, lDenominator);
|
62
|
+
// TODO: Find a way to round correctly lDivResult. It is currently truncated.
|
63
|
+
rResult = mpf_get_d(lDivResult);
|
64
|
+
mpf_clear(lDivResult);
|
65
|
+
mpf_clear(lDenominator);
|
66
|
+
|
67
|
+
return rResult;
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Fill a C function with a given function of type Piecewise Linear
|
72
|
+
*
|
73
|
+
* Parameters::
|
74
|
+
* * *oPtrCFunction* (<em>tFunction*</em>): The C function to fill
|
75
|
+
* * *iValFunction* (<em>map<Symbol,Object></em>): The function to apply
|
76
|
+
* * *iIdxBeginSample* (<em>tSampleIndex</em>): First sample beginning the function
|
77
|
+
* * *iIdxEndSample* (<em>tSampleIndex</em>): Last sample ending the function
|
78
|
+
*/
|
79
|
+
static int functionutils_fillCFunction_PiecewiseLinear(
|
80
|
+
tFunction* oPtrCFunction,
|
81
|
+
VALUE iValFunction,
|
82
|
+
tSampleIndex iIdxBeginSample,
|
83
|
+
tSampleIndex iIdxEndSample) {
|
84
|
+
int rResultCode = 0;
|
85
|
+
|
86
|
+
// Create the basic structure
|
87
|
+
tFunction_PiecewiseLinear* lPtrFctData = ALLOC(tFunction_PiecewiseLinear);
|
88
|
+
oPtrCFunction->fctData = (void*)lPtrFctData;
|
89
|
+
oPtrCFunction->freeFct = functionutils_freeCFct_PiecewiseLinear;
|
90
|
+
|
91
|
+
// Fill it
|
92
|
+
// Read points in a sorted list of couples [x,y]
|
93
|
+
VALUE lValSortedPoints = rb_funcall(rb_funcall(rb_hash_aref(iValFunction, ID2SYM(rb_intern("Points"))), rb_intern("to_a"), 0), rb_intern("sort"), 0);
|
94
|
+
lPtrFctData->nbrPoints = RARRAY(lValSortedPoints)->len;
|
95
|
+
lPtrFctData->pointsX = ALLOC_N(tSampleIndex, lPtrFctData->nbrPoints);
|
96
|
+
lPtrFctData->pointsY = ALLOC_N(long double, lPtrFctData->nbrPoints);
|
97
|
+
|
98
|
+
// Get the X bounds
|
99
|
+
long double lMinX = value2ld(rb_ary_entry(rb_ary_entry(lValSortedPoints, 0), 0));
|
100
|
+
long double lDistX = value2ld(rb_ary_entry(rb_ary_entry(lValSortedPoints, lPtrFctData->nbrPoints-1), 0))-lMinX;
|
101
|
+
long double lDistSample = iIdxEndSample-iIdxBeginSample;
|
102
|
+
|
103
|
+
// Loop on each points pair
|
104
|
+
VALUE lValPoint;
|
105
|
+
tSampleIndex lPointX;
|
106
|
+
// Set the first point alone, as no check is performed about duplicates.
|
107
|
+
lValPoint = rb_ary_entry(lValSortedPoints, 0);
|
108
|
+
lPtrFctData->pointsX[0] = iIdxBeginSample+((tSampleIndex)((lDistSample*(value2ld(rb_ary_entry(lValPoint, 0))-lMinX))/lDistX));
|
109
|
+
lPtrFctData->pointsY[0] = value2ld(rb_ary_entry(lValPoint, 1));
|
110
|
+
/*
|
111
|
+
printf("Function point n.0: %lld,%LF\n", lPtrFctData->pointsX[0], lPtrFctData->pointsY[0]);
|
112
|
+
*/
|
113
|
+
// Loop on other points
|
114
|
+
int lIdxPoint;
|
115
|
+
int lIdxLastCPoint = 0;
|
116
|
+
for (lIdxPoint = 1; lIdxPoint < lPtrFctData->nbrPoints; ++lIdxPoint) {
|
117
|
+
lValPoint = rb_ary_entry(lValSortedPoints, lIdxPoint);
|
118
|
+
lPointX = iIdxBeginSample+((tSampleIndex)((lDistSample*(value2ld(rb_ary_entry(lValPoint, 0))-lMinX))/lDistX));
|
119
|
+
// If this abscisse is already set, change the already set one
|
120
|
+
if (lPtrFctData->pointsX[lIdxLastCPoint] != lPointX) {
|
121
|
+
++lIdxLastCPoint;
|
122
|
+
lPtrFctData->pointsX[lIdxLastCPoint] = lPointX;
|
123
|
+
}
|
124
|
+
lPtrFctData->pointsY[lIdxLastCPoint] = value2ld(rb_ary_entry(lValPoint, 1));
|
125
|
+
/*
|
126
|
+
printf("Function point n.%d: %lld,%LF\n", lIdxLastCPoint, lPtrFctData->pointsX[lIdxLastCPoint], lPtrFctData->pointsY[lIdxLastCPoint]);
|
127
|
+
*/
|
128
|
+
}
|
129
|
+
// It is possible that the count differs
|
130
|
+
lPtrFctData->nbrPoints = lIdxLastCPoint + 1;
|
131
|
+
|
132
|
+
return rResultCode;
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Create a C function based on a given function to be applied on a given discrete range.
|
137
|
+
*
|
138
|
+
* Parameters::
|
139
|
+
* * *iSelf* (_Object_): Calling object
|
140
|
+
* * *iValFunction* (<em>map<Symbol,Object></em>): The function
|
141
|
+
* * *iValIdxBeginSample* (<em>map<Symbol,Object></em>): The first sample for this function
|
142
|
+
* * *iValIdxEndSample* (<em>map<Symbol,Object></em>): The last sample for this function
|
143
|
+
* Return::
|
144
|
+
* * _Object_: The Ruby object containing the C function
|
145
|
+
*/
|
146
|
+
static VALUE functionutils_createCFunction(
|
147
|
+
VALUE iSelf,
|
148
|
+
VALUE iValFunction,
|
149
|
+
VALUE iValIdxBeginSample,
|
150
|
+
VALUE iValIdxEndSample) {
|
151
|
+
tSampleIndex iIdxBeginSample = FIX2LONG(iValIdxBeginSample);
|
152
|
+
tSampleIndex iIdxEndSample = FIX2LONG(iValIdxEndSample);
|
153
|
+
|
154
|
+
tFunction* lPtrCFunction = ALLOC(tFunction);
|
155
|
+
// Retrieve the function type
|
156
|
+
lPtrCFunction->fctType = FIX2INT(rb_hash_aref(iValFunction, ID2SYM(rb_intern("FunctionType"))));
|
157
|
+
// Call the relevant method based on the type
|
158
|
+
switch (lPtrCFunction->fctType) {
|
159
|
+
case FCTTYPE_PIECEWISE_LINEAR:
|
160
|
+
functionutils_fillCFunction_PiecewiseLinear(lPtrCFunction, iValFunction, iIdxBeginSample, iIdxEndSample);
|
161
|
+
break;
|
162
|
+
default: ; // The ; is here to make gcc compile: variables declarations are forbidden after a label.
|
163
|
+
char lLogMessage[256];
|
164
|
+
sprintf(lLogMessage, "Unknown function type %d", lPtrCFunction->fctType);
|
165
|
+
rb_funcall(iSelf, rb_intern("log_err"), 1, rb_str_new2(lLogMessage));
|
166
|
+
break;
|
167
|
+
}
|
168
|
+
|
169
|
+
return Data_Wrap_Struct(rb_cObject, NULL, volumeutils_freeCFct, lPtrCFunction);
|
170
|
+
}
|
171
|
+
|
172
|
+
// Initialize the module
|
173
|
+
void Init_FunctionUtils() {
|
174
|
+
VALUE lWSKModule = rb_define_module("WSK");
|
175
|
+
VALUE lFunctionUtilsModule = rb_define_module_under(lWSKModule, "FunctionUtils");
|
176
|
+
VALUE lFunctionUtilsClass = rb_define_class_under(lFunctionUtilsModule, "FunctionUtils", rb_cObject);
|
177
|
+
|
178
|
+
rb_define_method(lFunctionUtilsClass, "createCFunction", functionutils_createCFunction, 3);
|
179
|
+
gID_to_s = rb_intern("to_s");
|
180
|
+
gID_numerator = rb_intern("numerator");
|
181
|
+
gID_denominator = rb_intern("denominator");
|
182
|
+
}
|
@@ -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('FunctionUtils')
|
@@ -0,0 +1,431 @@
|
|
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 <CommonUtils.h>
|
8
|
+
|
9
|
+
// Struct used to convey data among iterators in the getNextSilentSample method
|
10
|
+
typedef struct {
|
11
|
+
tSampleIndex* ptrIdxFirstSilentSample;
|
12
|
+
tThresholdInfo* ptrSilenceThresholds;
|
13
|
+
tSampleIndex* ptrIdxSilenceSample_Result;
|
14
|
+
tSampleIndex minSilenceSamples;
|
15
|
+
int nbrChannels;
|
16
|
+
} tFindSilentStruct;
|
17
|
+
|
18
|
+
// Struct used to convey data among iterators in the getFirstSampleBeyondThreshold method
|
19
|
+
typedef struct {
|
20
|
+
tSampleIndex* ptrIdxSample_Result;
|
21
|
+
tThresholdInfo* ptrThresholds;
|
22
|
+
int nbrChannels;
|
23
|
+
} tFirstSampleBeyondThresholdStruct;
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Process a value read from an input buffer for the NextSilentSample function.
|
27
|
+
*
|
28
|
+
* Parameters::
|
29
|
+
* * *iValue* (<em>const tSampleValue</em>): The value being read
|
30
|
+
* * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
|
31
|
+
* * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
|
32
|
+
* * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tFindSilentStruct*</em>.
|
33
|
+
* Return::
|
34
|
+
* * _int_: The return code:
|
35
|
+
* ** 0: Continue iteration
|
36
|
+
* ** 1: Break all iterations
|
37
|
+
* ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
|
38
|
+
*/
|
39
|
+
int silentutils_processValue(
|
40
|
+
const tSampleValue iValue,
|
41
|
+
const tSampleIndex iIdxSample,
|
42
|
+
const int iIdxChannel,
|
43
|
+
void* iPtrArgs) {
|
44
|
+
int rResult = 0;
|
45
|
+
|
46
|
+
// Interpret parameters
|
47
|
+
tFindSilentStruct* lPtrVariables = (tFindSilentStruct*)iPtrArgs;
|
48
|
+
|
49
|
+
if ((iValue < (lPtrVariables->ptrSilenceThresholds)[iIdxChannel].min) ||
|
50
|
+
(iValue > (lPtrVariables->ptrSilenceThresholds)[iIdxChannel].max)) {
|
51
|
+
// This value is not silent
|
52
|
+
// If we were in silence that has not yet reached its minimal duration, cancel this last silence
|
53
|
+
*(lPtrVariables->ptrIdxFirstSilentSample) = -1;
|
54
|
+
// Don't even read other channels
|
55
|
+
rResult = 2;
|
56
|
+
} else {
|
57
|
+
// This value is silent
|
58
|
+
if ((*(lPtrVariables->ptrIdxFirstSilentSample)) == -1) {
|
59
|
+
// This is the first silent value we have
|
60
|
+
*(lPtrVariables->ptrIdxFirstSilentSample) = iIdxSample;
|
61
|
+
}
|
62
|
+
// Check if the minimal duration has been reached
|
63
|
+
if (iIdxSample - (*(lPtrVariables->ptrIdxFirstSilentSample)) + 1 >= lPtrVariables->minSilenceSamples) {
|
64
|
+
// We have found a silence according to thresholds.
|
65
|
+
*(lPtrVariables->ptrIdxSilenceSample_Result) = *(lPtrVariables->ptrIdxFirstSilentSample);
|
66
|
+
// Stop iterations
|
67
|
+
rResult = 1;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
return rResult;
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Process a value read from an input buffer for the NextSilentSample function.
|
76
|
+
* Do it in backwards search.
|
77
|
+
*
|
78
|
+
* Parameters::
|
79
|
+
* * *iValue* (<em>const tSampleValue</em>): The value being read
|
80
|
+
* * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
|
81
|
+
* * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
|
82
|
+
* * *iPtrArgs* (<em>void*</em>): additional arguments. In fact a <em>tFindSilentStruct*</em>.
|
83
|
+
* Return::
|
84
|
+
* * _int_: The return code:
|
85
|
+
* ** 0: Continue iteration
|
86
|
+
* ** 1: Break all iterations
|
87
|
+
* ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
|
88
|
+
*/
|
89
|
+
int silentutils_Reverse_processValue(
|
90
|
+
const tSampleValue iValue,
|
91
|
+
const tSampleIndex iIdxSample,
|
92
|
+
const int iIdxChannel,
|
93
|
+
void* iPtrArgs) {
|
94
|
+
int rResult = 0;
|
95
|
+
|
96
|
+
// Interpret parameters
|
97
|
+
tFindSilentStruct* lPtrVariables = (tFindSilentStruct*)iPtrArgs;
|
98
|
+
|
99
|
+
if ((iValue < (lPtrVariables->ptrSilenceThresholds)[iIdxChannel].min) ||
|
100
|
+
(iValue > (lPtrVariables->ptrSilenceThresholds)[iIdxChannel].max)) {
|
101
|
+
// This value is not silent
|
102
|
+
// If we were in silence that has not yet reached its minimal duration, cancel this last silence
|
103
|
+
*(lPtrVariables->ptrIdxFirstSilentSample) = -1;
|
104
|
+
// Don't even read other channels
|
105
|
+
rResult = 2;
|
106
|
+
} else {
|
107
|
+
// This value is silent
|
108
|
+
if ((*(lPtrVariables->ptrIdxFirstSilentSample)) == -1) {
|
109
|
+
// This is the first silent value we have
|
110
|
+
*(lPtrVariables->ptrIdxFirstSilentSample) = iIdxSample;
|
111
|
+
}
|
112
|
+
// Check if the minimal duration has been reached
|
113
|
+
if ((*(lPtrVariables->ptrIdxFirstSilentSample)) - iIdxSample + 1 >= lPtrVariables->minSilenceSamples) {
|
114
|
+
// We have found a silence according to thresholds.
|
115
|
+
*(lPtrVariables->ptrIdxSilenceSample_Result) = *(lPtrVariables->ptrIdxFirstSilentSample);
|
116
|
+
// Stop iterations
|
117
|
+
rResult = 1;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
return rResult;
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Code block called by getNextSilentSample in the each_raw_buffer loop.
|
126
|
+
* This is meant to be used with rb_iterate.
|
127
|
+
*
|
128
|
+
* Parameters::
|
129
|
+
* * *iValYieldArgs* (<em>list<Object></em>): The yield arguments:
|
130
|
+
* ** *iValInputRawBuffer* (_String_): The raw buffer
|
131
|
+
* ** *iValNbrSamples* (_Integer_): The number of samples in this buffer
|
132
|
+
* ** *iValNbrChannels* (_Integer_): The number of channels in this buffer
|
133
|
+
* * *iValIterateArgs* (<em>list<Object></em>): The iterate arguments:
|
134
|
+
* ** *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
|
135
|
+
* ** *iValPtrIdxSample* (_Integer_): Address of the IdxSample variable
|
136
|
+
* ** *iValPtrIdxFirstSilentSample* (_Integer_): Address of the IdxFirstSilentSample variable
|
137
|
+
* ** *iValPtrSilenceThresholds* (_Integer_): Address of the SilenceThresholds variable
|
138
|
+
* ** *iValMinSilenceSamples* (_Integer_): Minimal silence samples
|
139
|
+
* ** *iValPtrIdxSilenceSample_Result* (_Integer_): Address of the IdxSilenceSample_Result variable
|
140
|
+
* ** *iValBackwardsSearch* (_Boolean_): Do we search backwards ?
|
141
|
+
*/
|
142
|
+
static VALUE silentutils_blockEachRawBuffer(
|
143
|
+
VALUE iValYieldArgs,
|
144
|
+
VALUE iValIterateArgs) {
|
145
|
+
// Read arguments
|
146
|
+
VALUE iValInputRawBuffer = rb_ary_entry(iValYieldArgs, 0);
|
147
|
+
VALUE iValNbrSamples = rb_ary_entry(iValYieldArgs, 1);
|
148
|
+
VALUE iValNbrChannels = rb_ary_entry(iValYieldArgs, 2);
|
149
|
+
VALUE iValNbrBitsPerSample = rb_ary_entry(iValIterateArgs, 0);
|
150
|
+
VALUE iValPtrIdxSample = rb_ary_entry(iValIterateArgs, 1);
|
151
|
+
VALUE iValPtrIdxFirstSilentSample = rb_ary_entry(iValIterateArgs, 2);
|
152
|
+
VALUE iValPtrSilenceThresholds = rb_ary_entry(iValIterateArgs, 3);
|
153
|
+
VALUE iValMinSilenceSamples = rb_ary_entry(iValIterateArgs, 4);
|
154
|
+
VALUE iValPtrIdxSilenceSample_Result = rb_ary_entry(iValIterateArgs, 5);
|
155
|
+
VALUE iValBackwardsSearch = rb_ary_entry(iValIterateArgs, 6);
|
156
|
+
// Translate parameters in C types
|
157
|
+
int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
|
158
|
+
tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
|
159
|
+
int iNbrChannels = FIX2INT(iValNbrChannels);
|
160
|
+
tSampleIndex* lPtrIdxSample = (tSampleIndex*)FIX2INT(iValPtrIdxSample);
|
161
|
+
tSampleIndex* lPtrIdxFirstSilentSample = (tSampleIndex*)FIX2INT(iValPtrIdxFirstSilentSample);
|
162
|
+
tThresholdInfo* lPtrSilenceThresholds = (tThresholdInfo*)FIX2INT(iValPtrSilenceThresholds);
|
163
|
+
tSampleIndex iMinSilenceSamples = FIX2LONG(iValMinSilenceSamples);
|
164
|
+
tSampleIndex* lPtrIdxSilenceSample_Result = (tSampleIndex*)FIX2INT(iValPtrIdxSilenceSample_Result);
|
165
|
+
|
166
|
+
// Get the real underlying raw buffer
|
167
|
+
char* lPtrRawBuffer = RSTRING_PTR(iValInputRawBuffer);
|
168
|
+
|
169
|
+
// Set variables to give to the process
|
170
|
+
tFindSilentStruct lProcessVariables;
|
171
|
+
lProcessVariables.ptrIdxFirstSilentSample = lPtrIdxFirstSilentSample;
|
172
|
+
lProcessVariables.ptrSilenceThresholds = lPtrSilenceThresholds;
|
173
|
+
lProcessVariables.ptrIdxSilenceSample_Result = lPtrIdxSilenceSample_Result;
|
174
|
+
lProcessVariables.minSilenceSamples = iMinSilenceSamples;
|
175
|
+
lProcessVariables.nbrChannels = iNbrChannels;
|
176
|
+
|
177
|
+
// Iterate through the raw buffer
|
178
|
+
if (iValBackwardsSearch == Qtrue) {
|
179
|
+
commonutils_iterateReverseThroughRawBuffer(
|
180
|
+
lPtrRawBuffer,
|
181
|
+
iNbrBitsPerSample,
|
182
|
+
iNbrChannels,
|
183
|
+
iNbrSamples,
|
184
|
+
*lPtrIdxSample,
|
185
|
+
&silentutils_Reverse_processValue,
|
186
|
+
&lProcessVariables
|
187
|
+
);
|
188
|
+
} else {
|
189
|
+
commonutils_iterateThroughRawBuffer(
|
190
|
+
lPtrRawBuffer,
|
191
|
+
iNbrBitsPerSample,
|
192
|
+
iNbrChannels,
|
193
|
+
iNbrSamples,
|
194
|
+
*lPtrIdxSample,
|
195
|
+
&silentutils_processValue,
|
196
|
+
&lProcessVariables
|
197
|
+
);
|
198
|
+
}
|
199
|
+
|
200
|
+
// If the result was found in this raw buffer, stop parsing everything
|
201
|
+
if (*lPtrIdxSilenceSample_Result != -1) {
|
202
|
+
rb_iter_break();
|
203
|
+
}
|
204
|
+
|
205
|
+
// Modify the sample index
|
206
|
+
if (iValBackwardsSearch == Qtrue) {
|
207
|
+
(*lPtrIdxSample) -= iNbrSamples;
|
208
|
+
} else {
|
209
|
+
(*lPtrIdxSample) += iNbrSamples;
|
210
|
+
}
|
211
|
+
|
212
|
+
return Qnil;
|
213
|
+
}
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Get the next silent sample from an input buffer
|
217
|
+
*
|
218
|
+
* Parameters::
|
219
|
+
* * *iSelf* (_FFTUtils_): Self
|
220
|
+
* * *iValInputData* (<em>WSK::Model::InputData</em>): The input data
|
221
|
+
* * *iValIdxStartSample* (_Integer_): Index of the first sample to search from
|
222
|
+
* * *iValSilenceThresholds* (<em>list< [Integer,Integer] ></em>): The silence thresholds specifications
|
223
|
+
* * *iValMinSilenceSamples* (_Integer_): Number of samples minimum to identify a silence
|
224
|
+
* * *iValBackwardsSearch* (_Boolean_): Do we search backwards ?
|
225
|
+
* Return::
|
226
|
+
* * _Integer_: Index of the next silent sample, or nil if none
|
227
|
+
**/
|
228
|
+
static VALUE silentutils_getNextSilentInThresholds(
|
229
|
+
VALUE iSelf,
|
230
|
+
VALUE iValInputData,
|
231
|
+
VALUE iValIdxStartSample,
|
232
|
+
VALUE iValSilenceThresholds,
|
233
|
+
VALUE iValMinSilenceSamples,
|
234
|
+
VALUE iValBackwardsSearch) {
|
235
|
+
VALUE rValNextSilentSample = Qnil;
|
236
|
+
|
237
|
+
// Translate parameters in C types
|
238
|
+
tSampleIndex iIdxStartSample = FIX2LONG(iValIdxStartSample);
|
239
|
+
|
240
|
+
// The cursor of samples. Set it to the first sample we start from searching.
|
241
|
+
tSampleIndex lIdxSample = iIdxStartSample;
|
242
|
+
// Read some info from the Header
|
243
|
+
VALUE lValHeader = rb_funcall(iValInputData, rb_intern("Header"), 0);
|
244
|
+
VALUE lValNbrBitsPerSample = rb_funcall(lValHeader, rb_intern("NbrBitsPerSample"), 0);
|
245
|
+
VALUE lValNbrChannels = rb_funcall(lValHeader, rb_intern("NbrChannels"), 0);
|
246
|
+
// Decode the thresholds
|
247
|
+
int lNbrChannels = FIX2INT(lValNbrChannels);
|
248
|
+
tThresholdInfo lSilenceThresholds[lNbrChannels];
|
249
|
+
VALUE lTmpThresholds;
|
250
|
+
int lIdxChannel;
|
251
|
+
for(lIdxChannel = 0; lIdxChannel < lNbrChannels; ++lIdxChannel) {
|
252
|
+
lTmpThresholds = rb_ary_entry(iValSilenceThresholds, lIdxChannel);
|
253
|
+
lSilenceThresholds[lIdxChannel].min = FIX2INT(rb_ary_entry(lTmpThresholds, 0));
|
254
|
+
lSilenceThresholds[lIdxChannel].max = FIX2INT(rb_ary_entry(lTmpThresholds, 1));
|
255
|
+
}
|
256
|
+
|
257
|
+
// Index of the first silent sample encountered while parsing.
|
258
|
+
// Used to assert the minimal duration of the silence. -1 means we don't have one yet.
|
259
|
+
tSampleIndex lIdxFirstSilentSample;
|
260
|
+
// The result
|
261
|
+
tSampleIndex lIdxSilenceSample_Result;
|
262
|
+
|
263
|
+
// Encapsulate pointers to the data that will be used and modified by the iteration block
|
264
|
+
VALUE lValPtrIdxSample = INT2FIX(&lIdxSample);
|
265
|
+
VALUE lValPtrIdxFirstSilentSample = INT2FIX(&lIdxFirstSilentSample);
|
266
|
+
VALUE lValPtrSilenceThresholds = INT2FIX(&lSilenceThresholds);
|
267
|
+
VALUE lValPtrIdxSilenceSample_Result = INT2FIX(&lIdxSilenceSample_Result);
|
268
|
+
|
269
|
+
lIdxFirstSilentSample = -1;
|
270
|
+
lIdxSilenceSample_Result = -1;
|
271
|
+
|
272
|
+
// Parse the data, using thresholds matching only
|
273
|
+
if (iValBackwardsSearch == Qtrue) {
|
274
|
+
rb_iterate(
|
275
|
+
commonutils_callEachReverseRawBuffer,
|
276
|
+
rb_ary_new3(2,
|
277
|
+
iValInputData,
|
278
|
+
LONG2FIX(lIdxSample)),
|
279
|
+
silentutils_blockEachRawBuffer,
|
280
|
+
rb_ary_new3(7,
|
281
|
+
lValNbrBitsPerSample,
|
282
|
+
lValPtrIdxSample,
|
283
|
+
lValPtrIdxFirstSilentSample,
|
284
|
+
lValPtrSilenceThresholds,
|
285
|
+
iValMinSilenceSamples,
|
286
|
+
lValPtrIdxSilenceSample_Result,
|
287
|
+
iValBackwardsSearch)
|
288
|
+
);
|
289
|
+
} else {
|
290
|
+
rb_iterate(
|
291
|
+
commonutils_callEachRawBuffer,
|
292
|
+
rb_ary_new3(2,
|
293
|
+
iValInputData,
|
294
|
+
LONG2FIX(lIdxSample)),
|
295
|
+
silentutils_blockEachRawBuffer,
|
296
|
+
rb_ary_new3(7,
|
297
|
+
lValNbrBitsPerSample,
|
298
|
+
lValPtrIdxSample,
|
299
|
+
lValPtrIdxFirstSilentSample,
|
300
|
+
lValPtrSilenceThresholds,
|
301
|
+
iValMinSilenceSamples,
|
302
|
+
lValPtrIdxSilenceSample_Result,
|
303
|
+
iValBackwardsSearch)
|
304
|
+
);
|
305
|
+
}
|
306
|
+
|
307
|
+
if (lIdxSilenceSample_Result != -1) {
|
308
|
+
rValNextSilentSample = LONG2FIX(lIdxSilenceSample_Result);
|
309
|
+
}
|
310
|
+
|
311
|
+
return rValNextSilentSample;
|
312
|
+
}
|
313
|
+
|
314
|
+
/**
|
315
|
+
* Process a value read from an input buffer for the NextSilentSample function.
|
316
|
+
*
|
317
|
+
* Parameters::
|
318
|
+
* * *iValue* (<em>const tSampleValue</em>): The value being read
|
319
|
+
* * *iIdxSample* (<em>const tSampleIndex</em>): Index of this sample
|
320
|
+
* * *iIdxChannel* (<em>const int</em>): Channel corresponding to the value being read
|
321
|
+
* * *iPtrArgs* (<em>void*</em>): additional arguments. In fact an <em>tFirstSampleBeyondThresholdStruct*</em>.
|
322
|
+
* Return::
|
323
|
+
* * _int_: The return code:
|
324
|
+
* ** 0: Continue iteration
|
325
|
+
* ** 1: Break all iterations
|
326
|
+
* ** 2: Skip directly to the next sample (don't call us for other channels of this sample)
|
327
|
+
*/
|
328
|
+
int silentutils_sbt_processValue(
|
329
|
+
const tSampleValue iValue,
|
330
|
+
const tSampleIndex iIdxSample,
|
331
|
+
const int iIdxChannel,
|
332
|
+
void* iPtrArgs) {
|
333
|
+
int rResult = 0;
|
334
|
+
|
335
|
+
// Interpret parameters
|
336
|
+
tFirstSampleBeyondThresholdStruct* lPtrVariables = (tFirstSampleBeyondThresholdStruct*)iPtrArgs;
|
337
|
+
|
338
|
+
if ((iValue < (lPtrVariables->ptrThresholds)[iIdxChannel].min) ||
|
339
|
+
(iValue > (lPtrVariables->ptrThresholds)[iIdxChannel].max)) {
|
340
|
+
// This value is not silent
|
341
|
+
rResult = 1;
|
342
|
+
*(lPtrVariables->ptrIdxSample_Result) = iIdxSample;
|
343
|
+
}
|
344
|
+
|
345
|
+
return rResult;
|
346
|
+
}
|
347
|
+
|
348
|
+
/**
|
349
|
+
* Get the sample index that exceeds a threshold in a raw buffer.
|
350
|
+
*
|
351
|
+
* Parameters::
|
352
|
+
* * *iSelf* (_FFTUtils_): Self
|
353
|
+
* * *iValRawBuffer* (_String_): The raw buffer
|
354
|
+
* * *iValThresholds* (<em>list< [Integer,Integer] ></em>): The thresholds
|
355
|
+
* * *iValNbrBitsPerSample* (_Integer_): Number of bits per sample
|
356
|
+
* * *iValNbrChannels* (_Integer_): Number of channels
|
357
|
+
* * *iValNbrSamples* (_Integer_): Number of samples
|
358
|
+
* * *iValLastSample* (_Boolean_): Are we looking for the last sample beyond threshold ?
|
359
|
+
* Return::
|
360
|
+
* * _Integer_: Index of the first sample exceeding thresholds, or nil if none
|
361
|
+
*/
|
362
|
+
static VALUE silentutils_getSampleBeyondThresholds(
|
363
|
+
VALUE iSelf,
|
364
|
+
VALUE iValRawBuffer,
|
365
|
+
VALUE iValThresholds,
|
366
|
+
VALUE iValNbrBitsPerSample,
|
367
|
+
VALUE iValNbrChannels,
|
368
|
+
VALUE iValNbrSamples,
|
369
|
+
VALUE iValLastSample) {
|
370
|
+
VALUE rValIdxFirstSample = Qnil;
|
371
|
+
|
372
|
+
// Translate parameters in C types
|
373
|
+
tSampleIndex iNbrSamples = FIX2LONG(iValNbrSamples);
|
374
|
+
int iNbrChannels = FIX2INT(iValNbrChannels);
|
375
|
+
int iNbrBitsPerSample = FIX2INT(iValNbrBitsPerSample);
|
376
|
+
// Get the underlying char*
|
377
|
+
char* lPtrRawBuffer = RSTRING_PTR(iValRawBuffer);
|
378
|
+
// Decode the thresholds
|
379
|
+
tThresholdInfo lThresholds[iNbrChannels];
|
380
|
+
VALUE lTmpThresholds;
|
381
|
+
int lIdxChannel;
|
382
|
+
for(lIdxChannel = 0; lIdxChannel < iNbrChannels; ++lIdxChannel) {
|
383
|
+
lTmpThresholds = rb_ary_entry(iValThresholds, lIdxChannel);
|
384
|
+
lThresholds[lIdxChannel].min = FIX2INT(rb_ary_entry(lTmpThresholds, 0));
|
385
|
+
lThresholds[lIdxChannel].max = FIX2INT(rb_ary_entry(lTmpThresholds, 1));
|
386
|
+
}
|
387
|
+
// Set variables to give to the process
|
388
|
+
tSampleIndex lIdxSampleOut = -1;
|
389
|
+
tFirstSampleBeyondThresholdStruct lProcessVariables;
|
390
|
+
lProcessVariables.ptrThresholds = &lThresholds[0];
|
391
|
+
lProcessVariables.ptrIdxSample_Result = &lIdxSampleOut;
|
392
|
+
lProcessVariables.nbrChannels = iNbrChannels;
|
393
|
+
|
394
|
+
// Parse the buffer
|
395
|
+
if (iValLastSample == Qtrue) {
|
396
|
+
commonutils_iterateReverseThroughRawBuffer(
|
397
|
+
lPtrRawBuffer,
|
398
|
+
iNbrBitsPerSample,
|
399
|
+
iNbrChannels,
|
400
|
+
iNbrSamples,
|
401
|
+
iNbrSamples-1,
|
402
|
+
&silentutils_sbt_processValue,
|
403
|
+
&lProcessVariables
|
404
|
+
);
|
405
|
+
} else {
|
406
|
+
commonutils_iterateThroughRawBuffer(
|
407
|
+
lPtrRawBuffer,
|
408
|
+
iNbrBitsPerSample,
|
409
|
+
iNbrChannels,
|
410
|
+
iNbrSamples,
|
411
|
+
0,
|
412
|
+
&silentutils_sbt_processValue,
|
413
|
+
&lProcessVariables
|
414
|
+
);
|
415
|
+
}
|
416
|
+
if (lIdxSampleOut != -1) {
|
417
|
+
rValIdxFirstSample = LONG2FIX(lIdxSampleOut);
|
418
|
+
}
|
419
|
+
|
420
|
+
return rValIdxFirstSample;
|
421
|
+
}
|
422
|
+
|
423
|
+
// Initialize the module
|
424
|
+
void Init_SilentUtils() {
|
425
|
+
VALUE lWSKModule = rb_define_module("WSK");
|
426
|
+
VALUE lSilentUtilsModule = rb_define_module_under(lWSKModule, "SilentUtils");
|
427
|
+
VALUE lSilentUtilsClass = rb_define_class_under(lSilentUtilsModule, "SilentUtils", rb_cObject);
|
428
|
+
|
429
|
+
rb_define_method(lSilentUtilsClass, "getNextSilentInThresholds", silentutils_getNextSilentInThresholds, 5);
|
430
|
+
rb_define_method(lSilentUtilsClass, "getSampleBeyondThresholds", silentutils_getSampleBeyondThresholds, 6);
|
431
|
+
}
|