beeps 0.3.16 → 0.4.0

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: 0d0df35732c641aea99d48e8fc4b3962ea6492bbc8195f3a03e8e89f2963a5fe
4
- data.tar.gz: 31ccd91b4ba4af5e856d6ca2b30870fb5c65f5c65e896ba060afb96d207f7a29
3
+ metadata.gz: f1f22a18de76ecdd7a16f937d01fe529f48d51f299706560c8c5c86d39ee1003
4
+ data.tar.gz: 6d4adc32a77b89dbcea531795dfc0de2aaacec1a4340cac9f4a00619a11bf6fa
5
5
  SHA512:
6
- metadata.gz: 9278dce2e957ea259e8d72b090c9b6e255fe798e87324b5b82e10b672e1d41132e2028bc17f08515a1c47af6fde2a1156e52f997519ab5c5ca5e573843536460
7
- data.tar.gz: 89b0671180ea7e85db3dc38d0d560191fceece767e9016973253675bfe30945de9a82d8ecbe71205c6ab6fed3ab22e7fe682fdeea7d402f2b5ef91fe0a64d96b
6
+ metadata.gz: 8e46cb83232541e8a232ab1812fc73e200bb40098211b1e8b5ca7fc765990c894bebfe63a32aa214ae7ea15dcfb1ff861f6b0d991289afdbb2e60e82c33aaa4f
7
+ data.tar.gz: 15f7058bd15d0551ea301955d44605c0d8b53b8696abba2da3e5c2b5b829156eea2b911b12f04791dc28189cdddca9f701c93883f7e900571a0ac1dff5c2c2d5
@@ -64,7 +64,7 @@ VALUE each_signal(VALUE self, VALUE nsamples_)
64
64
  {
65
65
  case 1:
66
66
  for (uint i = start; i < nsamples; ++i)
67
- rb_yield(value(samples[i]));
67
+ yield(value(samples[i]));
68
68
  break;
69
69
 
70
70
  case 2:
@@ -74,7 +74,7 @@ VALUE each_signal(VALUE self, VALUE nsamples_)
74
74
  {
75
75
  args.set(0, value(samples[i + 0]));
76
76
  args.set(1, value(samples[i + 1]));
77
- rb_yield(args);
77
+ yield(args);
78
78
  }
79
79
  break;
80
80
  }
@@ -91,7 +91,7 @@ VALUE each_spectrum(VALUE self)
91
91
  invalid_object_error(__FILE__, __LINE__);
92
92
 
93
93
  for (auto val : THIS->spectrum())
94
- rb_yield(value(val));
94
+ yield(value(val));
95
95
 
96
96
  return nil();
97
97
  }
@@ -51,7 +51,7 @@ VALUE each_input(VALUE self)
51
51
 
52
52
  Value ret;
53
53
  for (auto& input : *THIS)
54
- ret = rb_yield(value(input.get()));
54
+ ret = yield(value(input.get()));
55
55
  return ret;
56
56
  }
57
57
 
@@ -62,7 +62,7 @@ VALUE each_sample(VALUE self)
62
62
 
63
63
  Value ret;
64
64
  for (size_t i = 0; i < size; ++i)
65
- ret = rb_yield(value((float) samples[i]));
65
+ ret = yield(value((float) samples[i]));
66
66
  return ret;
67
67
  }
68
68
 
@@ -64,7 +64,7 @@ VALUE each_note(VALUE self)
64
64
  Value ret;
65
65
  for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
66
66
  {
67
- ret = rb_yield_values(3,
67
+ ret = yield(
68
68
  value(it->processor.get()),
69
69
  value(it->offset),
70
70
  value(it->duration));
@@ -84,13 +84,13 @@ VALUE each(VALUE self, VALUE channel_)
84
84
 
85
85
  const auto* p = samples + channel;
86
86
  for (uint i = 0; i < nsamples; ++i, p += nchannels)
87
- rb_yield(value(*p));
87
+ yield(value(*p));
88
88
  }
89
89
  else
90
90
  {
91
91
  uint size = nsamples * nchannels;
92
92
  for (uint i = 0; i < size; ++i)
93
- rb_yield(value(samples[i]));
93
+ yield(value(samples[i]));
94
94
  }
95
95
  }
