beeps 0.1.32 → 0.1.33
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 +139 -0
- data/.doc/ext/beeps/analyser.cpp +128 -0
- data/.doc/ext/beeps/beeps.cpp +9 -1
- data/.doc/ext/beeps/file_in.cpp +55 -9
- data/.doc/ext/beeps/gain.cpp +64 -0
- data/.doc/ext/beeps/mic_in.cpp +83 -0
- data/.doc/ext/beeps/native.cpp +20 -8
- data/.doc/ext/beeps/oscillator.cpp +88 -0
- data/.doc/ext/beeps/pitch_shift.cpp +64 -0
- data/.doc/ext/beeps/processor.cpp +31 -2
- data/.doc/ext/beeps/sound.cpp +90 -7
- data/.doc/ext/beeps/sound_player.cpp +156 -0
- data/.doc/ext/beeps/time_stretch.cpp +64 -0
- data/.github/workflows/release-gem.yml +4 -1
- data/ChangeLog.md +8 -0
- data/Rakefile +26 -4
- data/VERSION +1 -1
- data/beeps.gemspec +2 -2
- data/ext/beeps/adsr.cpp +150 -0
- data/ext/beeps/analyser.cpp +134 -0
- data/ext/beeps/beeps.cpp +10 -1
- data/ext/beeps/extconf.rb +1 -2
- data/ext/beeps/file_in.cpp +60 -9
- data/ext/beeps/gain.cpp +67 -0
- data/ext/beeps/mic_in.cpp +88 -0
- data/ext/beeps/native.cpp +20 -8
- data/ext/beeps/oscillator.cpp +93 -0
- data/ext/beeps/pitch_shift.cpp +67 -0
- data/ext/beeps/processor.cpp +34 -2
- data/ext/beeps/sound.cpp +99 -7
- data/ext/beeps/sound_player.cpp +169 -0
- data/ext/beeps/time_stretch.cpp +67 -0
- data/include/beeps/beeps.h +2 -1
- data/include/beeps/filter.h +179 -0
- data/include/beeps/generator.h +120 -0
- data/include/beeps/processor.h +37 -68
- data/include/beeps/ruby/filter.h +78 -0
- data/include/beeps/ruby/generator.h +60 -0
- data/include/beeps/ruby/processor.h +5 -45
- data/include/beeps/ruby/sound.h +14 -3
- data/include/beeps/signals.h +10 -4
- data/include/beeps/sound.h +67 -2
- data/lib/beeps/beeps.rb +6 -1
- data/lib/beeps/processor.rb +95 -15
- data/lib/beeps/sound.rb +29 -2
- data/src/adsr.cpp +245 -0
- data/src/analyser.cpp +254 -0
- data/src/beeps.cpp +11 -2
- data/src/file_in.cpp +94 -0
- data/src/gain.cpp +55 -0
- data/src/mic_in.cpp +262 -0
- data/src/mic_in.h +20 -0
- data/src/openal.cpp +2 -1
- data/src/oscillator.cpp +145 -0
- data/src/osx/signals.mm +83 -0
- data/src/pitch_shift.cpp +82 -0
- data/src/processor.cpp +202 -88
- data/src/processor.h +98 -0
- data/src/signals.cpp +326 -20
- data/src/signals.h +192 -2
- data/src/sound.cpp +735 -113
- data/src/sound.h +6 -1
- data/src/time_stretch.cpp +91 -0
- data/test/helper.rb +2 -1
- data/test/test_beeps.rb +10 -7
- data/test/test_beeps_init.rb +18 -0
- data/test/test_file_in.rb +15 -0
- data/test/test_processor.rb +50 -0
- data/test/test_sound.rb +87 -11
- data/test/test_sound_player.rb +134 -0
- metadata +54 -16
- data/.doc/ext/beeps/sawtooth_wave.cpp +0 -61
- data/.doc/ext/beeps/sine_wave.cpp +0 -61
- data/.doc/ext/beeps/square_wave.cpp +0 -61
- data/ext/beeps/sawtooth_wave.cpp +0 -64
- data/ext/beeps/sine_wave.cpp +0 -64
- data/ext/beeps/square_wave.cpp +0 -64
data/lib/beeps/sound.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
|
4
|
+
require 'xot/setter'
|
5
|
+
require 'xot/universal_accessor'
|
6
|
+
require 'xot/block_util'
|
4
7
|
require 'beeps/ext'
|
5
8
|
|
6
9
|
|
@@ -9,11 +12,35 @@ module Beeps
|
|
9
12
|
|
10
13
|
class Sound
|
11
14
|
|
12
|
-
|
13
|
-
|
15
|
+
include Xot::Setter
|
16
|
+
|
17
|
+
def initialize(
|
18
|
+
processor, seconds = 0, nchannels: 1, sample_rate: 0, **options, &block)
|
19
|
+
|
20
|
+
setup processor, seconds, nchannels, sample_rate
|
21
|
+
set(**options) unless options.empty?
|
22
|
+
Xot::BlockUtil.instance_eval_or_block_call self, &block if block
|
14
23
|
end
|
15
24
|
|
25
|
+
def play(**options, &block)
|
26
|
+
play!.tap do |player|
|
27
|
+
player.set(**options) unless options.empty?
|
28
|
+
Xot::BlockUtil.instance_eval_or_block_call player, &block if block
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
universal_accessor :gain, :loop
|
33
|
+
|
16
34
|
end# Sound
|
17
35
|
|
18
36
|
|
37
|
+
class SoundPlayer
|
38
|
+
|
39
|
+
include Xot::Setter
|
40
|
+
|
41
|
+
universal_accessor :gain, :loop
|
42
|
+
|
43
|
+
end# SoundPlayer
|
44
|
+
|
45
|
+
|
19
46
|
end# Beeps
|
data/src/adsr.cpp
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
#include "beeps/filter.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <ADSR.h>
|
5
|
+
#include "signals.h"
|
6
|
+
|
7
|
+
|
8
|
+
namespace Beeps
|
9
|
+
{
|
10
|
+
|
11
|
+
|
12
|
+
struct ADSR::Data
|
13
|
+
{
|
14
|
+
|
15
|
+
stk::ADSR adsr;
|
16
|
+
|
17
|
+
Signals adsr_signals;
|
18
|
+
|
19
|
+
float attack_time = 0, decay_time = 0, sustain_level = 1, release_time = 0;
|
20
|
+
|
21
|
+
float time = 0, note_on_time = -1, note_off_time = -1;
|
22
|
+
|
23
|
+
void update_envelope ()
|
24
|
+
{
|
25
|
+
adsr.setAttackTime( attack_time == 0 ? 0.01 : attack_time);
|
26
|
+
adsr.setSustainLevel(sustain_level);
|
27
|
+
adsr.setDecayTime( decay_time == 0 ? 0.01 : decay_time);
|
28
|
+
adsr.setReleaseTime( release_time == 0 ? 0.01 : release_time);
|
29
|
+
}
|
30
|
+
|
31
|
+
};// ADSR::Data
|
32
|
+
|
33
|
+
|
34
|
+
ADSR::ADSR (Processor* input)
|
35
|
+
: Super(input)
|
36
|
+
{
|
37
|
+
self->update_envelope();
|
38
|
+
}
|
39
|
+
|
40
|
+
ADSR::~ADSR ()
|
41
|
+
{
|
42
|
+
}
|
43
|
+
|
44
|
+
void
|
45
|
+
ADSR::note_on (float delay)
|
46
|
+
{
|
47
|
+
if (delay < 0)
|
48
|
+
argument_error(__FILE__, __LINE__);
|
49
|
+
|
50
|
+
float on = self->time + delay, off = self->note_off_time;
|
51
|
+
if (0 <= off && off < on)
|
52
|
+
self->note_off_time = -1;
|
53
|
+
|
54
|
+
self->note_on_time = on;
|
55
|
+
|
56
|
+
set_updated();
|
57
|
+
}
|
58
|
+
|
59
|
+
void
|
60
|
+
ADSR::note_off (float delay)
|
61
|
+
{
|
62
|
+
if (delay < 0)
|
63
|
+
argument_error(__FILE__, __LINE__);
|
64
|
+
|
65
|
+
float off = self->time + delay, on = self->note_on_time;
|
66
|
+
if (0 <= on && off < on)
|
67
|
+
argument_error(__FILE__, __LINE__);
|
68
|
+
|
69
|
+
self->note_off_time = off;
|
70
|
+
|
71
|
+
set_updated();
|
72
|
+
}
|
73
|
+
|
74
|
+
void
|
75
|
+
ADSR::set_attack_time (float time)
|
76
|
+
{
|
77
|
+
if (time < 0)
|
78
|
+
argument_error(__FILE__, __LINE__);
|
79
|
+
|
80
|
+
self->attack_time = time;
|
81
|
+
self->update_envelope();
|
82
|
+
|
83
|
+
set_updated();
|
84
|
+
}
|
85
|
+
|
86
|
+
float
|
87
|
+
ADSR::attack_time () const
|
88
|
+
{
|
89
|
+
return self->attack_time;
|
90
|
+
}
|
91
|
+
|
92
|
+
void
|
93
|
+
ADSR::set_decay_time (float time)
|
94
|
+
{
|
95
|
+
if (time < 0)
|
96
|
+
argument_error(__FILE__, __LINE__);
|
97
|
+
|
98
|
+
self->decay_time = time;
|
99
|
+
self->update_envelope();
|
100
|
+
|
101
|
+
set_updated();
|
102
|
+
}
|
103
|
+
|
104
|
+
float
|
105
|
+
ADSR::decay_time () const
|
106
|
+
{
|
107
|
+
return self->decay_time;
|
108
|
+
}
|
109
|
+
|
110
|
+
void
|
111
|
+
ADSR::set_sustain_level (float level)
|
112
|
+
{
|
113
|
+
if (level < 0)
|
114
|
+
argument_error(__FILE__, __LINE__);
|
115
|
+
|
116
|
+
self->sustain_level = level;
|
117
|
+
self->update_envelope();
|
118
|
+
|
119
|
+
set_updated();
|
120
|
+
}
|
121
|
+
|
122
|
+
float
|
123
|
+
ADSR::sustain_level () const
|
124
|
+
{
|
125
|
+
return self->sustain_level;
|
126
|
+
}
|
127
|
+
|
128
|
+
void
|
129
|
+
ADSR::set_release_time (float time)
|
130
|
+
{
|
131
|
+
if (time < 0)
|
132
|
+
argument_error(__FILE__, __LINE__);
|
133
|
+
|
134
|
+
self->release_time = time;
|
135
|
+
self->update_envelope();
|
136
|
+
|
137
|
+
set_updated();
|
138
|
+
}
|
139
|
+
|
140
|
+
float
|
141
|
+
ADSR::release_time () const
|
142
|
+
{
|
143
|
+
return self->release_time;
|
144
|
+
}
|
145
|
+
|
146
|
+
static size_t
|
147
|
+
slice (Frames* frames, size_t start, float length_sec = -1)
|
148
|
+
{
|
149
|
+
Float sample_rate = frames->dataRate();
|
150
|
+
size_t len = length_sec >= 0
|
151
|
+
? length_sec * sample_rate
|
152
|
+
: frames->nframes() - start;
|
153
|
+
assert(0 < len && (start + len) < frames->nsamples());
|
154
|
+
|
155
|
+
return frames->slice(start, len);
|
156
|
+
}
|
157
|
+
|
158
|
+
static void
|
159
|
+
process_envelope_signals (ADSR* adsr, Signals* signals)
|
160
|
+
{
|
161
|
+
assert(adsr && signals && signals->nchannels() == 1);
|
162
|
+
|
163
|
+
ADSR::Data* self = adsr->self.get();
|
164
|
+
|
165
|
+
Frames* frames = Signals_get_frames(signals);
|
166
|
+
assert(frames);
|
167
|
+
|
168
|
+
float start = self->time;
|
169
|
+
float end = start + Signals_get_seconds(*signals);
|
170
|
+
self->time = end;
|
171
|
+
|
172
|
+
float on = self->note_on_time;
|
173
|
+
float off = self->note_off_time;
|
174
|
+
assert(on <= off);
|
175
|
+
|
176
|
+
bool has_on = 0 <= on && start <= on && on < end;
|
177
|
+
bool has_off = 0 <= off && start <= off && off < end;
|
178
|
+
|
179
|
+
if (!has_on && !has_off)
|
180
|
+
{
|
181
|
+
self->adsr.tick(*frames);
|
182
|
+
return;
|
183
|
+
}
|
184
|
+
|
185
|
+
size_t last = 0;
|
186
|
+
if (has_on)
|
187
|
+
{
|
188
|
+
if (start < on)
|
189
|
+
{
|
190
|
+
last = slice(frames, 0, on - start);
|
191
|
+
self->adsr.tick(*frames);
|
192
|
+
frames->unslice();
|
193
|
+
}
|
194
|
+
self->adsr.keyOn();
|
195
|
+
}
|
196
|
+
if (has_on || has_off)
|
197
|
+
{
|
198
|
+
float len = has_off ? off - (has_on ? on : start) : -1;
|
199
|
+
last = slice(frames, last, len);
|
200
|
+
self->adsr.tick(*frames);
|
201
|
+
frames->unslice();
|
202
|
+
}
|
203
|
+
if (has_off)
|
204
|
+
{
|
205
|
+
self->adsr.keyOff();
|
206
|
+
if (off < end)
|
207
|
+
{
|
208
|
+
slice(frames, last, -1);
|
209
|
+
self->adsr.tick(*frames);
|
210
|
+
frames->unslice();
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
215
|
+
void
|
216
|
+
ADSR::filter (Context* context, Signals* signals, uint* offset)
|
217
|
+
{
|
218
|
+
Super::filter(context, signals, offset);
|
219
|
+
|
220
|
+
if (!self->adsr_signals)
|
221
|
+
{
|
222
|
+
self->adsr_signals =
|
223
|
+
Signals_create(signals->nsamples(), 1, signals->sample_rate());
|
224
|
+
}
|
225
|
+
|
226
|
+
if (self->adsr_signals.nsamples() != signals->nsamples())
|
227
|
+
Signals_resize(&self->adsr_signals, signals->nsamples(), 0);
|
228
|
+
|
229
|
+
process_envelope_signals(this, &self->adsr_signals);
|
230
|
+
Signals_apply(signals, self->adsr_signals);
|
231
|
+
}
|
232
|
+
|
233
|
+
ADSR::operator bool () const
|
234
|
+
{
|
235
|
+
if (!Super::operator bool()) return false;
|
236
|
+
return
|
237
|
+
self->attack_time >= 0 &&
|
238
|
+
self->decay_time >= 0 &&
|
239
|
+
self->sustain_level >= 0 &&
|
240
|
+
self->release_time >= 0 &&
|
241
|
+
self->time >= 0;
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
}// Beeps
|
data/src/analyser.cpp
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
#include "beeps/filter.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <math.h>
|
5
|
+
#include <algorithm>
|
6
|
+
#include "pffft.h"
|
7
|
+
#include "beeps/beeps.h"
|
8
|
+
#include "beeps/exception.h"
|
9
|
+
#include "signals.h"
|
10
|
+
|
11
|
+
|
12
|
+
namespace Beeps
|
13
|
+
{
|
14
|
+
|
15
|
+
|
16
|
+
struct PFFFTDestroySetup
|
17
|
+
{
|
18
|
+
void operator () (PFFFT_Setup* ptr)
|
19
|
+
{
|
20
|
+
pffft_destroy_setup(ptr);
|
21
|
+
}
|
22
|
+
};
|
23
|
+
|
24
|
+
struct PFFFTAlignedFree
|
25
|
+
{
|
26
|
+
void operator () (float* ptr)
|
27
|
+
{
|
28
|
+
pffft_aligned_free(ptr);
|
29
|
+
}
|
30
|
+
};
|
31
|
+
|
32
|
+
|
33
|
+
struct Analyser::Data
|
34
|
+
{
|
35
|
+
|
36
|
+
Signals signals;
|
37
|
+
|
38
|
+
Spectrum spectrum;
|
39
|
+
|
40
|
+
std::unique_ptr<PFFFT_Setup, PFFFTDestroySetup> pffft;
|
41
|
+
|
42
|
+
std::unique_ptr<float[], PFFFTAlignedFree> fft_buffer;
|
43
|
+
|
44
|
+
uint fft_size = 0;
|
45
|
+
|
46
|
+
~Data ()
|
47
|
+
{
|
48
|
+
clear();
|
49
|
+
}
|
50
|
+
|
51
|
+
void setup (uint size)
|
52
|
+
{
|
53
|
+
if (size == fft_size) return;
|
54
|
+
|
55
|
+
clear();
|
56
|
+
|
57
|
+
signals = Signals_create(std::min(size, (uint) Beeps::sample_rate()));
|
58
|
+
pffft .reset(pffft_new_setup(size, PFFFT_REAL));
|
59
|
+
fft_buffer.reset((float*) pffft_aligned_malloc(sizeof(float) * size));
|
60
|
+
fft_size = size;
|
61
|
+
}
|
62
|
+
|
63
|
+
void clear ()
|
64
|
+
{
|
65
|
+
if (!pffft) return;
|
66
|
+
|
67
|
+
signals = Signals();
|
68
|
+
spectrum .clear();
|
69
|
+
pffft .reset();
|
70
|
+
fft_buffer.reset();
|
71
|
+
fft_size = 0;
|
72
|
+
}
|
73
|
+
|
74
|
+
bool is_valid () const
|
75
|
+
{
|
76
|
+
return signals && pffft && fft_buffer && fft_size > 0;
|
77
|
+
}
|
78
|
+
|
79
|
+
};// Analyser::Data
|
80
|
+
|
81
|
+
|
82
|
+
Analyser::Analyser (uint fft_size, Processor* input)
|
83
|
+
: Super(input)
|
84
|
+
{
|
85
|
+
set_fft_size(fft_size);
|
86
|
+
}
|
87
|
+
|
88
|
+
Analyser::~Analyser ()
|
89
|
+
{
|
90
|
+
}
|
91
|
+
|
92
|
+
static bool
|
93
|
+
is_valid_fft_size (uint size)
|
94
|
+
{
|
95
|
+
if (size < 32) return false;
|
96
|
+
|
97
|
+
while (size > 1)
|
98
|
+
{
|
99
|
+
if (size % 2 == 0) size /= 2;
|
100
|
+
else if (size % 3 == 0) size /= 3;
|
101
|
+
else if (size % 5 == 0) size /= 5;
|
102
|
+
else break;
|
103
|
+
}
|
104
|
+
return size == 1;
|
105
|
+
}
|
106
|
+
|
107
|
+
void
|
108
|
+
Analyser::set_fft_size (uint size)
|
109
|
+
{
|
110
|
+
if (!is_valid_fft_size(size))
|
111
|
+
beeps_error(__FILE__, __LINE__, "fft_size must be divisible by 2, 3, or 5");
|
112
|
+
|
113
|
+
self->setup(size);
|
114
|
+
}
|
115
|
+
|
116
|
+
uint
|
117
|
+
Analyser::fft_size () const
|
118
|
+
{
|
119
|
+
return self->fft_size;
|
120
|
+
}
|
121
|
+
|
122
|
+
float
|
123
|
+
Analyser::resolution () const
|
124
|
+
{
|
125
|
+
if (self->fft_size == 0) return 0;
|
126
|
+
return self->signals.sample_rate() / self->fft_size;
|
127
|
+
}
|
128
|
+
|
129
|
+
const Signals&
|
130
|
+
Analyser::signals () const
|
131
|
+
{
|
132
|
+
return self->signals;
|
133
|
+
}
|
134
|
+
|
135
|
+
static void
|
136
|
+
copy_signals_to_fft_buffer (float* buffer, uint size, const Signals& signals)
|
137
|
+
{
|
138
|
+
const double* samples = signals.samples();
|
139
|
+
uint nsamples = size > signals.nsamples() ? signals.nsamples() : size;
|
140
|
+
|
141
|
+
switch (signals.nchannels())
|
142
|
+
{
|
143
|
+
case 1:
|
144
|
+
for (uint i = 0; i < nsamples; ++i)
|
145
|
+
buffer[i] = samples[i];
|
146
|
+
break;
|
147
|
+
|
148
|
+
case 2:
|
149
|
+
for (uint i = 0; i < nsamples; ++i, samples += 2)
|
150
|
+
buffer[i] = (samples[0] + samples[1]) * 0.5;
|
151
|
+
break;
|
152
|
+
|
153
|
+
default:
|
154
|
+
beeps_error(__FILE__, __LINE__);
|
155
|
+
}
|
156
|
+
|
157
|
+
for (uint i = nsamples; i < size; ++i)
|
158
|
+
buffer[i] = 0;
|
159
|
+
}
|
160
|
+
|
161
|
+
static void
|
162
|
+
update_spectrum (Analyser::Spectrum* spectrum, float* buffer, uint buffer_size)
|
163
|
+
{
|
164
|
+
assert(spectrum && spectrum->empty() && buffer && (buffer_size % 2) == 0);
|
165
|
+
|
166
|
+
uint size = buffer_size / 2;
|
167
|
+
float div = 1.0 / size;
|
168
|
+
float* p = buffer;
|
169
|
+
|
170
|
+
spectrum->reserve(size);
|
171
|
+
for (uint i = 0; i < size; ++i, p += 2)
|
172
|
+
spectrum->push_back(sqrt(p[0] * p[0] + p[1] * p[1]) * div);
|
173
|
+
}
|
174
|
+
|
175
|
+
const Analyser::Spectrum&
|
176
|
+
Analyser::spectrum () const
|
177
|
+
{
|
178
|
+
if (self->spectrum.empty() && *this)
|
179
|
+
{
|
180
|
+
float* p = &self->fft_buffer[0];
|
181
|
+
copy_signals_to_fft_buffer(p, self->fft_size, self->signals);
|
182
|
+
pffft_transform_ordered(self->pffft.get(), p, p, NULL, PFFFT_FORWARD);
|
183
|
+
update_spectrum(&self->spectrum, p, self->fft_size);
|
184
|
+
}
|
185
|
+
return self->spectrum;
|
186
|
+
}
|
187
|
+
|
188
|
+
static void
|
189
|
+
shift (Signals* signals, uint nsamples)
|
190
|
+
{
|
191
|
+
if (nsamples > signals->nsamples())
|
192
|
+
return Signals_clear(signals);
|
193
|
+
|
194
|
+
Frames* frames = Signals_get_frames(signals);
|
195
|
+
assert(frames);
|
196
|
+
|
197
|
+
Float* from = &(*frames)(nsamples, 0);
|
198
|
+
Float* to = &(*frames)(0, 0);
|
199
|
+
uint size = (signals->nsamples() - nsamples) * signals->nchannels();
|
200
|
+
for (uint i = 0; i < size; ++i)
|
201
|
+
*to++ = *from++;
|
202
|
+
|
203
|
+
Signals_set_nsamples(signals, signals->nsamples() - nsamples);
|
204
|
+
}
|
205
|
+
|
206
|
+
static void
|
207
|
+
append (Signals* to, const Signals& from)
|
208
|
+
{
|
209
|
+
assert(to);
|
210
|
+
|
211
|
+
Frames* tof = Signals_get_frames(to);
|
212
|
+
const Frames* fromf = Signals_get_frames(&from);
|
213
|
+
assert(fromf && tof);
|
214
|
+
|
215
|
+
uint to_cap = to->capacity();
|
216
|
+
uint to_nsamples = to->nsamples();
|
217
|
+
uint from_nsamples = from.nsamples();
|
218
|
+
uint from_start = from_nsamples > to_cap ? from_nsamples - to_cap : 0;
|
219
|
+
uint nsamples = from_nsamples - from_start;
|
220
|
+
assert(to_nsamples + nsamples <= to_capacity);
|
221
|
+
|
222
|
+
for (uint ch = 0; ch < tof->nchannels(); ++ch)
|
223
|
+
{
|
224
|
+
uint from_ch = ch < fromf->nchannels() ? ch : 0;
|
225
|
+
for (uint i = 0; i < nsamples; ++i)
|
226
|
+
(*tof)(to_nsamples + i, ch) = (*fromf)(from_start + i, from_ch);
|
227
|
+
}
|
228
|
+
|
229
|
+
Signals_set_nsamples(to, to_nsamples + nsamples);
|
230
|
+
}
|
231
|
+
|
232
|
+
void
|
233
|
+
Analyser::filter (Context* context, Signals* signals, uint* offset)
|
234
|
+
{
|
235
|
+
Super::filter(context, signals, offset);
|
236
|
+
|
237
|
+
Signals& sig = self->signals;
|
238
|
+
uint nsamples = sig.nsamples() + signals->nsamples();
|
239
|
+
if (nsamples > sig.capacity())
|
240
|
+
shift(&sig, nsamples - sig.capacity());
|
241
|
+
|
242
|
+
append(&sig, *signals);
|
243
|
+
|
244
|
+
self->spectrum.clear();
|
245
|
+
}
|
246
|
+
|
247
|
+
Analyser::operator bool () const
|
248
|
+
{
|
249
|
+
if (!Super::operator bool()) return false;
|
250
|
+
return self->is_valid();
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
}// Beeps
|
data/src/beeps.cpp
CHANGED
@@ -5,6 +5,8 @@
|
|
5
5
|
#include "Stk.h"
|
6
6
|
#include "beeps/exception.h"
|
7
7
|
#include "openal.h"
|
8
|
+
#include "sound.h"
|
9
|
+
#include "mic_in.h"
|
8
10
|
|
9
11
|
|
10
12
|
namespace Beeps
|
@@ -25,8 +27,15 @@ namespace Beeps
|
|
25
27
|
OpenAL_fin();
|
26
28
|
}
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
+
void
|
31
|
+
process_streams ()
|
32
|
+
{
|
33
|
+
MicIn_process_streams();
|
34
|
+
SoundPlayer_process_streams();
|
35
|
+
}
|
36
|
+
|
37
|
+
double
|
38
|
+
sample_rate ()
|
30
39
|
{
|
31
40
|
return stk::Stk::sampleRate();
|
32
41
|
}
|
data/src/file_in.cpp
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#include "beeps/generator.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include "beeps/exception.h"
|
5
|
+
#include "signals.h"
|
6
|
+
|
7
|
+
|
8
|
+
namespace Beeps
|
9
|
+
{
|
10
|
+
|
11
|
+
|
12
|
+
struct FileIn::Data
|
13
|
+
{
|
14
|
+
|
15
|
+
String path;
|
16
|
+
|
17
|
+
Signals signals;
|
18
|
+
|
19
|
+
};// FileIn::Data
|
20
|
+
|
21
|
+
|
22
|
+
FileIn::FileIn (const char* path)
|
23
|
+
{
|
24
|
+
if (path) set_path(path);
|
25
|
+
}
|
26
|
+
|
27
|
+
FileIn::~FileIn ()
|
28
|
+
{
|
29
|
+
}
|
30
|
+
|
31
|
+
void
|
32
|
+
FileIn::reset ()
|
33
|
+
{
|
34
|
+
Super::reset();
|
35
|
+
}
|
36
|
+
|
37
|
+
void
|
38
|
+
FileIn::set_path (const char* path)
|
39
|
+
{
|
40
|
+
if (*this)
|
41
|
+
invalid_state_error(__FILE__, __LINE__, "path is already set");
|
42
|
+
|
43
|
+
self->signals = Signals_load(path);
|
44
|
+
self->path = path;
|
45
|
+
|
46
|
+
set_updated();
|
47
|
+
}
|
48
|
+
|
49
|
+
const char*
|
50
|
+
FileIn::path () const
|
51
|
+
{
|
52
|
+
return self->path;
|
53
|
+
}
|
54
|
+
|
55
|
+
double
|
56
|
+
FileIn::sample_rate () const
|
57
|
+
{
|
58
|
+
return self->signals.sample_rate();
|
59
|
+
}
|
60
|
+
|
61
|
+
uint
|
62
|
+
FileIn::nchannels () const
|
63
|
+
{
|
64
|
+
return self->signals.nchannels();
|
65
|
+
}
|
66
|
+
|
67
|
+
uint
|
68
|
+
FileIn::nsamples () const
|
69
|
+
{
|
70
|
+
return self->signals.nsamples();
|
71
|
+
}
|
72
|
+
|
73
|
+
float
|
74
|
+
FileIn::seconds () const
|
75
|
+
{
|
76
|
+
return Signals_get_seconds(self->signals);
|
77
|
+
}
|
78
|
+
|
79
|
+
void
|
80
|
+
FileIn::generate (Context* context, Signals* signals, uint* offset)
|
81
|
+
{
|
82
|
+
Super::generate(context, signals, offset);
|
83
|
+
|
84
|
+
*offset += Signals_copy(signals, self->signals, *offset);
|
85
|
+
}
|
86
|
+
|
87
|
+
FileIn::operator bool () const
|
88
|
+
{
|
89
|
+
if (!Super::operator bool()) return false;
|
90
|
+
return self->signals;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
}// Beeps
|
data/src/gain.cpp
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
#include "beeps/filter.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include "signals.h"
|
5
|
+
|
6
|
+
|
7
|
+
namespace Beeps
|
8
|
+
{
|
9
|
+
|
10
|
+
|
11
|
+
struct Gain::Data
|
12
|
+
{
|
13
|
+
|
14
|
+
float gain = 1;
|
15
|
+
|
16
|
+
};// Gain::Data
|
17
|
+
|
18
|
+
|
19
|
+
Gain::Gain (Processor* input)
|
20
|
+
: Super(input)
|
21
|
+
{
|
22
|
+
}
|
23
|
+
|
24
|
+
Gain::~Gain ()
|
25
|
+
{
|
26
|
+
}
|
27
|
+
|
28
|
+
void
|
29
|
+
Gain::set_gain (float gain)
|
30
|
+
{
|
31
|
+
self->gain = gain;
|
32
|
+
|
33
|
+
set_updated();
|
34
|
+
}
|
35
|
+
|
36
|
+
float
|
37
|
+
Gain::gain () const
|
38
|
+
{
|
39
|
+
return self->gain;
|
40
|
+
}
|
41
|
+
|
42
|
+
void
|
43
|
+
Gain::filter (Context* context, Signals* signals, uint* offset)
|
44
|
+
{
|
45
|
+
Super::filter(context, signals, offset);
|
46
|
+
|
47
|
+
Frames* frames = Signals_get_frames(signals);
|
48
|
+
if (!frames)
|
49
|
+
argument_error(__FILE__, __LINE__);
|
50
|
+
|
51
|
+
*frames *= self->gain;
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
}// Beeps
|