beeps 0.3.9 → 0.3.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8f411f90d8d0ed9b8672d08b5039799ac6f9178835dac7dc24acccd8c93cc0e
4
- data.tar.gz: e7ba8574e7962d3b9de62238f4f42cb897dd0edbecce3d298928acc07f2fe161
3
+ metadata.gz: 83c3fb3d71043da5eaa1f4f6c9832442f68d9fb9ee765c1d19891306df2ca3da
4
+ data.tar.gz: 6f80df9fa3ada9ecf150708c9efaf090800044b38c3e694108bfcb2b766ef577
5
5
  SHA512:
6
- metadata.gz: 4874e8fba3a4e1962853b9ce05454c703065b89c77fa89a286aebbf76bc775c43fb9f6e47c326b9725d005d8f2c680a13ee6981d686836a50e19900ab4c9436e
7
- data.tar.gz: f84446b0b666cc6852fc95845e303668c844012208210b647bc71611539972d0d24339113ade1b1903d0df5f2cbc9264ff2d339dfdcf4bccb9ee6e501f6eb163
6
+ metadata.gz: a94142e5430d65b5d9539b2f9b9d5d92bf13b893cf77c9aa00a3bbe52ec5e3cdca78db410fe4400ee465f3c9d6124201046414059fbc32635540a024c10c0e8d
7
+ data.tar.gz: 9b1a87a0c216b7cee8afe2bfd2decabb7035c5723449c3f02876336e33cf5c2c36dff5c0f2e0c4e757e4278c3b89f93d51e8489b571893460b665a34dd37b792
@@ -72,8 +72,8 @@ VALUE each_signal(VALUE self, VALUE nsamples_)
72
72
  Value args(2, values);
73
73
  for (uint i = start; i < nsamples; i += 2)
74
74
  {
75
- args[0] = value(samples[i + 0]);
76
- args[1] = value(samples[i + 1]);
75
+ args.set(0, value(samples[i + 0]));
76
+ args.set(1, value(samples[i + 1]));
77
77
  rb_yield(args);
78
78
  }
79
79
  break;
@@ -9,6 +9,7 @@ void Init_beeps_sound ();
9
9
  void Init_beeps_sound_player ();
10
10
  void Init_beeps_processor ();
11
11
 
12
+ void Init_beeps_value ();
12
13
  void Init_beeps_oscillator ();
13
14
  void Init_beeps_sequencer ();
14
15
  void Init_beeps_file_in ();
@@ -27,11 +28,7 @@ void Init_beeps_analyser ();
27
28
 
28
29
 
29
30
  extern "C" void
30
- #ifdef COCOAPODS
31
- Init_beeps_native ()
32
- #else
33
- Init_native ()
34
- #endif
31
+ Init_beeps_ext ()
35
32
  {
36
33
  RUCY_TRY
37
34
 
@@ -45,6 +42,7 @@ extern "C" void
45
42
  Init_beeps_sound_player();
46
43
  Init_beeps_processor();
47
44
 
45
+ Init_beeps_value();
48
46
  Init_beeps_oscillator();
49
47
  Init_beeps_sequencer();
50
48
  Init_beeps_file_in();
@@ -40,8 +40,8 @@ VALUE set_samples(VALUE self, VALUE samples)
40
40
  {
41
41
  CHECK;
42
42
 
43
- Value* array = samples.as_array();
44
- size_t size = samples.size();
43
+ const Value* array = samples.as_array();
44
+ size_t size = samples.size();
45
45
 
46
46
  std::vector<Beeps::Sample> data;
47
47
  data.reserve(size);
@@ -56,6 +56,22 @@ VALUE get_time_scale(VALUE self)
56
56
  return value(THIS->time_scale());
57
57
  }
58
58
 
59
+ static
60
+ VALUE each_note(VALUE self)
61
+ {
62
+ CHECK;
63
+
64
+ Value ret;
65
+ for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
66
+ {
67
+ ret = rb_yield_values(3,
68
+ value(it->processor.get()),
69
+ value(it->offset),
70
+ value(it->duration));
71
+ }
72
+ return ret;
73
+ }
74
+
59
75
 
60
76
  static Class cSequencer;
61
77
 
@@ -70,6 +86,7 @@ Init_beeps_sequencer ()
70
86
  rb_define_method(cSequencer, "remove", RUBY_METHOD_FUNC(remove), 2);
71
87
  //rb_define_method(cSequencer, "time_scale=", RUBY_METHOD_FUNC(set_time_scale), 1);
72
88
  //rb_define_method(cSequencer, "time_scale", RUBY_METHOD_FUNC(get_time_scale), 0);
89
+ cSequencer.define_method("each_note!", each_note);
73
90
  }
74
91
 
75
92
 
