beeps 0.3 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|