96
96
 
@@ -18,7 +18,7 @@ VALUE alloc(VALUE klass)
18
18
  }
19
19
 
20
20
  static
21
- VALUE setup(VALUE self, VALUE processor, VALUE seconds, VALUE nchannels, VALUE sample_rate)
21
+ VALUE initialize(VALUE self, VALUE processor, VALUE seconds, VALUE nchannels, VALUE sample_rate)
22
22
  {
23
23
  CHECK;
24
24
 
@@ -28,6 +28,13 @@ VALUE setup(VALUE self, VALUE processor, VALUE seconds, VALUE nchannels, VALUE s
28
28
  return self;
29
29
  }
30
30
 
31
+ static
32
+ VALUE initialize_copy(VALUE self, VALUE obj)
33
+ {
34
+ CHECK;
35
+ *THIS = to<Beeps::Sound&>(obj).dup();
36
+ }
37
+
31
38
  static
32
39
  VALUE play(VALUE self)
33
40
  {
@@ -119,7 +126,8 @@ Init_beeps_sound ()
119
126
 
120
127
  cSound = rb_define_class_under(mBeeps, "Sound", rb_cObject);
121
128
  rb_define_alloc_func(cSound, alloc);
122
- rb_define_private_method(cSound, "setup", RUBY_METHOD_FUNC(setup), 4);
129
+ cSound.define_private_method("initialize!", initialize);
130
+ rb_define_private_method(cSound, "initialize_copy", RUBY_METHOD_FUNC(initialize_copy), 1);
123
131
  cSound.define_private_method("play!", play);
124
132
  rb_define_method(cSound, "sample_rate", RUBY_METHOD_FUNC(get_sample_rate), 0);
125
133
  rb_define_method(cSound, "nchannels", RUBY_METHOD_FUNC(get_nchannels), 0);
@@ -1,6 +1,7 @@
1
1
  #include "beeps/ruby/sound.h"
2
2
 
3
3
 
4
+ #include "beeps/exception.h"
4
5
  #include "defs.h"
5
6
 
6
7
 
@@ -17,6 +18,12 @@ VALUE alloc(VALUE klass)
17
18
  return new_type<Beeps::SoundPlayer>(klass);
18
19
  }
19
20
 
21
+ static
22
+ VALUE initialize_copy(VALUE self, VALUE obj)
23
+ {
24
+ Beeps::beeps_error(__FILE__, __LINE__, "can not duplicate SoundPlayer");
25
+ }
26
+
20
27
  static
21
28
  VALUE play(VALUE self)
22
29
  {
@@ -162,6 +169,7 @@ Init_beeps_sound_player ()
162
169
 
163
170
  cSoundPlayer = rb_define_class_under(mBeeps, "SoundPlayer", rb_cObject);
164
171
  rb_define_alloc_func(cSoundPlayer, alloc);
172
+ rb_define_private_method(cSoundPlayer, "initialize_copy", RUBY_METHOD_FUNC(initialize_copy), 1);
165
173
  rb_define_method(cSoundPlayer, "play", RUBY_METHOD_FUNC(play), 0);
166
174
  rb_define_method(cSoundPlayer, "pause", RUBY_METHOD_FUNC(pause), 0);
167
175
  rb_define_method(cSoundPlayer, "rewind", RUBY_METHOD_FUNC(rewind), 0);
@@ -67,7 +67,7 @@ VALUE each_value(VALUE self)
67
67
 
68
68
  Value ret;
69
69
  for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
70
- ret = rb_yield_values(2, value(it->value), value(it->time));
70
+ ret = yield(value(it->value), value(it->time));
71
71
  return ret;
72
72
  }
73
73
 
@@ -26,8 +26,17 @@ jobs:
26
26
  - name: setup dependencies
27
27
  run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
28
28
 
29
+ - name: packages
30
+ run: bundle exec rake packages
31
+
32
+ - name: setup zig
33
+ if: github.event.repository.name == 'reflex-terminal'
34
+ uses: mlugg/setup-zig@v2
35
+ with:
36
+ version: 0.16.0
37
+
29
38
  - name: test
30
- run: bundle exec rake packages test
39
+ run: bundle exec rake test
31
40
 
32
41
  - name: create gem
33
42
  id: gem
@@ -27,6 +27,15 @@ jobs:
27
27
  - name: packages
28
28
  run: bundle exec rake verbose packages
29
29
 
30
+ - name: setup zig
31
+ if: github.event.repository.name == 'reflex-terminal'
32
+ uses: mlugg/setup-zig@v2
33
+ with:
34
+ version: 0.16.0
35
+
36
+ - name: vendor
37
+ run: bundle exec rake vendor
38
+
30
39
  - name: lib
31
40
  run: bundle exec rake verbose lib
32
41
 
data/ChangeLog.md CHANGED
@@ -1,6 +1,13 @@
1
1
  # beeps ChangeLog
2
2
 
3
3
 
4
+ ## [v0.4.0] - 2026-08-04
5
+
6
+ - Support dup on value classes, reject it on stateful ones
7
+
8
+ - Fix loading audio files whose path is outside the ANSI code page on Windows
9
+
10
+
4
11
  ## [v0.3.16] - 2026-06-23
5
12
 
6
13
  - Update dependencies
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.16
1
+ 0.4.0
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.15'
29
- s.add_dependency 'rucy', '~> 0.3.15'
28
+ s.add_dependency 'xot', '~> 0.4.0'
29
+ s.add_dependency 'rucy', '~> 0.4.0'
30
30
 
31
31
  s.files = `git ls-files`.split $/
32
32
  s.executables = s.files.grep(%r{^bin/}) {|f| File.basename f}
@@ -68,7 +68,7 @@ RUCY_DEF1(each_signal, nsamples_)
68
68
  {
69
69
  case 1:
70
70
  for (uint i = start; i < nsamples; ++i)
71
- rb_yield(value(samples[i]));
71
+ yield(value(samples[i]));
72
72
  break;
73
73
 
74
74
  case 2:
@@ -78,7 +78,7 @@ RUCY_DEF1(each_signal, nsamples_)
78
78
  {
79
79
  args.set(0, value(samples[i + 0]));
80
80
  args.set(1, value(samples[i + 1]));
81
- rb_yield(args);
81
+ yield(args);
82
82
  }
83
83
  break;
84
84
  }
@@ -96,7 +96,7 @@ RUCY_DEF0(each_spectrum)
96
96
  invalid_object_error(__FILE__, __LINE__);
97
97
 
98
98
  for (auto val : THIS->spectrum())
99
- rb_yield(value(val));
99
+ yield(value(val));
100
100
 
101
101
  return nil();
102
102
  }