@@ -0,0 +1,107 @@
1
+ #include "beeps/ruby/generator.h"
2
+
3
+
4
+ #include "beeps/ruby/processor.h"
5
+ #include "defs.h"
6
+
7
+
8
+ RUCY_DEFINE_WRAPPER_VALUE_FROM_TO(BEEPS_EXPORT, Beeps::Value)
9
+
10
+ #define THIS to<Beeps::Value*>(self)
11
+
12
+ #define CHECK RUCY_CHECK_OBJ(Beeps::Value, self)
13
+
14
+
15
+ static
16
+ VALUE alloc(VALUE klass)
17
+ {
18
+ return value(new Beeps::RubyProcessor<Beeps::Value>, klass);
19
+ }
20
+
21
+ static
22
+ VALUE set_type(VALUE self, VALUE type)
23
+ {
24
+ CHECK;
25
+
26
+ THIS->set_type((Beeps::Value::Type) to<uint>(type));
27
+ return type;
28
+ }
29
+
30
+ static
31
+ VALUE get_type(VALUE self)
32
+ {
33
+ CHECK;
34
+
35
+ return value(THIS->type());
36
+ }
37
+
38
+ static
39
+ VALUE set_value(VALUE self, VALUE value)
40
+ {
41
+ CHECK;
42
+
43
+ THIS->set_value(to<float>(value));
44
+ return value;
45
+ }
46
+
47
+ static
48
+ VALUE insert(VALUE self, VALUE value, VALUE time)
49
+ {
50
+ CHECK;
51
+
52
+ THIS->insert(to<float>(value), to<float>(time));
53
+ }
54
+
55
+ static
56
+ VALUE clear(VALUE self)
57
+ {
58
+ CHECK;
59
+
60
+ THIS->clear();
61
+ }
62
+
63
+ static
64
+ VALUE each_value(VALUE self)
65
+ {
66
+ CHECK;
67
+
68
+ Value ret;
69
+ for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
70
+ ret = rb_yield_values(2, value(it->value), value(it->time));
71
+ return ret;
72
+ }
73
+
74
+
75
+ static Class cValue;
76
+
77
+ void
78
+ Init_beeps_value ()
79
+ {
80
+ Module mBeeps = rb_define_module("Beeps");
81
+
82
+ cValue = mBeeps.define_class("Value", Beeps::processor_class());
83
+ rb_define_alloc_func(cValue, alloc);
84
+ rb_define_method(cValue, "type=", RUBY_METHOD_FUNC(set_type), 1);
85
+ rb_define_method(cValue, "type", RUBY_METHOD_FUNC(get_type), 0);
86
+ rb_define_method(cValue, "value=", RUBY_METHOD_FUNC(set_value), 1);
87
+ rb_define_method(cValue, "insert", RUBY_METHOD_FUNC(insert), 2);
88
+ rb_define_method(cValue, "clear", RUBY_METHOD_FUNC(clear), 0);
89
+ cValue.define_method("each_value!", each_value);
90
+
91
+ cValue.define_const("TYPE_NONE", Beeps::Value::TYPE_NONE);
92
+ cValue.define_const("LINEAR", Beeps::Value::LINEAR);
93
+ }
94
+
95
+
96
+ namespace Beeps
97
+ {
98
+
99
+
100
+ Class
101
+ value_class ()
102
+ {
103
+ return cValue;
104
+ }
105
+
106
+
107
+ }// Beeps
data/CLAUDE.md ADDED
@@ -0,0 +1,24 @@
1
+ # Beeps
2
+
3
+ Audio synthesis and playback library. Provides an audio processing chain with oscillators, filters, envelopes, and effects.
4
+
5
+ ## Processor Chain
6
+
7
+ Connect processors with the `>>` operator:
8
+ ```ruby
9
+ Beeps::Oscillator.new >> Beeps::Gain.new(gain: 0.5)
10
+ ```
11
+
12
+ ## External Libraries
13
+
14
+ Automatically fetched and statically linked at build time:
15
+ - STK 5.0.1 — DSP toolkit
16
+ - AudioFile 1.1.1 — Audio file I/O
17
+ - r8brain-free-src 6.2 — Sample rate conversion
18
+ - signalsmith-stretch — Time stretching
19
+
20
+ ## Platform Dependencies
21
+
22
+ - macOS: OpenAL, AVFoundation
23
+ - Windows: OpenAL, Media Foundation
24
+ - Linux: libopenal-dev
data/ChangeLog.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # beeps ChangeLog
2
2
 
3
3
 
4
+ ## [v0.3.10] - 2026-04-09
5
+
6
+ - Add Sequencer#each_note
7
+ - Add 'apt' for install_packages()
8
+ - Add Value processor for time-varying value generation
9
+ - Change C-Extension name from 'native.so' to 'beeps_ext.so'
10
+ - Update dependencies
11
+
12
+
4
13
  ## [v0.3.9] - 2025-07-06
5
14
 
6
15
  - Add TextIn class
data/Rakefile CHANGED
@@ -14,7 +14,9 @@ require 'beeps/extension'
14
14
  EXTENSIONS = [Xot, Rucy, Beeps]
15
15
  TESTS_ALONE = ['test/test_beeps_init.rb']
16
16
 
17
- install_packages win32: %w[MINGW_PACKAGE_PREFIX-openal]
17
+ install_packages(
18
+ mingw: %w[MINGW_PACKAGE_PREFIX-openal],
19
+ apt: %w[libopenal-dev])
18
20
 
19
21
  use_external_library 'https://github.com/thestk/stk',
20
22
  tag: '5.0.1',
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.9
1
+ 0.3.10
data/beeps.gemspec CHANGED
@@ -25,8 +25,8 @@ Gem::Specification.new do |s|
25
25
  s.platform = Gem::Platform::RUBY
