beeps 0.3.6 → 0.3.7

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 (67) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/beeps/beeps.cpp +7 -0
  3. data/.doc/ext/beeps/high_pass.cpp +63 -0
  4. data/.doc/ext/beeps/low_pass.cpp +63 -0
  5. data/.doc/ext/beeps/native.cpp +8 -0
  6. data/.doc/ext/beeps/oscillator.cpp +87 -10
  7. data/.doc/ext/beeps/processor.cpp +14 -1
  8. data/.doc/ext/beeps/reverb.cpp +99 -0
  9. data/.doc/ext/beeps/signals.cpp +128 -0
  10. data/ChangeLog.md +24 -0
  11. data/Rakefile +1 -1
  12. data/VERSION +1 -1
  13. data/beeps.gemspec +2 -2
  14. data/ext/beeps/beeps.cpp +8 -0
  15. data/ext/beeps/high_pass.cpp +66 -0
  16. data/ext/beeps/low_pass.cpp +66 -0
  17. data/ext/beeps/native.cpp +8 -0
  18. data/ext/beeps/oscillator.cpp +95 -12
  19. data/ext/beeps/processor.cpp +15 -1
  20. data/ext/beeps/reverb.cpp +106 -0
  21. data/ext/beeps/signals.cpp +136 -0
  22. data/include/beeps/beeps.h +2 -2
  23. data/include/beeps/defs.h +3 -0
  24. data/include/beeps/filter.h +118 -17
  25. data/include/beeps/generator.h +50 -17
  26. data/include/beeps/processor.h +23 -6
  27. data/include/beeps/ruby/filter.h +33 -0
  28. data/include/beeps/ruby/signals.h +40 -0
  29. data/include/beeps/signals.h +1 -1
  30. data/lib/beeps/processor.rb +46 -1
  31. data/lib/beeps/signals.rb +19 -0
  32. data/lib/beeps.rb +1 -0
  33. data/src/analyser.cpp +34 -37
  34. data/src/beeps.cpp +7 -6
  35. data/src/envelope.cpp +60 -46
  36. data/src/file_in.cpp +6 -6
  37. data/src/gain.cpp +5 -5
  38. data/src/high_pass.cpp +57 -0
  39. data/src/low_pass.cpp +57 -0
  40. data/src/mic_in.cpp +16 -14
  41. data/src/mixer.cpp +38 -20
  42. data/src/oscillator.cpp +260 -168
  43. data/src/pitch_shift.cpp +6 -6
  44. data/src/processor.cpp +118 -11
  45. data/src/processor.h +8 -0
  46. data/src/reverb.cpp +124 -0
  47. data/src/sequencer.cpp +18 -14
  48. data/src/signals.cpp +264 -106
  49. data/src/signals.h +28 -89
  50. data/src/sound.cpp +28 -20
  51. data/src/time_stretch.cpp +6 -6
  52. data/src/win32/signals.cpp +8 -7
  53. data/src/x_pass.h +51 -0
  54. data/test/helper.rb +14 -0
  55. data/test/test_analyser.rb +26 -0
  56. data/test/test_envelope.rb +55 -0
  57. data/test/test_file_in.rb +22 -1
  58. data/test/test_gain.rb +28 -0
  59. data/test/test_high_pass.rb +41 -0
  60. data/test/test_low_pass.rb +41 -0
  61. data/test/test_mixer.rb +63 -0
  62. data/test/test_oscillator.rb +58 -0
  63. data/test/test_pitch_shift.rb +32 -0
  64. data/test/test_processor.rb +7 -0
  65. data/test/test_signals.rb +60 -0
  66. data/test/test_time_stretch.rb +36 -0
  67. metadata +48 -10
data/src/processor.cpp CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <assert.h>
5
5
  #include <xot/time.h>
6
+ #include "beeps/beeps.h"
6
7
  #include "beeps/exception.h"
7
8
  #include "beeps/debug.h"
8
9
 
@@ -14,7 +15,7 @@ namespace Beeps
14
15
  struct Processor::Data
15
16
  {
16
17
 
17
- bool generator = false, started = false;
18
+ bool generator = false, started = false, processing = false;
18
19
 
19
20
  float buffering_seconds = 0;
20
21
 
@@ -22,9 +23,33 @@ namespace Beeps
22
23
 
23
24
  Processor::Ref input;
24
25
 
26
+ Processor::Map sub_inputs;
27
+
25
28
  };// Processor::Data
26
29
 
27
30
 
