beeps 0.1.32 → 0.1.34

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/beeps/adsr.cpp +139 -0
  3. data/.doc/ext/beeps/analyser.cpp +128 -0
  4. data/.doc/ext/beeps/beeps.cpp +9 -1
  5. data/.doc/ext/beeps/file_in.cpp +55 -9
  6. data/.doc/ext/beeps/gain.cpp +64 -0
  7. data/.doc/ext/beeps/mic_in.cpp +83 -0
  8. data/.doc/ext/beeps/native.cpp +20 -8
  9. data/.doc/ext/beeps/oscillator.cpp +88 -0
  10. data/.doc/ext/beeps/pitch_shift.cpp +64 -0
  11. data/.doc/ext/beeps/processor.cpp +31 -2
  12. data/.doc/ext/beeps/sound.cpp +90 -7
  13. data/.doc/ext/beeps/sound_player.cpp +156 -0
  14. data/.doc/ext/beeps/time_stretch.cpp +64 -0
  15. data/.github/workflows/release-gem.yml +4 -1
  16. data/ChangeLog.md +14 -0
  17. data/Rakefile +26 -4
  18. data/VERSION +1 -1
  19. data/beeps.gemspec +2 -2
  20. data/ext/beeps/adsr.cpp +150 -0
  21. data/ext/beeps/analyser.cpp +134 -0
  22. data/ext/beeps/beeps.cpp +10 -1
  23. data/ext/beeps/extconf.rb +1 -2
  24. data/ext/beeps/file_in.cpp +60 -9
  25. data/ext/beeps/gain.cpp +67 -0
  26. data/ext/beeps/mic_in.cpp +88 -0
  27. data/ext/beeps/native.cpp +20 -8
  28. data/ext/beeps/oscillator.cpp +93 -0
  29. data/ext/beeps/pitch_shift.cpp +67 -0
  30. data/ext/beeps/processor.cpp +34 -2
  31. data/ext/beeps/sound.cpp +99 -7
  32. data/ext/beeps/sound_player.cpp +169 -0
  33. data/ext/beeps/time_stretch.cpp +67 -0
  34. data/include/beeps/beeps.h +2 -1
  35. data/include/beeps/filter.h +179 -0
  36. data/include/beeps/generator.h +120 -0
  37. data/include/beeps/processor.h +37 -68
  38. data/include/beeps/ruby/filter.h +78 -0
  39. data/include/beeps/ruby/generator.h +60 -0
  40. data/include/beeps/ruby/processor.h +5 -45
  41. data/include/beeps/ruby/sound.h +14 -3
  42. data/include/beeps/signals.h +10 -4
  43. data/include/beeps/sound.h +67 -2
  44. data/lib/beeps/beeps.rb +6 -1
  45. data/lib/beeps/processor.rb +95 -15
  46. data/lib/beeps/sound.rb +29 -2
  47. data/src/adsr.cpp +245 -0
  48. data/src/analyser.cpp +254 -0
  49. data/src/beeps.cpp +14 -2
  50. data/src/file_in.cpp +94 -0
  51. data/src/gain.cpp +55 -0
  52. data/src/mic_in.cpp +271 -0
  53. data/src/mic_in.h +22 -0
  54. data/src/openal.cpp +1 -2
  55. data/src/oscillator.cpp +145 -0
  56. data/src/osx/signals.mm +83 -0
  57. data/src/pitch_shift.cpp +82 -0
  58. data/src/processor.cpp +202 -88
  59. data/src/processor.h +98 -0
  60. data/src/signals.cpp +326 -20
  61. data/src/signals.h +192 -2
  62. data/src/sound.cpp +735 -113
  63. data/src/sound.h +6 -1
  64. data/src/time_stretch.cpp +91 -0
  65. data/test/helper.rb +2 -1
  66. data/test/test_beeps.rb +10 -7
  67. data/test/test_beeps_init.rb +18 -0
  68. data/test/test_file_in.rb +15 -0
  69. data/test/test_processor.rb +50 -0
  70. data/test/test_sound.rb +87 -11
  71. data/test/test_sound_player.rb +134 -0
  72. metadata +54 -16
  73. data/.doc/ext/beeps/sawtooth_wave.cpp +0 -61
  74. data/.doc/ext/beeps/sine_wave.cpp +0 -61
  75. data/.doc/ext/beeps/square_wave.cpp +0 -61
  76. data/ext/beeps/sawtooth_wave.cpp +0 -64
  77. data/ext/beeps/sine_wave.cpp +0 -64
  78. data/ext/beeps/square_wave.cpp +0 -64