26
26
  s.required_ruby_version = '>= 3.0.0'
27
27
 
28
- s.add_dependency 'xot', '~> 0.3.9', '>= 0.3.9'
29
- s.add_dependency 'rucy', '~> 0.3.9', '>= 0.3.9'
28
+ s.add_dependency 'xot', '~> 0.3.10'
29
+ s.add_dependency 'rucy', '~> 0.3.10'
30
30
 
31
31
  s.files = `git ls-files`.split $/
32
32
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
@@ -76,8 +76,8 @@ RUCY_DEF1(each_signal, nsamples_)
76
76
  Value args(2, values);
77
77
  for (uint i = start; i < nsamples; i += 2)
78
78
  {
79
- args[0] = value(samples[i + 0]);
80
- args[1] = value(samples[i + 1]);
79
+ args.set(0, value(samples[i + 0]));
80
+ args.set(1, value(samples[i + 1]));
81
81
  rb_yield(args);
82
82
  }
83
83
  break;
data/ext/beeps/extconf.rb CHANGED
@@ -13,16 +13,20 @@ Xot::ExtConf.new Xot, Rucy, Beeps do
13
13
  setup do
14
14
  headers << 'ruby.h'
15
15
 
16
- if win32?
17
- headers << 'AL/al.h' << 'AL/alc.h'
18
- libs << 'openal' << 'ole32' << 'mf' << 'mfplat' << 'mfreadwrite' << 'mfuuid'
19
- elsif osx?
16
+ case
17
+ when osx?
20
18
  headers << 'OpenAL/al.h' << 'OpenAL/alc.h'
21
19
  frameworks << 'OpenAL' << 'AVFoundation'
20
+ when win32?
21
+ headers << 'AL/al.h' << 'AL/alc.h'
22
+ libs << 'openal' << 'ole32' << 'mf' << 'mfplat' << 'mfreadwrite' << 'mfuuid'
23
+ when linux?
24
+ headers << 'AL/al.h' << 'AL/alc.h'
25
+ libs << 'openal'
22
26
  end
23
27
 
24
- $LDFLAGS << ' -Wl,--out-implib=native.dll.a' if mingw? || cygwin?
28
+ $LDFLAGS << ' -Wl,--out-implib=beeps_ext.dll.a' if mingw? || cygwin?
25
29
  end
26
30
 
27
- create_makefile 'beeps/native'
31
+ create_makefile 'beeps_ext'
28
32
  end
data/ext/beeps/native.cpp CHANGED
@@ -9,6 +9,7 @@ void Init_beeps_sound ();
9
9
  void Init_beeps_sound_player ();
10
10
  void Init_beeps_processor ();
11
11
 
12
+ void Init_beeps_value ();
12
13
  void Init_beeps_oscillator ();
13
14
  void Init_beeps_sequencer ();
14
15
  void Init_beeps_file_in ();
@@ -27,11 +28,7 @@ void Init_beeps_analyser ();
27
28
 
28
29
 
29
30
  extern "C" void
30
- #ifdef COCOAPODS
31
- Init_beeps_native ()
32
- #else
33
- Init_native ()
34
- #endif
31
+ Init_beeps_ext ()
35
32
  {
36
33
  RUCY_TRY
37
34
 
@@ -45,6 +42,7 @@ extern "C" void
45
42
  Init_beeps_sound_player();
46
43
  Init_beeps_processor();
47
44
 
45
+ Init_beeps_value();
48
46
  Init_beeps_oscillator();
49
47
  Init_beeps_sequencer();
50
48
  Init_beeps_file_in();
@@ -43,8 +43,8 @@ RUCY_DEF1(set_samples, samples)
43
43
  {
44
44
  CHECK;
45
45
 
46
- Value* array = samples.as_array();
47
- size_t size = samples.size();
46
+ const Value* array = samples.as_array();
47
+ size_t size = samples.size();
48
48
 
49
49
  std::vector<Beeps::Sample> data;
50
50
  data.reserve(size);
@@ -61,6 +61,23 @@ RUCY_DEF0(get_time_scale)
61
61
  }
62
62
  RUCY_END
63
63
 
64
+ static
65
+ RUCY_DEF0(each_note)
66
+ {
67
+ CHECK;
68
+
69
+ Value ret;
70
+ for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
71
+ {
72
+ ret = rb_yield_values(3,
73
+ value(it->processor.get()),
74
+ value(it->offset),
75
+ value(it->duration));
76
+ }
77
+ return ret;
78
+ }
79
+ RUCY_END
80
+
64
81
 
65
82
  static Class cSequencer;
66
83
 
@@ -75,6 +92,7 @@ Init_beeps_sequencer ()
75
92
  cSequencer.define_method("remove", remove);
76
93
  //cSequencer.define_method("time_scale=", set_time_scale);
77
94
  //cSequencer.define_method("time_scale", get_time_scale);
95
+ cSequencer.define_method("each_note!", each_note);
78
96
  }
79
97
 
80
98
 
