beeps 0.3.11 → 0.3.12
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/sound_player.cpp +57 -0
- data/.github/workflows/release-gem.yml +3 -0
- data/.github/workflows/utils.rb +88 -17
- data/ChangeLog.md +14 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/beeps.gemspec +3 -4
- data/ext/beeps/extconf.rb +1 -1
- data/ext/beeps/sound_player.cpp +64 -1
- data/include/beeps/defs.h +2 -0
- data/include/beeps/filter.h +6 -0
- data/include/beeps/generator.h +8 -2
- data/include/beeps/processor.h +10 -8
- data/include/beeps/ruby.h +2 -2
- data/include/beeps/signals.h +14 -0
- data/include/beeps/sound.h +12 -0
- data/include/beeps.h +2 -2
- data/lib/beeps/extension.rb +8 -2
- data/lib/beeps/sound.rb +1 -1
- data/src/analyser.cpp +10 -3
- data/src/envelope.cpp +2 -5
- data/src/file_in.cpp +7 -1
- data/src/gain.cpp +7 -0
- data/src/mixer.cpp +16 -3
- data/src/oscillator.cpp +7 -1
- data/src/osx/signals.mm +4 -4
- data/src/osx/text_in.mm +1 -1
- data/src/processor.cpp +51 -38
- data/src/processor.h +1 -5
- data/src/reverb.cpp +2 -3
- data/src/sequencer.cpp +4 -4
- data/src/signals.cpp +178 -161
- data/src/signals.h +2 -15
- data/src/sound.cpp +154 -5
- data/src/time_stretch.cpp +2 -2
- data/src/value.cpp +8 -2
- data/src/win32/signals.cpp +9 -9
- data/src/x_pass.h +2 -3
- data/test/test_sound_player.rb +70 -0
- metadata +6 -6
data/src/signals.cpp
CHANGED
|
@@ -104,37 +104,6 @@ namespace Beeps
|
|
|
104
104
|
};// Signals::Data
|
|
105
105
|
|
|
106
106
|
|
|
107
|
-
Signals
|
|
108
|
-
Signals_create (uint capacity, uint nchannels, double sample_rate)
|
|
109
|
-
{
|
|
110
|
-
Signals s;
|
|
111
|
-
s.self->frames.reset(
|
|
112
|
-
new Frames(capacity * nchannels, nchannels, sample_rate));
|
|
113
|
-
return s;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
Signals
|
|
117
|
-
Signals_create (
|
|
118
|
-
const float* const* channels,
|
|
119
|
-
uint nsamples, uint nchannels, double sample_rate, uint capacity)
|
|
120
|
-
{
|
|
121
|
-
if (!channels)
|
|
122
|
-
argument_error(__FILE__, __LINE__);
|
|
123
|
-
|
|
124
|
-
Signals s = Signals_create(
|
|
125
|
-
capacity > nsamples ? capacity : nsamples, nchannels, sample_rate);
|
|
126
|
-
|
|
127
|
-
for (uint channel = 0; channel < nchannels; ++channel)
|
|
128
|
-
{
|
|
129
|
-
Sample* p = Signals_at(&s, 0, channel);
|
|
130
|
-
for (uint i = 0; i < nsamples; ++i, p += nchannels)
|
|
131
|
-
*p = channels[channel][i];
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
s.self->nsamples = nsamples;
|
|
135
|
-
return s;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
107
|
uint
|
|
139
108
|
Signals_tick (Signals* signals, std::function<void(stk::StkFrames*)> fun)
|
|
140
109
|
{
|
|
@@ -160,7 +129,7 @@ namespace Beeps
|
|
|
160
129
|
if (!input)
|
|
161
130
|
argument_error(__FILE__, __LINE__);
|
|
162
131
|
|
|
163
|
-
|
|
132
|
+
output->clear(input.nsamples());
|
|
164
133
|
Signals_set_nsamples(output, output->capacity());
|
|
165
134
|
|
|
166
135
|
fun(output->self->frames.get(), *input.self->frames);
|
|
@@ -189,29 +158,6 @@ namespace Beeps
|
|
|
189
158
|
return end;
|
|
190
159
|
}
|
|
191
160
|
|
|
192
|
-
void
|
|
193
|
-
Signals_clear (Signals* signals)
|
|
194
|
-
{
|
|
195
|
-
if (!signals)
|
|
196
|
-
argument_error(__FILE__, __LINE__);
|
|
197
|
-
|
|
198
|
-
signals->self->nsamples = 0;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
void
|
|
202
|
-
Signals_clear (Signals* signals, uint capacity)
|
|
203
|
-
{
|
|
204
|
-
if (!signals)
|
|
205
|
-
argument_error(__FILE__, __LINE__);
|
|
206
|
-
if (!*signals)
|
|
207
|
-
argument_error(__FILE__, __LINE__);
|
|
208
|
-
if (capacity <= 0)
|
|
209
|
-
argument_error(__FILE__, __LINE__);
|
|
210
|
-
|
|
211
|
-
Signals_clear(signals);
|
|
212
|
-
signals->self->frames->resize(capacity, signals->nchannels());
|
|
213
|
-
}
|
|
214
|
-
|
|
215
161
|
void
|
|
216
162
|
Signals_fill (Signals* signals, uint nsamples, Sample value, uint offset)
|
|
217
163
|
{
|
|
@@ -256,109 +202,6 @@ namespace Beeps
|
|
|
256
202
|
Signals_set_nsamples(signals, new_nsamples);
|
|
257
203
|
}
|
|
258
204
|
|
|
259
|
-
static uint
|
|
260
|
-
copy_samples (Signals* to, const Signals& from, uint from_offset)
|
|
261
|
-
{
|
|
262
|
-
assert(to && *to && from);
|
|
263
|
-
|
|
264
|
-
if (from_offset >= from.nsamples())
|
|
265
|
-
return 0;
|
|
266
|
-
|
|
267
|
-
uint to_nchannels = to->nchannels();
|
|
268
|
-
uint from_nchannels = from.nchannels();
|
|
269
|
-
uint to_offset = to->nsamples();
|
|
270
|
-
uint to_nsamples = to->capacity() - to_offset;
|
|
271
|
-
uint from_nsamples = from.nsamples();
|
|
272
|
-
uint copy_nsamples =
|
|
273
|
-
std::min(from_offset + to_nsamples, from_nsamples) - from_offset;
|
|
274
|
-
|
|
275
|
-
for (uint channel = 0; channel < to_nchannels; ++channel)
|
|
276
|
-
{
|
|
277
|
-
uint from_channel = channel < from_nchannels ? channel : 0;
|
|
278
|
-
Sample* to_p = Signals_at(to, to_offset, channel);
|
|
279
|
-
const Sample* from_p = Signals_at(from, from_offset, from_channel);
|
|
280
|
-
for (uint i = 0; i < copy_nsamples; ++i)
|
|
281
|
-
{
|
|
282
|
-
*to_p = *from_p;
|
|
283
|
-
to_p += to_nchannels;
|
|
284
|
-
from_p += from_nchannels;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
Signals_set_nsamples(to, to->self->nsamples + copy_nsamples);
|
|
289
|
-
return copy_nsamples;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
static uint
|
|
293
|
-
resample (Signals* to, const Signals& from, uint from_offset)
|
|
294
|
-
{
|
|
295
|
-
assert(to && *to && from);
|
|
296
|
-
|
|
297
|
-
if (from_offset >= from.nsamples())
|
|
298
|
-
return 0;
|
|
299
|
-
|
|
300
|
-
uint to_offset = to->nsamples();
|
|
301
|
-
float to_sec = (to->capacity() - to_offset) / to->sample_rate();
|
|
302
|
-
float from_offset_sec = from_offset / from.sample_rate();
|
|
303
|
-
float from_sec = from.nsamples() / from.sample_rate();
|
|
304
|
-
|
|
305
|
-
float copy_seconds =
|
|
306
|
-
std::min(from_offset_sec + to_sec, from_sec) - from_offset_sec;
|
|
307
|
-
|
|
308
|
-
uint to_nsamples = 0, from_nsamples = 0;
|
|
309
|
-
if (from_offset_sec + to_sec <= from_sec)
|
|
310
|
-
{
|
|
311
|
-
to_nsamples = to->capacity() - to->nsamples();
|
|
312
|
-
from_nsamples = copy_seconds * from.sample_rate();
|
|
313
|
-
}
|
|
314
|
-
else
|
|
315
|
-
{
|
|
316
|
-
to_nsamples = copy_seconds * to->sample_rate();
|
|
317
|
-
from_nsamples = from.nsamples() - from_offset;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
r8b::CDSPResampler24 resampler(
|
|
321
|
-
from.sample_rate(), to->sample_rate(), from_nsamples);
|
|
322
|
-
r8b::CFixedBuffer<double> from_buf(from_nsamples), to_buf(to_nsamples);
|
|
323
|
-
|
|
324
|
-
for (uint channel = 0; channel < to->nchannels(); ++channel)
|
|
325
|
-
{
|
|
326
|
-
uint from_channel = channel < from.nchannels() ? channel : 0;
|
|
327
|
-
|
|
328
|
-
for (uint i = 0; i < from_nsamples; ++i)
|
|
329
|
-
from_buf[i] = *Signals_at(from, from_offset + i, from_channel);
|
|
330
|
-
|
|
331
|
-
resampler.clear();
|
|
332
|
-
resampler.oneshot(
|
|
333
|
-
(const double*) from_buf, from_nsamples,
|
|
334
|
-
(double*) to_buf, to_nsamples);
|
|
335
|
-
|
|
336
|
-
for (uint i = 0; i < to_nsamples; ++i)
|
|
337
|
-
*Signals_at(to, to_offset + i, channel) = to_buf[i];
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
Signals_set_nsamples(to, to->self->nsamples + to_nsamples);
|
|
341
|
-
return from_nsamples;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
uint
|
|
345
|
-
Signals_copy (Signals* to, const Signals& from, uint from_offset)
|
|
346
|
-
{
|
|
347
|
-
if (!to)
|
|
348
|
-
argument_error(__FILE__, __LINE__);
|
|
349
|
-
if (!*to)
|
|
350
|
-
argument_error(__FILE__, __LINE__);
|
|
351
|
-
if (!from)
|
|
352
|
-
argument_error(__FILE__, __LINE__);
|
|
353
|
-
|
|
354
|
-
Signals_clear(to);
|
|
355
|
-
|
|
356
|
-
if (to->sample_rate() == from.sample_rate())
|
|
357
|
-
return copy_samples(to, from, from_offset);
|
|
358
|
-
else
|
|
359
|
-
return resample(to, from, from_offset);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
205
|
void
|
|
363
206
|
Signals_add (Signals* signals, const Signals& add)
|
|
364
207
|
{
|
|
@@ -451,10 +294,10 @@ namespace Beeps
|
|
|
451
294
|
if (signals->capacity() < nsamples)
|
|
452
295
|
argument_error(__FILE__, __LINE__);
|
|
453
296
|
|
|
454
|
-
for (uint
|
|
297
|
+
for (uint ch = 0; ch < nchannels; ++ch)
|
|
455
298
|
{
|
|
456
|
-
Sample* sig_p = Signals_at(signals, 0,
|
|
457
|
-
const T* buf = samples.channel(
|
|
299
|
+
Sample* sig_p = Signals_at(signals, 0, ch);
|
|
300
|
+
const T* buf = samples.channel(ch);
|
|
458
301
|
for (uint i = 0; i < nsamples; ++i, sig_p += nchannels)
|
|
459
302
|
*sig_p = buf[i];
|
|
460
303
|
}
|
|
@@ -592,10 +435,184 @@ namespace Beeps
|
|
|
592
435
|
{
|
|
593
436
|
}
|
|
594
437
|
|
|
438
|
+
Signals::Signals (uint capacity, uint nchannels, double sample_rate)
|
|
439
|
+
{
|
|
440
|
+
self->frames.reset(
|
|
441
|
+
new Frames(capacity * nchannels, nchannels, sample_rate));
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
Signals::Signals (
|
|
445
|
+
const float* const* channels,
|
|
446
|
+
uint nsamples, uint nchannels, double sample_rate, uint capacity)
|
|
447
|
+
{
|
|
448
|
+
if (!channels)
|
|
449
|
+
argument_error(__FILE__, __LINE__);
|
|
450
|
+
|
|
451
|
+
self->frames.reset(new Frames(
|
|
452
|
+
std::max(capacity, nsamples) * nchannels, nchannels, sample_rate));
|
|
453
|
+
|
|
454
|
+
for (uint ch = 0; ch < nchannels; ++ch)
|
|
455
|
+
{
|
|
456
|
+
Sample* p = Signals_at(this, 0, ch);
|
|
457
|
+
for (uint i = 0; i < nsamples; ++i, p += nchannels)
|
|
458
|
+
*p = channels[ch][i];
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
self->nsamples = nsamples;
|
|
462
|
+
}
|
|
463
|
+
|
|
595
464
|
Signals::~Signals ()
|
|
596
465
|
{
|
|
597
466
|
}
|
|
598
467
|
|
|
468
|
+
void
|
|
469
|
+
Signals::clear (uint capacity)
|
|
470
|
+
{
|
|
471
|
+
if (!*this)
|
|
472
|
+
argument_error(__FILE__, __LINE__);
|
|
473
|
+
|
|
474
|
+
self->nsamples = 0;
|
|
475
|
+
if (capacity > 0)
|
|
476
|
+
self->frames->resize(capacity, nchannels());
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
template <typename T>
|
|
480
|
+
static uint
|
|
481
|
+
copy_samples (
|
|
482
|
+
Signals* to,
|
|
483
|
+
const T* const* from_channels, uint from_nsamples, uint from_nchannels,
|
|
484
|
+
uint from_offset, uint from_stride)
|
|
485
|
+
{
|
|
486
|
+
assert(to && *to && from_channels);
|
|
487
|
+
|
|
488
|
+
if (from_offset >= from_nsamples)
|
|
489
|
+
return 0;
|
|
490
|
+
|
|
491
|
+
uint to_nchannels = to->nchannels();
|
|
492
|
+
uint to_offset = to->nsamples();
|
|
493
|
+
uint to_nsamples = to->capacity() - to_offset;
|
|
494
|
+
uint copy_nsamples =
|
|
495
|
+
std::min(from_offset + to_nsamples, from_nsamples) - from_offset;
|
|
496
|
+
|
|
497
|
+
for (uint ch = 0; ch < to_nchannels; ++ch)
|
|
498
|
+
{
|
|
499
|
+
uint from_channel = ch < from_nchannels ? ch : 0;
|
|
500
|
+
Sample* to_p = Signals_at(to, to_offset, ch);
|
|
501
|
+
const T* from_p = from_channels[from_channel] + from_offset * from_stride;
|
|
502
|
+
for (uint i = 0; i < copy_nsamples; ++i)
|
|
503
|
+
{
|
|
504
|
+
*to_p = *from_p;
|
|
505
|
+
to_p += to_nchannels;
|
|
506
|
+
from_p += from_stride;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
Signals_set_nsamples(to, to->self->nsamples + copy_nsamples);
|
|
511
|
+
return copy_nsamples;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
template <typename T>
|
|
515
|
+
static uint
|
|
516
|
+
resample (
|
|
517
|
+
Signals* to,
|
|
518
|
+
const T* const* from_channels, uint from_nsamples, uint from_nchannels,
|
|
519
|
+
double from_sample_rate, uint from_offset, uint from_stride)
|
|
520
|
+
{
|
|
521
|
+
assert(to && *to && from_channels);
|
|
522
|
+
|
|
523
|
+
if (from_offset >= from_nsamples)
|
|
524
|
+
return 0;
|
|
525
|
+
|
|
526
|
+
uint to_offset = to->nsamples();
|
|
527
|
+
float to_sec = (to->capacity() - to_offset) / to->sample_rate();
|
|
528
|
+
float from_offset_sec = from_offset / from_sample_rate;
|
|
529
|
+
float from_sec = from_nsamples / from_sample_rate;
|
|
530
|
+
float copy_seconds =
|
|
531
|
+
std::min(from_offset_sec + to_sec, from_sec) - from_offset_sec;
|
|
532
|
+
|
|
533
|
+
uint to_nsamples = 0, copy_nsamples = 0;
|
|
534
|
+
if (from_offset_sec + to_sec <= from_sec)
|
|
535
|
+
{
|
|
536
|
+
to_nsamples = to->capacity() - to->nsamples();
|
|
537
|
+
copy_nsamples = copy_seconds * from_sample_rate;
|
|
538
|
+
}
|
|
539
|
+
else
|
|
540
|
+
{
|
|
541
|
+
to_nsamples = copy_seconds * to->sample_rate();
|
|
542
|
+
copy_nsamples = from_nsamples - from_offset;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
r8b::CDSPResampler24 resampler(
|
|
546
|
+
from_sample_rate, to->sample_rate(), copy_nsamples);
|
|
547
|
+
r8b::CFixedBuffer<double> from_buf(copy_nsamples), to_buf(to_nsamples);
|
|
548
|
+
|
|
549
|
+
for (uint ch = 0; ch < to->nchannels(); ++ch)
|
|
550
|
+
{
|
|
551
|
+
uint from_ch = ch < from_nchannels ? ch : 0;
|
|
552
|
+
const T* base = from_channels[from_ch] + from_offset * from_stride;
|
|
553
|
+
|
|
554
|
+
for (uint i = 0; i < copy_nsamples; ++i)
|
|
555
|
+
from_buf[i] = base[i * from_stride];
|
|
556
|
+
|
|
557
|
+
resampler.clear();
|
|
558
|
+
resampler.oneshot(
|
|
559
|
+
(const double*) from_buf, copy_nsamples,
|
|
560
|
+
(double*) to_buf, to_nsamples);
|
|
561
|
+
|
|
562
|
+
for (uint i = 0; i < to_nsamples; ++i)
|
|
563
|
+
*Signals_at(to, to_offset + i, ch) = to_buf[i];
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
Signals_set_nsamples(to, to->self->nsamples + to_nsamples);
|
|
567
|
+
return copy_nsamples;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
uint
|
|
571
|
+
Signals::append (
|
|
572
|
+
const float* const* channels,
|
|
573
|
+
uint nsamples, uint nchannels, double sample_rate)
|
|
574
|
+
{
|
|
575
|
+
if (!*this)
|
|
576
|
+
argument_error(__FILE__, __LINE__);
|
|
577
|
+
if (!channels)
|
|
578
|
+
argument_error(__FILE__, __LINE__);
|
|
579
|
+
|
|
580
|
+
if (sample_rate == 0)
|
|
581
|
+
sample_rate = this->sample_rate();
|
|
582
|
+
|
|
583
|
+
if (sample_rate == this->sample_rate())
|
|
584
|
+
return copy_samples(this, channels, nsamples, nchannels, 0, 1);
|
|
585
|
+
else
|
|
586
|
+
return resample(this, channels, nsamples, nchannels, sample_rate, 0, 1);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
uint
|
|
590
|
+
Signals::append (const Signals& source, uint source_offset)
|
|
591
|
+
{
|
|
592
|
+
if (!*this)
|
|
593
|
+
argument_error(__FILE__, __LINE__);
|
|
594
|
+
if (!source)
|
|
595
|
+
argument_error(__FILE__, __LINE__);
|
|
596
|
+
|
|
597
|
+
uint nchannels = source.nchannels();
|
|
598
|
+
std::vector<const Sample*> channels(nchannels);
|
|
599
|
+
for (uint ch = 0; ch < nchannels; ++ch)
|
|
600
|
+
channels[ch] = Signals_at(source, 0, ch);
|
|
601
|
+
|
|
602
|
+
if (sample_rate() == source.sample_rate())
|
|
603
|
+
{
|
|
604
|
+
return copy_samples(
|
|
605
|
+
this, channels.data(), source.nsamples(), nchannels,
|
|
606
|
+
source_offset, nchannels);
|
|
607
|
+
}
|
|
608
|
+
else
|
|
609
|
+
{
|
|
610
|
+
return resample(
|
|
611
|
+
this, channels.data(), source.nsamples(), nchannels, source.sample_rate(),
|
|
612
|
+
source_offset, nchannels);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
599
616
|
Signals
|
|
600
617
|
Signals::dup () const
|
|
601
618
|
{
|
data/src/signals.h
CHANGED
|
@@ -21,13 +21,6 @@ namespace Beeps
|
|
|
21
21
|
template <typename T> class SignalSamples;
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
Signals Signals_create (
|
|
25
|
-
uint capacity, uint nchannels = 1, double sample_rate = 0);
|
|
26
|
-
|
|
27
|
-
Signals Signals_create (
|
|
28
|
-
const float* const* channels,
|
|
29
|
-
uint nsamples, uint nchannels, double sample_rate = 0, uint capacity = 0);
|
|
30
|
-
|
|
31
24
|
uint Signals_tick (
|
|
32
25
|
Signals* signals,
|
|
33
26
|
std::function<void(stk::StkFrames*)> fun);
|
|
@@ -40,18 +33,12 @@ namespace Beeps
|
|
|
40
33
|
Signals* signals, uint start, uint length,
|
|
41
34
|
std::function<void(stk::StkFrames*)> fun);
|
|
42
35
|
|
|
43
|
-
void Signals_clear (Signals* signals);
|
|
44
|
-
|
|
45
|
-
void Signals_clear (Signals* signals, uint capacity);
|
|
46
|
-
|
|
47
36
|
void Signals_fill (
|
|
48
37
|
Signals* signals, uint nsamples, Sample value,
|
|
49
38
|
uint offset = 0);
|
|
50
39
|
|
|
51
40
|
void Signals_shift (Signals* signals, uint nsamples);
|
|
52
41
|
|
|
53
|
-
uint Signals_copy (Signals* to, const Signals& from, uint from_offset = 0);
|
|
54
|
-
|
|
55
42
|
void Signals_add ( Signals* signals, const Signals& add);
|
|
56
43
|
|
|
57
44
|
void Signals_multiply (Signals* signals, const Signals& multiplier);
|
|
@@ -107,9 +94,9 @@ namespace Beeps
|
|
|
107
94
|
auto& samples = self->samples;
|
|
108
95
|
samples.reserve(nsamples * nchannels);
|
|
109
96
|
|
|
110
|
-
for (uint
|
|
97
|
+
for (uint ch = 0; ch < nchannels; ++ch)
|
|
111
98
|
{
|
|
112
|
-
const Sample* p = Signals_at(signals, 0);
|
|
99
|
+
const Sample* p = Signals_at(signals, 0, ch);
|
|
113
100
|
for (uint i = 0; i < nsamples; ++i, p += nchannels)
|
|
114
101
|
samples.push_back(*p);
|
|
115
102
|
}
|
data/src/sound.cpp
CHANGED
|
@@ -65,10 +65,10 @@ namespace Beeps
|
|
|
65
65
|
if (nsamples <= 0) return 0;
|
|
66
66
|
|
|
67
67
|
std::unique_ptr<short[]> buffer(new short[size]);
|
|
68
|
-
for (uint
|
|
68
|
+
for (uint ch = 0; ch < nchannels; ++ch)
|
|
69
69
|
{
|
|
70
|
-
const Sample* p = Signals_at(signals, 0,
|
|
71
|
-
for (uint i =
|
|
70
|
+
const Sample* p = Signals_at(signals, 0, ch);
|
|
71
|
+
for (uint i = ch; i < size; i += nchannels, p += nchannels)
|
|
72
72
|
buffer[i] = *p * SHRT_MAX;
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -83,6 +83,20 @@ namespace Beeps
|
|
|
83
83
|
return nsamples;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
ALint nsamples () const
|
|
87
|
+
{
|
|
88
|
+
if (!*this) return 0;
|
|
89
|
+
|
|
90
|
+
ALint size = 0, bits = 0, channels = 0;
|
|
91
|
+
alGetBufferi(self->id, AL_SIZE, &size);
|
|
92
|
+
alGetBufferi(self->id, AL_BITS, &bits);
|
|
93
|
+
alGetBufferi(self->id, AL_CHANNELS, &channels);
|
|
94
|
+
if (bits <= 0 || channels <= 0)
|
|
95
|
+
return 0;
|
|
96
|
+
|
|
97
|
+
return size / (bits / 8) / channels;
|
|
98
|
+
}
|
|
99
|
+
|
|
86
100
|
operator bool () const
|
|
87
101
|
{
|
|
88
102
|
return self->is_valid();
|
|
@@ -168,6 +182,7 @@ namespace Beeps
|
|
|
168
182
|
SoundSource reuse ()
|
|
169
183
|
{
|
|
170
184
|
stop();
|
|
185
|
+
set_time_scale(1);
|
|
171
186
|
set_gain(1);
|
|
172
187
|
set_loop(false);
|
|
173
188
|
|
|
@@ -276,6 +291,47 @@ namespace Beeps
|
|
|
276
291
|
}
|
|
277
292
|
}
|
|
278
293
|
|
|
294
|
+
void set_position (uint position)
|
|
295
|
+
{
|
|
296
|
+
if (!*this) return;
|
|
297
|
+
|
|
298
|
+
alSourcei(self->id, AL_SAMPLE_OFFSET, (ALint) position);
|
|
299
|
+
OpenAL_check_error(__FILE__, __LINE__);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
uint position () const
|
|
303
|
+
{
|
|
304
|
+
if (!*this) return 0;
|
|
305
|
+
|
|
306
|
+
ALint pos = 0;
|
|
307
|
+
alGetSourcei(self->id, AL_SAMPLE_OFFSET, &pos);
|
|
308
|
+
OpenAL_check_error(__FILE__, __LINE__);
|
|
309
|
+
|
|
310
|
+
return (uint) pos;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
void set_time_scale (float scale)
|
|
314
|
+
{
|
|
315
|
+
if (scale <= 0)
|
|
316
|
+
argument_error(__FILE__, __LINE__);
|
|
317
|
+
|
|
318
|
+
if (!*this) return;
|
|
319
|
+
|
|
320
|
+
alSourcef(self->id, AL_PITCH, scale);
|
|
321
|
+
OpenAL_check_error(__FILE__, __LINE__);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
float time_scale () const
|
|
325
|
+
{
|
|
326
|
+
if (!*this) return 1;
|
|
327
|
+
|
|
328
|
+
float scale = 1;
|
|
329
|
+
alGetSourcef(self->id, AL_PITCH, &scale);
|
|
330
|
+
OpenAL_check_error(__FILE__, __LINE__);
|
|
331
|
+
|
|
332
|
+
return scale;
|
|
333
|
+
}
|
|
334
|
+
|
|
279
335
|
void set_gain (float gain)
|
|
280
336
|
{
|
|
281
337
|
if (gain < 0)
|
|
@@ -377,6 +433,10 @@ namespace Beeps
|
|
|
377
433
|
struct SoundPlayer::Data
|
|
378
434
|
{
|
|
379
435
|
|
|
436
|
+
double sample_rate = 0;
|
|
437
|
+
|
|
438
|
+
uint position = 0;
|
|
439
|
+
|
|
380
440
|
SoundSource source;
|
|
381
441
|
|
|
382
442
|
std::vector<SoundBuffer> buffers;
|
|
@@ -387,6 +447,9 @@ namespace Beeps
|
|
|
387
447
|
|
|
388
448
|
void clear ()
|
|
389
449
|
{
|
|
450
|
+
sample_rate = 0;
|
|
451
|
+
position = 0;
|
|
452
|
+
|
|
390
453
|
source.clear();
|
|
391
454
|
|
|
392
455
|
for (auto& buffer : buffers) buffer.clear();
|
|
@@ -397,6 +460,8 @@ namespace Beeps
|
|
|
397
460
|
{
|
|
398
461
|
assert(signals);
|
|
399
462
|
|
|
463
|
+
sample_rate = signals.sample_rate();
|
|
464
|
+
|
|
400
465
|
SoundBuffer buffer(signals);
|
|
401
466
|
source.attach(buffer);
|
|
402
467
|
buffers.emplace_back(buffer);
|
|
@@ -407,7 +472,8 @@ namespace Beeps
|
|
|
407
472
|
{
|
|
408
473
|
assert(processor && *processor && nchannels > 0 && sample_rate > 0);
|
|
409
474
|
|
|
410
|
-
this->
|
|
475
|
+
this->sample_rate = sample_rate;
|
|
476
|
+
this->processor = processor;
|
|
411
477
|
stream_context.reset(
|
|
412
478
|
new StreamContext(sample_rate / 10, nchannels, sample_rate));
|
|
413
479
|
|
|
@@ -447,6 +513,8 @@ namespace Beeps
|
|
|
447
513
|
if (!source.unqueue(&buffer))
|
|
448
514
|
return;
|
|
449
515
|
|
|
516
|
+
position += buffer.nsamples();
|
|
517
|
+
|
|
450
518
|
if (!process_stream(&buffer))
|
|
451
519
|
{
|
|
452
520
|
source.stop();
|
|
@@ -454,7 +522,23 @@ namespace Beeps
|
|
|
454
522
|
}
|
|
455
523
|
|
|
456
524
|
source.queue(buffer);
|
|
457
|
-
if (source.state() == STOPPED)
|
|
525
|
+
if (source.state() == STOPPED)
|
|
526
|
+
{
|
|
527
|
+
expand_buffer();
|
|
528
|
+
source.play();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
void expand_buffer ()
|
|
534
|
+
{
|
|
535
|
+
if (buffers.size() >= 10) return;
|
|
536
|
+
|
|
537
|
+
SoundBuffer extra(true);
|
|
538
|
+
if (process_stream(&extra))
|
|
539
|
+
{
|
|
540
|
+
source.queue(extra);
|
|
541
|
+
buffers.emplace_back(extra);
|
|
458
542
|
}
|
|
459
543
|
}
|
|
460
544
|
|
|
@@ -586,16 +670,20 @@ namespace Beeps
|
|
|
586
670
|
self->source.pause();
|
|
587
671
|
}
|
|
588
672
|
|
|
673
|
+
#pragma GCC diagnostic push
|
|
674
|
+
#pragma GCC diagnostic ignored "-Wmissing-noreturn"
|
|
589
675
|
void
|
|
590
676
|
SoundPlayer::rewind ()
|
|
591
677
|
{
|
|
592
678
|
not_implemented_error(__FILE__, __LINE__);
|
|
593
679
|
}
|
|
680
|
+
#pragma GCC diagnostic pop
|
|
594
681
|
|
|
595
682
|
void
|
|
596
683
|
SoundPlayer::stop ()
|
|
597
684
|
{
|
|
598
685
|
self->source.stop();
|
|
686
|
+
self->position = 0;
|
|
599
687
|
}
|
|
600
688
|
|
|
601
689
|
SoundPlayer::State
|
|
@@ -607,6 +695,67 @@ namespace Beeps
|
|
|
607
695
|
return s;
|
|
608
696
|
}
|
|
609
697
|
|
|
698
|
+
void
|
|
699
|
+
SoundPlayer::set_position (uint position)
|
|
700
|
+
{
|
|
701
|
+
if (self->is_streaming())
|
|
702
|
+
{
|
|
703
|
+
if (!self->processor || !self->processor->seekable())
|
|
704
|
+
invalid_state_error(__FILE__, __LINE__, "processor is not seekable");
|
|
705
|
+
|
|
706
|
+
State state = this->state();
|
|
707
|
+
self->source.stop();
|
|
708
|
+
|
|
709
|
+
self->position = position;
|
|
710
|
+
self->stream_context->seek(position);
|
|
711
|
+
for (auto& buffer : self->buffers)
|
|
712
|
+
{
|
|
713
|
+
if (!self->process_stream(&buffer)) break;
|
|
714
|
+
self->source.queue(buffer);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (state != STOPPED) self->source.play();
|
|
718
|
+
if (state == PAUSED) self->source.pause();
|
|
719
|
+
}
|
|
720
|
+
else
|
|
721
|
+
{
|
|
722
|
+
self->position = 0;
|
|
723
|
+
self->source.set_position(position);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
uint
|
|
728
|
+
SoundPlayer::position () const
|
|
729
|
+
{
|
|
730
|
+
return self->position + self->source.position();
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
void
|
|
734
|
+
SoundPlayer::set_time (float time)
|
|
735
|
+
{
|
|
736
|
+
if (self->sample_rate <= 0) return;
|
|
737
|
+
set_position((uint) (time * self->sample_rate));
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
float
|
|
741
|
+
SoundPlayer::time () const
|
|
742
|
+
{
|
|
743
|
+
if (self->sample_rate <= 0) return 0;
|
|
744
|
+
return (float) ((double) position() / self->sample_rate);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
void
|
|
748
|
+
SoundPlayer::set_time_scale (float scale)
|
|
749
|
+
{
|
|
750
|
+
self->source.set_time_scale(scale);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
float
|
|
754
|
+
SoundPlayer::time_scale () const
|
|
755
|
+
{
|
|
756
|
+
return self->source.time_scale();
|
|
757
|
+
}
|
|
758
|
+
|
|
610
759
|
void
|
|
611
760
|
SoundPlayer::set_gain (float gain)
|
|
612
761
|
{
|
data/src/time_stretch.cpp
CHANGED
|
@@ -66,8 +66,8 @@ namespace Beeps
|
|
|
66
66
|
if (self->scale == 1)
|
|
67
67
|
return Super::filter(context, signals, offset);
|
|
68
68
|
|
|
69
|
-
uint nsamples
|
|
70
|
-
Signals source
|
|
69
|
+
uint nsamples = signals->capacity();
|
|
70
|
+
Signals source(
|
|
71
71
|
nsamples / self->scale, signals->nchannels(), signals->sample_rate());
|
|
72
72
|
|
|
73
73
|
Super::filter(context, &source, offset);
|
data/src/value.cpp
CHANGED
|
@@ -113,6 +113,12 @@ namespace Beeps
|
|
|
113
113
|
return self->points.end();
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
bool
|
|
117
|
+
Value::seekable () const
|
|
118
|
+
{
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
|
|
116
122
|
static float
|
|
117
123
|
interpolate_linear (const Value::PointList& points, float time)
|
|
118
124
|
{
|
|
@@ -169,11 +175,11 @@ namespace Beeps
|
|
|
169
175
|
}
|
|
170
176
|
|
|
171
177
|
int
|
|
172
|
-
Value::
|
|
178
|
+
Value::get_max_segment_size_for_process (
|
|
173
179
|
double sample_rate, uint nsamples) const
|
|
174
180
|
{
|
|
175
181
|
if (self->points.size() == 1)
|
|
176
|
-
return Super::
|
|
182
|
+
return Super::get_max_segment_size_for_process(sample_rate, nsamples);
|
|
177
183
|
return sample_rate / 256;
|
|
178
184
|
}
|
|
179
185
|
|