data/src/processor.cpp CHANGED
@@ -1,200 +1,314 @@
1
- #include "beeps/processor.h"
1
+ #include "processor.h"
2
2
 
3
3
 
4
- #include "SineWave.h"
5
- #include "BlitSaw.h"
6
- #include "BlitSquare.h"
7
- #include "FileWvIn.h"
4
+ #include "xot/time.h"
8
5
  #include "beeps/exception.h"
9
- #include "signals.h"
10
6
 
11
7
 
12
8
  namespace Beeps
13
9
  {
14
10
 
15
11
 
16
- Processor::Processor ()
12
+ static ProcessorContext*
13
+ get_context(Processor::Context* context)
17
14
  {
15
+ return (ProcessorContext*) context;
18
16
  }
19
17
 
20
- Processor::~Processor ()
18
+
19
+ struct Processor::Data
21
20
  {
22
- }
23
21
 
24
- void
25
- Processor::process (Signals* signals)
22
+ bool generator = false;
23
+
24
+ float buffering_seconds = 0;
25
+
26
+ double last_update_time = 0;
27
+
28
+ Processor::Ref input;
29
+
30
+ bool has_generator () const
31
+ {
32
+ return generator || (input && input->self->has_generator());
33
+ }
34
+
35
+ };// Processor::Data
36
+
37
+
38
+ float
39
+ Processor_get_buffering_seconds (Processor* processor)
26
40
  {
27
- if (!signals || !*signals)
28
- argument_error(__FILE__, __LINE__);
41
+ assert(processor);
29
42
 
30
- if (!*this)
31
- invalid_state_error(__FILE__, __LINE__);
43
+ return processor->self->buffering_seconds;
32
44
  }
33
45
 
34
- Processor::operator bool () const
46
+
47
+ Processor::Processor (bool generator)
35
48
  {
36
- return true;
49
+ self->generator = generator;
37
50
  }
38
51
 
39
- bool
40
- Processor::operator ! () const
52
+ Processor::~Processor ()
41
53
  {
42
- return !operator bool();
43
54
  }
44
55
 
45
-
46
- struct SineWave::Data
56
+ void
57
+ Processor::reset ()
47
58
  {
59
+ if (self->input) self->input->reset();
48
60
 
49
- stk::SineWave oscillator;
61
+ set_updated();
62
+ }
50
63
 
51
- float frequency;
64
+ void
65
+ Processor::set_input (Processor* input)
66
+ {
67
+ if (input && self->generator)
68
+ invalid_state_error(__FILE__, __LINE__, "generator cannot have inputs");
52
69
 
53
- };// SineWave::Data
70
+ self->input = input;
54
71
 
72
+ set_updated();
73
+ }
55
74
 
56
- SineWave::SineWave ()
75
+ Processor*
76
+ Processor::input ()
57
77
  {
58
- set_frequency(440);
78
+ return self->input;
59
79
  }
60
80
 
61
- SineWave::~SineWave ()
81
+ const Processor*
82
+ Processor::input () const
62
83
  {
84
+ return const_cast<Processor*>(this)->input();
63
85
  }
64
86
 
65
- void
66
- SineWave::set_frequency (float frequency)
87
+ Processor::operator bool () const
67
88
  {
68
- self->frequency = frequency;
69
- self->oscillator.setFrequency(frequency);
89
+ return self->has_generator();
70
90
  }
