roctave 0.0.1

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 (61) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +33 -0
  4. data/ext/roctave/cu8_file_reader.c +331 -0
  5. data/ext/roctave/cu8_file_reader.h +30 -0
  6. data/ext/roctave/extconf.rb +6 -0
  7. data/ext/roctave/fir_filter.c +795 -0
  8. data/ext/roctave/fir_filter.h +29 -0
  9. data/ext/roctave/freq_shifter.c +410 -0
  10. data/ext/roctave/freq_shifter.h +29 -0
  11. data/ext/roctave/iir_filter.c +462 -0
  12. data/ext/roctave/iir_filter.h +29 -0
  13. data/ext/roctave/roctave.c +38 -0
  14. data/ext/roctave/roctave.h +27 -0
  15. data/lib/roctave.rb +168 -0
  16. data/lib/roctave/bilinear.rb +92 -0
  17. data/lib/roctave/butter.rb +87 -0
  18. data/lib/roctave/cheby.rb +180 -0
  19. data/lib/roctave/cu8_file_reader.rb +45 -0
  20. data/lib/roctave/dft.rb +280 -0
  21. data/lib/roctave/filter.rb +64 -0
  22. data/lib/roctave/finite_difference_coefficients.rb +73 -0
  23. data/lib/roctave/fir.rb +121 -0
  24. data/lib/roctave/fir1.rb +134 -0
  25. data/lib/roctave/fir2.rb +246 -0
  26. data/lib/roctave/fir_design.rb +311 -0
  27. data/lib/roctave/firls.rb +380 -0
  28. data/lib/roctave/firpm.rb +499 -0
  29. data/lib/roctave/freq_shifter.rb +47 -0
  30. data/lib/roctave/freqz.rb +233 -0
  31. data/lib/roctave/iir.rb +80 -0
  32. data/lib/roctave/interp1.rb +78 -0
  33. data/lib/roctave/plot.rb +748 -0
  34. data/lib/roctave/poly.rb +46 -0
  35. data/lib/roctave/roots.rb +73 -0
  36. data/lib/roctave/sftrans.rb +157 -0
  37. data/lib/roctave/version.rb +3 -0
  38. data/lib/roctave/window.rb +116 -0
  39. data/roctave.gemspec +79 -0
  40. data/samples/butter.rb +12 -0
  41. data/samples/cheby.rb +28 -0
  42. data/samples/dft.rb +18 -0
  43. data/samples/differentiator.rb +48 -0
  44. data/samples/differentiator_frequency_scaling.rb +52 -0
  45. data/samples/fft.rb +40 -0
  46. data/samples/finite_difference_coefficient.rb +53 -0
  47. data/samples/fir1.rb +13 -0
  48. data/samples/fir2.rb +14 -0
  49. data/samples/fir2_windows.rb +29 -0
  50. data/samples/fir2bank.rb +30 -0
  51. data/samples/fir_low_pass.rb +44 -0
  52. data/samples/firls.rb +77 -0
  53. data/samples/firpm.rb +78 -0
  54. data/samples/hilbert_transformer.rb +20 -0
  55. data/samples/hilbert_transformer_frequency_scaling.rb +47 -0
  56. data/samples/plot.rb +45 -0
  57. data/samples/stem.rb +8 -0
  58. data/samples/type1.rb +25 -0
  59. data/samples/type3.rb +24 -0
  60. data/samples/windows.rb +25 -0
  61. metadata +123 -0
