beeps 0.2.1 → 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/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
|