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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.doc/ext/beeps/analyser.cpp +1 -1
  3. data/.doc/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
  4. data/.doc/ext/beeps/file_in.cpp +1 -1
  5. data/.doc/ext/beeps/gain.cpp +1 -1
  6. data/.doc/ext/beeps/mic_in.cpp +1 -1
  7. data/.doc/ext/beeps/native.cpp +4 -2
  8. data/.doc/ext/beeps/oscillator.cpp +1 -1
  9. data/.doc/ext/beeps/pitch_shift.cpp +1 -1
  10. data/.doc/ext/beeps/processor.cpp +1 -1
  11. data/.doc/ext/beeps/sequencer.cpp +87 -0
  12. data/.doc/ext/beeps/sound.cpp +1 -1
  13. data/.doc/ext/beeps/sound_player.cpp +1 -1
  14. data/.doc/ext/beeps/time_stretch.cpp +1 -1
  15. data/.github/workflows/release-gem.yml +1 -1
  16. data/.github/workflows/test.yml +3 -0
  17. data/ChangeLog.md +13 -0
  18. data/Gemfile.lock +1 -1
  19. data/LICENSE +21 -0
  20. data/Rakefile +3 -2
  21. data/VERSION +1 -1
  22. data/beeps.gemspec +2 -2
  23. data/ext/beeps/analyser.cpp +1 -1
  24. data/ext/beeps/defs.h +2 -0
  25. data/ext/beeps/{adsr.cpp → envelope.cpp} +20 -20
  26. data/ext/beeps/extconf.rb +11 -3
  27. data/ext/beeps/file_in.cpp +1 -1
  28. data/ext/beeps/gain.cpp +1 -1
  29. data/ext/beeps/mic_in.cpp +1 -1
  30. data/ext/beeps/native.cpp +4 -2
  31. data/ext/beeps/oscillator.cpp +1 -1
  32. data/ext/beeps/pitch_shift.cpp +1 -1
  33. data/ext/beeps/processor.cpp +1 -1
  34. data/ext/beeps/sequencer.cpp +92 -0
  35. data/ext/beeps/sound.cpp +1 -1
  36. data/ext/beeps/sound_player.cpp +1 -1
  37. data/ext/beeps/time_stretch.cpp +1 -1
  38. data/include/beeps/defs.h +7 -0
  39. data/include/beeps/filter.h +4 -4
  40. data/include/beeps/generator.h +31 -0
  41. data/include/beeps/ruby/beeps.h +1 -1
  42. data/include/beeps/ruby/exception.h +2 -2
  43. data/include/beeps/ruby/filter.h +16 -10
  44. data/include/beeps/ruby/generator.h +18 -5
  45. data/include/beeps/ruby/processor.h +2 -2
  46. data/include/beeps/ruby/sound.h +4 -4
  47. data/lib/beeps/extension.rb +4 -0
  48. data/lib/beeps/processor.rb +2 -2
  49. data/src/beeps.cpp +3 -1
  50. data/src/beeps.h +22 -0
  51. data/src/{adsr.cpp → envelope.cpp} +21 -20
  52. data/src/openal.cpp +3 -1
  53. data/src/oscillator.cpp +75 -44
  54. data/src/osx/beeps.mm +19 -0
  55. data/src/processor.cpp +59 -49
  56. data/src/processor.h +30 -14
  57. data/src/sequencer.cpp +160 -0
  58. data/src/signals.cpp +45 -29
  59. data/src/signals.h +4 -4
  60. data/src/sound.cpp +32 -29
  61. data/src/win32/beeps.cpp +36 -0
  62. data/src/win32/exception.cpp +40 -0
  63. data/src/win32/exception.h +40 -0
  64. data/src/win32/signals.cpp +186 -0
  65. 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 || nchannels <= 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 || nsamples <= 0 || nchannels <= 0)
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
- Signals_resize (Signals* signals, uint capacity)
73
+ Signals_clear (Signals* signals)
68
74
  {
69
- if (!signals || !*signals || capacity <= 0)
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
- Signals_resize(signals, nsamples);
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 || !*to || !from)
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
- Signals_apply (Signals* signals, const Signals& multiplier)
220
+ Signals_multiply (Signals* signals, const Signals& multiplier)
207
221
  {
208
- if (!signals || multiplier.nchannels() != 1)
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 = &(*sigf)(0, ch);
220
- Float* mulp = &(*mulf)(0, 0);
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
- !signals || !*signals ||
236
- signals->nchannels() != samples.nchannels() ||
237
- signals->capacity() < nsamples)
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 Signals_resize (Signals* signals, uint capacity);
34
+ void Signals_clear (Signals* signals);
35
35
 
36
- void Signals_resize (Signals* signals, uint nsamples, Float value);
36
+ void Signals_clear (Signals* signals, uint capacity);
37
37
 
38
- void Signals_clear (Signals* signals);
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 Signals_apply (Signals* signals, const Signals& multiplier);
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 && nsamples > 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
- ~Data ()
107
+ Data (bool create)
106
108
  {
107
- clear();
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<ProcessorContext> processor_context;
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
- processor_context.reset(
407
- new ProcessorContext(sample_rate / 10, nchannels, sample_rate));
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 && processor_context);
422
-
423
- Signals signals = processor_context->process_signals(processor);
424
- if (!signals) return false;
428
+ assert(buffer && processor && stream_context);
425
429
 
426
- if (processor_context->is_finished())
427
- processor_context.reset();
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 && processor_context && *processor_context;
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
- ProcessorContext context(seconds * sample_rate, nchannels, sample_rate);
691
- Signals signals = context.process_signals(processor);
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 || !*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();
@@ -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