beeps 0.3 → 0.3.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.
- checksums.yaml +4 -4
- data/.doc/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
- data/.doc/ext/beeps/native.cpp +4 -2
- data/.doc/ext/beeps/sequencer.cpp +87 -0
- data/ChangeLog.md +8 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +21 -0
- data/Rakefile +0 -1
- data/VERSION +1 -1
- data/beeps.gemspec +2 -2
- data/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
- data/ext/beeps/native.cpp +4 -2
- data/ext/beeps/sequencer.cpp +92 -0
- data/include/beeps/filter.h +4 -4
- data/include/beeps/generator.h +31 -0
- data/include/beeps/ruby/filter.h +10 -4
- data/include/beeps/ruby/generator.h +13 -0
- data/lib/beeps/processor.rb +2 -2
- data/src/{adsr.cpp → envelope.cpp} +21 -20
- data/src/openal.cpp +3 -1
- data/src/oscillator.cpp +75 -44
- data/src/processor.cpp +59 -49
- data/src/processor.h +30 -14
- data/src/sequencer.cpp +160 -0
- data/src/signals.cpp +45 -29
- data/src/signals.h +4 -4
- data/src/sound.cpp +32 -29
- metadata +15 -10
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#include <assert.h>
|
5
5
|
#include <ADSR.h>
|
6
|
+
#include "beeps/debug.h"
|
6
7
|
#include "signals.h"
|
7
8
|
|
8
9
|
|
@@ -10,7 +11,7 @@ namespace Beeps
|
|
10
11
|
{
|
11
12
|
|
12
13
|
|
13
|
-
struct
|
14
|
+
struct Envelope::Data
|
14
15
|
{
|
15
16
|
|
16
17
|
stk::ADSR adsr;
|
@@ -29,21 +30,21 @@ namespace Beeps
|
|
29
30
|
adsr.setReleaseTime( release_time == 0 ? 0.01 : release_time);
|
30
31
|
}
|
31
32
|
|
32
|
-
};//
|
33
|
+
};// Envelope::Data
|
33
34
|
|
34
35
|
|
35
|
-
|
36
|
+
Envelope::Envelope (Processor* input)
|
36
37
|
: Super(input)
|
37
38
|
{
|
38
39
|
self->update_envelope();
|
39
40
|
}
|
40
41
|
|
41
|
-
|
42
|
+
Envelope::~Envelope ()
|
42
43
|
{
|
43
44
|
}
|
44
45
|
|
45
46
|
void
|
46
|
-
|
47
|
+
Envelope::note_on (float delay)
|
47
48
|
{
|
48
49
|
if (delay < 0)
|
49
50
|
argument_error(__FILE__, __LINE__);
|
@@ -58,7 +59,7 @@ namespace Beeps
|
|
58
59
|
}
|
59
60
|
|
60
61
|
void
|
61
|
-
|
62
|
+
Envelope::note_off (float delay)
|
62
63
|
{
|
63
64
|
if (delay < 0)
|
64
65
|
argument_error(__FILE__, __LINE__);
|
@@ -73,7 +74,7 @@ namespace Beeps
|
|
73
74
|
}
|
74
75
|
|
75
76
|
void
|
76
|
-
|
77
|
+
Envelope::set_attack_time (float time)
|
77
78
|
{
|
78
79
|
if (time < 0)
|
79
80
|
argument_error(__FILE__, __LINE__);
|
@@ -85,13 +86,13 @@ namespace Beeps
|
|
85
86
|
}
|
86
87
|
|
87
88
|
float
|
88
|
-
|
89
|
+
Envelope::attack_time () const
|
89
90
|
{
|
90
91
|
return self->attack_time;
|
91
92
|
}
|
92
93
|
|
93
94
|
void
|
94
|
-
|
95
|
+
Envelope::set_decay_time (float time)
|
95
96
|
{
|
96
97
|
if (time < 0)
|
97
98
|
argument_error(__FILE__, __LINE__);
|
@@ -103,13 +104,13 @@ namespace Beeps
|
|
103
104
|
}
|
104
105
|
|
105
106
|
float
|
106
|
-
|
107
|
+
Envelope::decay_time () const
|
107
108
|
{
|
108
109
|
return self->decay_time;
|
109
110
|
}
|
110
111
|
|
111
112
|
void
|
112
|
-
|
113
|
+
Envelope::set_sustain_level (float level)
|
113
114
|
{
|
114
115
|
if (level < 0)
|
115
116
|
argument_error(__FILE__, __LINE__);
|
@@ -121,13 +122,13 @@ namespace Beeps
|
|
121
122
|
}
|
122
123
|
|
123
124
|
float
|
124
|
-
|
125
|
+
Envelope::sustain_level () const
|
125
126
|
{
|
126
127
|
return self->sustain_level;
|
127
128
|
}
|
128
129
|
|
129
130
|
void
|
130
|
-
|
131
|
+
Envelope::set_release_time (float time)
|
131
132
|
{
|
132
133
|
if (time < 0)
|
133
134
|
argument_error(__FILE__, __LINE__);
|
@@ -139,7 +140,7 @@ namespace Beeps
|
|
139
140
|
}
|
140
141
|
|
141
142
|
float
|
142
|
-
|
143
|
+
Envelope::release_time () const
|
143
144
|
{
|
144
145
|
return self->release_time;
|
145
146
|
}
|
@@ -157,11 +158,11 @@ namespace Beeps
|
|
157
158
|
}
|
158
159
|
|
159
160
|
static void
|
160
|
-
process_envelope_signals (
|
161
|
+
process_envelope_signals (Envelope* envelope, Signals* signals)
|
161
162
|
{
|
162
|
-
assert(
|
163
|
+
assert(envelope && signals && signals->nchannels() == 1);
|
163
164
|
|
164
|
-
|
165
|
+
Envelope::Data* self = envelope->self.get();
|
165
166
|
|
166
167
|
Frames* frames = Signals_get_frames(signals);
|
167
168
|
assert(frames);
|
@@ -214,7 +215,7 @@ namespace Beeps
|
|
214
215
|
}
|
215
216
|
|
216
217
|
void
|
217
|
-
|
218
|
+
Envelope::filter (Context* context, Signals* signals, uint* offset)
|
218
219
|
{
|
219
220
|
Super::filter(context, signals, offset);
|
220
221
|
|
@@ -228,10 +229,10 @@ namespace Beeps
|
|
228
229
|
Signals_resize(&self->adsr_signals, signals->nsamples(), 0);
|
229
230
|
|
230
231
|
process_envelope_signals(this, &self->adsr_signals);
|
231
|
-
|
232
|
+
Signals_multiply(signals, self->adsr_signals);
|
232
233
|
}
|
233
234
|
|
234
|
-
|
235
|
+
Envelope::operator bool () const
|
235
236
|
{
|
236
237
|
if (!Super::operator bool()) return false;
|
237
238
|
return
|
data/src/openal.cpp
CHANGED
@@ -42,7 +42,9 @@ namespace Beeps
|
|
42
42
|
void
|
43
43
|
OpenAL_init ()
|
44
44
|
{
|
45
|
-
if (global::device
|
45
|
+
if (global::device)
|
46
|
+
beeps_error(__FILE__, __LINE__, "already initialized.");
|
47
|
+
if (global::context)
|
46
48
|
beeps_error(__FILE__, __LINE__, "already initialized.");
|
47
49
|
|
48
50
|
global::device = alcOpenDevice(NULL);
|
data/src/oscillator.cpp
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#include <assert.h>
|
5
5
|
#include "SineWave.h"
|
6
|
+
#include "Blit.h"
|
6
7
|
#include "BlitSquare.h"
|
7
8
|
#include "BlitSaw.h"
|
8
9
|
#include "beeps/exception.h"
|
@@ -13,6 +14,70 @@ namespace Beeps
|
|
13
14
|
{
|
14
15
|
|
15
16
|
|
17
|
+
class Osc
|
18
|
+
{
|
19
|
+
|
20
|
+
public:
|
21
|
+
|
22
|
+
virtual ~Osc () {}
|
23
|
+
|
24
|
+
virtual void reset () = 0;
|
25
|
+
|
26
|
+
virtual void tick (Frames* frames) = 0;
|
27
|
+
|
28
|
+
virtual void set_frequency (float freq) = 0;
|
29
|
+
|
30
|
+
};// Osc
|
31
|
+
|
32
|
+
|
33
|
+
template <typename OSC>
|
34
|
+
class StkOsc : public Osc
|
35
|
+
{
|
36
|
+
|
37
|
+
public:
|
38
|
+
|
39
|
+
void reset () override
|
40
|
+
{
|
41
|
+
osc.reset();
|
42
|
+
}
|
43
|
+
|
44
|
+
void tick (Frames* frames) override
|
45
|
+
{
|
46
|
+
osc.tick(*frames);
|
47
|
+
}
|
48
|
+
|
49
|
+
void set_frequency (float freq) override
|
50
|
+
{
|
51
|
+
osc.setFrequency(freq);
|
52
|
+
}
|
53
|
+
|
54
|
+
protected:
|
55
|
+
|
56
|
+
OSC osc;
|
57
|
+
|
58
|
+
};// StkOsc
|
59
|
+
|
60
|
+
|
61
|
+
typedef StkOsc<stk::SineWave> SineOsc;
|
62
|
+
|
63
|
+
typedef StkOsc<stk::BlitSquare> SquareOsc;
|
64
|
+
|
65
|
+
typedef StkOsc<stk::BlitSaw> SawtoothOsc;
|
66
|
+
|
67
|
+
|
68
|
+
class TriangleOsc : public StkOsc<stk::Blit>
|
69
|
+
{
|
70
|
+
|
71
|
+
public:
|
72
|
+
|
73
|
+
TriangleOsc ()
|
74
|
+
{
|
75
|
+
osc.setHarmonics(10);
|
76
|
+
}
|
77
|
+
|
78
|
+
};// TriangleOsc
|
79
|
+
|
80
|
+
|
16
81
|
struct Oscillator::Data
|
17
82
|
{
|
18
83
|
|
@@ -20,11 +85,7 @@ namespace Beeps
|
|
20
85
|
|
21
86
|
float frequency = 440;
|
22
87
|
|
23
|
-
std::unique_ptr<
|
24
|
-
|
25
|
-
std::unique_ptr<stk::BlitSquare> square;
|
26
|
-
|
27
|
-
std::unique_ptr<stk::BlitSaw> saw;
|
88
|
+
std::unique_ptr<Osc> osc;
|
28
89
|
|
29
90
|
};// Oscillator::Data
|
30
91
|
|
@@ -42,10 +103,7 @@ namespace Beeps
|
|
42
103
|
Oscillator::reset ()
|
43
104
|
{
|
44
105
|
Super::reset();
|
45
|
-
|
46
|
-
if (self->sine) self->sine->reset();
|
47
|
-
if (self->square) self->square->reset();
|
48
|
-
if (self->saw) self->saw->reset();
|
106
|
+
self->osc->reset();
|
49
107
|
}
|
50
108
|
|
51
109
|
void
|
@@ -54,16 +112,14 @@ namespace Beeps
|
|
54
112
|
if (type == self->type) return;
|
55
113
|
|
56
114
|
self->type = type;
|
57
|
-
|
58
|
-
self->sine .reset();
|
59
|
-
self->square.reset();
|
60
|
-
self->saw .reset();
|
115
|
+
self->osc.reset();
|
61
116
|
|
62
117
|
switch (self->type)
|
63
118
|
{
|
64
|
-
case SINE: self->
|
65
|
-
case
|
66
|
-
case
|
119
|
+
case SINE: self->osc.reset(new SineOsc()); break;
|
120
|
+
case TRIANGLE: self->osc.reset(new TriangleOsc()); break;
|
121
|
+
case SQUARE: self->osc.reset(new SquareOsc()); break;
|
122
|
+
case SAWTOOTH: self->osc.reset(new SawtoothOsc()); break;
|
67
123
|
default:
|
68
124
|
argument_error(
|
69
125
|
__FILE__, __LINE__, "unknown oscilator type '%d'", self->type);
|
@@ -105,31 +161,8 @@ namespace Beeps
|
|
105
161
|
if (!frames)
|
106
162
|
argument_error(__FILE__, __LINE__);
|
107
163
|
|
108
|
-
|
109
|
-
|
110
|
-
case SINE:
|
111
|
-
assert(self->sine);
|
112
|
-
self->sine->setFrequency(self->frequency);
|
113
|
-
self->sine->tick(*frames);
|
114
|
-
break;
|
115
|
-
|
116
|
-
case SQUARE:
|
117
|
-
assert(self->square);
|
118
|
-
self->square->setFrequency(self->frequency);
|
119
|
-
self->square->tick(*frames);
|
120
|
-
break;
|
121
|
-
|
122
|
-
case SAWTOOTH:
|
123
|
-
assert(self->saw);
|
124
|
-
self->saw->setFrequency(self->frequency);
|
125
|
-
self->saw->tick(*frames);
|
126
|
-
break;
|
127
|
-
|
128
|
-
default:
|
129
|
-
invalid_state_error(
|
130
|
-
__FILE__, __LINE__, "unknown oscilator type '%d'", self->type);
|
131
|
-
break;
|
132
|
-
}
|
164
|
+
self->osc->set_frequency(self->frequency);
|
165
|
+
self->osc->tick(frames);
|
133
166
|
|
134
167
|
Signals_set_nsamples(signals, frames->nframes());
|
135
168
|
}
|
@@ -137,9 +170,7 @@ namespace Beeps
|
|
137
170
|
Oscillator::operator bool () const
|
138
171
|
{
|
139
172
|
if (!Super::operator bool()) return false;
|
140
|
-
return
|
141
|
-
self->type != TYPE_NONE && self->frequency > 0 &&
|
142
|
-
(self->sine || self->square || self->saw);
|
173
|
+
return self->type != TYPE_NONE && self->frequency > 0 && self->osc;
|
143
174
|
}
|
144
175
|
|
145
176
|
|
data/src/processor.cpp
CHANGED
@@ -4,19 +4,13 @@
|
|
4
4
|
#include <assert.h>
|
5
5
|
#include <xot/time.h>
|
6
6
|
#include "beeps/exception.h"
|
7
|
+
#include "beeps/debug.h"
|
7
8
|
|
8
9
|
|
9
10
|
namespace Beeps
|
10
11
|
{
|
11
12
|
|
12
13
|
|
13
|
-
static ProcessorContext*
|
14
|
-
get_context(Processor::Context* context)
|
15
|
-
{
|
16
|
-
return (ProcessorContext*) context;
|
17
|
-
}
|
18
|
-
|
19
|
-
|
20
14
|
struct Processor::Data
|
21
15
|
{
|
22
16
|
|
@@ -36,6 +30,12 @@ namespace Beeps
|
|
36
30
|
};// Processor::Data
|
37
31
|
|
38
32
|
|
33
|
+
ProcessorContext*
|
34
|
+
Processor_get_context(Processor::Context* context)
|
35
|
+
{
|
36
|
+
return (ProcessorContext*) context;
|
37
|
+
}
|
38
|
+
|
39
39
|
float
|
40
40
|
Processor_get_buffering_seconds (Processor* processor)
|
41
41
|
{
|
@@ -108,24 +108,40 @@ namespace Beeps
|
|
108
108
|
void
|
109
109
|
Processor::generate (Context* context, Signals* signals, uint* offset)
|
110
110
|
{
|
111
|
-
if (!context
|
111
|
+
if (!context)
|
112
|
+
argument_error(__FILE__, __LINE__);
|
113
|
+
if (!signals)
|
114
|
+
argument_error(__FILE__, __LINE__);
|
115
|
+
if (!*signals)
|
116
|
+
argument_error(__FILE__, __LINE__);
|
117
|
+
if (signals->nsamples() > 0)
|
118
|
+
argument_error(__FILE__, __LINE__);
|
119
|
+
if (!offset)
|
112
120
|
argument_error(__FILE__, __LINE__);
|
113
121
|
|
114
|
-
if (!*this
|
122
|
+
if (!*this)
|
123
|
+
invalid_state_error(__FILE__, __LINE__);
|
124
|
+
if (self->input)
|
115
125
|
invalid_state_error(__FILE__, __LINE__);
|
116
126
|
}
|
117
127
|
|
118
128
|
void
|
119
129
|
Processor::filter (Context* context, Signals* signals, uint* offset)
|
120
130
|
{
|
121
|
-
if (!context
|
131
|
+
if (!context)
|
132
|
+
argument_error(__FILE__, __LINE__);
|
133
|
+
if (!signals)
|
134
|
+
argument_error(__FILE__, __LINE__);
|
135
|
+
if (!*signals)
|
136
|
+
argument_error(__FILE__, __LINE__);
|
137
|
+
if (!offset)
|
122
138
|
argument_error(__FILE__, __LINE__);
|
123
139
|
|
124
140
|
if (!*this)
|
125
141
|
invalid_state_error(__FILE__, __LINE__);
|
126
142
|
|
127
143
|
if (self->input)
|
128
|
-
|
144
|
+
Processor_get_context(context)->process(self->input, signals, offset);
|
129
145
|
}
|
130
146
|
|
131
147
|
void
|
@@ -235,25 +251,9 @@ namespace Beeps
|
|
235
251
|
}
|
236
252
|
|
237
253
|
|
238
|
-
ProcessorContext::ProcessorContext (
|
239
|
-
|
240
|
-
: signals(Signals_create(nsamples_per_process, nchannels, sample_rate))
|
241
|
-
{
|
242
|
-
assert(*this);
|
243
|
-
}
|
244
|
-
|
245
|
-
Signals
|
246
|
-
ProcessorContext::process_signals (Processor* processor)
|
254
|
+
ProcessorContext::ProcessorContext (uint nchannels, double sample_rate)
|
255
|
+
: sample_rate(sample_rate), nchannels(nchannels)
|
247
256
|
{
|
248
|
-
assert(processor);
|
249
|
-
|
250
|
-
Signals_clear(&signals);
|
251
|
-
process(processor, &signals, &offset);
|
252
|
-
|
253
|
-
if (signals.nsamples() < signals.capacity())
|
254
|
-
finished = true;
|
255
|
-
|
256
|
-
return signals.nsamples() > 0 ? signals : Signals();
|
257
257
|
}
|
258
258
|
|
259
259
|
void
|
@@ -269,23 +269,6 @@ namespace Beeps
|
|
269
269
|
processor->process(this, signals, offset);
|
270
270
|
}
|
271
271
|
|
272
|
-
bool
|
273
|
-
ProcessorContext::is_finished () const
|
274
|
-
{
|
275
|
-
return finished;
|
276
|
-
}
|
277
|
-
|
278
|
-
ProcessorContext::operator bool () const
|
279
|
-
{
|
280
|
-
return signals && !finished;
|
281
|
-
}
|
282
|
-
|
283
|
-
bool
|
284
|
-
ProcessorContext::operator ! () const
|
285
|
-
{
|
286
|
-
return !operator bool();
|
287
|
-
}
|
288
|
-
|
289
272
|
static uintptr_t
|
290
273
|
get_buffer_key (Processor* processor)
|
291
274
|
{
|
@@ -304,13 +287,40 @@ namespace Beeps
|
|
304
287
|
auto it = buffers.find(key);
|
305
288
|
if (it != buffers.end()) return it->second.get();
|
306
289
|
|
307
|
-
SignalsBuffer* buffer =
|
308
|
-
buffering_sec *
|
309
|
-
signals.nchannels(), signals.sample_rate());
|
290
|
+
SignalsBuffer* buffer =
|
291
|
+
new SignalsBuffer(buffering_sec * sample_rate, nchannels, sample_rate);
|
310
292
|
|
311
293
|
buffers.emplace(key, buffer);
|
312
294
|
return buffer;
|
313
295
|
}
|
314
296
|
|
315
297
|
|
298
|
+
StreamContext::StreamContext (
|
299
|
+
uint nsamples_per_process, uint nchannels, double sample_rate)
|
300
|
+
: context(nchannels, sample_rate),
|
301
|
+
signals(Signals_create(nsamples_per_process, nchannels, sample_rate))
|
302
|
+
{
|
303
|
+
}
|
304
|
+
|
305
|
+
Signals
|
306
|
+
StreamContext::process_next (Processor* processor)
|
307
|
+
{
|
308
|
+
assert(processor);
|
309
|
+
|
310
|
+
Signals_clear(&signals);
|
311
|
+
context.process(processor, &signals, &offset);
|
312
|
+
|
313
|
+
if (signals.nsamples() < signals.capacity())
|
314
|
+
finished = true;
|
315
|
+
|
316
|
+
return signals;
|
317
|
+
}
|
318
|
+
|
319
|
+
bool
|
320
|
+
StreamContext::is_finished () const
|
321
|
+
{
|
322
|
+
return finished;
|
323
|
+
}
|
324
|
+
|
325
|
+
|
316
326
|
}// Beeps
|
data/src/processor.h
CHANGED
@@ -16,6 +16,8 @@ namespace Beeps
|
|
16
16
|
class ProcessorContext;
|
17
17
|
|
18
18
|
|
19
|
+
ProcessorContext* Processor_get_context (Processor::Context* context);
|
20
|
+
|
19
21
|
float Processor_get_buffering_seconds (Processor* processor);
|
20
22
|
|
21
23
|
|
@@ -56,40 +58,54 @@ namespace Beeps
|
|
56
58
|
|
57
59
|
public:
|
58
60
|
|
59
|
-
ProcessorContext (
|
60
|
-
uint nsamples_per_process, uint nchannels, double sample_rate);
|
61
|
-
|
62
|
-
Signals process_signals (Processor* processor);
|
61
|
+
ProcessorContext (uint nchannels, double sample_rate);
|
63
62
|
|
64
63
|
void process (
|
65
64
|
Processor* processor, Signals* signals, uint* offset,
|
66
65
|
bool ignore_buffer = false);
|
67
66
|
|
67
|
+
private:
|
68
|
+
|
69
|
+
double sample_rate;
|
70
|
+
|
71
|
+
uint nchannels;
|
72
|
+
|
73
|
+
std::map<uintptr_t, std::unique_ptr<SignalsBuffer>> buffers;
|
74
|
+
|
75
|
+
SignalsBuffer* get_buffer (Processor* processor);
|
76
|
+
|
77
|
+
};// ProcessorContext
|
78
|
+
|
79
|
+
|
80
|
+
class StreamContext
|
81
|
+
{
|
82
|
+
|
83
|
+
public:
|
84
|
+
|
85
|
+
StreamContext (
|
86
|
+
uint nsamples_per_process, uint nchannels, double sample_rate);
|
87
|
+
|
88
|
+
Signals process_next (Processor* processor);
|
89
|
+
|
68
90
|
//void push_offset (uint offset);
|
69
91
|
|
70
92
|
//uint pop_offset ();
|
71
93
|
|
72
94
|
bool is_finished () const;
|
73
95
|
|
74
|
-
operator bool () const;
|
75
|
-
|
76
|
-
bool operator ! () const;
|
77
|
-
|
78
96
|
private:
|
79
97
|
|
98
|
+
ProcessorContext context;
|
99
|
+
|
80
100
|
Signals signals;
|
81
101
|
|
82
|
-
uint offset
|
102
|
+
uint offset = 0;
|
83
103
|
|
84
104
|
bool finished = false;
|
85
105
|
|
86
106
|
//std::vector<uint> offset_stack;
|
87
107
|
|
88
|
-
|
89
|
-
|
90
|
-
SignalsBuffer* get_buffer (Processor* processor);
|
91
|
-
|
92
|
-
};// ProcessorContext
|
108
|
+
};// StreamContext
|
93
109
|
|
94
110
|
|
95
111
|
}// Beeps
|