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.
- checksums.yaml +4 -4
- data/.doc/ext/beeps/beeps.cpp +7 -0
- data/.doc/ext/beeps/high_pass.cpp +63 -0
- data/.doc/ext/beeps/low_pass.cpp +63 -0
- data/.doc/ext/beeps/native.cpp +8 -0
- data/.doc/ext/beeps/oscillator.cpp +87 -10
- data/.doc/ext/beeps/processor.cpp +14 -1
- data/.doc/ext/beeps/reverb.cpp +99 -0
- data/.doc/ext/beeps/signals.cpp +128 -0
- data/ChangeLog.md +24 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/beeps.gemspec +2 -2
- data/ext/beeps/beeps.cpp +8 -0
- data/ext/beeps/high_pass.cpp +66 -0
- data/ext/beeps/low_pass.cpp +66 -0
- data/ext/beeps/native.cpp +8 -0
- data/ext/beeps/oscillator.cpp +95 -12
- data/ext/beeps/processor.cpp +15 -1
- data/ext/beeps/reverb.cpp +106 -0
- data/ext/beeps/signals.cpp +136 -0
- data/include/beeps/beeps.h +2 -2
- data/include/beeps/defs.h +3 -0
- data/include/beeps/filter.h +118 -17
- data/include/beeps/generator.h +50 -17
- data/include/beeps/processor.h +23 -6
- data/include/beeps/ruby/filter.h +33 -0
- data/include/beeps/ruby/signals.h +40 -0
- data/include/beeps/signals.h +1 -1
- data/lib/beeps/processor.rb +46 -1
- data/lib/beeps/signals.rb +19 -0
- data/lib/beeps.rb +1 -0
- data/src/analyser.cpp +34 -37
- data/src/beeps.cpp +7 -6
- data/src/envelope.cpp +60 -46
- data/src/file_in.cpp +6 -6
- data/src/gain.cpp +5 -5
- data/src/high_pass.cpp +57 -0
- data/src/low_pass.cpp +57 -0
- data/src/mic_in.cpp +16 -14
- data/src/mixer.cpp +38 -20
- data/src/oscillator.cpp +260 -168
- data/src/pitch_shift.cpp +6 -6
- data/src/processor.cpp +118 -11
- data/src/processor.h +8 -0
- data/src/reverb.cpp +124 -0
- data/src/sequencer.cpp +18 -14
- data/src/signals.cpp +264 -106
- data/src/signals.h +28 -89
- data/src/sound.cpp +28 -20
- data/src/time_stretch.cpp +6 -6
- data/src/win32/signals.cpp +8 -7
- data/src/x_pass.h +51 -0
- data/test/helper.rb +14 -0
- data/test/test_analyser.rb +26 -0
- data/test/test_envelope.rb +55 -0
- data/test/test_file_in.rb +22 -1
- data/test/test_gain.rb +28 -0
- data/test/test_high_pass.rb +41 -0
- data/test/test_low_pass.rb +41 -0
- data/test/test_mixer.rb +63 -0
- data/test/test_oscillator.rb +58 -0
- data/test/test_pitch_shift.rb +32 -0
- data/test/test_processor.rb +7 -0
- data/test/test_signals.rb +60 -0
- data/test/test_time_stretch.rb +36 -0
- 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
|
-
|
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
|
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() <
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
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
|