data/ext/beeps/mixer.cpp CHANGED
@@ -54,7 +54,7 @@ RUCY_DEF0(each_input)
54
54
 
55
55
  Value ret;
56
56
  for (auto& input : *THIS)
57
- ret = rb_yield(value(input.get()));
57
+ ret = yield(value(input.get()));
58
58
  return ret;
59
59
  }
60
60
  RUCY_END
@@ -66,7 +66,7 @@ RUCY_DEF0(each_sample)
66
66
 
67
67
  Value ret;
68
68
  for (size_t i = 0; i < size; ++i)
69
- ret = rb_yield(value((float) samples[i]));
69
+ ret = yield(value((float) samples[i]));
70
70
  return ret;
71
71
  }
72
72
  RUCY_END
@@ -69,7 +69,7 @@ RUCY_DEF0(each_note)
69
69
  Value ret;
70
70
  for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
71
71
  {
72
- ret = rb_yield_values(3,
72
+ ret = yield(
73
73
  value(it->processor.get()),
74
74
  value(it->offset),
75
75
  value(it->duration));
@@ -91,13 +91,13 @@ RUCY_DEF1(each, channel_)
91
91
 
92
92
  const auto* p = samples + channel;
93
93
  for (uint i = 0; i < nsamples; ++i, p += nchannels)
94
- rb_yield(value(*p));
94
+ yield(value(*p));
95
95
  }
96
96
  else
97
97
  {
98
98
  uint size = nsamples * nchannels;
99
99
  for (uint i = 0; i < size; ++i)
100
- rb_yield(value(samples[i]));
100
+ yield(value(samples[i]));
101
101
  }
102
102
  }