31
+ Signals
32
+ get_signals (
33
+ Processor* processor, float seconds, uint nchannels, double sample_rate)
34
+ {
35
+ if (sample_rate == 0)
36
+ sample_rate = Beeps::sample_rate();
37
+
38
+ if (!processor)
39
+ argument_error(__FILE__, __LINE__);
40
+ if (!*processor)
41
+ argument_error(__FILE__, __LINE__);
42
+ if (seconds <= 0)
43
+ argument_error(__FILE__, __LINE__);
44
+ if (nchannels <= 0)
45
+ argument_error(__FILE__, __LINE__);
46
+ if (sample_rate <= 0)
47
+ argument_error(__FILE__, __LINE__);
48
+
49
+ StreamContext context(seconds * sample_rate, nchannels, sample_rate);
50
+ return context.process_next(processor);
51
+ }
52
+
28
53
  ProcessorContext*
29
54
  Processor_get_context(Processor::Context* context)
30
55
  {
@@ -53,7 +78,12 @@ namespace Beeps
53
78
  Processor::reset ()
54
79
  {
55
80
  self->started = false;
56
- if (self->input) self->input->reset();
81
+
82
+ if (self->input)
83
+ self->input->reset();
84
+
85
+ for (auto& kv : self->sub_inputs)
86
+ kv.second->reset();
57
87
 
58
88
  set_updated();
59
89
  }
@@ -62,7 +92,7 @@ namespace Beeps
62
92
  Processor::set_input (Processor* input)
63
93
  {
64
94
  if (input && self->generator)
65
- invalid_state_error(__FILE__, __LINE__, "generator cannot have inputs");
95
+ invalid_state_error(__FILE__, __LINE__, "generator cannot have input");
66
96
 
67
97
  self->input = input;
68
98
 
@@ -75,17 +105,17 @@ namespace Beeps
75
105
  return self->input;
76
106
  }
77
107
 
78
- void
79
- Processor::on_start ()
80
- {
81
- }
82
-
83
108
  const Processor*
84
109
  Processor::input () const
85
110
  {
86
111
  return const_cast<Processor*>(this)->input();
87
112
  }
88
113
 
114
+ void
115
+ Processor::on_start ()
116
+ {
117
+ }
118
+
89
119
  Processor::operator bool () const
90
120
  {
91
121
  return self->generator || (self->input && *self->input);
@@ -106,10 +136,14 @@ namespace Beeps
106
136
  on_start();
107
137
  }
108
138
 
139
+ self->processing = true;
140
+
109
141
  if (self->generator)
110
142
  generate(context, signals, offset);
111
143
  else
112
144
  filter(context, signals, offset);
145
+
146
+ self->processing = false;
113
147
  }
114
148
 
115
149
  void
@@ -151,6 +185,56 @@ namespace Beeps
151
185
  Processor_get_context(context)->process(self->input, signals, offset);
152
186
  }
153
187
 
188
+ int
189
+ Processor::max_segment_size_for_process (
190
+ double sample_rate, uint nsamples) const
191
+ {
192
+ return -1;
193
+ }
194
+
195
+ uint
196
+ Processor::get_segment_size (double sample_rate, uint nsamples) const
197
+ {
198
+ uint size = nsamples;
199
+ for (const auto& kv : self->sub_inputs)
200
+ {
201
+ const auto& processor = kv.second;
202
+
203
+ int max = processor->max_segment_size_for_process(sample_rate, nsamples);
204
+ if (max > 0 && (uint) max < size)
205
+ size = (uint) max;
206
+ }
207
+ return size;
208
+ }
209
+
210
+ void
211
+ Processor::set_sub_input (uint index, Processor* input)
212
+ {
213
+ if (input)
214
+ self->sub_inputs[index] = input;
215
+ else
216
+ self->sub_inputs.erase(index);
217
+
218
+ set_updated();
219
+ }
220
+
221
+ Processor*
222
+ Processor::sub_input (uint index) const
223
+ {
224
+ auto it = self->sub_inputs.find(index);
225
+ if (it == self->sub_inputs.end())
226
+ return NULL;
227
+
228
+ return it->second;
229
+ }
230
+
231
+ void
232
+ Processor::clear_sub_input_unless_processing (uint index)
233
+ {
234
+ if (!self->processing)
235
+ set_sub_input(index, NULL);
236
+ }
237
+
154
238
  void
155
239
  Processor::set_updated ()
