beeps 0.3 → 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.
data/src/sequencer.cpp ADDED
@@ -0,0 +1,160 @@
1
+ #include "beeps/generator.h"
2
+
3
+
4
+ #include <list>
5
+ #include <algorithm>
6
+ #include "beeps/exception.h"
7
+ #include "beeps/debug.h"
8
+ #include "processor.h"
9
+ #include "signals.h"
10
+
11
+
12
+ namespace Beeps
13
+ {
14
+
15
+
16
+ struct Sequencer::Data
17
+ {
18
+
19
+ struct Note
20
+ {
21
+
22
+ Processor::Ref processor;
23
+
24
+ float offset, duration;
25
+
26
+ Note (Processor* processor, float offset, float duration)
27
+ : processor(processor), offset(offset), duration(duration)
28
+ {
29
+ }
30
+
31
+ };// Note
32
+
33
+ std::list<Note> notes;
34
+
35
+ float time_scale = 1;
36
+
37
+ uint sec2nsample (const Signals& signals, float sec) const
38
+ {
39
+ return sec * signals.sample_rate() / time_scale;
40
+ }
41
+
42
+ };// Sequencer::Data
43
+
44
+
45
+ Sequencer::Sequencer ()
46
+ {
47
+ }
48
+
49
+ Sequencer::~Sequencer ()
50
+ {
51
+ }
52
+
53
+ void
54
+ Sequencer::add (Processor* processor, float offset, float duration)
55
+ {
56
+ auto& notes = self->notes;
57
+ for (auto it = notes.begin(), end = notes.end(); it != end; ++it)
58
+ {
59
+ if (offset < it->offset)
60
+ {
61
+ notes.emplace(it, processor, offset, duration);
62
+ return;
63
+ }
64
+ }
65
+ notes.emplace_back(processor, offset, duration);
66
+ }
67
+
68
+ void
69
+ Sequencer::remove (Processor* processor, float offset)
70
+ {
71
+ auto it =
72
+ std::find_if(self->notes.begin(), self->notes.end(), [&](auto& note)
73
+ {
74
+ return note.processor == processor && note.offset == offset;
75
+ });
76
+ if (it == self->notes.end()) return;
77
+
78
+ self->notes.erase(it);
79
+ }
80
+
81
+ void
82
+ Sequencer::set_time_scale (float time_scale)
83
+ {
84
+ if (time_scale <= 0)
85
+ argument_error(__FILE__, __LINE__, "time_scale must be greater than 0");
86
+
87
+ self->time_scale = time_scale;
88
+ }
89
+
90
+ float
91
+ Sequencer::time_scale () const
92
+ {
93
+ return self->time_scale;
94
+ }
95
+
96
+ static void
97
+ mix (Signals* mixed, const Signals& source, uint source_offset)
98
+ {
99
+ Frames* mixf = Signals_get_frames(mixed);
100
+ Frames* srcf = Signals_get_frames(const_cast<Signals*>(&source));
101
+ Float* mixp = &(*mixf)(source_offset, 0);
102
+ Float* srcp = &(*srcf)(0, 0);
103
+ uint size = source.nsamples() * source.nchannels();
104
+ for (uint i = 0; i < size; ++i, ++mixp, ++srcp)
105
+ *mixp += *srcp;
106
+ }
107
+
108
+ void
109
+ Sequencer::generate (Context* pcontext, Signals* psignals, uint* offset)
110
+ {
111
+ Super::generate(pcontext, psignals, offset);
112
+
113
+ auto& context = *Processor_get_context(pcontext);
114
+ auto& signals = *psignals;
115
+ Signals_resize(&signals, signals.capacity(), 0);
116
+
117
+ uint generate_begin = *offset;
118
+ uint generate_end = *offset + signals.capacity();
119
+ Signals note_signals = Signals_create(
120
+ signals.capacity(), signals.nchannels(), signals.sample_rate());
121
+
122
+ uint nsamples = 0;
123
+ for (auto& note : self->notes)
124
+ {
125
+ uint note_begin = self->sec2nsample(signals, note.offset);
126
+ uint note_end = self->sec2nsample(signals, note.offset + note.duration);
127
+ if (note_end <= generate_begin) continue;
128
+ if (generate_end <= note_begin)
129
+ {
130
+ nsamples = generate_end - generate_begin;
131
+ break;
132
+ }
133
+
134
+ uint begin = std::max(generate_begin, note_begin);
135
+ uint end = std::min(generate_end, note_end);
136
+ assert(begin != end);
137
+
138
+ uint note_offset = begin - note_begin;
139
+ Signals_clear(&note_signals, end - begin);
140
+ context.process(note.processor.get(), &note_signals, &note_offset);
141
+
142
+ uint mix_offset = begin - generate_begin;
143
+ mix(&signals, note_signals, mix_offset);
144
+
145
+ if (mix_offset + note_signals.nsamples() > nsamples)
146
+ nsamples = mix_offset + note_signals.nsamples();
147
+ }
148
+
149
+ Signals_set_nsamples(&signals, nsamples);
150
+ *offset += nsamples;
151
+ }
152
+
153
+ Sequencer::operator bool () const
154
+ {
155
+ if (!Super::operator bool()) return false;
156
+ return self->time_scale > 0;
157
+ }
158
+
159
+
160
+ }// Beeps
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();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beeps
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.3'
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-05 00:00:00.000000000 Z
11
+ date: 2025-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,37 +16,37 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.3'
19
+ version: 0.3.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.3'
26
+ version: 0.3.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rucy
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.3'
33
+ version: 0.3.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0.3'
40
+ version: 0.3.1
41
41
  description: Synthesize and play beep sounds.