103
103
  RUCY_END
data/ext/beeps/sound.cpp CHANGED
@@ -19,7 +19,7 @@ RUCY_DEF_ALLOC(alloc, klass)
19
19
  RUCY_END
20
20
 
21
21
  static
22
- RUCY_DEF4(setup, processor, seconds, nchannels, sample_rate)
22
+ RUCY_DEF4(initialize, processor, seconds, nchannels, sample_rate)
23
23
  {
24
24
  CHECK;
25
25
 
@@ -30,6 +30,14 @@ RUCY_DEF4(setup, processor, seconds, nchannels, sample_rate)
30
30
  }
31
31
  RUCY_END
32
32
 
33
+ static
34
+ RUCY_DEF1(initialize_copy, obj)
35
+ {
36
+ CHECK;
37
+ *THIS = to<Beeps::Sound&>(obj).dup();
38
+ }
39
+ RUCY_END
40
+
33
41
  static
34
42
  RUCY_DEF0(play)
35
43
  {
@@ -131,7 +139,8 @@ Init_beeps_sound ()
131
139
 
132
140
  cSound = mBeeps.define_class("Sound");
133
141
  cSound.define_alloc_func(alloc);
134
- cSound.define_private_method("setup", setup);
142
+ cSound.define_private_method("initialize!", initialize);
143
+ cSound.define_private_method("initialize_copy", initialize_copy);
135
144
  cSound.define_private_method("play!", play);
136
145
  cSound.define_method("sample_rate", get_sample_rate);
137
146
  cSound.define_method("nchannels", get_nchannels);
@@ -1,6 +1,7 @@
1
1
  #include "beeps/ruby/sound.h"
2
2
 
3
3
 
4
+ #include "beeps/exception.h"
4
5
  #include "defs.h"
5
6
 
6
7
 
@@ -18,6 +19,13 @@ RUCY_DEF_ALLOC(alloc, klass)
18
19
  }
19
20
  RUCY_END
20
21
 
22
+ static
23
+ RUCY_DEF1(initialize_copy, obj)
24
+ {
25
+ Beeps::beeps_error(__FILE__, __LINE__, "can not duplicate SoundPlayer");
26
+ }
27
+ RUCY_END
28
+
21
29
  static
22
30
  RUCY_DEF0(play)
23
31
  {
@@ -179,6 +187,7 @@ Init_beeps_sound_player ()
179
187
 
180
188
  cSoundPlayer = mBeeps.define_class("SoundPlayer");
181
189
  cSoundPlayer.define_alloc_func(alloc);
190
+ cSoundPlayer.define_private_method("initialize_copy", initialize_copy);
182
191
  cSoundPlayer.define_method("play", play);
183
192
  cSoundPlayer.define_method("pause", pause);
184
193
  cSoundPlayer.define_method("rewind", rewind);
data/ext/beeps/value.cpp CHANGED
@@ -73,7 +73,7 @@ RUCY_DEF0(each_value)
73
73
 
74
74
  Value ret;
75
75
  for (auto it = THIS->begin(), end = THIS->end(); it != end; ++it)
76
- ret = rb_yield_values(2, value(it->value), value(it->time));
76
+ ret = yield(value(it->value), value(it->time));
77
77
  return ret;
78
78
  }