156
240
  {
@@ -263,6 +347,28 @@ namespace Beeps
263
347
  {
264
348
  }
265
349
 
350
+ Sample
351
+ ProcessorContext::process (
352
+ Processor* processor, uint nsamples, uint offset, bool ignore_buffer)
353
+ {
354
+ assert(processor);
355
+
356
+ if (!signal) signal = Signals_create(nsamples, 1, sample_rate);
357
+ Signals_clear(&signal, nsamples);
358
+
359
+ SignalsBuffer* buffer = NULL;
360
+ uint offset_ = offset;
361
+ if (!ignore_buffer && (buffer = get_buffer(processor)))
362
+ buffer->process(this, processor, &signal, &offset_);
363
+ else
364
+ processor->process(this, &signal, &offset_);
365
+
366
+ if (offset_ == offset || signal.empty())
367
+ return 0;
368
+
369
+ return *signal.samples();
370
+ }
371
+
266
372
  void
267
373
  ProcessorContext::process (
268
374
  Processor* processor, Signals* signals, uint* offset, bool ignore_buffer)
@@ -305,7 +411,8 @@ namespace Beeps
305
411
  StreamContext::StreamContext (
306
412
  uint nsamples_per_process, uint nchannels, double sample_rate)
307
413
  : context(nchannels, sample_rate),
308
- signals(Signals_create(nsamples_per_process, nchannels, sample_rate))
414
+ signals(Signals_create(nsamples_per_process, nchannels, sample_rate)),
415
+ nsamples_per_process(nsamples_per_process)
309
416
  {
310
417
  }
311
418
 
@@ -314,10 +421,10 @@ namespace Beeps
314
421
  {
315
422
  assert(processor);
316
423
 
317
- Signals_clear(&signals);
424
+ Signals_clear(&signals, nsamples_per_process);
318
425
  context.process(processor, &signals, &offset);
319
426
 
320
- if (signals.nsamples() < signals.capacity())
427
+ if (signals.nsamples() < nsamples_per_process)
321
428
  finished = true;
322
429
 
323
430
  return signals;
data/src/processor.h CHANGED
@@ -60,6 +60,10 @@ namespace Beeps
60
60
 
61
61
  ProcessorContext (uint nchannels, double sample_rate);
62
62
 
63
+ Sample process (
64
+ Processor* processor, uint nsamples, uint offset = 0,
65
+ bool ignore_buffer = false);
66
+
63
67
  void process (
64
68
  Processor* processor, Signals* signals, uint* offset,
65
69
  bool ignore_buffer = false);
@@ -70,6 +74,8 @@ namespace Beeps
70
74
 
71
75
  uint nchannels;
72
76
 
77
+ Signals signal;
78
+
73
79
  std::map<uintptr_t, std::unique_ptr<SignalsBuffer>> buffers;
74
80
 
75
81
  SignalsBuffer* get_buffer (Processor* processor);
@@ -99,6 +105,8 @@ namespace Beeps
99
105
 
100
106
  Signals signals;
101
107
 
108
+ uint nsamples_per_process;
109
+
102
110
  uint offset = 0;
103
111
 
104
112
  bool finished = false;
data/src/reverb.cpp ADDED
@@ -0,0 +1,124 @@
1
+ #include "beeps/filter.h"
2
+
3
+
4
+ #include <FreeVerb.h>
5
+ #include "beeps/exception.h"
6
+ #include "signals.h"
7
+
8
+
9
+ namespace Beeps
10
+ {
11
+
12
+
13
+ struct Reverb::Data
14
+ {
15
+
16
+ stk::FreeVerb freeverb;
17
+
18
+ float mix = 0.75;
19
+
20
+ float room_size = 0.75;
21
+
22
+ float damping = 0.25;
23
+
24
+ };// Reverb::Data
25
+
26
+
27
+ Reverb::Reverb (Processor* input)
28
+ : Super(input)
29
+ {
30
+ }
31
+
32
+ Reverb::~Reverb ()
33
+ {
34
+ }
35
+
36
+ void
37
+ Reverb::set_mix (float mix)
38
+ {
39
+ if (mix < 0)
40
+ argument_error(__FILE__, __LINE__);
41
+ if (mix > 1)
42
+ argument_error(__FILE__, __LINE__);
43
+
44
+ if (mix == self->mix)
45
+ return;
46
+
47
+ self->mix = mix;
48
+ set_updated();
49
+ }
50
+
51
+ float
52
+ Reverb::mix () const
53
+ {
54
+ return self->mix;
55
+ }
56
+
57
+ void
58
+ Reverb::set_room_size (float size)
59
+ {
60
+ if (size < 0)
61
+ argument_error(__FILE__, __LINE__);
62
+ if (size > 1)
63
+ argument_error(__FILE__, __LINE__);
64
+
65
+ if (size == self->room_size)
66
+ return;
67
+
68
+ self->room_size = size;
69
+ set_updated();
70
+ }
71
+
72
+ float
73
+ Reverb::room_size () const
74
+ {
75
+ return self->room_size;
76
+ }
77
+
78
+ void
79
+ Reverb::set_damping (float damping)
80
+ {
81
+ if (damping < 0)
82
+ argument_error(__FILE__, __LINE__);
83
+ if (damping > 1)
84
+ argument_error(__FILE__, __LINE__);
85
+
86
+ if (damping == self->damping)
87
+ return;
88
+
89
+ self->damping = damping;
90
+ set_updated();
91
+ }
92
+
93
+ float
94
+ Reverb::damping () const
95
+ {
96
+ return self->damping;
97
+ }
98
+
99
+ void
100
+ Reverb::filter (Context* context, Signals* signals, uint* offset)
101
+ {
102
+ Super::filter(context, signals, offset);
103
+
104
+ self->freeverb.setEffectMix(self->mix);
105
+ self->freeverb.setRoomSize( self->room_size);
106
+ self->freeverb.setDamping( self->damping);
107
+
108
+ uint nchannels = signals->nchannels();
109
+ Signals filtered = Signals_create(
110
+ signals->nsamples(), nchannels, signals->sample_rate());
111
+
112
+ Signals_tick(
113
+ &filtered, *signals,
114
+ [&](stk::StkFrames* out, const stk::StkFrames& in)
115
+ {
116
+ for (uint ch = 0; ch < nchannels; ++ch)
117
+ self->freeverb.tick(const_cast<stk::StkFrames&>(in), *out, ch, ch);
118
+ });
119
+
120
+ *signals = filtered;
121
+ }
122
+
123
+
124
+ }// Beeps
data/src/sequencer.cpp CHANGED
@@ -63,6 +63,8 @@ namespace Beeps
63
63
  }
64
64
  }