71
91
 
72
- float
73
- SineWave::frequency () const
92
+ bool
93
+ Processor::operator ! () const
74
94
  {
75
- return self->frequency;
95
+ return !operator bool();
76
96
  }
77
97
 
78
98
  void
79
- SineWave::process (Signals* signals)
99
+ Processor::process (Context* context, Signals* signals, uint* offset)
80
100
  {
81
- Super::process(signals);
82
-
83
- self->oscillator.tick(*Signals_get_frames(signals));
101
+ if (self->generator)
102
+ generate(context, signals, offset);
103
+ else
104
+ filter(context, signals, offset);
84
105
  }
85
106
 
86
-
87
- struct SquareWave::Data
107
+ void
108
+ Processor::generate (Context* context, Signals* signals, uint* offset)
88
109
  {
110
+ if (!context || !signals || !*signals || signals->nsamples() > 0 || !offset)
111
+ argument_error(__FILE__, __LINE__);
89
112
 
90
- stk::BlitSquare oscillator;
113
+ if (!*this || self->input)
114
+ invalid_state_error(__FILE__, __LINE__);
115
+ }
91
116
 
92
- float frequency;
117
+ void
118
+ Processor::filter (Context* context, Signals* signals, uint* offset)
119
+ {
120
+ if (!context || !signals || !*signals || !offset)
121
+ argument_error(__FILE__, __LINE__);
93
122
 
94
- };// SquareWave::Data
123
+ if (!*this)
124
+ invalid_state_error(__FILE__, __LINE__);
95
125
 
126
+ if (self->input)
127
+ get_context(context)->process(self->input, signals, offset);
128
+ }
96
129
 
97
- SquareWave::SquareWave ()
130
+ void
131
+ Processor::set_updated ()
98
132
  {
99
- set_frequency(440);
133
+ self->last_update_time = Xot::time();
100
134
  }
101
135
 
102
- SquareWave::~SquareWave ()
136
+
137
+ Generator::Generator ()
138
+ : Super(true)
103
139
  {
104
140
  }
105
141
 
106
142
  void
107
- SquareWave::set_frequency (float frequency)
143
+ Generator::filter (Context* context, Signals* signals, uint* offset)
108
144
  {
109
- self->frequency = frequency;
110
- self->oscillator.setFrequency(frequency);
145
+ beeps_error(__FILE__, __LINE__);
111
146
  }
112
147
 
113
- float
114
- SquareWave::frequency () const
148
+
149
+ Filter::Filter (Processor* input)
150
+ : Super(false)
115
151
  {
116
- return self->frequency;
152
+ if (input) set_input(input);
117
153
  }
118
154
 
119
155
  void
120
- SquareWave::process (Signals* signals)
156
+ Filter::set_buffering_seconds (float seconds)
121
157
  {
122
- Super::process(signals);
158
+ Super::self->buffering_seconds = seconds;
159
+
160
+ set_updated();
161
+ }
123
162
 
124
- self->oscillator.tick(*Signals_get_frames(signals));
163
+ void
164
+ Filter::generate (Context* context, Signals* signals, uint* offset)
165
+ {
166
+ beeps_error(__FILE__, __LINE__);
125
167
  }
126
168
 
127
169
 
128
- struct SawtoothWave::Data
170
+ SignalsBuffer::SignalsBuffer (
171
+ uint nsamples_per_block, uint nchannels, double sample_rate)
129
172
  {
173
+ buffer = Signals_create(nsamples_per_block, nchannels, sample_rate);
174
+ assert(*this);
175
+ }
130
176
 