@@ -0,0 +1,29 @@
1
+ /* Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of Roctave
4
+ *
5
+ * Roctave 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
+ * Roctave 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 Roctave. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+
20
+ #ifndef FIR_FILTER_H
21
+ #define FIR_FILTER_H
22
+
23
+ #include <ruby.h>
24
+
25
+ extern VALUE c_FIR;
26
+
27
+ void Init_fir_filter();
28
+
29
+ #endif /* FIR_FILTER_H */
@@ -0,0 +1,410 @@
1
+ /* Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of Roctave
4
+ *
5
+ * Roctave 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
+ * Roctave 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 Roctave. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+
20
+ #include <ruby.h>
21
+ #include "roctave.h"
22
+ #include "freq_shifter.h"
23
+
24
+ VALUE c_FreqShifter;
25
+
26
+
27
+ static ID id_real;
28
+ static ID id_imag;
29
+ static ID id_freq;
30
+ static ID id_fs;
31
+ static ID id_initial_phase;
32
+
33
+
34
+ struct freq_shifter {
35
+ double phase;
36
+ double sampling_frequency;
37
+ double frequency;
38
+ double phase_increment;
39
+ };
40
+
41
+
42
+ static void freq_shifter_free(void *p)
43
+ {
44
+ struct freq_shifter *frqsh = (struct freq_shifter*)p;
45
+
46
+ xfree(frqsh);
47
+ }
48
+
49
+
50
+ static size_t freq_shifter_size(const void* data)
51
+ {
52
+ return sizeof(struct freq_shifter);
53
+ }
54
+
55
+
56
+ static const rb_data_type_t freq_shifter_type = {
57
+ .wrap_struct_name = "roctave_freq_shifter_struct",
58
+ .function = {
59
+ .dmark = NULL,
60
+ .dfree = freq_shifter_free,
61
+ .dsize = freq_shifter_size,
62
+ },
63
+ .data = NULL,
64
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
65
+ };
66
+
67
+
68
+ static VALUE freq_shifter_alloc(VALUE klass)
69
+ {
70
+ VALUE obj;
71
+ struct freq_shifter *frqsh;
72
+
73
+ frqsh = ZALLOC(struct freq_shifter);
74
+
75
+ obj = TypedData_Wrap_Struct(klass, &freq_shifter_type, frqsh);
76
+
77
+ frqsh->phase = 0.0;
78
+ frqsh->sampling_frequency = 1.0;
79
+ frqsh->frequency = 1.0;
80
+ frqsh->phase_increment = 2.0*M_PI*frqsh->frequency/frqsh->sampling_frequency;
81
+
82
+ return obj;
83
+ }
84
+
85
+
86
+ /* @overload initialize(freq: 0.5, fs: 1.0, initial_phase: 0.0)
87
+ * @param freq [Float] the amount of frequency to shift
88
+ * @param fs [Float] the sampling frequency
89
+ * @param initial_phase [Float] the initial phase of the oscillator
90
+ * @return [Roctave::FreqShifter]
91
+ */
92
+ static VALUE freq_shifter_initialize(int argc, VALUE *argv, VALUE self)
93
+ {
94
+ struct freq_shifter *frqsh;
95
+ VALUE hash;
96
+ const ID kwkeys[] = {id_freq, id_fs, id_initial_phase};
97
+ VALUE kwvalues[] = {Qundef, Qundef, Qundef};
98
+
99
+ // int i;
100
+ // for (i = 0; i < argc; i++)
101
+ // rb_warn("argv[%d] = %"PRIsVALUE, i, rb_class_name(rb_obj_class(argv[i])));
102
+
103
+ rb_scan_args(argc, argv, ":", &hash);
104
+
105
+ if (!NIL_P(hash))
106
+ rb_get_kwargs(hash, kwkeys, 0, 3, kwvalues);
107
+
108
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
109
+
110
+ if (kwvalues[0] != Qundef)
111
+ frqsh->frequency = NUM2DBL(kwvalues[0]);
112
+ else
113
+ frqsh->frequency = 0.5;
114
+
115
+ if (kwvalues[1] != Qundef)
116
+ if (NUM2DBL(kwvalues[1]) > 0.0) frqsh->sampling_frequency = NUM2DBL(kwvalues[1]);
117
+ else
118
+ frqsh->sampling_frequency = 1.0;
119
+
120
+ if (kwvalues[2] != Qundef)
121
+ frqsh->phase = fmod(NUM2DBL(kwvalues[2]), 2.0*M_PI);
122
+ else
123
+ frqsh->phase = 0.0;
124
+
125
+ frqsh->phase_increment = 2.0*M_PI*frqsh->frequency/frqsh->sampling_frequency;
126
+
127
+ // rb_warn(" ");
128
+ // rb_warn("phase = %g", frqsh->phase);
129
+ // rb_warn("frequency = %g", frqsh->frequency);
130
+ // rb_warn("sampling_frequency = %g", frqsh->sampling_frequency);
131
+ // rb_warn(" ");
132
+
133
+ return self;
134
+ }
135
+
136
+
137
+ /* Get the current phase of the oscillator.
138
+ * @return [Float] the current phase of the oscillator
139
+ */
140
+ static VALUE freq_shifter_get_phase(VALUE self)
141
+ {
142
+ struct freq_shifter *frqsh;
143
+
144
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
145
+
146
+ return DBL2NUM(frqsh->phase);
147
+ }
148
+
149
+
150
+ /* Set the current phase of the oscillator.
151
+ * @param phase [Float] the requested phase of the oscillator
152
+ * @return [Float] the phase of the oscillator
153
+ */
154
+ static VALUE freq_shifter_set_phase(VALUE self, VALUE phase)
155
+ {
156
+ struct freq_shifter *frqsh;
157
+
158
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
159
+
160
+ frqsh->phase = fmod(NUM2DBL(phase), 2.0*M_PI);
161
+
162
+ return DBL2NUM(frqsh->phase);
163
+ }
164
+
165
+
166
+ /* Get the sampling frequency
167
+ * @return [Float] the sampling frequency
168
+ */
169
+ static VALUE freq_shifter_get_sampling_frequency(VALUE self)
170
+ {
171
+ struct freq_shifter *frqsh;
172
+
173
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
174
+
175
+ return DBL2NUM(frqsh->sampling_frequency);
176
+ }
177
+
178
+
179
+ /* Set the sampling frequency
180
+ * @param fs [Float] the requested sampling frequency. Must be > 0.
181
+ * @return [Float] the sampling frequency
182
+ */
183
+ static VALUE freq_shifter_set_sampling_frequency(VALUE self, VALUE fs)
184
+ {
185
+ struct freq_shifter *frqsh;
186
+
187
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
188
+
189
+ if (NUM2DBL(fs) > 0.0)
190
+ frqsh->sampling_frequency = NUM2DBL(fs);
191
+
192
+ frqsh->phase_increment = 2.0*M_PI*frqsh->frequency/frqsh->sampling_frequency;
193
+
194
+ return DBL2NUM(frqsh->sampling_frequency);
195
+ }
196
+
197
+
198
+ /* Get the frequency
199
+ * @return [Float] the frequency
200
+ */
201
+ static VALUE freq_shifter_get_frequency(VALUE self)
202
+ {
203
+ struct freq_shifter *frqsh;
204
+
205
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
206
+
207
+ return DBL2NUM(frqsh->frequency);
208
+ }
209
+
210
+
211
+ /* Set the frequency
212
+ * @param f [Float] the requested frequency. Must be > 0.
213
+ * @return [Float] the frequency
214
+ */
215
+ static VALUE freq_shifter_set_frequency(VALUE self, VALUE f)
216
+ {
217
+ struct freq_shifter *frqsh;
218
+
219
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
220
+
221
+ frqsh->sampling_frequency = NUM2DBL(f);
222
+
223
+ frqsh->phase_increment = 2.0*M_PI*frqsh->frequency/frqsh->sampling_frequency;
224
+
225
+ return DBL2NUM(frqsh->frequency);
226
+ }
227
+
228
+
229
+ static VALUE freq_shifter_shift_one_sample(struct freq_shifter *frqsh, VALUE sample)
230
+ {
231
+ const double i = cos(frqsh->phase);
232
+ const double q = sin(frqsh->phase);
233
+ double real, imag;
234
+ VALUE res;
235
+
236
+ if (rb_class_of(sample) == rb_cComplex) {
237
+ real = NUM2DBL(rb_funcallv(sample, id_real, 0, NULL));
238
+ imag = NUM2DBL(rb_funcallv(sample, id_imag, 0, NULL));
239
+ res = rb_complex_raw(
240
+ DBL2NUM(real*i - imag*q),
241
+ DBL2NUM(real*q + imag*i));
242
+ }
243
+ else {
244
+ real = NUM2DBL(sample);
245
+ res = rb_complex_raw(
246
+ DBL2NUM(real*i),
247
+ DBL2NUM(real*q));
248
+ }
249
+
250
+ frqsh->phase = fmod(frqsh->phase + frqsh->phase_increment, 2*M_PI);
251
+
252
+ return res;
253
+ }
254
+
255
+
256
+ static VALUE freq_shifter_am_one_sample(struct freq_shifter *frqsh, VALUE sample)
257
+ {
258
+ const double i = cos(frqsh->phase);
259
+ double real, imag;
260
+ VALUE res;
261
+
262
+ if (rb_class_of(sample) == rb_cComplex) {
263
+ real = NUM2DBL(rb_funcallv(sample, id_real, 0, NULL));
264
+ imag = NUM2DBL(rb_funcallv(sample, id_imag, 0, NULL));
265
+ res = rb_complex_raw(
266
+ DBL2NUM(real*i),
267
+ DBL2NUM(imag*i));
268
+ }
269
+ else
270
+ res = DBL2NUM(NUM2DBL(sample) * i);
271
+
272
+ frqsh->phase = fmod(frqsh->phase + frqsh->phase_increment, 2*M_PI);
273
+
274
+ return res;
275
+ }
276
+
277
+
278
+ /* Multiply the signal with exp(2*i*pi*f*t)
279
+ * @param signal [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
280
+ * @return [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
281
+ */
282
+ static VALUE freq_shifter_shift(VALUE self, VALUE sig)
283
+ {
284
+ struct freq_shifter *frqsh;
285
+ VALUE res;
286
+ int len, i;
287
+
288
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
289
+
290
+ if (rb_class_of(sig) == rb_cArray) {
291
+ len = rb_array_len(sig);
292
+ res = rb_ary_new_capa(len);
293
+ for (i = 0; i < len; i++)
294
+ rb_ary_store(res, i, freq_shifter_shift_one_sample(frqsh, rb_ary_entry(sig, i)));
295
+ }
296
+ else {
297
+ res = freq_shifter_shift_one_sample(frqsh, sig);
298
+ }
299
+
300
+ return res;
301
+ }
302
+
303
+
304
+ /* Multiply the signal with cos(2*i*pi*f*t)
305
+ * @param signal [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
306
+ * @return [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
307
+ */
308
+ static VALUE freq_shifter_am(VALUE self, VALUE sig)
309
+ {
310
+ struct freq_shifter *frqsh;
311
+ VALUE res;
312
+ int len, i;
313
+
314
+ TypedData_Get_Struct(self, struct freq_shifter, &freq_shifter_type, frqsh);
315
+
316
+ if (rb_class_of(sig) == rb_cArray) {
317
+ len = rb_array_len(sig);
318
+ res = rb_ary_new_capa(len);
319
+ for (i = 0; i < len; i++)
320
+ rb_ary_store(res, i, freq_shifter_am_one_sample(frqsh, rb_ary_entry(sig, i)));
321
+ }
322
+ else {
323
+ res = freq_shifter_am_one_sample(frqsh, sig);
324
+ }
325
+
326
+ return res;
327
+ }
328
+
329
+
330
+ #if 0
331
+ // Makes segmentation faults, maybe because rbo is garbage collected
332
+ // befor it can finish its shift.
333
+
334
+ /* Multiply the signal with exp(2*i*pi*f*t)
335
+ * @overload shift(signal, freq: 0.5, fs: 1.0, initial_phase: 0.0)
336
+ * @param signal [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
337
+ * @param freq [Float] the amount of frequency to shift
338
+ * @param fs [Float] the sampling frequency
339
+ * @param initial_phase [Float] the initial phase of the oscillator
340
+ * @return [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
341
+ */
342
+ static VALUE freq_shifter_module_shift(int argc, VALUE *argv, VALUE self)
343
+ {
344
+ VALUE sig;
345
+ VALUE hash;
346
+ VALUE rbo;
347
+ VALUE res;
348
+
349
+ rb_scan_args(argc, argv, "1:", &sig, &hash);
350
+
351
+ if (NIL_P(hash))
352
+ hash = rb_hash_new();
353
+
354
+ rbo = rb_class_new_instance(1, &hash, c_FreqShifter);
355
+ res = freq_shifter_shift(rbo, sig);
356
+
357
+ return res;
358
+ }
359
+
360
+
361
+ /* Multiply the signal with cos(2*i*pi*f*t)
362
+ * @overload shift(signal, freq: 0.5, fs: 1.0, initial_phase: 0.0)
363
+ * @param signal [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
364
+ * @param freq [Float] the amount of frequency to shift
365
+ * @param fs [Float] the sampling frequency
366
+ * @param initial_phase [Float] the initial phase of the oscillator
367
+ * @return [Array<Float,Complex>, Float, Complex] a single or and array of float or complex numbers
368
+ */
369
+ static VALUE freq_shifter_module_am(int argc, VALUE *argv, VALUE self)
370
+ {
371
+ VALUE sig;
372
+ VALUE hash;
373
+ VALUE rbo;
374
+
375
+ rb_scan_args(argc, argv, "1:", &sig, &hash);
376
+
377
+ if (NIL_P(hash))
378
+ hash = rb_hash_new();
379
+
380
+ rbo = rb_class_new_instance(1, &hash, c_FreqShifter);
381
+
382
+ return freq_shifter_am(rbo, sig);
383
+ }
384
+ #endif
385
+
386
+
387
+ void Init_freq_shifter()
388
+ {
389
+ id_real = rb_intern("real");
390
+ id_imag = rb_intern("imag");
391
+ id_freq = rb_intern("freq");
392
+ id_fs = rb_intern("fs");
393
+ id_initial_phase = rb_intern("initial_phase");
394
+
395
+ c_FreqShifter = rb_define_class_under(m_Roctave, "FreqShifter", rb_cData);
396
+
397
+ rb_define_alloc_func(c_FreqShifter, freq_shifter_alloc);
398
+ //rb_define_singleton_method(c_FreqShifter, "shift", freq_shifter_module_shift, -1);
399
+ //rb_define_singleton_method(c_FreqShifter, "amplitude_modulate", freq_shifter_module_am, -1);
400
+ rb_define_method(c_FreqShifter, "initialize", freq_shifter_initialize, -1);
401
+ rb_define_method(c_FreqShifter, "shift", freq_shifter_shift, 1);
402
+ rb_define_method(c_FreqShifter, "amplitude_modulate", freq_shifter_am, 1);
403
+ rb_define_method(c_FreqShifter, "frequency", freq_shifter_get_frequency, 0);
404
+ rb_define_method(c_FreqShifter, "frequency=", freq_shifter_set_frequency, 1);
405
+ rb_define_method(c_FreqShifter, "sampling_frequency", freq_shifter_get_sampling_frequency, 0);
406
+ rb_define_method(c_FreqShifter, "sampling_frequency=", freq_shifter_set_sampling_frequency, 1);
407
+ rb_define_method(c_FreqShifter, "phase", freq_shifter_get_phase, 0);
408
+ rb_define_method(c_FreqShifter, "phase=", freq_shifter_set_phase, 1);
409
+ }
410
+
@@ -0,0 +1,29 @@
1
+ /* Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ *
3
+ * This file is part of Roctave
4
+ *
5
+ * Roctave 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
+ * Roctave 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 Roctave. If not, see <https://www.gnu.org/licenses/>.
17
+ */
18
+
19
+
20
+ #ifndef FREQ_SHIFTER_H
21
+ #define FREQ_SHIFTER_H
22
+
23
+ #include <ruby.h>
24
+
25
+ extern VALUE c_FreqShifter;
26
+
27
+ void Init_freq_shifter();
28
+
29
+ #endif /* FREQ_SHIFTER_H */