65
65
  notes.emplace_back(processor, offset, duration);
66
+
67
+ set_updated();
66
68
  }
67
69
 
68
70
  void
@@ -76,6 +78,8 @@ namespace Beeps
76
78
  if (it == self->notes.end()) return;
77
79
 
78
80
  self->notes.erase(it);
81
+
82
+ set_updated();
79
83
  }
80
84
 
81
85
  void
@@ -85,6 +89,8 @@ namespace Beeps
85
89
  argument_error(__FILE__, __LINE__, "time_scale must be greater than 0");
86
90
 
87
91
  self->time_scale = time_scale;
92
+
93
+ set_updated();
88
94
  }
89
95
 
90
96
  float
@@ -93,16 +99,20 @@ namespace Beeps
93
99
  return self->time_scale;
94
100
  }
95
101
 
102
+ Sequencer::operator bool () const
103
+ {
104
+ if (!Super::operator bool()) return false;
105
+ return self->time_scale > 0;
106
+ }
107
+
96
108
  static void
97
109
  mix (Signals* mixed, const Signals& source, uint source_offset)
98
110
  {
99
- Frames* mixf = Signals_get_frames(mixed);
100
- Frames* srcf = Signals_get_frames(const_cast<Signals*>(&source));
101
- Float* mixp = &(*mixf)(source_offset, 0);
102
- Float* srcp = &(*srcf)(0, 0);
103
- uint size = source.nsamples() * source.nchannels();
104
- for (uint i = 0; i < size; ++i, ++mixp, ++srcp)
105
- *mixp += *srcp;
111
+ Sample* mix_p = Signals_at(mixed, source_offset);
112
+ const Sample* src_p = Signals_at(source, 0);
113
+ uint size = source.nsamples() * source.nchannels();
114
+ for (uint i = 0; i < size; ++i, ++mix_p, ++src_p)
115
+ *mix_p += *src_p;
106
116
  }
107
117
 
108
118
  void
@@ -112,7 +122,7 @@ namespace Beeps
112
122
 
113
123
  auto& context = *Processor_get_context(pcontext);
114
124
  auto& signals = *psignals;
115
- Signals_resize(&signals, signals.capacity(), 0);
125
+ Signals_fill(&signals, signals.capacity(), 0);
116
126
 
117
127
  uint generate_begin = *offset;
118
128
  uint generate_end = *offset + signals.capacity();
@@ -150,11 +160,5 @@ namespace Beeps
150
160
  *offset += nsamples;
151
161
  }
152
162
 
153
- Sequencer::operator bool () const
154
- {
155
- if (!Super::operator bool()) return false;
156
- return self->time_scale > 0;
157
- }
158
-
159
163
 
160
164
  }// Beeps