131
- stk::BlitSaw oscillator;
177
+ void
178
+ SignalsBuffer::process (
179
+ ProcessorContext* context,
180
+ Processor* processor, Signals* signals, uint* offset)
181
+ {
182
+ assert(processor && context && signals && offset);
132
183
 
133
- float frequency;
184
+ if (
185
+ last_update_time < processor->self->last_update_time ||
186
+ *offset < buffer_offset)
187
+ {
188
+ clear();
189
+ }
134
190
 
135
- };// SawtoothWave::Data
191
+ if (buffer.nsamples() == 0)
192
+ buffer_next(context, processor, *offset);
136
193
 
194
+ while (true)
195
+ {
196
+ *offset += Signals_copy(signals, buffer, *offset - buffer_offset);
137
197
 
138
- SawtoothWave::SawtoothWave ()
139
- {
140
- set_frequency(440);
198
+ bool signals_full = signals->nsamples() == signals->capacity();
199
+ bool buffer_full = buffer.nsamples() == buffer.capacity();
200
+ if (signals_full || !buffer_full)
201
+ break;
202
+
203
+ buffer_next(context, processor, buffer_offset + buffer.nsamples());
204
+ }
141
205
  }
142
206
 
143
- SawtoothWave::~SawtoothWave ()
207
+ SignalsBuffer::operator bool () const
144
208
  {
209
+ return buffer;
145
210
  }
146
211
 
147
- void
148
- SawtoothWave::set_frequency (float frequency)
212
+ bool
213
+ SignalsBuffer::operator ! () const
149
214
  {
150
- self->frequency = frequency;
151
- self->oscillator.setFrequency(frequency);
215
+ return !operator bool();
152
216
  }
153
217
 
154
- float
155
- SawtoothWave::frequency () const
218
+ void
219
+ SignalsBuffer::buffer_next (
220
+ ProcessorContext* context, Processor* processor, uint offset)
156
221
  {
157
- return self->frequency;
222
+ Signals_clear(&buffer);
223
+ buffer_offset = offset;
224
+ context->process(processor, &buffer, &offset, true);
225
+
226
+ last_update_time = Xot::time();
158
227
  }
159
228
 
160
229
  void
161
- SawtoothWave::process (Signals* signals)
230
+ SignalsBuffer::clear ()
162
231
  {
163
- Super::process(signals);
164
-
165
- self->oscillator.tick(*Signals_get_frames(signals));
232
+ Signals_clear(&buffer);
233
+ buffer_offset = 0;
166
234
  }
167
235
 
168
236
 
169
- struct FileIn::Data
237
+ ProcessorContext::ProcessorContext (
238
+ uint nsamples_per_process, uint nchannels, double sample_rate)
239
+ : signals(Signals_create(nsamples_per_process, nchannels, sample_rate))
240
+ {
241
+ assert(*this);
242
+ }
243
+
244
+ Signals
245
+ ProcessorContext::process_signals (Processor* processor)
170
246
  {
247
+ assert(processor);
171
248
 
172
- stk::FileWvIn input;
249
+ Signals_clear(&signals);
250
+ process(processor, &signals, &offset);
173
251
 
174
- };// FileIn::Data
252
+ if (signals.nsamples() < signals.capacity())
253
+ finished = true;
175
254
 
255
+ return signals.nsamples() > 0 ? signals : Signals();
256
+ }
176
257
 
177
- FileIn::FileIn (const char* path)
258
+ void
259
+ ProcessorContext::process (
260
+ Processor* processor, Signals* signals, uint* offset, bool ignore_buffer)
178
261
  {
179
- if (path)
180
- self->input.openFile(path);
262
+ assert(processor);
263
+
264
+ SignalsBuffer* buffer = NULL;
265
+ if (!ignore_buffer && (buffer = get_buffer(processor)))
266
+ buffer->process(this, processor, signals, offset);
267
+ else
268
+ processor->process(this, signals, offset);
181
269
  }
182
270
 
183
- FileIn::~FileIn ()
271
+ bool
272
+ ProcessorContext::is_finished () const
184
273
  {
274
+ return finished;
185
275
  }
186
276
 
187
- void
188
- FileIn::process (Signals* signals)
277
+ ProcessorContext::operator bool () const
189
278
  {
190
- Super::process(signals);
279
+ return signals && !finished;
280
+ }
191
281
 
