beeps 0.3.2 → 0.3.4
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/mixer.cpp +85 -0
- data/.doc/ext/beeps/native.cpp +2 -0
- data/.doc/ext/beeps/oscillator.cpp +54 -0
- data/.doc/ext/beeps/processor.cpp +10 -0
- data/ChangeLog.md +28 -0
- data/VERSION +1 -1
- data/beeps.gemspec +4 -2
- data/ext/beeps/mixer.cpp +89 -0
- data/ext/beeps/native.cpp +2 -0
- data/ext/beeps/oscillator.cpp +58 -0
- data/ext/beeps/processor.cpp +11 -0
- data/include/beeps/filter.h +41 -0
- data/include/beeps/generator.h +16 -1
- data/include/beeps/processor.h +2 -0
- data/include/beeps/ruby/filter.h +11 -0
- data/include/beeps/ruby/processor.h +17 -1
- data/lib/beeps/processor.rb +76 -17
- data/src/envelope.cpp +14 -5
- data/src/mixer.cpp +112 -0
- data/src/oscillator.cpp +280 -6
- data/src/processor.cpp +14 -7
- data/src/signals.cpp +24 -6
- data/src/signals.h +8 -1
- data/test/test_processor.rb +1 -1
- metadata +16 -11
data/lib/beeps/processor.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'xot/setter'
|
2
2
|
require 'xot/const_symbol_accessor'
|
3
3
|
require 'xot/universal_accessor'
|
4
|
+
require 'xot/hookable'
|
4
5
|
require 'xot/block_util'
|
5
6
|
require 'beeps/ext'
|
6
7
|
|
@@ -11,55 +12,76 @@ module Beeps
|
|
11
12
|
class Processor
|
12
13
|
|
13
14
|
include Xot::Setter
|
15
|
+
include Xot::Hookable
|
14
16
|
|
15
|
-
def initialize(**options, &block)
|
17
|
+
def initialize(*inputs, **options, &block)
|
16
18
|
super()
|
19
|
+
add_input(*inputs)
|
17
20
|
set options unless options.empty?
|
18
21
|
Xot::BlockUtil.instance_eval_or_block_call self, &block if block
|
19
22
|
end
|
20
23
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
+
universal_accessor :input
|
25
|
+
|
26
|
+
def add_input(*inputs)
|
27
|
+
last = inputs.flatten.compact.last
|
28
|
+
self.input = last if last
|
24
29
|
end
|
25
30
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
31
|
+
def >>(processor)
|
32
|
+
processor.add_input self
|
33
|
+
processor
|
29
34
|
end
|
30
35
|
|
31
|
-
|
36
|
+
#def <<(processors)
|
37
|
+
# self.add_input(*processors)
|
38
|
+
# self
|
39
|
+
#end
|
32
40
|
|
33
41
|
end# Processor
|
34
42
|
|
35
43
|
|
36
44
|
class Oscillator
|
37
45
|
|
46
|
+
include Enumerable
|
47
|
+
|
38
48
|
const_symbol_accessor :type, **{
|
39
49
|
none: TYPE_NONE,
|
40
50
|
sine: SINE,
|
41
51
|
triangle: TRIANGLE,
|
42
52
|
square: SQUARE,
|
43
|
-
sawtooth: SAWTOOTH
|
53
|
+
sawtooth: SAWTOOTH,
|
54
|
+
noise: NOISE,
|
55
|
+
samples: SAMPLES
|
44
56
|
}
|
45
57
|
|
46
|
-
def initialize(type = :sine,
|
47
|
-
super(
|
48
|
-
|
58
|
+
def initialize(type = :sine, samples: nil, **kwargs, &block)
|
59
|
+
super(**kwargs, &block)
|
60
|
+
if samples
|
61
|
+
self.samples = samples
|
62
|
+
else
|
63
|
+
self.type = type
|
64
|
+
end
|
49
65
|
end
|
50
66
|
|
67
|
+
universal_accessor :type, :frequency, :phase
|
68
|
+
|
51
69
|
alias freq= frequency=
|
52
70
|
alias freq frequency
|
53
71
|
|
54
|
-
|
72
|
+
def each_sample(&block)
|
73
|
+
block ? each_sample!(&block) : enum_for(:each_sample!)
|
74
|
+
end
|
75
|
+
|
76
|
+
alias each each_sample
|
55
77
|
|
56
78
|
end# Oscillator
|
57
79
|
|
58
80
|
|
59
81
|
class FileIn
|
60
82
|
|
61
|
-
def initialize(path = nil,
|
62
|
-
super(
|
83
|
+
def initialize(path = nil, **kwargs, &block)
|
84
|
+
super(**kwargs, &block)
|
63
85
|
self.path = path if path
|
64
86
|
end
|
65
87
|
|
@@ -70,13 +92,50 @@ module Beeps
|
|
70
92
|
|
71
93
|
class Gain
|
72
94
|
|
95
|
+
def initialize(gain = 1, **kwargs, &block)
|
96
|
+
super(gain: gain, **kwargs, &block)
|
97
|
+
end
|
98
|
+
|
73
99
|
universal_accessor :gain
|
74
100
|
|
75
101
|
end# Gain
|
76
102
|
|
77
103
|
|
104
|
+
class Mixer
|
105
|
+
|
106
|
+
include Enumerable
|
107
|
+
|
108
|
+
def add_input(*inputs)
|
109
|
+
add_input! inputs.flatten.compact
|
110
|
+
end
|
111
|
+
|
112
|
+
def remove_input(*inputs)
|
113
|
+
remove_input! inputs.flatten.compact
|
114
|
+
end
|
115
|
+
|
116
|
+
def each_input(&block)
|
117
|
+
block ? each_input!(&block) : enum_for(:each_input!)
|
118
|
+
end
|
119
|
+
|
120
|
+
alias each each_input
|
121
|
+
|
122
|
+
end# Mixer
|
123
|
+
|
124
|
+
|
78
125
|
class Envelope
|
79
126
|
|
127
|
+
def initialize(
|
128
|
+
attack = nil, decay = nil, sustain = nil, release = nil,
|
129
|
+
*args, **kwargs, &block)
|
130
|
+
|
131
|
+
attack_time attack if attack
|
132
|
+
decay_time decay if decay
|
133
|
+
sustain_level sustain if sustain
|
134
|
+
release_time release if release
|
135
|
+
|
136
|
+
super(*args, **kwargs, &block)
|
137
|
+
end
|
138
|
+
|
80
139
|
def note_on(delay = 0)
|
81
140
|
note_on! delay
|
82
141
|
end
|
@@ -115,6 +174,8 @@ module Beeps
|
|
115
174
|
|
116
175
|
class Analyser
|
117
176
|
|
177
|
+
universal_accessor :fft_size
|
178
|
+
|
118
179
|
def each_signal(nsamples = fft_size, &block)
|
119
180
|
return enum_for(:each_signal, nsamples) unless block
|
120
181
|
each_signal!(nsamples, &block)
|
@@ -125,8 +186,6 @@ module Beeps
|
|
125
186
|
each_spectrum!(&block)
|
126
187
|
end
|
127
188
|
|
128
|
-
universal_accessor :fft_size
|
129
|
-
|
130
189
|
end# Analyser
|
131
190
|
|
132
191
|
|
data/src/envelope.cpp
CHANGED
@@ -11,6 +11,9 @@ namespace Beeps
|
|
11
11
|
{
|
12
12
|
|
13
13
|
|
14
|
+
static const float TIME_ZERO = 0.0000001;
|
15
|
+
|
16
|
+
|
14
17
|
struct Envelope::Data
|
15
18
|
{
|
16
19
|
|
@@ -18,16 +21,19 @@ namespace Beeps
|
|
18
21
|
|
19
22
|
Signals adsr_signals;
|
20
23
|
|
21
|
-
float attack_time
|
24
|
+
float attack_time = 0.005;
|
25
|
+
float decay_time = 0.005;
|
26
|
+
float sustain_level = 1;
|
27
|
+
float release_time = 0.005;
|
22
28
|
|
23
29
|
float time = 0, note_on_time = -1, note_off_time = -1;
|
24
30
|
|
25
31
|
void update_envelope ()
|
26
32
|
{
|
27
|
-
adsr.setAttackTime( attack_time == 0 ? 0.01 : attack_time);
|
28
33
|
adsr.setSustainLevel(sustain_level);
|
29
|
-
adsr.
|
30
|
-
adsr.
|
34
|
+
adsr.setAttackTime( attack_time == 0 ? TIME_ZERO : attack_time);
|
35
|
+
adsr.setDecayTime( decay_time == 0 ? TIME_ZERO : decay_time);
|
36
|
+
adsr.setReleaseTime(release_time == 0 ? TIME_ZERO : release_time);
|
31
37
|
}
|
32
38
|
|
33
39
|
};// Envelope::Data
|
@@ -167,6 +173,9 @@ namespace Beeps
|
|
167
173
|
Frames* frames = Signals_get_frames(signals);
|
168
174
|
assert(frames);
|
169
175
|
|
176
|
+
if (self->time == 0 && self->attack_time == 0)
|
177
|
+
self->adsr.setValue(self->sustain_level);// skip attack phase
|
178
|
+
|
170
179
|
float start = self->time;
|
171
180
|
float end = start + Signals_get_seconds(*signals);
|
172
181
|
self->time = end;
|
@@ -175,7 +184,7 @@ namespace Beeps
|
|
175
184
|
float off = self->note_off_time;
|
176
185
|
assert(on <= off);
|
177
186
|
|
178
|
-
bool has_on
|
187
|
+
bool has_on = 0 <= on && start <= on && on < end;
|
179
188
|
bool has_off = 0 <= off && start <= off && off < end;
|
180
189
|
|
181
190
|
if (!has_on && !has_off)
|
data/src/mixer.cpp
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#include "beeps/filter.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <algorithm>
|
5
|
+
#include <vector>
|
6
|
+
#include "processor.h"
|
7
|
+
#include "signals.h"
|
8
|
+
|
9
|
+
|
10
|
+
namespace Beeps
|
11
|
+
{
|
12
|
+
|
13
|
+
|
14
|
+
struct Mixer::Data
|
15
|
+
{
|
16
|
+
|
17
|
+
std::vector<Processor::Ref> inputs;
|
18
|
+
|
19
|
+
};// Mixer::Data
|
20
|
+
|
21
|
+
|
22
|
+
Mixer::Mixer (Processor* input)
|
23
|
+
{
|
24
|
+
if (input) add_input(input);
|
25
|
+
}
|
26
|
+
|
27
|
+
Mixer::~Mixer ()
|
28
|
+
{
|
29
|
+
}
|
30
|
+
|
31
|
+
void
|
32
|
+
Mixer::add_input (Processor* input)
|
33
|
+
{
|
34
|
+
auto it = std::find(self->inputs.begin(), self->inputs.end(), input);
|
35
|
+
if (it != self->inputs.end()) return;
|
36
|
+
|
37
|
+
self->inputs.emplace_back(input);
|
38
|
+
|
39
|
+
set_updated();
|
40
|
+
}
|
41
|
+
|
42
|
+
void
|
43
|
+
Mixer::remove_input (Processor* input)
|
44
|
+
{
|
45
|
+
auto it = std::find(self->inputs.begin(), self->inputs.end(), input);
|
46
|
+
if (it == self->inputs.end()) return;
|
47
|
+
|
48
|
+
self->inputs.erase(it);
|
49
|
+
|
50
|
+
set_updated();
|
51
|
+
}
|
52
|
+
|
53
|
+
Mixer::iterator
|
54
|
+
Mixer::begin ()
|
55
|
+
{
|
56
|
+
return self->inputs.begin();
|
57
|
+
}
|
58
|
+
|
59
|
+
Mixer::const_iterator
|
60
|
+
Mixer::begin () const
|
61
|
+
{
|
62
|
+
return self->inputs.begin();
|
63
|
+
}
|
64
|
+
|
65
|
+
Mixer::iterator
|
66
|
+
Mixer::end ()
|
67
|
+
{
|
68
|
+
return self->inputs.end();
|
69
|
+
}
|
70
|
+
|
71
|
+
Mixer::const_iterator
|
72
|
+
Mixer::end () const
|
73
|
+
{
|
74
|
+
return self->inputs.end();
|
75
|
+
}
|
76
|
+
|
77
|
+
void
|
78
|
+
Mixer::filter (Context* context, Signals* signals, uint* offset)
|
79
|
+
{
|
80
|
+
Super::filter(context, signals, offset);
|
81
|
+
|
82
|
+
Signals_resize(signals, signals->capacity(), 0);
|
83
|
+
|
84
|
+
Signals sig = Signals_create(signals->capacity(), signals->nchannels());
|
85
|
+
uint min_size = signals->capacity();
|
86
|
+
for (auto& input : self->inputs)
|
87
|
+
{
|
88
|
+
Signals_clear(&sig);
|
89
|
+
|
90
|
+
uint sig_offset = *offset;
|
91
|
+
Processor_get_context(context)->process(input, &sig, &sig_offset);
|
92
|
+
|
93
|
+
uint size = sig_offset - *offset;
|
94
|
+
if (size < min_size) min_size = size;
|
95
|
+
|
96
|
+
Signals_add(signals, sig);
|
97
|
+
}
|
98
|
+
|
99
|
+
*offset += min_size;
|
100
|
+
}
|
101
|
+
|
102
|
+
Mixer::operator bool () const
|
103
|
+
{
|
104
|
+
if (self->inputs.empty()) return false;
|
105
|
+
|
106
|
+
for (auto& input : self->inputs)
|
107
|
+
if (!*input) return false;
|
108
|
+
return true;
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
}// Beeps
|
data/src/oscillator.cpp
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
|
4
4
|
#include <assert.h>
|
5
|
+
#include <cmath>
|
6
|
+
#include <vector>
|
5
7
|
#include "SineWave.h"
|
6
8
|
#include "Blit.h"
|
7
9
|
#include "BlitSquare.h"
|
@@ -14,6 +16,42 @@ namespace Beeps
|
|
14
16
|
{
|
15
17
|
|
16
18
|
|
19
|
+
class SineWave : public stk::SineWave
|
20
|
+
{
|
21
|
+
|
22
|
+
public:
|
23
|
+
|
24
|
+
void setPhase (stk::StkFloat phase)
|
25
|
+
{
|
26
|
+
time_ = std::fmod(phase, 1.f) * TABLE_SIZE;
|
27
|
+
}
|
28
|
+
|
29
|
+
stk::StkFloat getPhase () const
|
30
|
+
{
|
31
|
+
return time_ / TABLE_SIZE;
|
32
|
+
}
|
33
|
+
|
34
|
+
};// SineWave
|
35
|
+
|
36
|
+
|
37
|
+
class BlitSaw : public stk::BlitSaw
|
38
|
+
{
|
39
|
+
|
40
|
+
public:
|
41
|
+
|
42
|
+
void setPhase (stk::StkFloat phase)
|
43
|
+
{
|
44
|
+
phase_ = M_PI * phase;
|
45
|
+
}
|
46
|
+
|
47
|
+
stk::StkFloat getPhase () const
|
48
|
+
{
|
49
|
+
return phase_ / M_PI;
|
50
|
+
}
|
51
|
+
|
52
|
+
};// BlitSaw
|
53
|
+
|
54
|
+
|
17
55
|
class Osc
|
18
56
|
{
|
19
57
|
|
@@ -27,10 +65,14 @@ namespace Beeps
|
|
27
65
|
|
28
66
|
virtual void set_frequency (float freq) = 0;
|
29
67
|
|
68
|
+
virtual void set_phase (float phase) = 0;
|
69
|
+
|
70
|
+
virtual float phase () const = 0;
|
71
|
+
|
30
72
|
};// Osc
|
31
73
|
|
32
74
|
|
33
|
-
template <typename OSC>
|
75
|
+
template <typename OSC, uint DROP_MSEC>
|
34
76
|
class StkOsc : public Osc
|
35
77
|
{
|
36
78
|
|
@@ -39,10 +81,18 @@ namespace Beeps
|
|
39
81
|
void reset () override
|
40
82
|
{
|
41
83
|
osc.reset();
|
84
|
+
drop_msec = DROP_MSEC;
|
42
85
|
}
|
43
86
|
|
44
87
|
void tick (Frames* frames) override
|
45
88
|
{
|
89
|
+
if (drop_msec > 0)
|
90
|
+
{
|
91
|
+
Frames f((uint) (frames->dataRate() * (drop_msec / 1000.0)));
|
92
|
+
osc.tick(f);
|
93
|
+
drop_msec = 0;
|
94
|
+
}
|
95
|
+
|
46
96
|
osc.tick(*frames);
|
47
97
|
}
|
48
98
|
|
@@ -51,21 +101,33 @@ namespace Beeps
|
|
51
101
|
osc.setFrequency(freq);
|
52
102
|
}
|
53
103
|
|
104
|
+
void set_phase (float phase) override
|
105
|
+
{
|
106
|
+
osc.setPhase(phase);
|
107
|
+
}
|
108
|
+
|
109
|
+
float phase () const override
|
110
|
+
{
|
111
|
+
return osc.getPhase();
|
112
|
+
}
|
113
|
+
|
54
114
|
protected:
|
55
115
|
|
56
116
|
OSC osc;
|
57
117
|
|
118
|
+
uint drop_msec = DROP_MSEC;
|
119
|
+
|
58
120
|
};// StkOsc
|
59
121
|
|
60
122
|
|
61
|
-
typedef StkOsc<
|
123
|
+
typedef StkOsc<SineWave, 0> SineOsc;
|
62
124
|
|
63
|
-
typedef StkOsc<stk::BlitSquare> SquareOsc;
|
125
|
+
typedef StkOsc<stk::BlitSquare, 100> SquareOsc;
|
64
126
|
|
65
|
-
typedef StkOsc<
|
127
|
+
typedef StkOsc<BlitSaw, 200> SawtoothOsc;
|
66
128
|
|
67
129
|
|
68
|
-
class TriangleOsc : public StkOsc<stk::Blit>
|
130
|
+
class TriangleOsc : public StkOsc<stk::Blit, 0>
|
69
131
|
{
|
70
132
|
|
71
133
|
public:
|
@@ -78,6 +140,164 @@ namespace Beeps
|
|
78
140
|
};// TriangleOsc
|
79
141
|
|
80
142
|
|
143
|
+
class NoiseOsc : public Osc
|
144
|
+
{
|
145
|
+
|
146
|
+
public:
|
147
|
+
|
148
|
+
void reset () override
|
149
|
+
{
|
150
|
+
time = 0;
|
151
|
+
}
|
152
|
+
|
153
|
+
void tick (Frames* frames) override
|
154
|
+
{
|
155
|
+
if (0 < freq && (freq * 2) <= frames->sample_rate())
|
156
|
+
tick_with_freq(frames);
|
157
|
+
else
|
158
|
+
tick_without_freq(frames);
|
159
|
+
}
|
160
|
+
|
161
|
+
void set_frequency (float freq) override
|
162
|
+
{
|
163
|
+
this->freq = freq;
|
164
|
+
}
|
165
|
+
|
166
|
+
void set_phase (float phase) override
|
167
|
+
{
|
168
|
+
time = freq == 0 ? 0 : phase * (1.f / freq);
|
169
|
+
}
|
170
|
+
|
171
|
+
float phase () const override
|
172
|
+
{
|
173
|
+
return freq == 0 ? 0 : time / (1.f / freq);
|
174
|
+
}
|
175
|
+
|
176
|
+
private:
|
177
|
+
|
178
|
+
float freq = 0;
|
179
|
+
|
180
|
+
double time = 0;
|
181
|
+
|
182
|
+
void tick_without_freq (Frames* frames)
|
183
|
+
{
|
184
|
+
uint nchannels = frames->nchannels();
|
185
|
+
uint nframes = frames->nframes();
|
186
|
+
Float* pframe = &(*frames)(0, 0);
|
187
|
+
for (uint i = 0; i < nframes; ++i, ++pframe)
|
188
|
+
{
|
189
|
+
uint ch = i % nchannels;
|
190
|
+
*pframe = ch == 0 ? noise() : pframe[-ch];
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
void tick_with_freq (Frames* frames)
|
195
|
+
{
|
196
|
+
float time_per_sample = 1.f / frames->sample_rate();
|
197
|
+
float time_per_freq = 1.f / (freq * 2);
|
198
|
+
|
199
|
+
uint nchannels = frames->nchannels();
|
200
|
+
uint nframes = frames->nframes();
|
201
|
+
Float* pframe = &(*frames)(0, 0);
|
202
|
+
float value = noise();
|
203
|
+
for (uint i = 0; i < nframes; ++i, ++pframe)
|
204
|
+
{
|
205
|
+
if (i % nchannels == 0)
|
206
|
+
{
|
207
|
+
*pframe = value;
|
208
|
+
|
209
|
+
time += time_per_sample;
|
210
|
+
while (time >= time_per_freq)
|
211
|
+
{
|
212
|
+
value = noise();
|
213
|
+
time -= time_per_freq;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
else
|
217
|
+
*pframe = value;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
double noise () const
|
222
|
+
{
|
223
|
+
return rand() / ((double) RAND_MAX + 1) * 2 - 1;
|
224
|
+
}
|
225
|
+
|
226
|
+
};// NoiseOsc
|
227
|
+
|
228
|
+
|
229
|
+
class WaveformOsc : public Osc
|
230
|
+
{
|
231
|
+
|
232
|
+
public:
|
233
|
+
|
234
|
+
typedef std::vector<float> Table;
|
235
|
+
|
236
|
+
WaveformOsc (float* samples, size_t nsamples, float frequency)
|
237
|
+
: table(samples, samples + nsamples), freq(frequency), time(0)
|
238
|
+
{
|
239
|
+
}
|
240
|
+
|
241
|
+
void reset () override
|
242
|
+
{
|
243
|
+
time = 0;
|
244
|
+
}
|
245
|
+
|
246
|
+
void tick (Frames* frames) override
|
247
|
+
{
|
248
|
+
size_t size = table.size();
|
249
|
+
float dt = size * freq / frames->sample_rate();
|
250
|
+
|
251
|
+
uint nchannels = frames->nchannels();
|
252
|
+
uint nframes = frames->nframes();
|
253
|
+
Float* pframe = &(*frames)(0, 0);
|
254
|
+
for (uint i = 0; i < nframes; ++i, ++pframe)
|
255
|
+
{
|
256
|
+
uint ch = i % nchannels;
|
257
|
+
if (ch == 0)
|
258
|
+
{
|
259
|
+
size_t index0 = (size_t) time;
|
260
|
+
size_t index1 = index0 == size - 1 ? 0 : index0 + 1;
|
261
|
+
float frac = time - index0;
|
262
|
+
*pframe = table[index0] * (1.f - frac) + table[index1] * frac;
|
263
|
+
|
264
|
+
time += dt;
|
265
|
+
while (time >= size) time -= size;
|
266
|
+
}
|
267
|
+
else
|
268
|
+
*pframe = pframe[-ch];
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
void set_frequency (float freq) override
|
273
|
+
{
|
274
|
+
this->freq = freq;
|
275
|
+
}
|
276
|
+
|
277
|
+
void set_phase (float phase) override
|
278
|
+
{
|
279
|
+
this->time = std::fmod(phase, 1.f) * table.size();
|
280
|
+
}
|
281
|
+
|
282
|
+
float phase () const override
|
283
|
+
{
|
284
|
+
return time / table.size();
|
285
|
+
}
|
286
|
+
|
287
|
+
const Table& samples () const
|
288
|
+
{
|
289
|
+
return table;
|
290
|
+
}
|
291
|
+
|
292
|
+
private:
|
293
|
+
|
294
|
+
Table table;
|
295
|
+
|
296
|
+
float freq, time;
|
297
|
+
|
298
|
+
};// WaveformOsc
|
299
|
+
|
300
|
+
|
81
301
|
struct Oscillator::Data
|
82
302
|
{
|
83
303
|
|
@@ -95,6 +315,11 @@ namespace Beeps
|
|
95
315
|
set_type(type);
|
96
316
|
}
|
97
317
|
|
318
|
+
Oscillator::Oscillator (float* samples, size_t size)
|
319
|
+
{
|
320
|
+
set_samples(samples, size);
|
321
|
+
}
|
322
|
+
|
98
323
|
Oscillator::~Oscillator ()
|
99
324
|
{
|
100
325
|
}
|
@@ -111,6 +336,8 @@ namespace Beeps
|
|
111
336
|
{
|
112
337
|
if (type == self->type) return;
|
113
338
|
|
339
|
+
float phase = self->osc ? self->osc->phase() : 0;
|
340
|
+
|
114
341
|
self->type = type;
|
115
342
|
self->osc.reset();
|
116
343
|
|
@@ -120,12 +347,15 @@ namespace Beeps
|
|
120
347
|
case TRIANGLE: self->osc.reset(new TriangleOsc()); break;
|
121
348
|
case SQUARE: self->osc.reset(new SquareOsc()); break;
|
122
349
|
case SAWTOOTH: self->osc.reset(new SawtoothOsc()); break;
|
350
|
+
case NOISE: self->osc.reset(new NoiseOsc()); break;
|
123
351
|
default:
|
124
352
|
argument_error(
|
125
353
|
__FILE__, __LINE__, "unknown oscilator type '%d'", self->type);
|
126
354
|
break;
|
127
355
|
}
|
128
356
|
|
357
|
+
self->osc->set_phase(phase);
|
358
|
+
|
129
359
|
set_updated();
|
130
360
|
}
|
131
361
|
|
@@ -135,6 +365,38 @@ namespace Beeps
|
|
135
365
|
return self->type;
|
136
366
|
}
|
137
367
|
|
368
|
+
void
|
369
|
+
Oscillator::set_samples (float* samples, size_t size)
|
370
|
+
{
|
371
|
+
float phase = self->osc ? self->osc->phase() : 0;
|
372
|
+
|
373
|
+
self->type = SAMPLES;
|
374
|
+
self->osc.reset(new WaveformOsc(samples, size, frequency()));
|
375
|
+
self->osc->set_phase(phase);
|
376
|
+
|
377
|
+
set_updated();
|
378
|
+
}
|
379
|
+
|
380
|
+
const float*
|
381
|
+
Oscillator::samples () const
|
382
|
+
{
|
383
|
+
if (self->type != SAMPLES)
|
384
|
+
return NULL;
|
385
|
+
|
386
|
+
auto* osc = (const WaveformOsc*) self->osc.get();
|
387
|
+
return &osc->samples()[0];
|
388
|
+
}
|
389
|
+
|
390
|
+
size_t
|
391
|
+
Oscillator::nsamples () const
|
392
|
+
{
|
393
|
+
if (self->type != SAMPLES)
|
394
|
+
return 0;
|
395
|
+
|
396
|
+
auto* osc = (WaveformOsc*) self->osc.get();
|
397
|
+
return osc->samples().size();
|
398
|
+
}
|
399
|
+
|
138
400
|
void
|
139
401
|
Oscillator::set_frequency (float frequency)
|
140
402
|
{
|
@@ -142,7 +404,6 @@ namespace Beeps
|
|
142
404
|
argument_error(__FILE__, __LINE__);
|
143
405
|
|
144
406
|
self->frequency = frequency;
|
145
|
-
|
146
407
|
set_updated();
|
147
408
|
}
|
148
409
|
|
@@ -152,6 +413,19 @@ namespace Beeps
|
|
152
413
|
return self->frequency;
|
153
414
|
}
|
154
415
|
|
416
|
+
void
|
417
|
+
Oscillator::set_phase (float phase)
|
418
|
+
{
|
419
|
+
self->osc->set_phase(phase);
|
420
|
+
set_updated();
|
421
|
+
}
|
422
|
+
|
423
|
+
float
|
424
|
+
Oscillator::phase () const
|
425
|
+
{
|
426
|
+
return self->osc->phase();
|
427
|
+
}
|
428
|
+
|
155
429
|
void
|
156
430
|
Oscillator::generate (Context* context, Signals* signals, uint* offset)
|
157
431
|
{
|