79
79
  RUCY_END
data/include/beeps/defs.h CHANGED
@@ -19,14 +19,24 @@ namespace Beeps
19
19
  {
20
20
 
21
21
 
22
- using namespace Xot::Types;
22
+ namespace Types
23
+ {
23
24
 
24
- using Xot::String;
25
25
 
26
- using Xot::StringList;
26
+ typedef double Sample;
27
+
28
+
29
+ }// Types
30
+
27
31
 
32
+ using namespace Xot ::Types;
28
33
 
29
- typedef double Sample;
34
+ using namespace Beeps::Types;
35
+
36
+
37
+ using Xot::String;
38
+
39
+ using Xot::StringList;
30
40
 
31
41
 
32
42
  }// Beeps
@@ -91,6 +91,8 @@ namespace Beeps
91
91
 
92
92
  ~Sound ();
93
93
 
94
+ Sound dup () const;
95
+
94
96
  SoundPlayer play ();
95
97
 
96
98
  double sample_rate () const;
@@ -117,6 +119,10 @@ namespace Beeps
117
119
 
118
120
  Xot::PSharedImpl<Data> self;
119
121
 
122
+ private:
123
+
124
+ Sound (Data* data);
125
+
120
126
  };// Sound
121
127
 
122
128
 
@@ -6,7 +6,7 @@ module Beeps
6
6
  module_function
7
7
 
8
8
  def name(downcase = false)
