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/signals.cpp
CHANGED
@@ -27,7 +27,9 @@ namespace Beeps
|
|
27
27
|
Signals
|
28
28
|
Signals_create (uint capacity, uint nchannels, double sample_rate)
|
29
29
|
{
|
30
|
-
if (capacity <= 0
|
30
|
+
if (capacity <= 0)
|
31
|
+
argument_error(__FILE__, __LINE__);
|
32
|
+
if (nchannels <= 0)
|
31
33
|
argument_error(__FILE__, __LINE__);
|
32
34
|
|
33
35
|
if (sample_rate <= 0) sample_rate = Beeps::sample_rate();
|
@@ -43,7 +45,11 @@ namespace Beeps
|
|
43
45
|
const float* const* channels,
|
44
46
|
uint nsamples, uint nchannels, double sample_rate)
|
45
47
|
{
|
46
|
-
if (!channels
|
48
|
+
if (!channels)
|
49
|
+
argument_error(__FILE__, __LINE__);
|
50
|
+
if (nsamples <= 0)
|
51
|
+
argument_error(__FILE__, __LINE__);
|
52
|
+
if (nchannels <= 0)
|
47
53
|
argument_error(__FILE__, __LINE__);
|
48
54
|
|
49
55
|
if (sample_rate <= 0) sample_rate = Beeps::sample_rate();
|
@@ -64,19 +70,32 @@ namespace Beeps
|
|
64
70
|
}
|
65
71
|
|
66
72
|
void
|
67
|
-
|
73
|
+
Signals_clear (Signals* signals)
|
68
74
|
{
|
69
|
-
if (!signals
|
75
|
+
if (!signals)
|
76
|
+
argument_error(__FILE__, __LINE__);
|
77
|
+
|
78
|
+
signals->self->nsamples = 0;
|
79
|
+
}
|
80
|
+
|
81
|
+
void
|
82
|
+
Signals_clear (Signals* signals, uint capacity)
|
83
|
+
{
|
84
|
+
if (!signals)
|
85
|
+
argument_error(__FILE__, __LINE__);
|
86
|
+
if (!*signals)
|
87
|
+
argument_error(__FILE__, __LINE__);
|
88
|
+
if (capacity <= 0)
|
70
89
|
argument_error(__FILE__, __LINE__);
|
71
90
|
|
72
|
-
signals->self->frames->resize(capacity, signals->nchannels());
|
73
91
|
Signals_clear(signals);
|
92
|
+
signals->self->frames->resize(capacity, signals->nchannels());
|
74
93
|
}
|
75
94
|
|
76
95
|
void
|
77
96
|
Signals_resize (Signals* signals, uint nsamples, Float value)
|
78
97
|
{
|
79
|
-
|
98
|
+
Signals_clear(signals, nsamples);
|
80
99
|
|
81
100
|
Frames* frames = Signals_get_frames(signals);
|
82
101
|
assert(frames);
|
@@ -89,15 +108,6 @@ namespace Beeps
|
|
89
108
|
Signals_set_nsamples(signals, nsamples);
|
90
109
|
}
|
91
110
|
|
92
|
-
void
|
93
|
-
Signals_clear (Signals* signals)
|
94
|
-
{
|
95
|
-
if (!signals)
|
96
|
-
argument_error(__FILE__, __LINE__);
|
97
|
-
|
98
|
-
signals->self->nsamples = 0;
|
99
|
-
}
|
100
|
-
|
101
111
|
static uint
|
102
112
|
copy_frames (Signals* to, const Signals& from, uint from_offset)
|
103
113
|
{
|
@@ -191,7 +201,11 @@ namespace Beeps
|
|
191
201
|
uint
|
192
202
|
Signals_copy (Signals* to, const Signals& from, uint from_offset)
|
193
203
|
{
|
194
|
-
if (!to
|
204
|
+
if (!to)
|
205
|
+
argument_error(__FILE__, __LINE__);
|
206
|
+
if (!*to)
|
207
|
+
argument_error(__FILE__, __LINE__);
|
208
|
+
if (!from)
|
195
209
|
argument_error(__FILE__, __LINE__);
|
196
210
|
|
197
211
|
Signals_clear(to);
|
@@ -203,23 +217,24 @@ namespace Beeps
|
|
203
217
|
}
|
204
218
|
|
205
219
|
void
|
206
|
-
|
220
|
+
Signals_multiply (Signals* signals, const Signals& multiplier)
|
207
221
|
{
|
208
|
-
if (!signals
|
222
|
+
if (!signals)
|
223
|
+
argument_error(__FILE__, __LINE__);
|
224
|
+
if (multiplier.nchannels() != 1)
|
209
225
|
argument_error(__FILE__, __LINE__);
|
210
|
-
|
211
226
|
if (signals->capacity() != multiplier.capacity())
|
212
227
|
argument_error(__FILE__, __LINE__);
|
213
228
|
|
214
229
|
Frames* sigf = Signals_get_frames(signals);
|
215
230
|
Frames* mulf = Signals_get_frames(const_cast<Signals*>(&multiplier));
|
231
|
+
uint nframes = sigf->nframes();
|
232
|
+
uint stride = sigf->nchannels();
|
216
233
|
|
217
234
|
for (uint ch = 0; ch < sigf->nchannels(); ++ch)
|
218
235
|
{
|
219
|
-
Float* sigp
|
220
|
-
Float* mulp
|
221
|
-
uint nframes = sigf->nframes();
|
222
|
-
uint stride = sigf->nchannels();
|
236
|
+
Float* sigp = &(*sigf)(0, ch);
|
237
|
+
Float* mulp = &(*mulf)(0, 0);
|
223
238
|
for (uint i = 0; i < nframes; ++i, sigp += stride, ++mulp)
|
224
239
|
*sigp *= *mulp;
|
225
240
|
}
|
@@ -231,13 +246,14 @@ namespace Beeps
|
|
231
246
|
{
|
232
247
|
uint nsamples = nsamples_ < 0 ? samples.nsamples() : (uint) nsamples_;
|
233
248
|
|
234
|
-
if (
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
249
|
+
if (!signals)
|
250
|
+
argument_error(__FILE__, __LINE__);
|
251
|
+
if (!*signals)
|
252
|
+
argument_error(__FILE__, __LINE__);
|
253
|
+
if (signals->nchannels() != samples.nchannels())
|
254
|
+
argument_error(__FILE__, __LINE__);
|
255
|
+
if (signals->capacity() < nsamples)
|
239
256
|
argument_error(__FILE__, __LINE__);
|
240
|
-
}
|
241
257
|
|
242
258
|
Frames* f = Signals_get_frames(signals);
|
243
259
|
assert(f);
|
data/src/signals.h
CHANGED
@@ -31,15 +31,15 @@ namespace Beeps
|
|
31
31
|
const float* const* channels,
|
32
32
|
uint nsamples, uint nchannels, double sample_rate = 0);
|
33
33
|
|
34
|
-
void
|
34
|
+
void Signals_clear (Signals* signals);
|
35
35
|
|
36
|
-
void
|
36
|
+
void Signals_clear (Signals* signals, uint capacity);
|
37
37
|
|
38
|
-
void
|
38
|
+
void Signals_resize (Signals* signals, uint nsamples, Float value);
|
39
39
|
|
40
40
|
uint Signals_copy (Signals* to, const Signals& from, uint from_offset);
|
41
41
|
|
42
|
-
void
|
42
|
+
void Signals_multiply (Signals* signals, const Signals& multiplier);
|
43
43
|
|
44
44
|
template <typename T>
|
45
45
|
void Signals_write_samples (
|
data/src/sound.cpp
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
#include "beeps/beeps.h"
|
10
10
|
#include "beeps/exception.h"
|
11
11
|
#include "beeps/generator.h"
|
12
|
+
#include "beeps/debug.h"
|
12
13
|
#include "openal.h"
|
13
14
|
#include "processor.h"
|
14
15
|
#include "signals.h"
|
@@ -29,19 +30,19 @@ namespace Beeps
|
|
29
30
|
{
|
30
31
|
|
31
32
|
SoundBuffer (bool create = false)
|
33
|
+
: self(new Data(create))
|
32
34
|
{
|
33
|
-
if (create) self->create();
|
34
35
|
}
|
35
36
|
|
36
37
|
SoundBuffer (const Signals& signals)
|
38
|
+
: self(new Data(true))
|
37
39
|
{
|
38
|
-
self->create();
|
39
40
|
write(signals);
|
40
41
|
}
|
41
42
|
|
42
43
|
SoundBuffer (ALint id)
|
44
|
+
: self(new Data(id))
|
43
45
|
{
|
44
|
-
self->id = id;
|
45
46
|
}
|
46
47
|
|
47
48
|
void clear ()
|
@@ -59,7 +60,8 @@ namespace Beeps
|
|
59
60
|
double sample_rate = signals.sample_rate();
|
60
61
|
uint nchannels = signals.nchannels();
|
61
62
|
uint nsamples = signals.nsamples();
|
62
|
-
assert(sample_rate > 0 && nchannels > 0
|
63
|
+
assert(sample_rate > 0 && nchannels > 0);
|
64
|
+
if (nsamples <= 0) return 0;
|
63
65
|
|
64
66
|
const Frames* frames = Signals_get_frames(&signals);
|
65
67
|
assert(frames);
|
@@ -93,7 +95,7 @@ namespace Beeps
|
|
93
95
|
return !operator bool();
|
94
96
|
}
|
95
97
|
|
96
|
-
struct Data
|
98
|
+
struct Data : public Xot::NonCopyable
|
97
99
|
{
|
98
100
|
|
99
101
|
void* context = NULL;
|
@@ -102,14 +104,9 @@ namespace Beeps
|
|
102
104
|
|
103
105
|
bool owner = false;
|
104
106
|
|
105
|
-
|
107
|
+
Data (bool create)
|
106
108
|
{
|
107
|
-
|
108
|
-
}
|
109
|
-
|
110
|
-
void create ()
|
111
|
-
{
|
112
|
-
clear();
|
109
|
+
if (!create) return;
|
113
110
|
|
114
111
|
ALuint id_ = 0;
|
115
112
|
alGenBuffers(1, &id_);
|
@@ -120,6 +117,16 @@ namespace Beeps
|
|
120
117
|
owner = true;
|
121
118
|
}
|
122
119
|
|
120
|
+
Data (ALint id)
|
121
|
+
: context(OpenAL_get_context()), id(id)
|
122
|
+
{
|
123
|
+
}
|
124
|
+
|
125
|
+
~Data ()
|
126
|
+
{
|
127
|
+
clear();
|
128
|
+
}
|
129
|
+
|
123
130
|
void clear ()
|
124
131
|
{
|
125
132
|
if (owner && is_valid())
|
@@ -378,7 +385,7 @@ namespace Beeps
|
|
378
385
|
|
379
386
|
Processor::Ref processor;
|
380
387
|
|
381
|
-
std::unique_ptr<
|
388
|
+
std::unique_ptr<StreamContext> stream_context;
|
382
389
|
|
383
390
|
void clear ()
|
384
391
|
{
|
@@ -403,8 +410,8 @@ namespace Beeps
|
|
403
410
|
assert(processor && *processor && nchannels > 0 && sample_rate > 0);
|
404
411
|
|
405
412
|
this->processor = processor;
|
406
|
-
|
407
|
-
new
|
413
|
+
stream_context.reset(
|
414
|
+
new StreamContext(sample_rate / 10, nchannels, sample_rate));
|
408
415
|
|
409
416
|
for (int i = 0; i < 2; ++i)
|
410
417
|
{
|
@@ -418,13 +425,11 @@ namespace Beeps
|
|
418
425
|
|
419
426
|
bool process_stream (SoundBuffer* buffer)
|
420
427
|
{
|
421
|
-
assert(buffer && processor &&
|
422
|
-
|
423
|
-
Signals signals = processor_context->process_signals(processor);
|
424
|
-
if (!signals) return false;
|
428
|
+
assert(buffer && processor && stream_context);
|
425
429
|
|
426
|
-
|
427
|
-
|
430
|
+
Signals signals = stream_context->process_next(processor);
|
431
|
+
if (stream_context->is_finished())
|
432
|
+
stream_context.reset();
|
428
433
|
|
429
434
|
return buffer->write(signals) > 0;
|
430
435
|
}
|
@@ -447,7 +452,7 @@ namespace Beeps
|
|
447
452
|
|
448
453
|
bool is_streaming () const
|
449
454
|
{
|
450
|
-
return processor &&
|
455
|
+
return processor && stream_context;
|
451
456
|
}
|
452
457
|
|
453
458
|
};// SoundPlayer::Data
|
@@ -687,12 +692,8 @@ namespace Beeps
|
|
687
692
|
processor && *processor &&
|
688
693
|
seconds > 0 && nchannels > 0 && sample_rate > 0);
|
689
694
|
|
690
|
-
|
691
|
-
|
692
|
-
if (!signals)
|
693
|
-
beeps_error(__FILE__, __LINE__, "failed to process signals");
|
694
|
-
|
695
|
-
this->signals = signals;
|
695
|
+
StreamContext context(seconds * sample_rate, nchannels, sample_rate);
|
696
|
+
this->signals = context.process_next(processor);
|
696
697
|
}
|
697
698
|
|
698
699
|
void attach_to (SoundPlayer* player) override
|
@@ -798,7 +799,9 @@ namespace Beeps
|
|
798
799
|
{
|
799
800
|
Processor::Ref ref = processor;
|
800
801
|
|
801
|
-
if (!processor
|
802
|
+
if (!processor)
|
803
|
+
argument_error(__FILE__, __LINE__);
|
804
|
+
if (!*processor)
|
802
805
|
argument_error(__FILE__, __LINE__);
|
803
806
|
|
804
807
|
if (sample_rate <= 0) sample_rate = Beeps::sample_rate();
|
data/src/win32/beeps.cpp
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#include "../beeps.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <mfapi.h>
|
5
|
+
#include <xot/windows.h>
|
6
|
+
#include "exception.h"
|
7
|
+
|
8
|
+
|
9
|
+
namespace Beeps
|
10
|
+
{
|
11
|
+
|
12
|
+
|
13
|
+
void
|
14
|
+
Beeps_init ()
|
15
|
+
{
|
16
|
+
check_media_foundation_error(
|
17
|
+
CoInitializeEx(NULL, COINIT_MULTITHREADED),
|
18
|
+
__FILE__, __LINE__);
|
19
|
+
|
20
|
+
check_media_foundation_error(
|
21
|
+
MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET),
|
22
|
+
__FILE__, __LINE__);
|
23
|
+
}
|
24
|
+
|
25
|
+
void
|
26
|
+
Beeps_fin ()
|
27
|
+
{
|
28
|
+
check_media_foundation_error(
|
29
|
+
MFShutdown(),
|
30
|
+
__FILE__, __LINE__);
|
31
|
+
|
32
|
+
CoUninitialize();
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
}// Beeps
|
@@ -0,0 +1,40 @@
|
|
1
|
+
#include "exception.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <xot/string.h>
|
5
|
+
|
6
|
+
|
7
|
+
namespace Beeps
|
8
|
+
{
|
9
|
+
|
10
|
+
|
11
|
+
MediaFoundationError::MediaFoundationError (const char* str)
|
12
|
+
: Super(str)
|
13
|
+
{
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
namespace ErrorFunctions
|
18
|
+
{
|
19
|
+
|
20
|
+
void
|
21
|
+
media_foundation_error (
|
22
|
+
const char* file, int line, HRESULT hresult, const char* format, ...)
|
23
|
+
{
|
24
|
+
XOT_STRINGF(format, s);
|
25
|
+
throw MediaFoundationError(
|
26
|
+
Xot::error_text(file, line, s + Xot::stringf(" (0x%p)", hresult)));
|
27
|
+
}
|
28
|
+
|
29
|
+
}// ErrorFunctions
|
30
|
+
|
31
|
+
|
32
|
+
void
|
33
|
+
check_media_foundation_error (HRESULT hresult, const char* file, int line)
|
34
|
+
{
|
35
|
+
if (FAILED(hresult))
|
36
|
+
media_foundation_error(file, line, hresult);
|
37
|
+
}
|
38
|
+
|
39
|
+
|
40
|
+
}// Beeps
|
@@ -0,0 +1,40 @@
|
|
1
|
+
// -*- c++ -*-
|
2
|
+
#pragma once
|
3
|
+
#ifndef __BEEPS_SRC_WIN32_EXCEPTION_H__
|
4
|
+
#define __BEEPS_SRC_WIN32_EXCEPTION_H__
|
5
|
+
|
6
|
+
|
7
|
+
#include <xot/windows.h>
|
8
|
+
#include "beeps/exception.h"
|
9
|
+
|
10
|
+
|
11
|
+
namespace Beeps
|
12
|
+
{
|
13
|
+
|
14
|
+
|
15
|
+
class MediaFoundationError : public BeepsError
|
16
|
+
{
|
17
|
+
typedef BeepsError Super;
|
18
|
+
public: MediaFoundationError (const char* str = NULL);
|
19
|
+
};
|
20
|
+
|
21
|
+
|
22
|
+
namespace ErrorFunctions
|
23
|
+
{
|
24
|
+
|
25
|
+
[[noreturn]]
|
26
|
+
void media_foundation_error (
|
27
|
+
const char* file, int line,
|
28
|
+
HRESULT hresult, const char* format = NULL, ...);
|
29
|
+
|
30
|
+
}// ErrorFunctions
|
31
|
+
|
32
|
+
|
33
|
+
void check_media_foundation_error (
|
34
|
+
HRESULT hresult, const char* file, int line);
|
35
|
+
|
36
|
+
|
37
|
+
}// Beeps
|
38
|
+
|
39
|
+
|
40
|
+
#endif//EOH
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#include "../signals.h"
|
2
|
+
|
3
|
+
|
4
|
+
#include <mfapi.h>
|
5
|
+
#include <mfidl.h>
|
6
|
+
#include <mfreadwrite.h>
|
7
|
+
#include <xot/noncopyable.h>
|
8
|
+
#include <xot/string.h>
|
9
|
+
#include <xot/windows.h>
|
10
|
+
#include "exception.h"
|
11
|
+
|
12
|
+
|
13
|
+
namespace Beeps
|
14
|
+
{
|
15
|
+
|
16
|
+
|
17
|
+
template <typename T, void (*Delete) (T*)>
|
18
|
+
struct Ptr : public Xot::NonCopyable
|
19
|
+
{
|
20
|
+
|
21
|
+
T* ptr;
|
22
|
+
|
23
|
+
Ptr () : ptr(NULL) {}
|
24
|
+
|
25
|
+
~Ptr () {Delete(ptr);}
|
26
|
+
|
27
|
+
T* operator -> () {return ptr;}
|
28
|
+
|
29
|
+
operator bool () const {return ptr;}
|
30
|
+
|
31
|
+
bool operator ! () const {return !operator bool();}
|
32
|
+
|
33
|
+
};// Ptr
|
34
|
+
|
35
|
+
template <typename T>
|
36
|
+
static void
|
37
|
+
release (T* object)
|
38
|
+
{
|
39
|
+
if (object) object->Release();
|
40
|
+
}
|
41
|
+
|
42
|
+
template <typename T>
|
43
|
+
static void
|
44
|
+
mem_free (T* object)
|
45
|
+
{
|
46
|
+
if (object) CoTaskMemFree(object);
|
47
|
+
}
|
48
|
+
|
49
|
+
template <typename T>
|
50
|
+
using ReleasePtr = Ptr<T, release<T>>;
|
51
|
+
|
52
|
+
template <typename T>
|
53
|
+
using MemFreePtr = Ptr<T, mem_free<T>>;
|
54
|
+
|
55
|
+
|
56
|
+
static bool is_file_exist (const char* path)
|
57
|
+
{
|
58
|
+
DWORD attribs = GetFileAttributes(path);
|
59
|
+
return
|
60
|
+
attribs != INVALID_FILE_ATTRIBUTES &&
|
61
|
+
!(attribs & FILE_ATTRIBUTE_DIRECTORY);
|
62
|
+
}
|
63
|
+
|
64
|
+
static std::wstring
|
65
|
+
to_wcs (const char* mbs)
|
66
|
+
{
|
67
|
+
size_t len = strlen(mbs);
|
68
|
+
std::wstring wcs(len, L'#');
|
69
|
+
mbstowcs(&wcs[0], mbs, len);
|
70
|
+
return wcs;
|
71
|
+
}
|
72
|
+
|
73
|
+
static void
|
74
|
+
load_bytes (WAVEFORMATEX* format, std::vector<BYTE>* bytes, const char* path)
|
75
|
+
{
|
76
|
+
std::wstring wpath = to_wcs(path);
|
77
|
+
|
78
|
+
ReleasePtr<IMFMediaType> pcm_media_type;
|
79
|
+
check_media_foundation_error(
|
80
|
+
MFCreateMediaType(&pcm_media_type.ptr),
|
81
|
+
__FILE__, __LINE__);
|
82
|
+
pcm_media_type->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
|
83
|
+
pcm_media_type->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
|
84
|
+
|
85
|
+
ReleasePtr<IMFSourceReader> source_reader;
|
86
|
+
check_media_foundation_error(
|
87
|
+
MFCreateSourceReaderFromURL(wpath.c_str(), NULL, &source_reader.ptr),
|
88
|
+
__FILE__, __LINE__);
|
89
|
+
|
90
|
+
check_media_foundation_error(
|
91
|
+
source_reader->SetCurrentMediaType(
|
92
|
+
MF_SOURCE_READER_FIRST_AUDIO_STREAM, NULL, pcm_media_type.ptr),
|
93
|
+
__FILE__, __LINE__);
|
94
|
+
|
95
|
+
ReleasePtr<IMFMediaType> media_type;
|
96
|
+
check_media_foundation_error(
|
97
|
+
source_reader->GetCurrentMediaType(
|
98
|
+
MF_SOURCE_READER_FIRST_AUDIO_STREAM, &media_type.ptr),
|
99
|
+
__FILE__, __LINE__);
|
100
|
+
|
101
|
+
MemFreePtr<WAVEFORMATEX> format_;
|
102
|
+
check_media_foundation_error(
|
103
|
+
MFCreateWaveFormatExFromMFMediaType(media_type.ptr, &format_.ptr, NULL),
|
104
|
+
__FILE__, __LINE__);
|
105
|
+
|
106
|
+
*format = *format_.ptr;
|
107
|
+
if (format->wFormatTag != WAVE_FORMAT_PCM)
|
108
|
+
beeps_error(__FILE__, __LINE__, "'%s' is not a PCM file.", path);
|
109
|
+
|
110
|
+
while (true)
|
111
|
+
{
|
112
|
+
ReleasePtr<IMFSample> sample;
|
113
|
+
DWORD flags = 0;
|
114
|
+
check_media_foundation_error(
|
115
|
+
source_reader->ReadSample(
|
116
|
+
MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, &flags, NULL, &sample.ptr),
|
117
|
+
__FILE__, __LINE__);
|
118
|
+
if (flags & MF_SOURCE_READERF_ENDOFSTREAM)
|
119
|
+
break;
|
120
|
+
|
121
|
+
ReleasePtr<IMFMediaBuffer> buffer;
|
122
|
+
check_media_foundation_error(
|
123
|
+
sample->ConvertToContiguousBuffer(&buffer.ptr),
|
124
|
+
__FILE__, __LINE__);
|
125
|
+
|
126
|
+
BYTE* data = NULL;
|
127
|
+
DWORD size = 0;
|
128
|
+
check_media_foundation_error(
|
129
|
+
buffer->Lock(&data, NULL, &size),
|
130
|
+
__FILE__, __LINE__);
|
131
|
+
|
132
|
+
bytes->resize(bytes->size() + size);
|
133
|
+
memcpy(&(*bytes)[0] + bytes->size() - size, data, size);
|
134
|
+
|
135
|
+
check_media_foundation_error(
|
136
|
+
buffer->Unlock(),
|
137
|
+
__FILE__, __LINE__);
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
Signals
|
142
|
+
Signals_load (const char* path)
|
143
|
+
{
|
144
|
+
if (!is_file_exist(path))
|
145
|
+
beeps_error(__FILE__, __LINE__, "'%s' not found.", path);
|
146
|
+
|
147
|
+
WAVEFORMATEX format = {0};
|
148
|
+
std::vector<BYTE> bytes;
|
149
|
+
load_bytes(&format, &bytes, path);
|
150
|
+
if (bytes.empty())
|
151
|
+
beeps_error(__FILE__, __LINE__, "failed to read bytes: '%s'", path);
|
152
|
+
|
153
|
+
uint Bps = format.wBitsPerSample / 8;
|
154
|
+
uint nchannels = format.nChannels;
|
155
|
+
uint nsamples = bytes.size() / Bps / nchannels;
|
156
|
+
Signals signals = Signals_create(nsamples, nchannels, format.nSamplesPerSec);
|
157
|
+
Frames* frames = Signals_get_frames(&signals);
|
158
|
+
|
159
|
+
for (uint channel = 0; channel < nchannels; ++channel)
|
160
|
+
{
|
161
|
+
switch (Bps)
|
162
|
+
{
|
163
|
+
case 1:
|
164
|
+
{
|
165
|
+
const uchar* p = ((uchar*) &bytes[0]) + channel;
|
166
|
+
for (uint sample = 0; sample < nsamples; ++sample, p += nchannels)
|
167
|
+
(*frames)(sample, channel) = (*p - 128) / 128.f;
|
168
|
+
break;
|
169
|
+
}
|
170
|
+
|
171
|
+
case 2:
|
172
|
+
{
|
173
|
+
const ushort* p = ((ushort*) &bytes[0]) + channel;
|
174
|
+
for (uint sample = 0; sample < nsamples; ++sample, p += nchannels)
|
175
|
+
(*frames)(sample, channel) = *p / 32768.f;
|
176
|
+
break;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
181
|
+
Signals_set_nsamples(&signals, nsamples);
|
182
|
+
return signals;
|
183
|
+
}
|
184
|
+
|
185
|
+
|
186
|
+
}// Beeps
|