paddlec 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ /* Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of PaddleC
4
+ *
5
+ * PaddleC is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * PaddleC is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with PaddleC. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ #ifndef PADDLEC_COMPLEX_BUFFER_H
20
+ #define PADDLEC_COMPLEX_BUFFER_H
21
+
22
+ #include <ruby.h>
23
+ #include "libpaddlec.h"
24
+
25
+ void Init_paddlec_complex_buffer();
26
+ pdlc_complex_buffer_t* paddlec_complex_buffer_get_struct(VALUE obj);
27
+
28
+ #endif /* PADDLEC_COMPLEX_BUFFER_H */
@@ -0,0 +1,214 @@
1
+ /* Copyright (C) 2020 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of PaddleC
4
+ *
5
+ * PaddleC is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * PaddleC is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with PaddleC. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ #include <ruby.h>
20
+ #include "libpaddlec.h"
21
+ #include "paddlec.h"
22
+ #include "float_buffer.h"
23
+ #include "complex_buffer.h"
24
+
25
+ /* Document-class: PaddleC::Delay
26
+ *
27
+ * A delay line. It can be used to balance delays brought by filters.
28
+ *
29
+ * To prevent incoherent data,
30
+ * a given {PaddleC::Delay} object must be used exclusively with {PaddleC::FloatBuffer} and Float,
31
+ * or {PaddleC::ComplexBuffer} and Complex.
32
+ */
33
+
34
+
35
+ VALUE c_Delay;
36
+
37
+
38
+ static void paddlec_delay_free(void *p)
39
+ {
40
+ pdlc_delay_t *del = (pdlc_delay_t*)p;
41
+ pdlc_delay_free(del);
42
+ }
43
+
44
+
45
+ static size_t paddlec_delay_size(const void* data)
46
+ {
47
+ const pdlc_delay_t *del = (pdlc_delay_t*)data;
48
+ return pdlc_delay_size(del);
49
+ }
50
+
51
+
52
+ static const rb_data_type_t paddlec_delay_type = {
53
+ .wrap_struct_name = "paddlec_delay_struct",
54
+ .function = {
55
+ .dmark = NULL,
56
+ .dfree = paddlec_delay_free,
57
+ .dsize = paddlec_delay_size,
58
+ },
59
+ .data = NULL,
60
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
61
+ };
62
+
63
+
64
+ static VALUE paddlec_delay_alloc(VALUE klass)
65
+ {
66
+ VALUE obj;
67
+ pdlc_delay_t *del;
68
+
69
+ del = pdlc_delay_new(0);
70
+ obj = TypedData_Wrap_Struct(klass, &paddlec_delay_type, del);
71
+
72
+ return obj;
73
+ }
74
+
75
+
76
+ pdlc_delay_t* paddlec_delay_get_struct(VALUE obj)
77
+ {
78
+ pdlc_delay_t *del;
79
+ TypedData_Get_Struct(obj, pdlc_delay_t, &paddlec_delay_type, del);
80
+ return del;
81
+ }
82
+
83
+
84
+ /* Return a new {PaddleC::Delay}.
85
+ * @param len [Integer] the number of samples the input will be delayed, must be strictly positive
86
+ * @return [PaddleC::Delay]
87
+ */
88
+ static VALUE paddlec_delay_initialize(VALUE self, VALUE len)
89
+ {
90
+ int dl;
91
+ pdlc_delay_t *del;
92
+
93
+ if (rb_class_of(len) != rb_cInteger)
94
+ rb_raise(rb_eTypeError, "expecting an integer, not a %"PRIsVALUE, rb_class_name(rb_class_of(len)));
95
+ dl = NUM2INT(len);
96
+ if (dl <= 0)
97
+ rb_raise(rb_eRangeError, "delay length must be strictly positive");
98
+
99
+ del = paddlec_delay_get_struct(self);
100
+ pdlc_delay_initialize(del, dl);
101
+
102
+ return self;
103
+ }
104
+
105
+
106
+ /* Reset the state of the delay line.
107
+ * @return [self]
108
+ */
109
+ static VALUE paddlec_delay_reset(VALUE self)
110
+ {
111
+ pdlc_delay_t *del = paddlec_delay_get_struct(self);
112
+ pdlc_delay_reset(del);
113
+ return self;
114
+ }
115
+
116
+
117
+ /* Return the length of the delay line.
118
+ * @return [Integer]
119
+ */
120
+ static VALUE paddlec_delay_length(VALUE self)
121
+ {
122
+ pdlc_delay_t *del = paddlec_delay_get_struct(self);
123
+ return UINT2NUM(del->delay);
124
+ }
125
+
126
+
127
+ /* Push new samples, pull delayed samples.
128
+ * If +outbuf+ is provided, it will receive the delayed data.
129
+ * @overload delay(float)
130
+ * @param float [Float]
131
+ * @return [Float]
132
+ * @overload delay(complex)
133
+ * @param complex [Complex]
134
+ * @return [Complex]
135
+ * @overload delay(fbuf, outbuf = nil)
136
+ * @param fbuf [PaddleC::FloatBuffer]
137
+ * @param outbuf [PaddleC::FloatBuffer, nil]
138
+ * @return [PaddleC::FloatBuffer]
139
+ * @overload delay(cbuf, outbuf = nil)
140
+ * @param cbuf [PaddleC::ComplexBuffer]
141
+ * @param outbuf [PaddleC::ComplexBuffer, nil]
142
+ * @return [PaddleC::ComplexBuffer]
143
+ */
144
+ static VALUE paddlec_delay_delay(int argc, VALUE *argv, VALUE self)
145
+ {
146
+ VALUE in, out;
147
+ pdlc_delay_t *del;
148
+ float flt;
149
+ pdlc_complex_t cmp;
150
+ const pdlc_buffer_t *ifbuf;
151
+ pdlc_buffer_t *ofbuf;
152
+ const pdlc_complex_buffer_t *icbuf;
153
+ pdlc_complex_buffer_t *ocbuf;
154
+
155
+ rb_scan_args(argc, argv, "11", &in, &out);
156
+
157
+ del = paddlec_delay_get_struct(self);
158
+
159
+ if (rb_class_of(in) == rb_cComplex) {
160
+ if (out != Qnil)
161
+ rb_raise(rb_eArgError, "outbuf argument is not used when a scalar is delayed");
162
+ cmp.real = (float)NUM2DBL(rb_funcallv(in, id_real, 0, NULL));
163
+ cmp.imag = (float)NUM2DBL(rb_funcallv(in, id_imag, 0, NULL));
164
+ cmp = pdlc_delay_delay_complex(del, cmp);
165
+ out = rb_complex_new(DBL2NUM((double)cmp.real), DBL2NUM((double)cmp.imag));
166
+ }
167
+ else if (rb_obj_is_kind_of(in, rb_cNumeric)) {
168
+ if (out != Qnil)
169
+ rb_raise(rb_eArgError, "outbuf argument is not used when a scalar is delayed");
170
+ flt = (float)NUM2DBL(in);
171
+ flt = pdlc_delay_delay_float(del, flt);
172
+ out = DBL2NUM((double)flt);
173
+ }
174
+ else if (rb_class_of(in) == c_FloatBuffer) {
175
+ if (out != Qnil) {
176
+ if (rb_class_of(out) != c_FloatBuffer)
177
+ rb_raise(rb_eTypeError, "outbuf must be the same type of buffer than the input");
178
+ }
179
+ else
180
+ out = rb_class_new_instance(0, NULL, c_FloatBuffer);
181
+ ifbuf = paddlec_float_buffer_get_struct(in);
182
+ ofbuf = paddlec_float_buffer_get_struct(out);
183
+ pdlc_delay_delay_float_buffer(del, ifbuf, ofbuf);
184
+ }
185
+ else if (rb_class_of(in) == c_ComplexBuffer) {
186
+ if (out != Qnil) {
187
+ if (rb_class_of(out) != c_ComplexBuffer)
188
+ rb_raise(rb_eTypeError, "outbuf must be the same type of buffer than the input");
189
+ }
190
+ else
191
+ out = rb_class_new_instance(0, NULL, c_ComplexBuffer);
192
+ icbuf = paddlec_complex_buffer_get_struct(in);
193
+ ocbuf = paddlec_complex_buffer_get_struct(out);
194
+ pdlc_delay_delay_complex_buffer(del, icbuf, ocbuf);
195
+ }
196
+ else
197
+ rb_raise(rb_eTypeError, "expecting a float, a complex, a %"PRIsVALUE" or a %"PRIsVALUE", not a %"PRIsVALUE,
198
+ rb_class_name(c_FloatBuffer), rb_class_name(c_ComplexBuffer), rb_class_name(rb_class_of(in)));
199
+
200
+ return out;
201
+ }
202
+
203
+
204
+ void Init_paddlec_delay()
205
+ {
206
+ c_Delay = rb_define_class_under(m_PaddleC, "Delay", rb_cObject);
207
+ rb_define_alloc_func(c_Delay, paddlec_delay_alloc);
208
+ rb_define_method(c_Delay, "initialize", paddlec_delay_initialize, 1);
209
+ rb_define_method(c_Delay, "lenght", paddlec_delay_length, 0);
210
+ rb_define_method(c_Delay, "reset", paddlec_delay_reset, 0);
211
+ rb_define_method(c_Delay, "delay", paddlec_delay_delay, -1);
212
+ }
213
+
214
+
@@ -0,0 +1,29 @@
1
+ /* Copyright (C) 2020 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of PaddleC
4
+ *
5
+ * PaddleC is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * PaddleC is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with PaddleC. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ #ifndef PADDLEC_DELAY_H
20
+ #define PADDLEC_DELAY_H
21
+
22
+ #include <ruby.h>
23
+ #include "libpaddlec.h"
24
+
25
+ void Init_paddlec_delay();
26
+ pdlc_buffer_t* paddlec_delay_get_struct(VALUE obj);
27
+
28
+ #endif /* PADDLEC_DELAY_H */
29
+
@@ -0,0 +1,106 @@
1
+ require 'mkmf'
2
+
3
+ if have_library('pulse') and have_library('pulse-simple') then
4
+ $defs << '-DHAVE_PULSEAUDIO_L'
5
+ else
6
+ warn "Cannot find pulseaudio library, you should do 'sudo apt install libpulse-dev' and install this gem again'"
7
+ end
8
+
9
+ if have_library('fftw3f') then
10
+ $defs << '-DHAVE_FFTW3F_L'
11
+ else
12
+ warn "Cannot find fftw3f library, you should do 'sudo apt install libfftw3-dev libfftw3-single3' and install this gem again'"
13
+ end
14
+
15
+ if RUBY_PLATFORM =~ /linux/ then
16
+ cpuinfo = File.read '/proc/cpuinfo'
17
+ avx = not(not(cpuinfo =~ /\savx/i))
18
+ sse = not(not(cpuinfo =~ /\ssse/i))
19
+ neon = not(not(cpuinfo =~ /\sneon/i))
20
+ vfpv4 = not(not(cpuinfo =~ /\svfpv4/i))
21
+ else
22
+ avx = false
23
+ sse = false
24
+ neon = false
25
+ vfpv4 = false
26
+ end
27
+
28
+ vflgs = ''
29
+ if avx then
30
+ vflgs += ' -mavx'
31
+ elsif sse then
32
+ vflgs += ' -msse'
33
+ elsif neon then
34
+ vflgs += ' -mfpu=neon'
35
+ vflgs += '-vfpv4' if vfpv4
36
+ elsif vfpv4 then
37
+ vflgs += ' -mfpu=vfpv4'
38
+ end
39
+
40
+ File.open(File.expand_path(File.join('..', '..', 'libpaddlec', 'Makefile'), __FILE__), 'w') do |m|
41
+ m.puts <<EOF
42
+
43
+ CC = gcc
44
+ CFLAGS += -W -Wall
45
+ CFLAGS += -fPIC
46
+ CFLAGS += -O3 -march=native -ffast-math#{vflgs}
47
+
48
+ #SRC = $(wildcard *.c)
49
+ SRC += libpaddlec.c
50
+ SRC += fir_filter.c
51
+ SRC += delay.c
52
+ SRC += arithmetic.c
53
+ SRC += math.c
54
+ SRC += complex.c
55
+ SRC += comparison.c
56
+ SRC += rounding.c
57
+ SRC += no_fast_math.c
58
+ OBJS = $(SRC:.c=.o)
59
+
60
+ all: libpaddlec.a libpaddlec.so
61
+
62
+ libpaddlec.a: $(OBJS)
63
+ ar rcs $@ $^
64
+
65
+ libpaddlec.so: $(OBJS)
66
+ $(CC) $(CFLAGS) -shared -o $@ $^ -lm
67
+
68
+ fir_filter.o: fir_filter.c fir_filter_avx.c fir_filter_sse.c fir_filter_neon.c Makefile
69
+ $(CC) $(CFLAGS) -c -o $@ $<
70
+
71
+ no_fast_math.o: no_fast_math.c Makefile
72
+ $(CC) $(CFLAGS) -fno-fast-math -c -o $@ $<
73
+
74
+ %.o: %.c Makefile
75
+ $(CC) $(CFLAGS) -c -o $@ $<
76
+
77
+ clean:
78
+ @rm -vf *.o
79
+ @rm -vf libpaddlec.a
80
+ @rm -vf libpaddlec.so
81
+
82
+ .PHONY: clean
83
+
84
+ EOF
85
+ end
86
+
87
+ libpaddlec_dir = File.expand_path(File.join('..', '..', 'libpaddlec'), __FILE__)
88
+ $CFLAGS += " -I #{libpaddlec_dir}"
89
+ #$CFLAGS += ' -O3 -mtune=native -ffast-math'
90
+ #$CFLAGS += " -O0 -g "
91
+
92
+ libpaddlec_static = false
93
+ if libpaddlec_static then
94
+ $LDFLAGS += " -L #{libpaddlec_dir}"
95
+ #$LOCAL_LIBS << ' -Wl,--whole-archive -lpaddlec -Wl,--no-whole-archive '
96
+ $LOCAL_LIBS << '-lpaddlec'
97
+ abort "Cannot make libpaddlec.a" unless system "cd #{libpaddlec_dir} && make clean && make libpaddlec.a"
98
+ else
99
+ $LOCAL_LIBS += " -Wl,-rpath,#{libpaddlec_dir} -L#{libpaddlec_dir} -lpaddlec"
100
+ abort "Cannot make libpaddlec.so" unless system "cd #{libpaddlec_dir} && make clean && make libpaddlec.so"
101
+ end
102
+
103
+ create_header 'paddlec_defs.h'
104
+ create_makefile 'paddlec/paddlec'
105
+
106
+
@@ -0,0 +1,892 @@
1
+ /* Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of PaddleC
4
+ *
5
+ * PaddleC is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * PaddleC is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU General Public License
16
+ * along with PaddleC. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+ #include <ruby.h>
20
+ #include "libpaddlec.h"
21
+ #include "paddlec.h"
22
+ #include "fir_filter.h"
23
+ #include "float_buffer.h"
24
+ #include "complex_buffer.h"
25
+
26
+
27
+ VALUE c_FirFilter;
28
+ VALUE c_FirTransformer;
29
+ VALUE c_FirDecimator;
30
+ VALUE c_FirInterpolator;
31
+
32
+
33
+ static void paddlec_fir_filter_free(void *p)
34
+ {
35
+ pdlc_fir_filter_t *fir = (pdlc_fir_filter_t*)p;
36
+ pdlc_fir_filter_free(fir);
37
+ }
38
+
39
+
40
+ static size_t paddlec_fir_filter_size(const void* data)
41
+ {
42
+ pdlc_fir_filter_t *fir = (pdlc_fir_filter_t*)data;
43
+ return pdlc_fir_filter_size(fir);
44
+ }
45
+
46
+
47
+ static const rb_data_type_t paddlec_fir_filter_type = {
48
+ .wrap_struct_name = "paddlec_fir_filter_struct",
49
+ .function = {
50
+ .dmark = NULL,
51
+ .dfree = paddlec_fir_filter_free,
52
+ .dsize = paddlec_fir_filter_size,
53
+ },
54
+ .data = NULL,
55
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
56
+ };
57
+
58
+
59
+ static VALUE paddlec_fir_filter_alloc(VALUE klass)
60
+ {
61
+ VALUE obj;
62
+ pdlc_fir_filter_t *fir;
63
+
64
+ fir = pdlc_fir_filter_new(-1);
65
+ obj = TypedData_Wrap_Struct(klass, &paddlec_fir_filter_type, fir);
66
+
67
+ return obj;
68
+ }
69
+
70
+
71
+ static inline pdlc_fir_filter_t* paddlec_fir_filter_get_struct(VALUE obj)
72
+ {
73
+ pdlc_fir_filter_t *fir;
74
+ TypedData_Get_Struct(obj, pdlc_fir_filter_t, &paddlec_fir_filter_type, fir);
75
+ return fir;
76
+ }
77
+
78
+
79
+ /* @return [PaddleC::FirFilter]
80
+ * @overload initialize(n)
81
+ * @param n [Integer] the filter order
82
+ * @return [Paddlec::FirFilter]
83
+ * @overload initialize(b)
84
+ * @param b [Array<Float>, PaddleC::FloatBuffer] the coefficients, as an array or a {FloatBuffer}
85
+ * @return [Paddlec::FirFilter]
86
+ */
87
+ static VALUE paddlec_fir_filter_initialize(VALUE self, VALUE b_or_n)
88
+ {
89
+ pdlc_fir_filter_t *fir;
90
+ const pdlc_buffer_t *fbuf;
91
+ int order, i;
92
+
93
+ fir = paddlec_fir_filter_get_struct(self);
94
+
95
+ if (rb_class_of(b_or_n) == c_FloatBuffer) {
96
+ fbuf = paddlec_float_buffer_get_struct(b_or_n);
97
+ order = fbuf->length;
98
+ if (order < 1)
99
+ rb_raise(rb_eArgError, "Negative order");
100
+ pdlc_fir_filter_initialize(fir, order - 1);
101
+ for (i = 0; i < order; i++)
102
+ pdlc_fir_filter_set_coef_at(fir, i, fbuf->data[i]);
103
+ }
104
+ else if (rb_class_of(b_or_n) == rb_cArray) {
105
+ order = rb_array_len(b_or_n);
106
+ if (order < 1)
107
+ rb_raise(rb_eArgError, "Negative order");
108
+ pdlc_fir_filter_initialize(fir, order - 1);
109
+ for (i = 0; i < order; i++)
110
+ pdlc_fir_filter_set_coef_at(fir, i, (float)NUM2DBL(rb_ary_entry(b_or_n, i)));
111
+ }
112
+ else {
113
+ order = NUM2INT(b_or_n);
114
+ if (order < 0)
115
+ rb_raise(rb_eArgError, "Negative order");
116
+ pdlc_fir_filter_initialize(fir, order);
117
+ }
118
+
119
+ return self;
120
+ }
121
+
122
+
123
+ /* Reset the filter state.
124
+ * @return [self]
125
+ */
126
+ static VALUE paddlec_fir_filter_reset(VALUE self)
127
+ {
128
+ pdlc_fir_filter_t *fir;
129
+
130
+ fir = paddlec_fir_filter_get_struct(self);
131
+ pdlc_fir_filter_reset(fir);
132
+
133
+ return self;
134
+ }
135
+
136
+
137
+ /* @return [Integer] the filter order
138
+ */
139
+ static VALUE paddlec_fir_filter_order(VALUE self)
140
+ {
141
+ const pdlc_fir_filter_t *fir;
142
+
143
+ fir = paddlec_fir_filter_get_struct(self);
144
+
145
+ return INT2NUM((int)fir->nb_coefs - 1);
146
+ }
147
+
148
+
149
+ /* @return [Integer] number of coefficients (order + 1)
150
+ */
151
+ static VALUE paddlec_fir_filter_nb_coefficients(VALUE self)
152
+ {
153
+ const pdlc_fir_filter_t *fir;
154
+
155
+ fir = paddlec_fir_filter_get_struct(self);
156
+
157
+ return INT2NUM((int)fir->nb_coefs);
158
+ }
159
+
160
+
161
+ /* Return a copy of the filter's numerator coefficients.
162
+ * @return [PaddleC::FloatBuffer] the filter coefficients
163
+ */
164
+ static VALUE paddlec_fir_filter_coefficients(VALUE self)
165
+ {
166
+ const pdlc_fir_filter_t *fir;
167
+ pdlc_buffer_t *fbuf;
168
+ VALUE res;
169
+ unsigned int i;
170
+
171
+ fir = paddlec_fir_filter_get_struct(self);
172
+
173
+ res = UINT2NUM(fir->nb_coefs);
174
+ res = rb_class_new_instance(1, &res, c_FloatBuffer);
175
+ fbuf = paddlec_float_buffer_get_struct(res);
176
+
177
+ for (i = 0; i < fir->nb_coefs; i++)
178
+ pdlc_fir_filter_get_coef_at(fir, (int)i, fbuf->data + i);
179
+
180
+ return res;
181
+ }
182
+
183
+
184
+ /* Return a copy of the filter's denominator coefficients, allways [1].
185
+ * @return [PaddleC::FloatBuffer] the filter denominator coefficients
186
+ */
187
+ static VALUE paddlec_fir_filter_denominator(VALUE self)
188
+ {
189
+ pdlc_buffer_t *fbuf;
190
+ VALUE res;
191
+
192
+ res = UINT2NUM(1);
193
+ res = rb_class_new_instance(1, &res, c_FloatBuffer);
194
+ fbuf = paddlec_float_buffer_get_struct(res);
195
+
196
+ fbuf->data[0] = 1.0;
197
+
198
+ return res;
199
+ }
200
+
201
+
202
+ /* @param index [Integer] the coefficient index
203
+ * @return [Float] the coefficient at +index+
204
+ */
205
+ static VALUE paddlec_fir_filter_get_coefficient_at(VALUE self, VALUE index)
206
+ {
207
+ const pdlc_fir_filter_t *fir;
208
+ int ind;
209
+ float val;
210
+ VALUE res;
211
+
212
+ fir = paddlec_fir_filter_get_struct(self);
213
+
214
+ ind = NUM2INT(index);
215
+ if (pdlc_fir_filter_get_coef_at(fir, ind, &val) == 0)
216
+ res = DBL2NUM((double)val);
217
+ else
218
+ res = DBL2NUM(0.0);
219
+
220
+ return res;
221
+ }
222
+
223
+
224
+ /* @param index [Integer] the coefficient index
225
+ * @param coef [Float] the coefficient value
226
+ * @return [Float, nil] the coefficient if the index is valid, or +nil+ otherwise
227
+ */
228
+ static VALUE paddlec_fir_filter_set_coefficient_at(VALUE self, VALUE index, VALUE coef)
229
+ {
230
+ pdlc_fir_filter_t *fir;
231
+ int ind;
232
+ float val;
233
+ VALUE res = Qnil;
234
+
235
+ fir = paddlec_fir_filter_get_struct(self);
236
+ val = (float)NUM2DBL(coef);
237
+
238
+ ind = NUM2INT(index);
239
+ if (pdlc_fir_filter_set_coef_at(fir, ind, val) == 0)
240
+ res = DBL2NUM(val);
241
+
242
+ return res;
243
+ }
244
+
245
+
246
+ /* This method returns 1.0 if +index+ is 0, 0.0 otherwise. It is there to be compatible with {IirFilter}
247
+ * @param index [Integer] the denominator coefficient index
248
+ * @return [Float] the denominator coefficient at index
249
+ */
250
+ static VALUE paddlec_fir_filter_get_denominator_at(VALUE self, VALUE index)
251
+ {
252
+ int ind;
253
+ VALUE res;
254
+
255
+ ind = NUM2INT(index);
256
+ if (ind == 0)
257
+ res = DBL2NUM(1.0);
258
+ else
259
+ res = DBL2NUM(0.0);
260
+
261
+ return res;
262
+ }
263
+
264
+
265
+ /* This method does nothing, it is there to be compatible with {IirFilter}
266
+ * @param index [Integer] the coefficient index
267
+ * @param coef [Float] the denominator coefficient value
268
+ * @return [Float, nil] the denominator coefficient if the index is valid, or nil otherwise
269
+ */
270
+ static VALUE paddlec_fir_filter_set_denominator_at(VALUE self, VALUE index, VALUE coef)
271
+ {
272
+ (void)self;
273
+ (void)index;
274
+ (void)coef;
275
+
276
+ return Qnil;
277
+ }
278
+
279
+
280
+ /* Filter a single sample, complex or real, or a {FloatBuffer} or {ComplexBuffer}.
281
+ * The returned element is of the same type as the input element.
282
+ *
283
+ * If complex samples are fed to the filter, float samples must not be fed before a {FirFilter#reset}.
284
+ *
285
+ * The keyword argument +buffer:+ can be used to provide the filter with an already allocated buffer for the output.
286
+ *
287
+ * The keyword argument +delayed:+ can be used to provide the filter with an already allocated buffer filled
288
+ * with the input signal delayed by +order / 2+.
289
+ * If +delayed:+ is not +nil+, then the output is an array containing the filtered signal and the delayed signal.
290
+ *
291
+ * @overload filter(r_sample)
292
+ * @param r_sample [Float] a real input sample
293
+ * @return [Float] a real processed sample
294
+ *
295
+ * @overload filter(c_sample)
296
+ * @param c_sample [Complex] a complex input sample
297
+ * @return [Complex] a complex processed sample
298
+ *
299
+ * @overload filter(r_sample, delayed: true)
300
+ * @param r_sample [Float] a real input sample
301
+ * @param delayed [Boolean, nil] whether to output the delayed sample or not
302
+ * @return [Array<Float>] a two element array containing the processed sample and the delayed sample
303
+ *
304
+ * @overload filter(c_sample, delayed: true)
305
+ * @param c_sample [Complex] a complex input sample
306
+ * @param delayed [Boolean, nil] whether to output the delayed sample or not
307
+ * @return [Array<Complex>] a two element array containing the processed sample and the delayed sample
308
+ *
309
+ * @overload filter(float_buffer, buffer: obuf)
310
+ * @param float_buffer [PaddleC::FloatBuffer] a buffer of real input samples
311
+ * @param buffer [PaddleC::FloatBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
312
+ * @return [PaddleC::FloatBuffer] a buffer of real processed samples
313
+ *
314
+ * @overload filter(complex_buffer, buffer: obuf)
315
+ * @param complex_buffer [PaddleC::ComplexBuffer] a buffer of complex input samples
316
+ * @param buffer [PaddleC::ComplexBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
317
+ * @return [PaddleC::ComplexBuffer] a buffer of complex processed samples
318
+ *
319
+ * @overload filter(float_buffer, buffer: obuf, delayed: true)
320
+ * @param float_buffer [PaddleC::FloatBuffer] a buffer of real input samples
321
+ * @param buffer [PaddleC::FloatBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
322
+ * @param delayed [PaddleC::FloatBuffer, Boolean, nil] a boolean or an already allocated buffer
323
+ * @return [Array<PaddleC::FloatBuffer>] a two element array containing the processed samples and the delayed samples
324
+ *
325
+ * @overload filter(complex_buffer, buffer: obuf, delayed: true)
326
+ * @param complex_buffer [PaddleC::ComplexBuffer] a buffer of complex input samples
327
+ * @param buffer [PaddleC::ComplexBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
328
+ * @param delayed [PaddleC::ComplexBuffer, Boolean, nil] a boolean or an already allocated buffer
329
+ * @return [Array<PaddleC::ComplexBuffer>] a two element array containing the processed samples and the delayed samples
330
+ */
331
+ static VALUE paddlec_fir_filter_filter(int argc, VALUE *argv, VALUE self)
332
+ {
333
+ pdlc_fir_filter_t *fir;
334
+ VALUE rbSample, rbOptHash;
335
+ VALUE buffer_and_delayed[2] = {Qundef, Qundef};
336
+ const ID kwkeys[2] = {id_buffer, id_delayed};
337
+ VALUE obuf = Qnil, delayed = Qnil;
338
+ VALUE res = Qnil;
339
+ float delayed_float;
340
+ pdlc_complex_t delayed_complex;
341
+ float output_float;
342
+ pdlc_complex_t output_complex;
343
+ const pdlc_buffer_t *ifbuf;
344
+ const pdlc_complex_buffer_t *icbuf;
345
+ pdlc_buffer_t *ofbuf, *dfbuf;
346
+ pdlc_complex_buffer_t *ocbuf, *dcbuf;
347
+
348
+ rb_scan_args(argc, argv, "1:", &rbSample, &rbOptHash);
349
+
350
+ if (!NIL_P(rbOptHash))
351
+ rb_get_kwargs(rbOptHash, kwkeys, 0, 2, buffer_and_delayed);
352
+ if (buffer_and_delayed[0] != Qundef)
353
+ obuf = buffer_and_delayed[0];
354
+ if (buffer_and_delayed[1] != Qundef)
355
+ delayed = buffer_and_delayed[1];
356
+
357
+ fir = paddlec_fir_filter_get_struct(self);
358
+
359
+ if (rb_class_of(rbSample) == c_FloatBuffer) {
360
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_FloatBuffer)
361
+ rb_raise(rb_eArgError, "only a FloatBuffer is valid for buffer when a FloatBuffer is provided to the filter");
362
+ if (delayed != Qtrue && delayed != Qnil && delayed != Qfalse && rb_class_of(obuf) != c_FloatBuffer)
363
+ rb_raise(rb_eArgError, "only true, false, nil and a FloatBuffer are valid values for delayed when a FloatBuffer is provided to the filter");
364
+ ifbuf = paddlec_float_buffer_get_struct(rbSample);
365
+
366
+ if (rb_class_of(obuf) != c_FloatBuffer)
367
+ obuf = rb_class_new_instance(0, NULL, c_FloatBuffer);
368
+ ofbuf = paddlec_float_buffer_get_struct(obuf);
369
+
370
+ if (delayed == Qnil || delayed == Qfalse) {
371
+ pdlc_fir_filter_filter_float_buffer(fir, ifbuf, ofbuf, NULL);
372
+ res = obuf;
373
+ }
374
+ else {
375
+ if (rb_class_of(delayed) != c_FloatBuffer)
376
+ delayed = rb_class_new_instance(0, NULL, c_FloatBuffer);
377
+ dfbuf = paddlec_float_buffer_get_struct(delayed);
378
+ pdlc_fir_filter_filter_float_buffer(fir, ifbuf, ofbuf, dfbuf);
379
+ res = rb_ary_new_capa(2);
380
+ rb_ary_store(res, 0, obuf);
381
+ rb_ary_store(res, 1, delayed);
382
+ }
383
+ }
384
+ else if (rb_class_of(rbSample) == c_ComplexBuffer) {
385
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_ComplexBuffer)
386
+ rb_raise(rb_eArgError, "only a ComplexBuffer is valid for buffer when a ComplexBuffer is provided to the filter");
387
+ if (delayed != Qtrue && delayed != Qnil && delayed != Qfalse && rb_class_of(obuf) != c_ComplexBuffer)
388
+ rb_raise(rb_eArgError, "only true, false, nil and a ComplexBuffer are valid values for delayed when a ComplexBuffer is provided to the filter");
389
+ icbuf = paddlec_complex_buffer_get_struct(rbSample);
390
+
391
+ if (rb_class_of(obuf) != c_ComplexBuffer)
392
+ obuf = rb_class_new_instance(0, NULL, c_ComplexBuffer);
393
+ ocbuf = paddlec_complex_buffer_get_struct(obuf);
394
+
395
+ if (delayed == Qnil || delayed == Qfalse) {
396
+ pdlc_fir_filter_filter_complex_buffer(fir, icbuf, ocbuf, NULL);
397
+ res = obuf;
398
+ }
399
+ else {
400
+ if (rb_class_of(delayed) != c_ComplexBuffer)
401
+ delayed = rb_class_new_instance(0, NULL, c_ComplexBuffer);
402
+ dcbuf = paddlec_complex_buffer_get_struct(delayed);
403
+ pdlc_fir_filter_filter_complex_buffer(fir, icbuf, ocbuf, dcbuf);
404
+ res = rb_ary_new_capa(2);
405
+ rb_ary_store(res, 0, obuf);
406
+ rb_ary_store(res, 1, delayed);
407
+ }
408
+ }
409
+ else {
410
+ if (!NIL_P(obuf))
411
+ rb_raise(rb_eArgError, "output buffer must not be provided when a single sample is given to the filter");
412
+ if (delayed != Qtrue && delayed != Qnil && delayed != Qfalse)
413
+ rb_raise(rb_eArgError, "only true, false and nil are valid values for delayed when a single sample is provided to the filter");
414
+ if (rb_class_of(rbSample) == rb_cComplex) {
415
+ output_complex.real = (float)NUM2DBL(rb_funcallv(rbSample, id_real, 0, NULL));
416
+ output_complex.imag = (float)NUM2DBL(rb_funcallv(rbSample, id_real, 0, NULL));
417
+ if (delayed == Qtrue) {
418
+ output_complex = pdlc_fir_filter_filter_complex(fir, output_complex, &delayed_complex);
419
+ res = rb_ary_new_capa(2);
420
+ rb_ary_store(res, 0, rb_complex_raw(DBL2NUM((double)output_complex.real), DBL2NUM((double)output_complex.imag)));
421
+ rb_ary_store(res, 1, rb_complex_raw(DBL2NUM((double)delayed_complex.real), DBL2NUM((double)delayed_complex.imag)));
422
+ }
423
+ else {
424
+ output_complex = pdlc_fir_filter_filter_complex(fir, output_complex, NULL);
425
+ res = rb_complex_raw(DBL2NUM((double)output_complex.real), DBL2NUM((double)output_complex.imag));
426
+ }
427
+ }
428
+ else {
429
+ if (delayed == Qtrue) {
430
+ output_float = pdlc_fir_filter_filter_float(fir, (float)NUM2DBL(rbSample), &delayed_float);
431
+ res = rb_ary_new_capa(2);
432
+ rb_ary_store(res, 0, DBL2NUM((double)output_float));
433
+ rb_ary_store(res, 1, DBL2NUM((double)delayed_float));
434
+ }
435
+ else {
436
+ output_float = pdlc_fir_filter_filter_float(fir, (float)NUM2DBL(rbSample), NULL);
437
+ res = DBL2NUM((double)output_float);
438
+ }
439
+ }
440
+ }
441
+
442
+ return res;
443
+ }
444
+
445
+
446
+ /* @return [PaddleC::FirInterpolator]
447
+ * @overload initialize(n, interpolation_factor)
448
+ * @param n [Integer] the filter order
449
+ * @param interpolation_factor [Integer] the interpolation factor (>= 1)
450
+ * @return [PaddleC::FirInterpolator]
451
+ * @overload initialize(b, interpolation_factor)
452
+ * @param interpolation_factor [Integer] the interpolation factor (>= 1)
453
+ * @param b [Array<Float>, PaddleC::FloatBuffer] the coefficients, as an array or a {FloatBuffer}
454
+ * @return [PaddleC::FirInterpolator]
455
+ */
456
+ static VALUE paddlec_fir_filter_interpolator_initialize(VALUE self, VALUE b_or_n, VALUE factor)
457
+ {
458
+ pdlc_fir_filter_t *fir;
459
+ const pdlc_buffer_t *fbuf;
460
+ int order, i, ifactor;
461
+
462
+ ifactor = NUM2INT(factor);
463
+ if (ifactor < 1)
464
+ rb_raise(rb_eRangeError, "Interpolation factor cannot be less than one");
465
+ if (ifactor > 32)
466
+ rb_raise(rb_eRangeError, "Interpolation factor greater than 32 is too much");
467
+
468
+ fir = paddlec_fir_filter_get_struct(self);
469
+
470
+ if (rb_class_of(b_or_n) == c_FloatBuffer) {
471
+ fbuf = paddlec_float_buffer_get_struct(b_or_n);
472
+ order = fbuf->length;
473
+ if (order < 1)
474
+ rb_raise(rb_eArgError, "Negative order");
475
+ pdlc_fir_filter_interpolator_initialize(fir, order - 1, ifactor);
476
+ for (i = 0; i < order; i++)
477
+ pdlc_fir_filter_set_coef_at(fir, i, fbuf->data[i]);
478
+ }
479
+ else if (rb_class_of(b_or_n) == rb_cArray) {
480
+ order = rb_array_len(b_or_n);
481
+ if (order < 1)
482
+ rb_raise(rb_eArgError, "Negative order");
483
+ pdlc_fir_filter_interpolator_initialize(fir, order - 1, ifactor);
484
+ for (i = 0; i < order; i++)
485
+ pdlc_fir_filter_set_coef_at(fir, i, (float)NUM2DBL(rb_ary_entry(b_or_n, i)));
486
+ }
487
+ else {
488
+ order = NUM2INT(b_or_n);
489
+ if (order < 0)
490
+ rb_raise(rb_eArgError, "Negative order");
491
+ pdlc_fir_filter_interpolator_initialize(fir, order, ifactor);
492
+ }
493
+
494
+ return self;
495
+ }
496
+
497
+
498
+ /* @return [Integer] the interpolation factor
499
+ */
500
+ static VALUE paddlec_fir_filter_interpolator_interpolation_factor(VALUE self)
501
+ {
502
+ const pdlc_fir_filter_t *fir;
503
+
504
+ fir = paddlec_fir_filter_get_struct(self);
505
+
506
+ return INT2NUM(pdlc_fir_filter_get_factor(fir));
507
+ }
508
+
509
+
510
+ /* Interpolate a {FloatBuffer} or {ComplexBuffer}.
511
+ * The returned element is of the same type as the input element.
512
+ *
513
+ * If complex samples are fed to the interpolator, float samples must not be fed before a {FirFilter#reset}.
514
+ *
515
+ * The keyword argument +buffer:+ can be used to provide the interpolator with an already allocated buffer for the output.
516
+ *
517
+ * @overload interpolate(float_buffer, buffer: obuf)
518
+ * @param float_buffer [PaddleC::FloatBuffer] a buffer of real input samples
519
+ * @param buffer [PaddleC::FloatBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
520
+ * @return [PaddleC::FloatBuffer] a buffer of real processed samples of size +float_buffer.length * #interpolation_factor+
521
+ *
522
+ * @overload interpolate(complex_buffer, buffer: obuf)
523
+ * @param complex_buffer [PaddleC::ComplexBuffer] a buffer of complex input samples
524
+ * @param buffer [PaddleC::ComplexBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
525
+ * @return [PaddleC::ComplexBuffer] a buffer of complex processed samples of size +complex_buffer.length * #interpolation_factor+
526
+ */
527
+ static VALUE paddlec_fir_filter_interpolator_interpolate(int argc, VALUE *argv, VALUE self)
528
+ {
529
+ pdlc_fir_filter_t *fir;
530
+ VALUE rbSample, rbOptHash;
531
+ VALUE buffer_hash[2] = {Qundef};
532
+ const ID kwkeys[2] = {id_buffer};
533
+ VALUE obuf = Qnil;
534
+ VALUE res = Qnil;
535
+ const pdlc_buffer_t *ifbuf;
536
+ const pdlc_complex_buffer_t *icbuf;
537
+ pdlc_buffer_t *ofbuf;
538
+ pdlc_complex_buffer_t *ocbuf;
539
+
540
+ rb_scan_args(argc, argv, "1:", &rbSample, &rbOptHash);
541
+
542
+ if (!NIL_P(rbOptHash))
543
+ rb_get_kwargs(rbOptHash, kwkeys, 0, 1, buffer_hash);
544
+ if (buffer_hash[0] != Qundef)
545
+ obuf = buffer_hash[0];
546
+
547
+ fir = paddlec_fir_filter_get_struct(self);
548
+
549
+ if (rb_class_of(rbSample) == c_FloatBuffer) {
550
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_FloatBuffer)
551
+ rb_raise(rb_eArgError, "only a %"PRIsVALUE" is valid for buffer when a %"PRIsVALUE" is provided to the Interpolator", rb_class_name(c_FloatBuffer), rb_class_name(c_FloatBuffer));
552
+ ifbuf = paddlec_float_buffer_get_struct(rbSample);
553
+
554
+ if (rb_class_of(obuf) != c_FloatBuffer)
555
+ obuf = rb_class_new_instance(0, NULL, c_FloatBuffer);
556
+ ofbuf = paddlec_float_buffer_get_struct(obuf);
557
+
558
+ pdlc_fir_filter_interpolate_float_buffer(fir, ifbuf, ofbuf);
559
+ res = obuf;
560
+ }
561
+ else if (rb_class_of(rbSample) == c_ComplexBuffer) {
562
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_ComplexBuffer)
563
+ rb_raise(rb_eArgError, "only a %"PRIsVALUE" is valid for buffer when a %"PRIsVALUE" is provided to the Interpolator", rb_class_name(c_ComplexBuffer), rb_class_name(c_ComplexBuffer));
564
+ icbuf = paddlec_complex_buffer_get_struct(rbSample);
565
+
566
+ if (rb_class_of(obuf) != c_ComplexBuffer)
567
+ obuf = rb_class_new_instance(0, NULL, c_ComplexBuffer);
568
+ ocbuf = paddlec_complex_buffer_get_struct(obuf);
569
+
570
+ pdlc_fir_filter_interpolate_complex_buffer(fir, icbuf, ocbuf);
571
+ res = obuf;
572
+ }
573
+ else
574
+ rb_raise(rb_eTypeError, "expecting a %"PRIsVALUE" or a %"PRIsVALUE, rb_class_name(c_FloatBuffer), rb_class_name(c_ComplexBuffer));
575
+
576
+ return res;
577
+ }
578
+
579
+
580
+ /* @return [PaddleC::FirDecimator]
581
+ * @overload initialize(n, decimation_factor)
582
+ * @param n [Integer] the filter order
583
+ * @param decimation_factor [Integer] the decimation factor (>= 1)
584
+ * @return [PaddleC::FirDecimator]
585
+ * @overload initialize(b, decimation_factor)
586
+ * @param b [Array<Float>, PaddleC::FloatBuffer] the coefficients, as an array or a {FloatBuffer}
587
+ * @param decimation_factor [Integer] the decimation factor (>= 1)
588
+ * @return [PaddleC::FirDecimator]
589
+ */
590
+ static VALUE paddlec_fir_filter_decimator_initialize(VALUE self, VALUE b_or_n, VALUE factor)
591
+ {
592
+ pdlc_fir_filter_t *fir;
593
+ const pdlc_buffer_t *fbuf;
594
+ int order, i, ifactor;
595
+
596
+ ifactor = NUM2INT(factor);
597
+ if (ifactor < 1)
598
+ rb_raise(rb_eRangeError, "Decimation factor cannot be less than one");
599
+ if (ifactor > 32)
600
+ rb_raise(rb_eRangeError, "Decimation factor greater than 32 is too much");
601
+
602
+ fir = paddlec_fir_filter_get_struct(self);
603
+
604
+ if (rb_class_of(b_or_n) == c_FloatBuffer) {
605
+ fbuf = paddlec_float_buffer_get_struct(b_or_n);
606
+ order = fbuf->length;
607
+ if (order < 1)
608
+ rb_raise(rb_eArgError, "Negative order");
609
+ pdlc_fir_filter_decimator_initialize(fir, order - 1, ifactor);
610
+ for (i = 0; i < order; i++)
611
+ pdlc_fir_filter_set_coef_at(fir, i, fbuf->data[i]);
612
+ }
613
+ else if (rb_class_of(b_or_n) == rb_cArray) {
614
+ order = rb_array_len(b_or_n);
615
+ if (order < 1)
616
+ rb_raise(rb_eArgError, "Negative order");
617
+ pdlc_fir_filter_decimator_initialize(fir, order - 1, ifactor);
618
+ for (i = 0; i < order; i++)
619
+ pdlc_fir_filter_set_coef_at(fir, i, (float)NUM2DBL(rb_ary_entry(b_or_n, i)));
620
+ }
621
+ else {
622
+ order = NUM2INT(b_or_n);
623
+ if (order < 0)
624
+ rb_raise(rb_eArgError, "Negative order");
625
+ pdlc_fir_filter_decimator_initialize(fir, order, ifactor);
626
+ }
627
+
628
+ return self;
629
+ }
630
+
631
+
632
+ /* @return [Integer] the decimation factor
633
+ */
634
+ static VALUE paddlec_fir_filter_decimator_decimation_factor(VALUE self)
635
+ {
636
+ const pdlc_fir_filter_t *fir;
637
+
638
+ fir = paddlec_fir_filter_get_struct(self);
639
+
640
+ return INT2NUM(pdlc_fir_filter_get_factor(fir));
641
+ }
642
+
643
+
644
+ /* Decimate a {FloatBuffer} or {ComplexBuffer}.
645
+ * The returned element is of the same type as the input element.
646
+ *
647
+ * If complex samples are fed to the decimator, float samples must not be fed before a {FirFilter#reset}.
648
+ *
649
+ * The keyword argument +buffer:+ can be used to provide the decimator with an already allocated buffer for the output.
650
+ *
651
+ * @overload decimate(float_buffer, buffer: obuf)
652
+ * @param float_buffer [PaddleC::FloatBuffer] a buffer of real input samples
653
+ * @param buffer [PaddleC::FloatBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
654
+ * @return [PaddleC::FloatBuffer] a buffer of real processed samples of size ≈ +float_buffer.length / #decimation_factor+
655
+ *
656
+ * @overload decimate(complex_buffer, buffer: obuf)
657
+ * @param complex_buffer [PaddleC::ComplexBuffer] a buffer of complex input samples
658
+ * @param buffer [PaddleC::ComplexBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
659
+ * @return [PaddleC::ComplexBuffer] a buffer of complex processed samples of size ≈ +complex_buffer.length / #decimation_factor+
660
+ */
661
+ static VALUE paddlec_fir_filter_decimator_decimate(int argc, VALUE *argv, VALUE self)
662
+ {
663
+ pdlc_fir_filter_t *fir;
664
+ VALUE rbSample, rbOptHash;
665
+ VALUE buffer_hash[2] = {Qundef};
666
+ const ID kwkeys[2] = {id_buffer};
667
+ VALUE obuf = Qnil;
668
+ VALUE res = Qnil;
669
+ const pdlc_buffer_t *ifbuf;
670
+ const pdlc_complex_buffer_t *icbuf;
671
+ pdlc_buffer_t *ofbuf;
672
+ pdlc_complex_buffer_t *ocbuf;
673
+
674
+ rb_scan_args(argc, argv, "1:", &rbSample, &rbOptHash);
675
+
676
+ if (!NIL_P(rbOptHash))
677
+ rb_get_kwargs(rbOptHash, kwkeys, 0, 1, buffer_hash);
678
+ if (buffer_hash[0] != Qundef)
679
+ obuf = buffer_hash[0];
680
+
681
+ fir = paddlec_fir_filter_get_struct(self);
682
+
683
+ if (rb_class_of(rbSample) == c_FloatBuffer) {
684
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_FloatBuffer)
685
+ rb_raise(rb_eArgError, "only a %"PRIsVALUE" is valid for buffer when a %"PRIsVALUE" is provided to the decimator", rb_class_name(c_FloatBuffer), rb_class_name(c_FloatBuffer));
686
+ ifbuf = paddlec_float_buffer_get_struct(rbSample);
687
+
688
+ if (rb_class_of(obuf) != c_FloatBuffer)
689
+ obuf = rb_class_new_instance(0, NULL, c_FloatBuffer);
690
+ ofbuf = paddlec_float_buffer_get_struct(obuf);
691
+
692
+ pdlc_fir_filter_decimate_float_buffer(fir, ifbuf, ofbuf);
693
+ res = obuf;
694
+ }
695
+ else if (rb_class_of(rbSample) == c_ComplexBuffer) {
696
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_ComplexBuffer)
697
+ rb_raise(rb_eArgError, "only a %"PRIsVALUE" is valid for buffer when a %"PRIsVALUE" is provided to the decimator", rb_class_name(c_ComplexBuffer), rb_class_name(c_ComplexBuffer));
698
+ icbuf = paddlec_complex_buffer_get_struct(rbSample);
699
+
700
+ if (rb_class_of(obuf) != c_ComplexBuffer)
701
+ obuf = rb_class_new_instance(0, NULL, c_ComplexBuffer);
702
+ ocbuf = paddlec_complex_buffer_get_struct(obuf);
703
+
704
+ pdlc_fir_filter_decimate_complex_buffer(fir, icbuf, ocbuf);
705
+ res = obuf;
706
+ }
707
+ else
708
+ rb_raise(rb_eTypeError, "expecting a %"PRIsVALUE" or a %"PRIsVALUE, rb_class_name(c_FloatBuffer), rb_class_name(c_ComplexBuffer));
709
+
710
+ return res;
711
+ }
712
+
713
+
714
+ /* @return [PaddleC::FirTransformer]
715
+ * @overload initialize(n)
716
+ * @param n [Integer] the filter order
717
+ * @return [Paddlec::FirTransformer]
718
+ * @overload initialize(b)
719
+ * @param b [Array<Float>, PaddleC::FloatBuffer] the coefficients, as an array or a {FloatBuffer}
720
+ * @return [Paddlec::FirTransformer]
721
+ */
722
+ static VALUE paddlec_fir_filter_transformer_initialize(VALUE self, VALUE b_or_n)
723
+ {
724
+ pdlc_fir_filter_t *fir;
725
+ const pdlc_buffer_t *fbuf;
726
+ int order, i;
727
+
728
+ fir = paddlec_fir_filter_get_struct(self);
729
+
730
+ if (rb_class_of(b_or_n) == c_FloatBuffer) {
731
+ fbuf = paddlec_float_buffer_get_struct(b_or_n);
732
+ order = fbuf->length;
733
+ if (order < 1)
734
+ rb_raise(rb_eArgError, "Negative order");
735
+ pdlc_fir_filter_initialize(fir, order - 1);
736
+ for (i = 0; i < order; i++)
737
+ pdlc_fir_filter_set_coef_at(fir, i, fbuf->data[i]);
738
+ }
739
+ else if (rb_class_of(b_or_n) == rb_cArray) {
740
+ order = rb_array_len(b_or_n);
741
+ if (order < 1)
742
+ rb_raise(rb_eArgError, "Negative order");
743
+ pdlc_fir_filter_initialize(fir, order - 1);
744
+ for (i = 0; i < order; i++)
745
+ pdlc_fir_filter_set_coef_at(fir, i, (float)NUM2DBL(rb_ary_entry(b_or_n, i)));
746
+ }
747
+ else {
748
+ order = NUM2INT(b_or_n);
749
+ if (order < 0)
750
+ rb_raise(rb_eArgError, "Negative order");
751
+ pdlc_fir_filter_initialize(fir, order);
752
+ }
753
+
754
+ return self;
755
+ }
756
+
757
+
758
+ /* Transform a {FloatBuffer} into a {ComplexBuffer}.
759
+ * The real part of the output is the input signal delayed,
760
+ * and the imaginary part of the output is the input signal filtered.
761
+ *
762
+ * @overload transform(float_buffer, buffer: obuf)
763
+ * @param float_buffer [PaddleC::FloatBuffer] a buffer of real input samples
764
+ * @param buffer [PaddleC::ComplexBuffer, nil] if provided, the buffer is resized if needed and filled with output samples, then returned
765
+ * @return [PaddleC::ComplexBuffer] a complex buffer whose real part is the original signal delayed, and the imaginary part the signal filtered
766
+ */
767
+ static VALUE paddlec_fir_filter_transformer_transform(int argc, VALUE *argv, VALUE self)
768
+ {
769
+ pdlc_fir_filter_t *fir;
770
+ VALUE rbSample, rbOptHash;
771
+ VALUE buffer_hash = Qundef;
772
+ const ID kwkeys = id_buffer;
773
+ VALUE obuf = Qnil;
774
+ VALUE res = Qnil;
775
+ const pdlc_buffer_t *ifbuf;
776
+ pdlc_complex_buffer_t *ocbuf;
777
+
778
+ rb_scan_args(argc, argv, "1:", &rbSample, &rbOptHash);
779
+
780
+ if (!NIL_P(rbOptHash))
781
+ rb_get_kwargs(rbOptHash, &kwkeys, 0, 1, &buffer_hash);
782
+ if (buffer_hash != Qundef)
783
+ obuf = buffer_hash;
784
+
785
+ fir = paddlec_fir_filter_get_struct(self);
786
+
787
+ if (rb_class_of(rbSample) == c_FloatBuffer) {
788
+ if (!NIL_P(obuf) && rb_class_of(obuf) != c_ComplexBuffer)
789
+ rb_raise(rb_eArgError, "only a %"PRIsVALUE" is valid for buffer", rb_class_name(c_ComplexBuffer));
790
+ ifbuf = paddlec_float_buffer_get_struct(rbSample);
791
+
792
+ if (rb_class_of(obuf) != c_ComplexBuffer)
793
+ obuf = rb_class_new_instance(0, NULL, c_ComplexBuffer);
794
+ ocbuf = paddlec_complex_buffer_get_struct(obuf);
795
+
796
+ pdlc_fir_filter_transform(fir, ifbuf, ocbuf);
797
+ res = obuf;
798
+ }
799
+ else
800
+ rb_raise(rb_eTypeError, "expecting a %"PRIsVALUE, rb_class_name(c_FloatBuffer));
801
+
802
+ return res;
803
+ }
804
+
805
+
806
+
807
+ /* Document-class: PaddleC::FirTransformer
808
+ *
809
+ * PaddleC::FirTransformer is a FIR filter with the +#transform+ method. It is mostly implemented for Hilbert transformers.
810
+ *
811
+ * It can process {PaddleC::FloatBuffer} into {PaddleC::ComplexBuffer}.
812
+ */
813
+
814
+
815
+ static void Init_paddlec_fir_transformer()
816
+ {
817
+ c_FirTransformer = rb_define_class_under(m_PaddleC, "FirTransformer", c_FirFilter);
818
+ rb_define_method(c_FirTransformer, "initialize", paddlec_fir_filter_transformer_initialize, 1);
819
+ rb_define_method(c_FirTransformer, "transform", paddlec_fir_filter_transformer_transform, -1);
820
+ }
821
+
822
+
823
+ /* Document-class: PaddleC::FirDecimator
824
+ *
825
+ * A finite impulse response (FIR) decimator (filter + downsample), relying on {PaddleC::FirFilter}.
826
+ *
827
+ * It can process {PaddleC::FloatBuffer} and {PaddleC::ComplexBuffer}.
828
+ */
829
+
830
+
831
+ static void Init_paddlec_fir_decimator()
832
+ {
833
+ c_FirDecimator = rb_define_class_under(m_PaddleC, "FirDecimator", c_FirFilter);
834
+ rb_define_method(c_FirDecimator, "initialize", paddlec_fir_filter_decimator_initialize, 2);
835
+ rb_define_method(c_FirDecimator, "decimation_factor", paddlec_fir_filter_decimator_decimation_factor, 0);
836
+ rb_define_method(c_FirDecimator, "decimate", paddlec_fir_filter_decimator_decimate, -1);
837
+ }
838
+
839
+
840
+ /* Document-class: PaddleC::FirInterpolator
841
+ *
842
+ * A finite impulse response (FIR) interpolator (upsample + filter), relying on {PaddleC::FirFilter}.
843
+ *
844
+ * It can process {PaddleC::FloatBuffer} and {PaddleC::ComplexBuffer}.
845
+ */
846
+
847
+
848
+ static void Init_paddlec_fir_interpolator()
849
+ {
850
+ c_FirInterpolator = rb_define_class_under(m_PaddleC, "FirInterpolator", c_FirFilter);
851
+ rb_define_method(c_FirInterpolator, "initialize", paddlec_fir_filter_interpolator_initialize, 2);
852
+ rb_define_method(c_FirInterpolator, "interpolation_factor", paddlec_fir_filter_interpolator_interpolation_factor, 0);
853
+ rb_define_method(c_FirInterpolator, "interpolate", paddlec_fir_filter_interpolator_interpolate, -1);
854
+ }
855
+
856
+
857
+ /* Document-class: PaddleC::FirFilter
858
+ *
859
+ * A finite impulse response (FIR) filter.
860
+ *
861
+ * It can process +Float+, +Complex+, {PaddleC::FloatBuffer} and {PaddleC::ComplexBuffer}.
862
+ *
863
+ * Internal coefficients and state are hold using native arrays of single floats.
864
+ *
865
+ * Deppending on the host architecture, computation may be accelerated using +AVX+, +SSE+ or +NEON+ SIMD instructions.
866
+ */
867
+
868
+
869
+ void Init_paddlec_fir_filter()
870
+ {
871
+ c_FirFilter = rb_define_class_under(m_PaddleC, "FirFilter", rb_cObject);
872
+
873
+ rb_define_alloc_func(c_FirFilter, paddlec_fir_filter_alloc);
874
+ rb_define_method(c_FirFilter, "initialize", paddlec_fir_filter_initialize, 1);
875
+ rb_define_method(c_FirFilter, "filter", paddlec_fir_filter_filter, -1);
876
+ rb_define_method(c_FirFilter, "order", paddlec_fir_filter_order, 0);
877
+ rb_define_method(c_FirFilter, "nb_coefficients", paddlec_fir_filter_nb_coefficients, 0);
878
+ rb_define_method(c_FirFilter, "reset", paddlec_fir_filter_reset, 0);
879
+ rb_define_method(c_FirFilter, "coefficients", paddlec_fir_filter_coefficients, 0);
880
+ rb_define_alias(c_FirFilter, "numerator", "coefficients");
881
+ rb_define_method(c_FirFilter, "denominator", paddlec_fir_filter_denominator, 0);
882
+ rb_define_method(c_FirFilter, "get_numerator_at", paddlec_fir_filter_get_coefficient_at, 1);
883
+ rb_define_method(c_FirFilter, "set_numerator_at", paddlec_fir_filter_set_coefficient_at, 2);
884
+ rb_define_method(c_FirFilter, "get_denominator_at", paddlec_fir_filter_get_denominator_at, 1);
885
+ rb_define_method(c_FirFilter, "set_denominator_at", paddlec_fir_filter_set_denominator_at, 2);
886
+
887
+ Init_paddlec_fir_transformer();
888
+ Init_paddlec_fir_decimator();
889
+ Init_paddlec_fir_interpolator();
890
+ }
891
+
892
+