9
- super().split('::')[-2].then {|s|
9
+ super().split('::')[..-2].join.then {|s|
10
10
  downcase ? s.gsub(/([a-z])([A-Z])/) {"#{$1}-#{$2}"}.downcase : s
11
11
  }
12
12
  end
data/lib/beeps/sound.rb CHANGED
@@ -15,7 +15,7 @@ module Beeps
15
15
  def initialize(
16
16
  processor, seconds = 0, nchannels: 1, sample_rate: 0, **options, &block)
17
17
 
18
- setup processor, seconds, nchannels, sample_rate
18
+ initialize! processor, seconds, nchannels, sample_rate
19
19
  set(**options) unless options.empty?
20
20
  Xot::BlockUtil.instance_eval_or_block_call self, &block if block
21
21
  end
data/src/file_in.cpp CHANGED
@@ -37,6 +37,8 @@ namespace Beeps
37
37
  void
38
38
  FileIn::set_path (const char* path)
39
39
  {
40
+ if (!path)
41
+ argument_error(__FILE__, __LINE__, "path is NULL");
40
42
  if (*this)
41
43
  invalid_state_error(__FILE__, __LINE__, "path is already set");
42
44
 
data/src/sound.cpp CHANGED
@@ -802,11 +802,21 @@ namespace Beeps
802
802
  {
803
803
  }
804
804
 
805
+ virtual Data* dup () const
806
+ {
807
+ return new Data(*this);
808
+ }
809
+
805
810
  virtual void attach_to (SoundPlayer* player)
806
811
  {
807
812
  not_implemented_error(__FILE__, __LINE__);
808
813
  }
809
814
 
815
+ virtual void save (const char* path) const
816
+ {
817
+ not_implemented_error(__FILE__, __LINE__);
818
+ }
819
+
810
820
  virtual double sample_rate () const
811
821
  {
812
822
  return 0;
@@ -822,11 +832,6 @@ namespace Beeps
822
832
  return 0;
823
833
  }
824
834
 
825
- virtual void save (const char* path) const
826
- {
827
- not_implemented_error(__FILE__, __LINE__);
828
- }
829
-
830
835
  virtual bool is_valid () const
831
836
  {
832
837
  return false;
@@ -848,6 +853,11 @@ namespace Beeps
848
853
  {
849
854
  }
850
855
 
856
+ Data* dup () const override
857
+ {
858
+ return new SoundData(*this);
859
+ }
860
+
851
861
  void attach_to (SoundPlayer* player) override
852
862
  {
853
863
  assert(player && *player);
@@ -855,6 +865,14 @@ namespace Beeps
855
865
  player->self->attach_signals(signals);
856
866
  }
857
867
 
868
+ void save (const char* path) const override
869
+ {
870
+ if (!signals)
871
+ invalid_state_error(__FILE__, __LINE__);
872
+
873
+ Signals_save(signals, path);
874
+ }
875
+
858
876
  double sample_rate () const override
859
877
  {
860
878
  return signals ? signals.sample_rate() : Super::sample_rate();
@@ -870,14 +888,6 @@ namespace Beeps
870
888
  return signals ? Signals_get_seconds(signals) : Super::seconds();
871
889
  }
872
890
 
873
- void save (const char* path) const override
874
- {
875
- if (!signals)
876
- invalid_state_error(__FILE__, __LINE__);
877
-
878
- Signals_save(signals, path);
879
- }
880
-
881
891
  bool is_valid () const override
882
892
  {
883
893
  return signals;
@@ -893,7 +903,7 @@ namespace Beeps
893
903
 
894
904
  double sample_rate_ = 0;
895
905
 
896
- uint nchannels_ = 0;
906
+ uint nchannels_ = 0;
897
907
 
898
908
  StreamSoundData (Processor* processor, uint nchannels, double sample_rate)
899
909
  {
@@ -904,6 +914,12 @@ namespace Beeps
904
914
  this->nchannels_ = nchannels;
905
915
  }
906
916
 
917
+ Data* dup () const override
918
+ {
919
+ invalid_state_error(
920
+ __FILE__, __LINE__, "can not duplicate a streaming sound");
921
+ }
922
+
907
923
  void attach_to (SoundPlayer* player) override
908
924
  {
909
925
  assert(player && *player);
@@ -969,10 +985,21 @@ namespace Beeps
969
985
  self.reset(new StreamSoundData(processor, nchannels, sample_rate));
970
986
  }
971
987
 
988
+ Sound::Sound (Data* data)
989
+ : self(data)
990
+ {
991
+ }
992
+
972
993
  Sound::~Sound ()
973
994
  {
974
995
  }
975
996
 
997
+ Sound
998
+ Sound::dup () const
999
+ {
1000
+ return Sound(self->dup());
1001
+ }
1002
+
976
1003
  SoundPlayer
977
1004
  Sound::play ()
978
1005
  {
@@ -55,25 +55,18 @@ namespace Beeps
55
55
 
56
56
  static bool is_file_exist (const char* path)
57
57
  {
58
- DWORD attribs = GetFileAttributes(path);
58
+ if (!path) return false;
59
+
60
+ DWORD attribs = GetFileAttributesW(Xot::String(path).to_wstr().c_str());
59
61
  return
60
62
  attribs != INVALID_FILE_ATTRIBUTES &&
61
63
  !(attribs & FILE_ATTRIBUTE_DIRECTORY);
62
64
  }
63
65
 
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
66
  static void
74
67
  load_bytes (WAVEFORMATEX* format, std::vector<BYTE>* bytes, const char* path)
75
68
  {
76
- std::wstring wpath = to_wcs(path);
69
+ std::wstring wpath = Xot::String(path).to_wstr();
77
70
 
78
71
  ReleasePtr<IMFMediaType> pcm_media_type;
79
72
  check_media_foundation_error(
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.16
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - xordog
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-22 00:00:00.000000000 Z
11
+ date: 2026-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xot
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.15
19
+ version: 0.4.0
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.15
26
+ version: 0.4.0
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.15
33
+ version: 0.4.0
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.15
40
+ version: 0.4.0
41
41
  description: Synthesize and play beep sounds.
42
42
  email: xordog@gmail.com
43
43
  executables: []