WaveSwissKnife 0.2.0.20120302

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/AUTHORS +4 -0
  2. data/ChangeLog +31 -0
  3. data/Credits +3 -0
  4. data/LICENSE +31 -0
  5. data/README +15 -0
  6. data/ReleaseInfo +8 -0
  7. data/bin/WSK.rb +14 -0
  8. data/ext/WSK/AnalyzeUtils/AnalyzeUtils.c +272 -0
  9. data/ext/WSK/AnalyzeUtils/extconf.rb +7 -0
  10. data/ext/WSK/ArithmUtils/ArithmUtils.c +862 -0
  11. data/ext/WSK/ArithmUtils/extconf.rb +15 -0
  12. data/ext/WSK/CommonBuild.rb +29 -0
  13. data/ext/WSK/FFTUtils/FFTUtils.c +662 -0
  14. data/ext/WSK/FFTUtils/extconf.rb +15 -0
  15. data/ext/WSK/FunctionUtils/FunctionUtils.c +182 -0
  16. data/ext/WSK/FunctionUtils/extconf.rb +15 -0
  17. data/ext/WSK/SilentUtils/SilentUtils.c +431 -0
  18. data/ext/WSK/SilentUtils/extconf.rb +7 -0
  19. data/ext/WSK/VolumeUtils/VolumeUtils.c +494 -0
  20. data/ext/WSK/VolumeUtils/extconf.rb +15 -0
  21. data/external/CommonUtils/build.rb +28 -0
  22. data/external/CommonUtils/include/CommonUtils.h +177 -0
  23. data/external/CommonUtils/src/CommonUtils.c +639 -0
  24. data/lib/WSK/Actions/Analyze.rb +176 -0
  25. data/lib/WSK/Actions/ApplyMap.desc.rb +15 -0
  26. data/lib/WSK/Actions/ApplyMap.rb +57 -0
  27. data/lib/WSK/Actions/ApplyVolumeFct.desc.rb +30 -0
  28. data/lib/WSK/Actions/ApplyVolumeFct.rb +72 -0
  29. data/lib/WSK/Actions/Compare.desc.rb +25 -0
  30. data/lib/WSK/Actions/Compare.rb +238 -0
  31. data/lib/WSK/Actions/ConstantCompare.desc.rb +20 -0
  32. data/lib/WSK/Actions/ConstantCompare.rb +61 -0
  33. data/lib/WSK/Actions/Cut.desc.rb +20 -0
  34. data/lib/WSK/Actions/Cut.rb +60 -0
  35. data/lib/WSK/Actions/CutFirstSignal.desc.rb +25 -0
  36. data/lib/WSK/Actions/CutFirstSignal.rb +72 -0
  37. data/lib/WSK/Actions/DCShifter.desc.rb +15 -0
  38. data/lib/WSK/Actions/DCShifter.rb +67 -0
  39. data/lib/WSK/Actions/DrawFct.desc.rb +20 -0
  40. data/lib/WSK/Actions/DrawFct.rb +59 -0
  41. data/lib/WSK/Actions/FFT.rb +104 -0
  42. data/lib/WSK/Actions/GenAllValues.rb +67 -0
  43. data/lib/WSK/Actions/GenConstant.desc.rb +20 -0
  44. data/lib/WSK/Actions/GenConstant.rb +56 -0
  45. data/lib/WSK/Actions/GenSawtooth.rb +57 -0
  46. data/lib/WSK/Actions/GenSine.desc.rb +20 -0
  47. data/lib/WSK/Actions/GenSine.rb +73 -0
  48. data/lib/WSK/Actions/Identity.rb +43 -0
  49. data/lib/WSK/Actions/Mix.desc.rb +15 -0
  50. data/lib/WSK/Actions/Mix.rb +149 -0
  51. data/lib/WSK/Actions/Multiply.desc.rb +15 -0
  52. data/lib/WSK/Actions/Multiply.rb +73 -0
  53. data/lib/WSK/Actions/NoiseGate.desc.rb +35 -0
  54. data/lib/WSK/Actions/NoiseGate.rb +129 -0
  55. data/lib/WSK/Actions/SilenceInserter.desc.rb +20 -0
  56. data/lib/WSK/Actions/SilenceInserter.rb +87 -0
  57. data/lib/WSK/Actions/SilenceRemover.desc.rb +30 -0
  58. data/lib/WSK/Actions/SilenceRemover.rb +74 -0
  59. data/lib/WSK/Actions/VolumeProfile.desc.rb +35 -0
  60. data/lib/WSK/Actions/VolumeProfile.rb +63 -0
  61. data/lib/WSK/Common.rb +292 -0
  62. data/lib/WSK/FFT.rb +527 -0
  63. data/lib/WSK/Functions.rb +770 -0
  64. data/lib/WSK/Launcher.rb +216 -0
  65. data/lib/WSK/Maps.rb +29 -0
  66. data/lib/WSK/Model/CachedBufferReader.rb +151 -0
  67. data/lib/WSK/Model/Header.rb +133 -0
  68. data/lib/WSK/Model/InputData.rb +193 -0
  69. data/lib/WSK/Model/RawReader.rb +78 -0
  70. data/lib/WSK/Model/WaveReader.rb +91 -0
  71. data/lib/WSK/OutputInterfaces/DirectStream.rb +146 -0
  72. data/lib/WSK/RIFFReader.rb +60 -0
  73. metadata +155 -0
@@ -0,0 +1,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
+ }
@@ -0,0 +1,7 @@
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
+ create_makefile('SilentUtils')