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 +4 -4
- data/.doc/ext/beeps/analyser.cpp +2 -2
- data/.doc/ext/beeps/native.cpp +3 -5
- data/.doc/ext/beeps/oscillator.cpp +2 -2
- data/.doc/ext/beeps/sequencer.cpp +17 -0
- data/.doc/ext/beeps/value.cpp +107 -0
- data/CLAUDE.md +24 -0
- data/ChangeLog.md +9 -0
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/beeps.gemspec +2 -2
- data/ext/beeps/analyser.cpp +2 -2
- data/ext/beeps/extconf.rb +10 -6
- data/ext/beeps/native.cpp +3 -5
- data/ext/beeps/oscillator.cpp +2 -2
- data/ext/beeps/sequencer.cpp +18 -0
- data/ext/beeps/value.cpp +114 -0
- data/include/beeps/generator.h +92 -0
- data/include/beeps/ruby/generator.h +11 -0
- data/lib/beeps/ext.rb +1 -1
- data/lib/beeps/processor.rb +46 -1
- data/src/sdl/beeps.cpp +19 -0
- data/src/sdl/signals.cpp +18 -0
- data/src/sdl/text_in.cpp +61 -0
- data/src/sequencer.cpp +31 -16
- data/src/value.cpp +181 -0
- data/test/test_oscillator.rb +2 -2
- data/test/test_sequencer.rb +25 -0
- data/test/test_value.rb +47 -0
- metadata +18 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83c3fb3d71043da5eaa1f4f6c9832442f68d9fb9ee765c1d19891306df2ca3da
|
|
4
|
+
data.tar.gz: 6f80df9fa3ada9ecf150708c9efaf090800044b38c3e694108bfcb2b766ef577
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a94142e5430d65b5d9539b2f9b9d5d92bf13b893cf77c9aa00a3bbe52ec5e3cdca78db410fe4400ee465f3c9d6124201046414059fbc32635540a024c10c0e8d
|
|
7
|
+
data.tar.gz: 9b1a87a0c216b7cee8afe2bfd2decabb7035c5723449c3f02876336e33cf5c2c36dff5c0f2e0c4e757e4278c3b89f93d51e8489b571893460b665a34dd37b792
|
data/.doc/ext/beeps/analyser.cpp
CHANGED
|
@@ -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
|
|
76
|
-
args
|
|
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;
|
data/.doc/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
|
-
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
29
|
-
s.add_dependency 'rucy', '~> 0.3.
|
|
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}
|
data/ext/beeps/analyser.cpp
CHANGED
|
@@ -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
|
|
80
|
-
args
|
|
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
|
-
|
|
17
|
-
|
|
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=
|
|
28
|
+
$LDFLAGS << ' -Wl,--out-implib=beeps_ext.dll.a' if mingw? || cygwin?
|
|
25
29
|
end
|
|
26
30
|
|
|
27
|
-
create_makefile '
|
|
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
|
-
|
|
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();
|
data/ext/beeps/oscillator.cpp
CHANGED
|
@@ -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
|
|
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);
|
data/ext/beeps/sequencer.cpp
CHANGED
|
@@ -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
|
|
data/ext/beeps/value.cpp
ADDED
|
@@ -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
|
data/include/beeps/generator.h
CHANGED
|
@@ -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 '
|
|
1
|
+
require 'beeps_ext'
|
data/lib/beeps/processor.rb
CHANGED
|
@@ -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
|
-
|
|
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
data/src/sdl/signals.cpp
ADDED
data/src/sdl/text_in.cpp
ADDED
|
@@ -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
|
-
|
|
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
|
data/test/test_oscillator.rb
CHANGED
|
@@ -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
|
|
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
|
|
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
|
data/test/test_value.rb
ADDED
|
@@ -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.
|
|
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:
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|