42
42
  email: xordog@gmail.com
43
43
  executables: []
44
44
  extensions:
45
45
  - Rakefile
46
46
  extra_rdoc_files:
47
- - ".doc/ext/beeps/adsr.cpp"
48
47
  - ".doc/ext/beeps/analyser.cpp"
49
48
  - ".doc/ext/beeps/beeps.cpp"
49
+ - ".doc/ext/beeps/envelope.cpp"
50
50
  - ".doc/ext/beeps/exception.cpp"
51
51
  - ".doc/ext/beeps/file_in.cpp"
52
52
  - ".doc/ext/beeps/gain.cpp"
@@ -55,13 +55,14 @@ extra_rdoc_files:
55
55
  - ".doc/ext/beeps/oscillator.cpp"
56
56
  - ".doc/ext/beeps/pitch_shift.cpp"
57
57
  - ".doc/ext/beeps/processor.cpp"
58
+ - ".doc/ext/beeps/sequencer.cpp"
58
59
  - ".doc/ext/beeps/sound.cpp"
59
60
  - ".doc/ext/beeps/sound_player.cpp"
60
61
  - ".doc/ext/beeps/time_stretch.cpp"
61
62
  files:
62
- - ".doc/ext/beeps/adsr.cpp"
63
63
  - ".doc/ext/beeps/analyser.cpp"
64
64
  - ".doc/ext/beeps/beeps.cpp"
65
+ - ".doc/ext/beeps/envelope.cpp"
65
66
  - ".doc/ext/beeps/exception.cpp"
66
67
  - ".doc/ext/beeps/file_in.cpp"
67
68
  - ".doc/ext/beeps/gain.cpp"
@@ -70,6 +71,7 @@ files:
70
71
  - ".doc/ext/beeps/oscillator.cpp"
71
72
  - ".doc/ext/beeps/pitch_shift.cpp"
72
73
  - ".doc/ext/beeps/processor.cpp"
74
+ - ".doc/ext/beeps/sequencer.cpp"
73
75
  - ".doc/ext/beeps/sound.cpp"
74
76
  - ".doc/ext/beeps/sound_player.cpp"
75
77
  - ".doc/ext/beeps/time_stretch.cpp"
@@ -80,14 +82,15 @@ files:
80
82
  - ChangeLog.md
81
83
  - Gemfile
82
84
  - Gemfile.lock
85
+ - LICENSE
83
86
  - README.md
84
87
  - Rakefile
85
88
  - VERSION
86
89
  - beeps.gemspec
87
- - ext/beeps/adsr.cpp
88
90
  - ext/beeps/analyser.cpp
89
91
  - ext/beeps/beeps.cpp
90
92
  - ext/beeps/defs.h
93
+ - ext/beeps/envelope.cpp
91
94
  - ext/beeps/exception.cpp
92
95
  - ext/beeps/extconf.rb
93
96
  - ext/beeps/file_in.cpp
@@ -97,6 +100,7 @@ files:
97
100
  - ext/beeps/oscillator.cpp
98
101
  - ext/beeps/pitch_shift.cpp
99
102
  - ext/beeps/processor.cpp
103
+ - ext/beeps/sequencer.cpp
100
104
  - ext/beeps/sound.cpp
101
105
  - ext/beeps/sound_player.cpp
102
106
  - ext/beeps/time_stretch.cpp
@@ -125,10 +129,10 @@ files:
125
129
  - lib/beeps/extension.rb
126
130
  - lib/beeps/processor.rb
127
131
  - lib/beeps/sound.rb
128
- - src/adsr.cpp
129
132
  - src/analyser.cpp
130
133
  - src/beeps.cpp
131
134
  - src/beeps.h
135
+ - src/envelope.cpp
132
136
  - src/exception.cpp
133
137
  - src/file_in.cpp
134
138
  - src/gain.cpp
@@ -142,6 +146,7 @@ files:
142
146
  - src/pitch_shift.cpp
143
147
  - src/processor.cpp
144
148
  - src/processor.h
149
+ - src/sequencer.cpp
145
150
  - src/signals.cpp
146
151
  - src/signals.h
147
152
  - src/sound.cpp