beeps 0.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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