WaveSwissKnife 0.2.0.20120302

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.
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')