192
- self->input.tick(*Signals_get_frames(signals));
282
+ bool
283
+ ProcessorContext::operator ! () const
284
+ {
285
+ return !operator bool();
286
+ }
287
+
288
+ static uintptr_t
289
+ get_buffer_key (Processor* processor)
290
+ {
291
+ assert(processor);
292
+
293
+ return (uintptr_t) processor->self.get();
193
294
  }
194
295
 
195
- FileIn::operator bool () const
296
+ SignalsBuffer*
297
+ ProcessorContext::get_buffer (Processor* processor)
196
298
  {
197
- return self->input.isOpen();
299
+ float buffering_sec = Processor_get_buffering_seconds(processor);
300
+ if (buffering_sec <= 0) return NULL;
301
+
302
+ uintptr_t key = get_buffer_key(processor);
303
+ auto it = buffers.find(key);
304
+ if (it != buffers.end()) return it->second.get();
305
+
306
+ SignalsBuffer* buffer = new SignalsBuffer(
307
+ buffering_sec * signals.sample_rate(),
308
+ signals.nchannels(), signals.sample_rate());
309
+
310
+ buffers.emplace(key, buffer);
311
+ return buffer;
198
312
  }
199
313
 
200
314
 
data/src/processor.h ADDED
@@ -0,0 +1,98 @@
1
+ // -*- c++ -*-
2
+ #pragma once
3
+ #ifndef __BEEPS_SRC_PROCESSOR_H__
4
+ #define __BEEPS_SRC_PROCESSOR_H__
5
+
6
+
7
+ #include <map>
8
+ #include <beeps/processor.h>
9
+ #include "signals.h"
10
+
11
+
12
+ namespace Beeps
13
+ {
14
+
15
+
16
+ class ProcessorContext;
17
+
18
+
19
+ float Processor_get_buffering_seconds (Processor* processor);
20
+
21
+
22
+ class SignalsBuffer
23
+ {
24
+
25
+ public:
26
+
27
+ SignalsBuffer (
28
+ uint nsamples_per_block, uint nchannels, double sample_rate);
29
+
30
+ void process (
31
+ ProcessorContext* context,
32
+ Processor* processor, Signals* signals, uint* offset);
33
+
34
+ operator bool () const;
35
+
36
+ bool operator ! () const;
37
+
38
+ private:
39
+
40
+ Signals buffer;
41
+
42
+ uint buffer_offset = 0;
43
+
44
+ double last_update_time = 0;
45
+
46
+ void buffer_next (
47
+ ProcessorContext* context, Processor* processor, uint offset);
48
+
49
+ void clear ();
50
+
51
+ };// SignalsBuffer
52
+
53
+
54
+ class ProcessorContext : public Processor::Context
55
+ {
56
+
57
+ public:
58
+
59
+ ProcessorContext (
60
+ uint nsamples_per_process, uint nchannels, double sample_rate);
61
+
62
+ Signals process_signals (Processor* processor);
63
+
64
+ void process (
65
+ Processor* processor, Signals* signals, uint* offset,
66
+ bool ignore_buffer = false);
67
+
68
+ //void push_offset (uint offset);
69
+
70
+ //uint pop_offset ();
71
+
72
+ bool is_finished () const;
73
+
74
+ operator bool () const;
75
+
76
+ bool operator ! () const;
77
+
78
+ private:
79
+
80
+ Signals signals;
81
+
82
+ uint offset = 0;
83
+
84
+ bool finished = false;
85
+
86
+ //std::vector<uint> offset_stack;
87
+
88
+ std::map<uintptr_t, std::unique_ptr<SignalsBuffer>> buffers;
89
+
90
+ SignalsBuffer* get_buffer (Processor* processor);
91
+
92
+ };// ProcessorContext
93
+
94
+
95
+ }// Beeps
96
+
97
+
98
+ #endif//EOH