@@ -0,0 +1,114 @@
1
+ #include "beeps/ruby/generator.h"
2
+
3
+
4
+ #include "beeps/ruby/processor.h"
5
+ #include "defs.h"
6
+
7
+
8
+ RUCY_DEFINE_WRAPPER_VALUE_FROM_TO(BEEPS_EXPORT, Beeps::Value)
9
+
10
+ #define THIS to<Beeps::Value*>(self)
11
+
12
+ #define CHECK RUCY_CHECK_OBJ(Beeps::Value, self)
13
+
14
+
15
+ static
16
+ RUCY_DEF_ALLOC(alloc, klass)
17
+ {
18
+ return value(new Beeps::RubyProcessor<Beeps::Value>, klass);
19
+ }
20
+ RUCY_END
21
+
22
+ static
23
+ RUCY_DEF1(set_type, type)
24
+ {
25
+ CHECK;
26
+
27
+ THIS->set_type((Beeps::Value::Type) to<uint>(type));
28
+ return type;
29
+ }
30
+ RUCY_END
31
+
32
+ static
33
+ RUCY_DEF0(get_type)
34
+ {
35
+ CHECK;
36
+
37
+ return value(THIS->type());
38
+ }
39
+ RUCY_END
40
+
41
+ static
42
+ RUCY_DEF1(set_value, value)
43
+ {
44
+ CHECK;
45
+
46
+ THIS->set_value(to<float>(value));
47
+ return value;
48
+ }
49
+ RUCY_END
50
+
51
+ static
52
+ RUCY_DEF2(insert, value, time)
53
+ {
54
+ CHECK;
55
+
56
+ THIS->insert(to<float>(value), to<float>(time));
57
+ }
58
+ RUCY_END
59
+
60
+ static
61
+ RUCY_DEF0(clear)
62
+ {
63
+ CHECK;
64
+
65
+ THIS->clear();
66
+ }
67
+ RUCY_END
68
+
69
+ static
70
+ RUCY_DEF0(each_value)
71
+ {
72
+ CHECK;
73
+
74
+ Value ret;
75
+ for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
76
+ ret = rb_yield_values(2, value(it->value), value(it->time));
77
+ return ret;
78
+ }
79
+ RUCY_END
80
+
81
+
82
+ static Class cValue;
83
+
84
+ void
85
+ Init_beeps_value ()
86
+ {
87
+ Module mBeeps = define_module("Beeps");
88
+
89
+ cValue = mBeeps.define_class("Value", Beeps::processor_class());
90
+ cValue.define_alloc_func(alloc);
91
+ cValue.define_method("type=", set_type);
92
+ cValue.define_method("type", get_type);
93
+ cValue.define_method("value=", set_value);
94
+ cValue.define_method("insert", insert);
95
+ cValue.define_method("clear", clear);
96
+ cValue.define_method("each_value!", each_value);
97
+
98
+ cValue.define_const("TYPE_NONE", Beeps::Value::TYPE_NONE);
99
+ cValue.define_const("LINEAR", Beeps::Value::LINEAR);
100
+ }
101
+
102
+
103
+ namespace Beeps
104
+ {
105
+
106
+
107
+ Class
108
+ value_class ()
109
+ {
110
+ return cValue;
111
+ }
112
+
113
+
114
+ }// Beeps
@@ -4,6 +4,7 @@
4
4
  #define __BEEPS_GENERATOR_H__
5
5
 
6
6
 
7
+ #include <list>
7
8
  #include <beeps/processor.h>
8
9
 
9
10
 
