beeps 0.2.1 → 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/analyser.cpp +1 -1
- data/.doc/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
- data/.doc/ext/beeps/file_in.cpp +1 -1
- data/.doc/ext/beeps/gain.cpp +1 -1
- data/.doc/ext/beeps/mic_in.cpp +1 -1
- data/.doc/ext/beeps/native.cpp +4 -2
- data/.doc/ext/beeps/oscillator.cpp +1 -1
- data/.doc/ext/beeps/pitch_shift.cpp +1 -1
- data/.doc/ext/beeps/processor.cpp +1 -1
- data/.doc/ext/beeps/sequencer.cpp +87 -0
- data/.doc/ext/beeps/sound.cpp +1 -1
- data/.doc/ext/beeps/sound_player.cpp +1 -1
- data/.doc/ext/beeps/time_stretch.cpp +1 -1
- data/.github/workflows/release-gem.yml +1 -1
- data/.github/workflows/test.yml +3 -0
- data/ChangeLog.md +13 -0
- data/Gemfile.lock +1 -1
- data/LICENSE +21 -0
- data/Rakefile +3 -2
- data/VERSION +1 -1
- data/beeps.gemspec +2 -2
- data/ext/beeps/analyser.cpp +1 -1
- data/ext/beeps/defs.h +2 -0
- data/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
- data/ext/beeps/extconf.rb +11 -3
- data/ext/beeps/file_in.cpp +1 -1
- data/ext/beeps/gain.cpp +1 -1
- data/ext/beeps/mic_in.cpp +1 -1
- data/ext/beeps/native.cpp +4 -2
- data/ext/beeps/oscillator.cpp +1 -1
- data/ext/beeps/pitch_shift.cpp +1 -1
- data/ext/beeps/processor.cpp +1 -1
- data/ext/beeps/sequencer.cpp +92 -0
- data/ext/beeps/sound.cpp +1 -1
- data/ext/beeps/sound_player.cpp +1 -1
- data/ext/beeps/time_stretch.cpp +1 -1
- data/include/beeps/defs.h +7 -0
- data/include/beeps/filter.h +4 -4
- data/include/beeps/generator.h +31 -0
- data/include/beeps/ruby/beeps.h +1 -1
- data/include/beeps/ruby/exception.h +2 -2
- data/include/beeps/ruby/filter.h +16 -10
- data/include/beeps/ruby/generator.h +18 -5
- data/include/beeps/ruby/processor.h +2 -2
- data/include/beeps/ruby/sound.h +4 -4
- data/lib/beeps/extension.rb +4 -0
- data/lib/beeps/processor.rb +2 -2
- data/src/beeps.cpp +3 -1
- data/src/beeps.h +22 -0
- data/src/{adsr.cpp → envelope.cpp} +21 -20
- data/src/openal.cpp +3 -1
- data/src/oscillator.cpp +75 -44
- data/src/osx/beeps.mm +19 -0
- 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
- data/src/win32/beeps.cpp +36 -0
- data/src/win32/exception.cpp +40 -0
- data/src/win32/exception.h +40 -0
- data/src/win32/signals.cpp +186 -0
- metadata +21 -10
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/osx/beeps.mm
ADDED
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
|
data/src/sequencer.cpp
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
#include "beeps/generator.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <list>
|
5
|
+
#include <algorithm>
|
6
|
+
#include "beeps/exception.h"
|
7
|
+
#include "beeps/debug.h"
|
8
|
+
#include "processor.h"
|
9
|
+
#include "signals.h"
|
10
|
+
|
11
|
+
|
12
|
+
namespace Beeps
|
13
|
+
{
|
14
|
+
|
15
|
+
|
16
|
+
struct Sequencer::Data
|
17
|
+
{
|
18
|
+
|
19
|
+
struct Note
|
20
|
+
{
|
21
|
+
|
22
|
+
Processor::Ref processor;
|
23
|
+
|
24
|
+
float offset, duration;
|
25
|
+
|
26
|
+
Note (Processor* processor, float offset, float duration)
|
27
|
+
: processor(processor), offset(offset), duration(duration)
|
28
|
+
{
|
29
|
+
}
|
30
|
+
|
31
|
+
};// Note
|
32
|
+
|
33
|
+
std::list<Note> notes;
|
34
|
+
|
35
|
+
float time_scale = 1;
|
36
|
+
|
37
|
+
uint sec2nsample (const Signals& signals, float sec) const
|
38
|
+
{
|
39
|
+
return sec * signals.sample_rate() / time_scale;
|
40
|
+
}
|
41
|
+
|
42
|
+
};// Sequencer::Data
|
43
|
+
|
44
|
+
|
45
|
+
Sequencer::Sequencer ()
|
46
|
+
{
|
47
|
+
}
|
48
|
+
|
49
|
+
Sequencer::~Sequencer ()
|
50
|
+
{
|
51
|
+
}
|
52
|
+
|
53
|
+
void
|
54
|
+
Sequencer::add (Processor* processor, float offset, float duration)
|
55
|
+
{
|
56
|
+
auto& notes = self->notes;
|
57
|
+
for (auto it = notes.begin(), end = notes.end(); it != end; ++it)
|
58
|
+
{
|
59
|
+
if (offset < it->offset)
|
60
|
+
{
|
61
|
+
notes.emplace(it, processor, offset, duration);
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
}
|
65
|
+
notes.emplace_back(processor, offset, duration);
|
66
|
+
}
|
67
|
+
|
68
|
+
void
|
69
|
+
Sequencer::remove (Processor* processor, float offset)
|
70
|
+
{
|
71
|
+
auto it =
|
72
|
+
std::find_if(self->notes.begin(), self->notes.end(), [&](auto& note)
|
73
|
+
{
|
74
|
+
return note.processor == processor && note.offset == offset;
|
75
|
+
});
|
76
|
+
if (it == self->notes.end()) return;
|
77
|
+
|
78
|
+
self->notes.erase(it);
|
79
|
+
}
|
80
|
+
|
81
|
+
void
|
82
|
+
Sequencer::set_time_scale (float time_scale)
|
83
|
+
{
|
84
|
+
if (time_scale <= 0)
|
85
|
+
argument_error(__FILE__, __LINE__, "time_scale must be greater than 0");
|
86
|
+
|
87
|
+
self->time_scale = time_scale;
|
88
|
+
}
|
89
|
+
|
90
|
+
float
|
91
|
+
Sequencer::time_scale () const
|
92
|
+
{
|
93
|
+
return self->time_scale;
|
94
|
+
}
|
95
|
+
|
96
|
+
static void
|
97
|
+
mix (Signals* mixed, const Signals& source, uint source_offset)
|
98
|
+
{
|
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;
|
106
|
+
}
|
107
|
+
|
108
|
+
void
|
109
|
+
Sequencer::generate (Context* pcontext, Signals* psignals, uint* offset)
|
110
|
+
{
|
111
|
+
Super::generate(pcontext, psignals, offset);
|
112
|
+
|
113
|
+
auto& context = *Processor_get_context(pcontext);
|
114
|
+
auto& signals = *psignals;
|
115
|
+
Signals_resize(&signals, signals.capacity(), 0);
|
116
|
+
|
117
|
+
uint generate_begin = *offset;
|
118
|
+
uint generate_end = *offset + signals.capacity();
|
119
|
+
Signals note_signals = Signals_create(
|
120
|
+
signals.capacity(), signals.nchannels(), signals.sample_rate());
|
121
|
+
|
122
|
+
uint nsamples = 0;
|
123
|
+
for (auto& note : self->notes)
|
124
|
+
{
|
125
|
+
uint note_begin = self->sec2nsample(signals, note.offset);
|
126
|
+
uint note_end = self->sec2nsample(signals, note.offset + note.duration);
|
127
|
+
if (note_end <= generate_begin) continue;
|
128
|
+
if (generate_end <= note_begin)
|
129
|
+
{
|
130
|
+
nsamples = generate_end - generate_begin;
|
131
|
+
break;
|
132
|
+
}
|
133
|
+
|
134
|
+
uint begin = std::max(generate_begin, note_begin);
|
135
|
+
uint end = std::min(generate_end, note_end);
|
136
|
+
assert(begin != end);
|
137
|
+
|
138
|
+
uint note_offset = begin - note_begin;
|
139
|
+
Signals_clear(¬e_signals, end - begin);
|
140
|
+
context.process(note.processor.get(), ¬e_signals, ¬e_offset);
|
141
|
+
|
142
|
+
uint mix_offset = begin - generate_begin;
|
143
|
+
mix(&signals, note_signals, mix_offset);
|
144
|
+
|
145
|
+
if (mix_offset + note_signals.nsamples() > nsamples)
|
146
|
+
nsamples = mix_offset + note_signals.nsamples();
|
147
|
+
}
|
148
|
+
|
149
|
+
Signals_set_nsamples(&signals, nsamples);
|
150
|
+
*offset += nsamples;
|
151
|
+
}
|
152
|
+
|
153
|
+
Sequencer::operator bool () const
|
154
|
+
{
|
155
|
+
if (!Super::operator bool()) return false;
|
156
|
+
return self->time_scale > 0;
|
157
|
+
}
|
158
|
+
|
159
|
+
|
160
|
+
}// Beeps
|