@@ -11,6 +12,72 @@ namespace Beeps
11
12
  {
12
13
 
13
14
 
15
+ class Value : public Generator
16
+ {
17
+
18
+ typedef Generator Super;
19
+
20
+ public:
21
+
22
+ enum Type
23
+ {
24
+ TYPE_NONE = 0, LINEAR
25
+ };
26
+
27
+ struct Point
28
+ {
29
+
30
+ float value;
31
+
32
+ float time;
33
+
34
+ Point (float value, float time);
35
+
36
+ };// Point
37
+
38
+ typedef std::vector<Point> PointList;
39
+
40
+ typedef PointList:: iterator iterator;
41
+
42
+ typedef PointList::const_iterator const_iterator;
43
+
44
+ Value (float value = 0, Type type = LINEAR);
45
+
46
+ virtual ~Value ();
47
+
48
+ virtual void set_type (Type type);
49
+
50
+ virtual Type type () const;
51
+
52
+ virtual void set_value (float value);
53
+
54
+ virtual void insert (float value, float time);
55
+
56
+ virtual void clear ();
57
+
58
+ virtual iterator begin ();
59
+
60
+ virtual const_iterator begin () const;
61
+
62
+ virtual iterator end ();
63
+
64
+ virtual const_iterator end () const;
65
+
66
+ struct Data;
67
+
68
+ Xot::PImpl<Data> self;
69
+
70
+ private:
71
+
72
+ virtual void generate (
73
+ Context* context, Signals* signals, uint* offset) override;
74
+
75
+ virtual int max_segment_size_for_process (
76
+ double sample_rate, uint nsamples) const override;
77
+
78
+ };// Value
79
+
80
+
14
81
  class Oscillator : public Generator
15
82
  {
16
83
 
@@ -95,6 +162,23 @@ namespace Beeps
95
162
 
96
163
  public:
97
164
 
165
+ struct Note
166
+ {
167
+
168
+ Processor::Ref processor;
169
+
170
+ float offset, duration;
171
+
172
+ Note (Processor* processor, float offset, float duration);
173
+
174
+ };// Note
175
+
176
+ typedef std::list<Note> NoteList;
177
+
178
+ typedef NoteList:: iterator iterator;
179
+
180
+ typedef NoteList::const_iterator const_iterator;
181
+
98
182
  Sequencer ();
99
183
 
100
184
  virtual ~Sequencer ();
@@ -107,6 +191,14 @@ namespace Beeps
107
191
 
108
192
  virtual float time_scale () const;
109
193
 
194
+ virtual iterator begin ();
195
+
196
+ virtual const_iterator begin () const;
197
+
198
+ virtual iterator end ();
199
+
200
+ virtual const_iterator end () const;
201
+
110
202
  virtual operator bool () const override;
111
203
 
112
204
  struct Data;
@@ -9,6 +9,8 @@
9
9
  #include <beeps/generator.h>
10
10
 
11
11
 
12
+ RUCY_DECLARE_WRAPPER_VALUE_FROM_TO(BEEPS_EXPORT, Beeps::Value)
13
+
12
14
  RUCY_DECLARE_WRAPPER_VALUE_FROM_TO(BEEPS_EXPORT, Beeps::Oscillator)
13
15
 
14
16
  RUCY_DECLARE_WRAPPER_VALUE_FROM_TO(BEEPS_EXPORT, Beeps::Sequencer)
@@ -24,6 +26,9 @@ namespace Beeps
24
26
  {
25
27
 
26
28
 
29
+ BEEPS_EXPORT Rucy::Class value_class ();
30
+ // class Beeps::Value
31
+
27
32
  BEEPS_EXPORT Rucy::Class oscillator_class ();
28
33
  // class Beeps::Oscillator
29
34
 
@@ -47,6 +52,12 @@ namespace Rucy
47
52
  {
48
53
 
49
54
 
55
+ template <> inline Class
56
+ get_ruby_class<Beeps::Value> ()
57
+ {
58
+ return Beeps::value_class();
59
+ }
60
+
50
61
  template <> inline Class
51
62
  get_ruby_class<Beeps::Oscillator> ()
52
63
  {
data/lib/beeps/ext.rb CHANGED
@@ -1 +1 @@
1
- require 'beeps/native'
1
+ require 'beeps_ext'
@@ -45,6 +45,32 @@ module Beeps
45
45
  end# Processor
46
46
 
47
47
 
48
+ class Value
49
+
50
+ include Enumerable
51
+
52
+ const_symbol_accessor :type, **{
53
+ none: TYPE_NONE,
54
+ linear: LINEAR
55
+ }
56
+
57
+ def initialize(value, type = :linear, **kwargs, &block)
58
+ super(**kwargs, &block)
59
+ self.value, self.type = value, type
60
+ end
61
+
62
+ universal_accessor :type
63
+
64
+ def each_value(&block)
65
+ return enum_for :each_value unless block
66
+ each_value!(&block)
67
+ end
68
+
69
+ alias each each_value
70
+
71
+ end# Value
72
+
73
+
48
74
  class Oscillator
49
75
 
50
76
  include Enumerable
@@ -74,14 +100,33 @@ module Beeps
74
100
  alias freq frequency
75
101
 
76
102
  def each_sample(&block)
77
- block ? each_sample!(&block) : enum_for(:each_sample!)
103
+ return enum_for :each_sample unless block
104
+ each_sample!(&block)
78
105
  end
79
106
 
80
107
  alias each each_sample
81
108
 
109
+ def samples()
110
+ to_a
111
+ end
112
+
82
113
  end# Oscillator
83
114
 
84
115
 
116
+ class Sequencer
117
+
118
+ include Enumerable
119
+
120
+ def each_note(&block)
121
+ return enum_for :each_note unless block
122
+ each_note!(&block)
123
+ end
124
+
125
+ alias each each_note
126
+
127
+ end# Sequencer
128
+
129
+
85
130
  class FileIn
86
131
 
87
132
  def initialize(path = nil, **kwargs, &block)
data/src/sdl/beeps.cpp ADDED
@@ -0,0 +1,19 @@
1
+ #include "../beeps.h"
2
+
3
+
4
+ namespace Beeps
5
+ {
6
+
7
+
8
+ void
9
+ Beeps_init ()
10
+ {
11
+ }
12
+
13
+ void
14
+ Beeps_fin ()
15
+ {
16
+ }
17
+
18
+
19
+ }// Beeps
@@ -0,0 +1,18 @@
1
+ #include "../signals.h"
2
+
3
+
4
+ #include "beeps/exception.h"
5
+
6
+
7
+ namespace Beeps
8
+ {
9
+
10
+
11
+ Signals
12
+ Signals_load (const char* path)
13
+ {
14
+ not_implemented_error(__FILE__, __LINE__);
15
+ }
16
+
17
+
18
+ }// Beeps
@@ -0,0 +1,61 @@
1
+ #include "beeps/generator.h"
2
+
3
+
4
+ #include "beeps/exception.h"
5
+ #include "../signals.h"
6
+
7
+
8
+ namespace Beeps
9
+ {
10
+
11
+
12
+ struct TextIn::Data
13
+ {
14
+
15
+ double sample_rate = 0;
16
+
17
+ };// TextIn::Data
18
+
19
+
20
+ TextIn::TextIn (const char* text, double sample_rate)
21
+ {
22
+ if (sample_rate == 0)
23
+ sample_rate = Beeps::sample_rate();
24
+ if (sample_rate <= 0)
25
+ argument_error(__FILE__, __LINE__);
26
+
27
+ self->sample_rate = sample_rate;
28
+
29
+ if (text) synthesize(text);
30
+ }
31
+
32
+ TextIn::~TextIn ()
33
+ {
34
+ }
35
+
36
+ void
37
+ TextIn::synthesize (const char* text)
38
+ {
39
+ not_implemented_error(__FILE__, __LINE__);
40
+ }
41
+
42
+ double
43
+ TextIn::sample_rate () const
44
+ {
45
+ return self->sample_rate;
46
+ }
47
+
48
+ TextIn::operator bool () const
49
+ {
50
+ if (!Super::operator bool()) return false;
51
+ return self->sample_rate > 0;
52
+ }
53
+
54
+ void
55
+ TextIn::generate (Context* context, Signals* signals, uint* offset)
56
+ {
57
+ Super::generate(context, signals, offset);
58
+ }
59
+
60
+
61
+ }// Beeps
data/src/sequencer.cpp CHANGED
@@ -1,7 +1,6 @@
1
1
  #include "beeps/generator.h"
2
2
 
3
3
 
4
- #include <list>
5
4
  #include <algorithm>
6
5
  #include "beeps/exception.h"
7
6
  #include "beeps/debug.h"
@@ -16,21 +15,7 @@ namespace Beeps
16
15
  struct Sequencer::Data
17
16
  {
18
17
 
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;
18
+ NoteList notes;
34
19
 
35
20
  float time_scale = 1;
36
21
 
@@ -42,6 +27,12 @@ namespace Beeps
42
27
  };// Sequencer::Data
43
28
 
44
29
 
30
+ Sequencer::Note::Note (Processor* processor, float offset, float duration)
31
+ : processor(processor), offset(offset), duration(duration)
32
+ {
33
+ }
34
+
35
+
45
36
  Sequencer::Sequencer ()
46
37
  {
47
38
  }
@@ -99,6 +90,30 @@ namespace Beeps
99
90
  return self->time_scale;
100
91
  }
101
92
 
93
+ Sequencer::iterator
94
+ Sequencer::begin ()
95
+ {
96
+ return self->notes.begin();
97
+ }
98
+
99
+ Sequencer::const_iterator
100
+ Sequencer::begin () const
101
+ {
102
+ return self->notes.begin();
103
+ }
104
+
105
+ Sequencer::iterator
106
+ Sequencer::end ()
107
+ {
108
+ return self->notes.end();
109
+ }
110
+
111
+ Sequencer::const_iterator
112
+ Sequencer::end () const
113
+ {
114
+ return self->notes.end();
115
+ }
116
+
102
117
  Sequencer::operator bool () const
103
118
  {
104
119
  if (!Super::operator bool()) return false;
data/src/value.cpp ADDED
@@ -0,0 +1,181 @@
1
+ #include "beeps/generator.h"
2
+
3
+
4
+ #include <algorithm>
5
+ #include "beeps/exception.h"
6
+ #include "processor.h"
7
+ #include "signals.h"
8
+
9
+
10
+ namespace Beeps
11
+ {
12
+
13
+
14
+ struct Value::Data
15
+ {
16
+
17
+ Type type = TYPE_NONE;
18
+
19
+ PointList points;
20
+
21
+ };// Value::Data
22
+
23
+
24
+ Value::Point::Point (float value, float time)
25
+ : value(value), time(time)
26
+ {
27
+ }
28
+
29
+
30
+ Value::Value (float value, Type type)
31
+ {
32
+ self->type = type;
33
+ set_value(value);
34
+ }
35
+
36
+ Value::~Value ()
37
+ {
38
+ }
39
+
40
+ void
41
+ Value::set_type (Type type)
42
+ {
43
+ self->type = type;
44
+
45
+ set_updated();
46
+ }
47
+
48
+ Value::Type
49
+ Value::type () const
50
+ {
51
+ return self->type;
52
+ }
53
+
54
+ void
55
+ Value::set_value (float value)
56
+ {
57
+ self->points.clear();
58
+ self->points.push_back(Point(value, 0));
59
+
60
+ set_updated();
61
+ }
62
+
63
+ void
64
+ Value::insert (float value, float time)
65
+ {
66
+ if (time < 0)
67
+ argument_error(__FILE__, __LINE__, "time must be >= 0");
68
+
69
+ auto& points = self->points;
70
+ auto it = std::find_if(
71
+ points.begin(), points.end(),
72
+ [&](const auto& p) {return time <= p.time;});
73
+ if (it != points.end() && it->time == time)
74
+ {
75
+ if (it->value == value) return;
76
+ it->value = value;
77
+ }
78
+ else
79
+ points.emplace(it, value, time);
80
+
81
+ set_updated();
82
+ }
83
+
84
+ void
85
+ Value::clear ()
86
+ {
87
+ self->points.clear();
88
+
89
+ set_updated();
90
+ }
91
+
92
+ Value::iterator
93
+ Value::begin ()
94
+ {
95
+ return self->points.begin();
96
+ }
97
+
98
+ Value::const_iterator
99
+ Value::begin () const
100
+ {
101
+ return self->points.begin();
102
+ }
103
+
104
+ Value::iterator
105
+ Value::end ()
106
+ {
107
+ return self->points.end();
108
+ }
109
+
110
+ Value::const_iterator
111
+ Value::end () const
112
+ {
113
+ return self->points.end();
114
+ }
115
+
116
+ static float
117
+ interpolate_linear (const Value::PointList& points, float time)
118
+ {
119
+ if (points.empty()) return 0;
120
+ if (time <= points[0].time) return points[0].value;
121
+
122
+ for (size_t i = 0; i + 1 < points.size(); ++i)
123
+ {
124
+ const auto& p0 = points[i];
125
+ const auto& p1 = points[i + 1];
126
+ if (time < p1.time)
127
+ {
128
+ float t = (time - p0.time) / (p1.time - p0.time);
129
+ return p0.value + (p1.value - p0.value) * t;
130
+ }
131
+ }
132
+ return points.back().value;
133
+ }
134
+
135
+ static decltype(&interpolate_linear)
136
+ get_interpolate_func (Value::Type type)
137
+ {
138
+ switch (type)
139
+ {
140
+ case Value::LINEAR: return interpolate_linear;
141
+ default: return NULL;
142
+ }
143
+ }
144
+
145
+ void
146
+ Value::generate (Context* context, Signals* signals, uint* offset)
147
+ {
148
+ Super::generate(context, signals, offset);
149
+
150
+ auto& points = self->points;
151
+ uint nsamples = signals->capacity();
152
+
153
+ if (points.size() == 1)
154
+ Signals_fill(signals, nsamples, points[0].value);
155
+ else
156
+ {
157
+ auto interpolate = get_interpolate_func(self->type);
158
+ if (!interpolate)
159
+ invalid_state_error(__FILE__, __LINE__);
160
+
161
+ double sample_rate = signals->sample_rate();
162
+ Sample* p = Signals_at(signals, 0);
163
+ for (uint i = 0; i < nsamples; ++i)
164
+ p[i] = interpolate(points, (*offset + i) / sample_rate);
165
+ Signals_set_nsamples(signals, nsamples);
166
+ }
167
+
168
+ *offset += signals->nsamples();
169
+ }
170
+
171
+ int
172
+ Value::max_segment_size_for_process (
173
+ double sample_rate, uint nsamples) const
174
+ {
175
+ if (self->points.size() == 1)
176
+ return Super::max_segment_size_for_process(sample_rate, nsamples);
177
+ return sample_rate / 256;
178
+ }
179
+
180
+
181
+ }// Beeps
@@ -23,12 +23,12 @@ class TestOscillator < Test::Unit::TestCase
23
23
  def test_offset()
24
24
  assert_in_delta 0, get_samples(10000, osc(offset: 0)).sum / 10000
25
25
  assert_in_delta 3, get_samples(10000, osc(offset: 3)).sum / 10000
26
- assert_in_delta -3, get_samples(10000, osc(offset: -3)).sum / 10000
26
+ assert_in_delta(-3, get_samples(10000, osc(offset: -3)).sum / 10000)
27
27
  end
28
28
 
29
29
  def test_gain()
30
30
  assert_in_delta 3, get_samples(100, osc(gain: 3)).max
31
- assert_in_delta -3, get_samples(100, osc(gain: 3)).min
31
+ assert_in_delta(-3, get_samples(100, osc(gain: 3)).min)
32
32
  end
33
33
 
34
34
  def test_offset_and_gain()
@@ -0,0 +1,25 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestSequencer < Test::Unit::TestCase
5
+
6
+ B = Beeps
7
+
8
+ def seq(&b)
9
+ B::Sequencer.new.tap {b.call _1}
10
+ end
11
+
12
+ def osc(type = :sine, samples: nil, freq: 1, **kwargs)
13
+ B::Oscillator.new(type, samples: samples, freq: freq, **kwargs)
14
+ end
15
+
16
+ def test_each_note()
17
+ assert_equal(
18
+ [[B::Oscillator, 0, 1]],
19
+ seq {_1.add osc, 0, 1}.map {|p, *args| [p.class, *args]})
20
+
21
+ assert_equal [0], seq {_1.add osc, 0, 1} .map {_2}
22
+ assert_equal [0, 2], seq {_1.add osc, 0, 1; _1.add osc, 2, 3}.map {_2}
23
+ end
24
+
25
+ end# TestSequencer
@@ -0,0 +1,47 @@
1
+ require_relative 'helper'
2
+
3
+
4
+ class TestValue < Test::Unit::TestCase
5
+
6
+ B = Beeps
7
+
8
+ def val(...) = B::Value.new(...)
9
+
10
+ def test_constant()
11
+ assert_each_in_delta [5] * 3, get_samples(2, val(5))
12
+ end
13
+
14
+ def test_linear_interpolation()
15
+ v = val 0
16
+ v.insert 2, 1
17
+ v.insert 1, 2
18
+ assert_each_in_delta [0, 1, 2, 1.5, 1], get_samples(2, v, seconds: 2)
19
+ end
20
+
21
+ def test_insert()
22
+ v = val 0
23
+ v.insert 1, 1
24
+ assert_equal [[0, 0], [1, 1]], v.to_a
25
+
26
+ v.insert 2, 1
27
+ assert_equal [[0, 0], [2, 1]], v.to_a
28
+
29
+ assert_raise(ArgumentError) {v.insert 1, -1}
30
+ end
31
+
32
+ def test_clear()
33
+ v = val 0
34
+ assert_equal 1, v.to_a.size
35
+
36
+ v.clear
37
+ assert_equal 0, v.to_a.size
38
+ end
39
+
40
+ def test_each()
41
+ v = val 0
42
+ v.insert 1, 1
43
+ v.insert 2, 2
44
+ assert_equal [[0, 0], [1, 1], [2, 2]], v.to_a
45
+ end
46
+
47
+ end# TestValue
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.9
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-05 00:00:00.000000000 Z
11
+ date: 2026-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,40 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.9
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 0.3.9
19
+ version: 0.3.10
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 0.3.9
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 0.3.9
26
+ version: 0.3.10
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: rucy
35
29
  requirement: !ruby/object:Gem::Requirement
36
30
  requirements:
37
31
  - - "~>"
38
32
  - !ruby/object:Gem::Version
39
- version: 0.3.9
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- version: 0.3.9
33
+ version: 0.3.10
43
34
  type: :runtime
44
35
  prerelease: false
45
36
  version_requirements: !ruby/object:Gem::Requirement
46
37
  requirements:
47
38
  - - "~>"
48
39
  - !ruby/object:Gem::Version
49
- version: 0.3.9
50
- - - ">="
51
- - !ruby/object:Gem::Version
52
- version: 0.3.9
40
+ version: 0.3.10
53
41
  description: Synthesize and play beep sounds.
54
42
  email: xordog@gmail.com
55
43
  executables: []
@@ -77,6 +65,7 @@ extra_rdoc_files:
77
65
  - ".doc/ext/beeps/sound_player.cpp"
78
66
  - ".doc/ext/beeps/text_in.cpp"
79
67
  - ".doc/ext/beeps/time_stretch.cpp"
68
+ - ".doc/ext/beeps/value.cpp"
80
69
  files:
81
70
  - ".doc/ext/beeps/analyser.cpp"
82
71
  - ".doc/ext/beeps/beeps.cpp"
@@ -99,11 +88,13 @@ files:
99
88
  - ".doc/ext/beeps/sound_player.cpp"
100
89
  - ".doc/ext/beeps/text_in.cpp"
101
90
  - ".doc/ext/beeps/time_stretch.cpp"
91
+ - ".doc/ext/beeps/value.cpp"
102
92
  - ".github/PULL_REQUEST_TEMPLATE.md"
103
93
  - ".github/workflows/release-gem.yml"
104
94
  - ".github/workflows/tag.yml"
105
95
  - ".github/workflows/test.yml"
106
96
  - ".github/workflows/utils.rb"
97
+ - CLAUDE.md
107
98
  - CONTRIBUTING.md
108
99
  - ChangeLog.md
109
100
  - Gemfile
@@ -136,6 +127,7 @@ files:
136
127
  - ext/beeps/sound_player.cpp
137
128
  - ext/beeps/text_in.cpp
138
129
  - ext/beeps/time_stretch.cpp
130
+ - ext/beeps/value.cpp
139
131
  - include/beeps.h
140
132
  - include/beeps/beeps.h
141
133
  - include/beeps/debug.h
@@ -186,12 +178,16 @@ files:
186
178
  - src/processor.cpp
187
179
  - src/processor.h
188
180
  - src/reverb.cpp
181
+ - src/sdl/beeps.cpp
182
+ - src/sdl/signals.cpp
183
+ - src/sdl/text_in.cpp
189
184
  - src/sequencer.cpp
190
185
  - src/signals.cpp
191
186
  - src/signals.h
192
187
  - src/sound.cpp
193
188
  - src/sound.h
194
189
  - src/time_stretch.cpp
190
+ - src/value.cpp
195
191
  - src/win32/beeps.cpp
196
192
  - src/win32/exception.cpp
197
193
  - src/win32/exception.h
@@ -211,10 +207,12 @@ files:
211
207
  - test/test_oscillator.rb
212
208
  - test/test_pitch_shift.rb
213
209
  - test/test_processor.rb
210
+ - test/test_sequencer.rb
214
211
  - test/test_signals.rb
215
212
  - test/test_sound.rb
216
213
  - test/test_sound_player.rb
217
214
  - test/test_time_stretch.rb
215
+ - test/test_value.rb
218
216
  homepage: https://github.com/xord/beeps
219
217
  licenses:
220
218
  - MIT
@@ -253,7 +251,9 @@ test_files:
253
251
  - test/test_oscillator.rb
254
252
  - test/test_pitch_shift.rb
255
253
  - test/test_processor.rb
254
+ - test/test_sequencer.rb
256
255
  - test/test_signals.rb
257
256
  - test/test_sound.rb
258
257
  - test/test_sound_player.rb
259
258
  - test/test_time_stretch.rb
259
+ - test/test_value.rb