sfml3-rb 0.2.2 → 0.3.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 +4 -4
- data/.yardopts +9 -0
- data/CHANGELOG.md +43 -17
- data/README.md +97 -29
- data/ext/audio/audio_enums.c +58 -20
- data/ext/audio/listener.c +89 -6
- data/ext/audio/music.c +206 -5
- data/ext/audio/sound.c +175 -5
- data/ext/audio/sound_buffer.c +189 -47
- data/ext/audio/sound_buffer_recorder.c +83 -16
- data/ext/audio/sound_recorder.c +172 -52
- data/ext/audio/sound_source_cone.c +108 -29
- data/ext/audio/sound_stream.c +178 -5
- data/ext/core/exceptions.c +10 -8
- data/ext/core/unicode.c +12 -2
- data/ext/ext.c +4 -0
- data/ext/graphics/blend_mode.c +203 -53
- data/ext/graphics/circle.c +271 -4
- data/ext/graphics/color.c +240 -90
- data/ext/graphics/drawable.c +15 -4
- data/ext/graphics/font.c +138 -25
- data/ext/graphics/glyph.c +31 -8
- data/ext/graphics/image.c +180 -37
- data/ext/graphics/polygon.c +293 -26
- data/ext/graphics/rect.c +211 -54
- data/ext/graphics/rectangle.c +279 -26
- data/ext/graphics/render_state.c +116 -2
- data/ext/graphics/render_texture.c +163 -2
- data/ext/graphics/shader.c +283 -17
- data/ext/graphics/shape.c +252 -26
- data/ext/graphics/sprite.c +216 -25
- data/ext/graphics/stencil_mode.c +148 -39
- data/ext/graphics/target.c +67 -22
- data/ext/graphics/target.h +15 -15
- data/ext/graphics/text.c +306 -6
- data/ext/graphics/texture.c +257 -3
- data/ext/graphics/transform.c +178 -5
- data/ext/graphics/transformable.c +126 -2
- data/ext/graphics/vertex.c +79 -2
- data/ext/graphics/vertex_array.c +128 -16
- data/ext/graphics/vertex_buffer.c +124 -2
- data/ext/graphics/view.c +130 -2
- data/ext/network/ftp.c +249 -10
- data/ext/network/http.c +156 -38
- data/ext/network/ip_address.c +107 -26
- data/ext/network/network_enums.c +248 -141
- data/ext/network/packet.c +273 -39
- data/ext/network/socket_selector.c +91 -19
- data/ext/network/tcp_listener.c +75 -16
- data/ext/network/tcp_socket.c +128 -25
- data/ext/network/udp_socket.c +122 -26
- data/ext/ports.rb +7 -0
- data/ext/system/buffer.c +41 -12
- data/ext/system/clock.c +68 -9
- data/ext/system/input_stream.c +94 -42
- data/ext/system/sleep.c +10 -2
- data/ext/system/time.c +172 -34
- data/ext/system/vec2.c +156 -35
- data/ext/system/vec3.c +166 -35
- data/ext/window/clipboard.c +47 -17
- data/ext/window/context.c +59 -9
- data/ext/window/context_settings.c +116 -38
- data/ext/window/cursor.c +39 -9
- data/ext/window/event.c +163 -42
- data/ext/window/joystick.c +69 -3
- data/ext/window/keyboard.c +168 -116
- data/ext/window/mouse.c +36 -2
- data/ext/window/sensor.c +28 -2
- data/ext/window/touch.c +20 -2
- data/ext/window/video_mode.c +90 -19
- data/ext/window/vulkan.c +34 -6
- data/ext/window/window.c +340 -16
- data/lib/sfml/version.rb +1 -1
- data/sig/audio/audio_enums.rbs +30 -0
- data/sig/audio/listener.rbs +16 -0
- data/sig/audio/music.rbs +56 -0
- data/sig/audio/sound.rbs +51 -0
- data/sig/audio/sound_buffer.rbs +17 -0
- data/sig/audio/sound_buffer_recorder.rbs +14 -0
- data/sig/audio/sound_recorder.rbs +17 -0
- data/sig/audio/sound_source_cone.rbs +14 -0
- data/sig/audio/sound_stream.rbs +51 -0
- data/sig/graphics/blend_mode.rbs +29 -0
- data/sig/graphics/circle.rbs +44 -0
- data/sig/graphics/color.rbs +39 -0
- data/sig/graphics/drawable.rbs +5 -0
- data/sig/graphics/font.rbs +20 -0
- data/sig/graphics/glyph.rbs +7 -0
- data/sig/graphics/image.rbs +22 -0
- data/sig/graphics/polygon.rbs +42 -0
- data/sig/graphics/rect.rbs +33 -0
- data/sig/graphics/rectangle.rbs +42 -0
- data/sig/graphics/render_state.rbs +21 -0
- data/sig/graphics/render_texture.rbs +37 -0
- data/sig/graphics/shader.rbs +39 -0
- data/sig/graphics/shape.rbs +38 -0
- data/sig/graphics/sprite.rbs +34 -0
- data/sig/graphics/stencil_mode.rbs +18 -0
- data/sig/graphics/target.rbs +10 -0
- data/sig/graphics/text.rbs +48 -0
- data/sig/graphics/texture.rbs +34 -0
- data/sig/graphics/transform.rbs +37 -0
- data/sig/graphics/transformable.rbs +25 -0
- data/sig/graphics/vertex.rbs +17 -0
- data/sig/graphics/vertex_array.rbs +17 -0
- data/sig/graphics/vertex_buffer.rbs +22 -0
- data/sig/graphics/view.rbs +24 -0
- data/sig/network/ftp.rbs +46 -0
- data/sig/network/http.rbs +27 -0
- data/sig/network/ip_address.rbs +22 -0
- data/sig/network/network_enums.rbs +95 -0
- data/sig/network/packet.rbs +40 -0
- data/sig/network/socket_selector.rbs +14 -0
- data/sig/network/tcp_listener.rbs +13 -0
- data/sig/network/tcp_socket.rbs +18 -0
- data/sig/network/udp_socket.rbs +17 -0
- data/sig/system/buffer.rbs +11 -0
- data/sig/system/clock.rbs +13 -0
- data/sig/system/input_stream.rbs +7 -0
- data/sig/system/sleep.rbs +3 -0
- data/sig/system/time.rbs +28 -0
- data/sig/system/vec2.rbs +26 -0
- data/sig/system/vec3.rbs +27 -0
- data/sig/window/clipboard.rbs +8 -0
- data/sig/window/context.rbs +11 -0
- data/sig/window/context_settings.rbs +20 -0
- data/sig/window/cursor.rbs +6 -0
- data/sig/window/event.rbs +20 -0
- data/sig/window/joystick.rbs +15 -0
- data/sig/window/keyboard.rbs +10 -0
- data/sig/window/mouse.rbs +9 -0
- data/sig/window/sensor.rbs +8 -0
- data/sig/window/touch.rbs +6 -0
- data/sig/window/video_mode.rbs +16 -0
- data/sig/window/vulkan.rbs +7 -0
- data/sig/window/window.rbs +57 -0
- metadata +66 -2
data/ext/audio/sound_recorder.c
CHANGED
|
@@ -1,33 +1,48 @@
|
|
|
1
1
|
#include "audio/sound_recorder.h"
|
|
2
2
|
|
|
3
3
|
#include <ruby.h>
|
|
4
|
-
#include <ruby/thread.h>
|
|
5
4
|
#include <stdint.h>
|
|
6
5
|
#include <stdlib.h>
|
|
7
6
|
|
|
8
7
|
#include "audio/audio_enums.h"
|
|
8
|
+
#include "core/foreign_thread.h"
|
|
9
9
|
#include "core/macros.h"
|
|
10
10
|
|
|
11
|
-
/* A subclassable recorder. The capture callbacks arrive on SFML's
|
|
12
|
-
thread
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
/* A subclassable recorder. The capture callbacks arrive on SFML's capture
|
|
12
|
+
thread -- a real OS thread never created by Ruby, exactly like the audio
|
|
13
|
+
playback thread effect_processor.c/sound_stream.c are built to handle --
|
|
14
|
+
so re-entering Ruby directly (e.g. via rb_thread_call_with_gvl, as this
|
|
15
|
+
file previously did for #on_process, or via rb_protect with no GVL
|
|
16
|
+
handling at all, as it previously did for #on_start/#on_stop) is a fatal
|
|
17
|
+
VM error. Every callback here instead posts its work to the shared
|
|
18
|
+
foreign-thread worker (core/foreign_thread.h), the same mechanism the
|
|
19
|
+
other two files use, and treats an exception as "stop capturing" rather
|
|
20
|
+
than unwinding into the audio engine. A subclass only has to implement
|
|
21
|
+
#on_process; #on_start and #on_stop are optional and default to
|
|
22
|
+
continuing. */
|
|
23
|
+
|
|
24
|
+
#define SOUND_RECORDER_JOB_TIMEOUT_MS 50
|
|
16
25
|
typedef struct {
|
|
17
26
|
VALUE rb_self;
|
|
18
|
-
sfSoundRecorder
|
|
27
|
+
sfSoundRecorder* handle;
|
|
19
28
|
} SoundRecorder;
|
|
20
29
|
|
|
21
30
|
static VALUE rb_cSoundRecorder;
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
/* CSFML reports "no such device" as NULL; that is an absent name, not an
|
|
33
|
+
error, so it maps to nil rather than raising out of rb_str_new_cstr. */
|
|
34
|
+
static VALUE SoundRecorder_nullable_string(const char* value) {
|
|
35
|
+
return value == NULL ? Qnil : rb_str_new_cstr(value);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static void SoundRecorder_mark(void* ptr) {
|
|
39
|
+
SoundRecorder* recorder = ptr;
|
|
25
40
|
|
|
26
41
|
rb_gc_mark(recorder->rb_self);
|
|
27
42
|
}
|
|
28
43
|
|
|
29
|
-
static void SoundRecorder_free(void
|
|
30
|
-
SoundRecorder
|
|
44
|
+
static void SoundRecorder_free(void* ptr) {
|
|
45
|
+
SoundRecorder* recorder = ptr;
|
|
31
46
|
|
|
32
47
|
if (recorder->handle != NULL) {
|
|
33
48
|
sfSoundRecorder_destroy(recorder->handle);
|
|
@@ -39,8 +54,7 @@ static void SoundRecorder_free(void *ptr) {
|
|
|
39
54
|
static const rb_data_type_t SoundRecorder_data_type = {
|
|
40
55
|
.wrap_struct_name = "SFML::SoundRecorder",
|
|
41
56
|
.function = {.dmark = SoundRecorder_mark, .dfree = SoundRecorder_free, .dsize = NULL},
|
|
42
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
43
|
-
};
|
|
57
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY};
|
|
44
58
|
|
|
45
59
|
typedef struct {
|
|
46
60
|
VALUE self;
|
|
@@ -48,25 +62,31 @@ typedef struct {
|
|
|
48
62
|
} InvokeContext;
|
|
49
63
|
|
|
50
64
|
static VALUE SoundRecorder_invoke_body(VALUE raw) {
|
|
51
|
-
InvokeContext
|
|
65
|
+
InvokeContext* ctx = (InvokeContext*)raw;
|
|
52
66
|
|
|
53
67
|
return rb_funcall(ctx->self, ctx->method, 0);
|
|
54
68
|
}
|
|
55
69
|
|
|
56
|
-
/*
|
|
57
|
-
static void
|
|
58
|
-
InvokeContext ctx = {.self = self, .method = method};
|
|
70
|
+
/* Runs on the shared foreign-thread worker, which holds the GVL. */
|
|
71
|
+
static void SoundRecorder_invoke_run(void* raw) {
|
|
59
72
|
int state = 0;
|
|
60
73
|
|
|
61
|
-
rb_protect(SoundRecorder_invoke_body, (VALUE)
|
|
74
|
+
rb_protect(SoundRecorder_invoke_body, (VALUE)raw, &state);
|
|
62
75
|
|
|
63
76
|
if (state) {
|
|
64
77
|
rb_set_errinfo(Qnil);
|
|
65
78
|
}
|
|
66
79
|
}
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
/* Calls a zero-argument Ruby method, swallowing any exception it raises. */
|
|
82
|
+
static void SoundRecorder_invoke(VALUE self, ID method) {
|
|
83
|
+
InvokeContext ctx = {.self = self, .method = method};
|
|
84
|
+
|
|
85
|
+
run_on_ruby_thread(SoundRecorder_invoke_run, &ctx, SOUND_RECORDER_JOB_TIMEOUT_MS);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static bool SoundRecorder_on_start(void* userData) {
|
|
89
|
+
SoundRecorder* recorder = userData;
|
|
70
90
|
|
|
71
91
|
if (rb_respond_to(recorder->rb_self, rb_intern("on_start"))) {
|
|
72
92
|
SoundRecorder_invoke(recorder->rb_self, rb_intern("on_start"));
|
|
@@ -76,15 +96,15 @@ static bool SoundRecorder_on_start(void *userData) {
|
|
|
76
96
|
}
|
|
77
97
|
|
|
78
98
|
typedef struct {
|
|
79
|
-
SoundRecorder
|
|
80
|
-
const int16_t
|
|
99
|
+
SoundRecorder* recorder;
|
|
100
|
+
const int16_t* samples;
|
|
81
101
|
size_t sample_count;
|
|
82
102
|
int ok;
|
|
83
103
|
} ProcessContext;
|
|
84
104
|
|
|
85
105
|
static VALUE SoundRecorder_process_body(VALUE raw) {
|
|
86
|
-
ProcessContext
|
|
87
|
-
VALUE rb_samples = rb_ary_new_capa((long)
|
|
106
|
+
ProcessContext* ctx = (ProcessContext*)raw;
|
|
107
|
+
VALUE rb_samples = rb_ary_new_capa((long)ctx->sample_count);
|
|
88
108
|
VALUE result;
|
|
89
109
|
size_t i;
|
|
90
110
|
|
|
@@ -98,41 +118,58 @@ static VALUE SoundRecorder_process_body(VALUE raw) {
|
|
|
98
118
|
return Qnil;
|
|
99
119
|
}
|
|
100
120
|
|
|
101
|
-
|
|
121
|
+
/* Runs on the shared foreign-thread worker, which holds the GVL. */
|
|
122
|
+
static void SoundRecorder_process_run(void* raw) {
|
|
102
123
|
int state = 0;
|
|
103
124
|
|
|
104
|
-
rb_protect(SoundRecorder_process_body, (VALUE)
|
|
125
|
+
rb_protect(SoundRecorder_process_body, (VALUE)raw, &state);
|
|
105
126
|
|
|
106
127
|
if (state) {
|
|
107
128
|
rb_set_errinfo(Qnil);
|
|
108
|
-
((ProcessContext
|
|
129
|
+
((ProcessContext*)raw)->ok = 0;
|
|
109
130
|
}
|
|
110
|
-
|
|
111
|
-
return NULL;
|
|
112
131
|
}
|
|
113
132
|
|
|
114
|
-
static bool SoundRecorder_on_process(const int16_t
|
|
115
|
-
SoundRecorder
|
|
133
|
+
static bool SoundRecorder_on_process(const int16_t* samples, size_t sample_count, void* userData) {
|
|
134
|
+
SoundRecorder* recorder = userData;
|
|
116
135
|
ProcessContext ctx = {
|
|
117
|
-
.recorder = recorder, .samples = samples, .sample_count = sample_count, .ok = 0
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
136
|
+
.recorder = recorder, .samples = samples, .sample_count = sample_count, .ok = 0};
|
|
137
|
+
|
|
138
|
+
if (!run_on_ruby_thread(SoundRecorder_process_run, &ctx, SOUND_RECORDER_JOB_TIMEOUT_MS)) {
|
|
139
|
+
/* Timed out before the worker even claimed the job (e.g. GVL
|
|
140
|
+
contention): drop this one chunk rather than block the capture
|
|
141
|
+
thread indefinitely, but keep recording rather than aborting the
|
|
142
|
+
whole session over one missed callback. */
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
121
145
|
|
|
122
146
|
return ctx.ok ? true : false;
|
|
123
147
|
}
|
|
124
148
|
|
|
125
|
-
static void SoundRecorder_on_stop(void
|
|
126
|
-
SoundRecorder
|
|
149
|
+
static void SoundRecorder_on_stop(void* userData) {
|
|
150
|
+
SoundRecorder* recorder = userData;
|
|
127
151
|
|
|
128
152
|
if (rb_respond_to(recorder->rb_self, rb_intern("on_stop"))) {
|
|
129
153
|
SoundRecorder_invoke(recorder->rb_self, rb_intern("on_stop"));
|
|
130
154
|
}
|
|
131
155
|
}
|
|
132
156
|
|
|
157
|
+
/* call-seq:
|
|
158
|
+
* SoundRecorder.new -> SoundRecorder
|
|
159
|
+
*
|
|
160
|
+
* SoundRecorder must be subclassed: the subclass is required to implement
|
|
161
|
+
* +#on_process(samples)+, called from the audio thread with an Array of
|
|
162
|
+
* captured Integer samples whenever a chunk is ready (return a truthy value
|
|
163
|
+
* to keep recording, falsy to stop), and may optionally implement
|
|
164
|
+
* +#on_start+ and +#on_stop+.
|
|
165
|
+
*
|
|
166
|
+
* @return [SoundRecorder]
|
|
167
|
+
* @raise [NotImplementedError] if the subclass does not define #on_process
|
|
168
|
+
* @raise [RuntimeError] if no capture device is available
|
|
169
|
+
*/
|
|
133
170
|
static VALUE SoundRecorder_new(VALUE klass) {
|
|
134
|
-
SoundRecorder
|
|
135
|
-
sfSoundRecorder
|
|
171
|
+
SoundRecorder* ptr;
|
|
172
|
+
sfSoundRecorder* handle;
|
|
136
173
|
VALUE self;
|
|
137
174
|
|
|
138
175
|
ptr = malloc(sizeof(SoundRecorder));
|
|
@@ -160,27 +197,59 @@ static VALUE SoundRecorder_new(VALUE klass) {
|
|
|
160
197
|
return self;
|
|
161
198
|
}
|
|
162
199
|
|
|
200
|
+
/* call-seq:
|
|
201
|
+
* start(sample_rate) -> true or false
|
|
202
|
+
*
|
|
203
|
+
* Starts capturing audio at the given sample rate.
|
|
204
|
+
*
|
|
205
|
+
* @return [Boolean] whether recording started successfully
|
|
206
|
+
*/
|
|
163
207
|
static VALUE SoundRecorder_start(VALUE self, VALUE rb_sample_rate) {
|
|
164
208
|
return BOOL2RB(sfSoundRecorder_start(Get_SoundRecorder_Struct(self),
|
|
165
|
-
(unsigned int)
|
|
209
|
+
(unsigned int)NUM2INT(rb_sample_rate)));
|
|
166
210
|
}
|
|
167
211
|
|
|
212
|
+
/* call-seq: stop -> self
|
|
213
|
+
*
|
|
214
|
+
* Stops capturing audio.
|
|
215
|
+
*
|
|
216
|
+
* @return [self]
|
|
217
|
+
*/
|
|
168
218
|
static VALUE SoundRecorder_stop(VALUE self) {
|
|
169
219
|
sfSoundRecorder_stop(Get_SoundRecorder_Struct(self));
|
|
170
220
|
return self;
|
|
171
221
|
}
|
|
172
222
|
|
|
223
|
+
/* call-seq: sample_rate -> Integer
|
|
224
|
+
*
|
|
225
|
+
* Returns the sample rate used for capture.
|
|
226
|
+
*
|
|
227
|
+
* @return [Integer]
|
|
228
|
+
*/
|
|
173
229
|
static VALUE SoundRecorder_sample_rate(VALUE self) {
|
|
174
230
|
return UINT2NUM(sfSoundRecorder_getSampleRate(Get_SoundRecorder_Struct(self)));
|
|
175
231
|
}
|
|
176
232
|
|
|
233
|
+
/* call-seq: SoundRecorder.available? -> true or false
|
|
234
|
+
*
|
|
235
|
+
* Returns +true+ if the audio backend supports capture.
|
|
236
|
+
*
|
|
237
|
+
* @return [Boolean] whether the audio backend supports capture at all
|
|
238
|
+
*/
|
|
177
239
|
static VALUE SoundRecorder_available(VALUE klass) {
|
|
178
240
|
return BOOL2RB(sfSoundRecorder_isAvailable());
|
|
179
241
|
}
|
|
180
242
|
|
|
243
|
+
/* call-seq: SoundRecorder.available_devices -> Array<String>
|
|
244
|
+
*
|
|
245
|
+
* Returns the names of the capture devices available on this system.
|
|
246
|
+
*
|
|
247
|
+
* @return [Array<String>] names of the capture devices available on this
|
|
248
|
+
* system
|
|
249
|
+
*/
|
|
181
250
|
static VALUE SoundRecorder_available_devices(VALUE klass) {
|
|
182
251
|
size_t count = 0;
|
|
183
|
-
const char *
|
|
252
|
+
const char* const* devices = sfSoundRecorder_getAvailableDevices(&count);
|
|
184
253
|
VALUE rb_array;
|
|
185
254
|
size_t i;
|
|
186
255
|
|
|
@@ -188,7 +257,7 @@ static VALUE SoundRecorder_available_devices(VALUE klass) {
|
|
|
188
257
|
return rb_ary_new();
|
|
189
258
|
}
|
|
190
259
|
|
|
191
|
-
rb_array = rb_ary_new_capa((long)
|
|
260
|
+
rb_array = rb_ary_new_capa((long)count);
|
|
192
261
|
|
|
193
262
|
for (i = 0; i < count; i++) {
|
|
194
263
|
rb_ary_push(rb_array, rb_str_new_cstr(devices[i]));
|
|
@@ -197,31 +266,74 @@ static VALUE SoundRecorder_available_devices(VALUE klass) {
|
|
|
197
266
|
return rb_array;
|
|
198
267
|
}
|
|
199
268
|
|
|
269
|
+
/* call-seq: SoundRecorder.default_device -> String or nil
|
|
270
|
+
*
|
|
271
|
+
* Returns the name of the system's default capture device.
|
|
272
|
+
*
|
|
273
|
+
* @return [String, nil] the name of the system's default capture device, or
|
|
274
|
+
* +nil+ when the system reports none
|
|
275
|
+
*/
|
|
200
276
|
static VALUE SoundRecorder_default_device(VALUE klass) {
|
|
201
|
-
return
|
|
277
|
+
return SoundRecorder_nullable_string(sfSoundRecorder_getDefaultDevice());
|
|
202
278
|
}
|
|
203
279
|
|
|
280
|
+
/* call-seq: device -> String or nil
|
|
281
|
+
*
|
|
282
|
+
* Returns the name of the capture device in use.
|
|
283
|
+
*
|
|
284
|
+
* @return [String, nil] the name of the capture device in use, or +nil+ when
|
|
285
|
+
* the recorder has none
|
|
286
|
+
*/
|
|
204
287
|
static VALUE SoundRecorder_device(VALUE self) {
|
|
205
|
-
return
|
|
288
|
+
return SoundRecorder_nullable_string(sfSoundRecorder_getDevice(Get_SoundRecorder_Struct(self)));
|
|
206
289
|
}
|
|
207
290
|
|
|
291
|
+
/* call-seq:
|
|
292
|
+
* device=(value) -> true or false
|
|
293
|
+
*
|
|
294
|
+
* Must be called while not recording. Get available names from
|
|
295
|
+
* .available_devices.
|
|
296
|
+
*
|
|
297
|
+
* @return [Boolean] whether the device was set successfully
|
|
298
|
+
*/
|
|
208
299
|
static VALUE SoundRecorder_set_device(VALUE self, VALUE rb_name) {
|
|
209
300
|
return BOOL2RB(
|
|
210
301
|
sfSoundRecorder_setDevice(Get_SoundRecorder_Struct(self), StringValueCStr(rb_name)));
|
|
211
302
|
}
|
|
212
303
|
|
|
304
|
+
/* call-seq: channel_count -> Integer
|
|
305
|
+
*
|
|
306
|
+
* Returns the number of capture channels.
|
|
307
|
+
*
|
|
308
|
+
* @return [Integer]
|
|
309
|
+
*/
|
|
213
310
|
static VALUE SoundRecorder_channel_count(VALUE self) {
|
|
214
311
|
return UINT2NUM(sfSoundRecorder_getChannelCount(Get_SoundRecorder_Struct(self)));
|
|
215
312
|
}
|
|
216
313
|
|
|
314
|
+
/* call-seq:
|
|
315
|
+
* channel_count=(value) -> Integer
|
|
316
|
+
*
|
|
317
|
+
* Must be called while not recording.
|
|
318
|
+
*
|
|
319
|
+
* @return [Integer] +value+
|
|
320
|
+
*/
|
|
217
321
|
static VALUE SoundRecorder_set_channel_count(VALUE self, VALUE rb_count) {
|
|
218
|
-
sfSoundRecorder_setChannelCount(Get_SoundRecorder_Struct(self),
|
|
322
|
+
sfSoundRecorder_setChannelCount(Get_SoundRecorder_Struct(self),
|
|
323
|
+
(unsigned int)NUM2INT(rb_count));
|
|
219
324
|
return rb_count;
|
|
220
325
|
}
|
|
221
326
|
|
|
327
|
+
/* call-seq: channel_map -> Array<Symbol>
|
|
328
|
+
*
|
|
329
|
+
* Returns the channel layout of the recorder.
|
|
330
|
+
*
|
|
331
|
+
* @return [Array<Symbol>] one entry per channel, e.g.
|
|
332
|
+
* +[:front_left, :front_right]+
|
|
333
|
+
*/
|
|
222
334
|
static VALUE SoundRecorder_channel_map(VALUE self) {
|
|
223
335
|
size_t count = 0;
|
|
224
|
-
sfSoundChannel
|
|
336
|
+
sfSoundChannel* map = sfSoundRecorder_getChannelMap(Get_SoundRecorder_Struct(self), &count);
|
|
225
337
|
VALUE rb_array;
|
|
226
338
|
size_t i;
|
|
227
339
|
|
|
@@ -229,7 +341,7 @@ static VALUE SoundRecorder_channel_map(VALUE self) {
|
|
|
229
341
|
return rb_ary_new();
|
|
230
342
|
}
|
|
231
343
|
|
|
232
|
-
rb_array = rb_ary_new_capa((long)
|
|
344
|
+
rb_array = rb_ary_new_capa((long)count);
|
|
233
345
|
|
|
234
346
|
for (i = 0; i < count; i++) {
|
|
235
347
|
rb_ary_push(rb_array, ID2SYM(rb_intern(sound_channel_name(map[i]))));
|
|
@@ -238,14 +350,22 @@ static VALUE SoundRecorder_channel_map(VALUE self) {
|
|
|
238
350
|
return rb_array;
|
|
239
351
|
}
|
|
240
352
|
|
|
241
|
-
|
|
242
|
-
|
|
353
|
+
/* Document-class: SFML::SoundRecorder
|
|
354
|
+
* Base class for a custom audio capture consumer. Subclasses must implement
|
|
355
|
+
* +#on_process(samples)+, called from the audio thread whenever a chunk of
|
|
356
|
+
* captured samples is ready, and may implement +#on_start+/+#on_stop+ to
|
|
357
|
+
* react to recording starting/stopping. For simply capturing into a
|
|
358
|
+
* SoundBuffer without custom processing, use SoundBufferRecorder instead.
|
|
359
|
+
*/
|
|
360
|
+
void Init_SoundRecorder(VALUE rb_mSFML) {
|
|
361
|
+
rb_cSoundRecorder = rb_define_class_under(rb_mSFML, "SoundRecorder", rb_cObject);
|
|
243
362
|
|
|
244
363
|
rb_define_singleton_method(rb_cSoundRecorder, "new", SoundRecorder_new, 0);
|
|
245
364
|
rb_define_singleton_method(rb_cSoundRecorder, "available?", SoundRecorder_available, 0);
|
|
246
365
|
rb_define_singleton_method(rb_cSoundRecorder, "available_devices",
|
|
247
366
|
SoundRecorder_available_devices, 0);
|
|
248
|
-
rb_define_singleton_method(rb_cSoundRecorder, "default_device", SoundRecorder_default_device,
|
|
367
|
+
rb_define_singleton_method(rb_cSoundRecorder, "default_device", SoundRecorder_default_device,
|
|
368
|
+
0);
|
|
249
369
|
|
|
250
370
|
rb_define_method(rb_cSoundRecorder, "start", SoundRecorder_start, 1);
|
|
251
371
|
rb_define_method(rb_cSoundRecorder, "stop", SoundRecorder_stop, 0);
|
|
@@ -261,8 +381,8 @@ VALUE Get_Klass_SoundRecorder(void) {
|
|
|
261
381
|
return rb_cSoundRecorder;
|
|
262
382
|
}
|
|
263
383
|
|
|
264
|
-
void
|
|
265
|
-
SoundRecorder
|
|
384
|
+
void* Get_SoundRecorder_Struct(VALUE self) {
|
|
385
|
+
SoundRecorder* ptr;
|
|
266
386
|
TypedData_Get_Struct(self, SoundRecorder, &SoundRecorder_data_type, ptr);
|
|
267
387
|
return ptr->handle;
|
|
268
388
|
}
|
|
@@ -12,84 +12,165 @@ typedef struct {
|
|
|
12
12
|
|
|
13
13
|
static VALUE rb_cSoundSourceCone;
|
|
14
14
|
|
|
15
|
-
static void SoundSourceCone_free(void
|
|
15
|
+
static void SoundSourceCone_free(void* ptr) {
|
|
16
16
|
free(ptr);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
static const rb_data_type_t SoundSourceCone_data_type = {
|
|
20
20
|
.wrap_struct_name = "SFML::SoundSourceCone",
|
|
21
21
|
.function = {.dmark = NULL, .dfree = SoundSourceCone_free, .dsize = NULL},
|
|
22
|
-
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
|
23
|
-
};
|
|
22
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY};
|
|
24
23
|
|
|
25
24
|
static VALUE SoundSourceCone_wrap(sfSoundSourceCone cone) {
|
|
26
|
-
SoundSourceCone
|
|
25
|
+
SoundSourceCone* ptr = malloc(sizeof(SoundSourceCone));
|
|
27
26
|
|
|
28
27
|
ptr->cone = cone;
|
|
29
28
|
|
|
30
29
|
return TypedData_Wrap_Struct(rb_cSoundSourceCone, &SoundSourceCone_data_type, ptr);
|
|
31
30
|
}
|
|
32
31
|
|
|
32
|
+
/* call-seq:
|
|
33
|
+
* SoundSourceCone.new(inner_angle, outer_angle, outer_gain) -> SoundSourceCone
|
|
34
|
+
*
|
|
35
|
+
* Creates a directional attenuation cone with the given angles and gain.
|
|
36
|
+
*
|
|
37
|
+
* @return [SoundSourceCone]
|
|
38
|
+
*/
|
|
33
39
|
static VALUE SoundSourceCone_new(VALUE klass, VALUE rb_inner, VALUE rb_outer, VALUE rb_gain) {
|
|
34
|
-
sfSoundSourceCone cone = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
.outerGain = (float) NUM2DBL(rb_gain)
|
|
38
|
-
};
|
|
40
|
+
sfSoundSourceCone cone = {.innerAngle = (float)NUM2DBL(rb_inner),
|
|
41
|
+
.outerAngle = (float)NUM2DBL(rb_outer),
|
|
42
|
+
.outerGain = (float)NUM2DBL(rb_gain)};
|
|
39
43
|
|
|
40
44
|
return SoundSourceCone_wrap(cone);
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
/* call-seq: inner_angle -> Float
|
|
48
|
+
*
|
|
49
|
+
* Returns the inner cone angle in degrees.
|
|
50
|
+
*
|
|
51
|
+
* @return [Float] angle, in degrees, of the inner cone within which the
|
|
52
|
+
* source is heard at full volume
|
|
53
|
+
*/
|
|
43
54
|
static VALUE SoundSourceCone_get_inner_angle(VALUE self) {
|
|
44
|
-
return DBL2NUM(((SoundSourceCone
|
|
55
|
+
return DBL2NUM(((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.innerAngle);
|
|
45
56
|
}
|
|
46
57
|
|
|
58
|
+
/* call-seq: outer_angle -> Float
|
|
59
|
+
*
|
|
60
|
+
* Returns the outer cone angle in degrees.
|
|
61
|
+
*
|
|
62
|
+
* @return [Float] angle, in degrees, of the outer cone beyond which the
|
|
63
|
+
* source is heard at +outer_gain+ volume
|
|
64
|
+
*/
|
|
47
65
|
static VALUE SoundSourceCone_get_outer_angle(VALUE self) {
|
|
48
|
-
return DBL2NUM(((SoundSourceCone
|
|
66
|
+
return DBL2NUM(((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.outerAngle);
|
|
49
67
|
}
|
|
50
68
|
|
|
69
|
+
/* call-seq: outer_gain -> Float
|
|
70
|
+
*
|
|
71
|
+
* Returns the gain applied outside the outer cone.
|
|
72
|
+
*
|
|
73
|
+
* @return [Float] volume factor applied outside the outer cone
|
|
74
|
+
*/
|
|
51
75
|
static VALUE SoundSourceCone_get_outer_gain(VALUE self) {
|
|
52
|
-
return DBL2NUM(((SoundSourceCone
|
|
76
|
+
return DBL2NUM(((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.outerGain);
|
|
53
77
|
}
|
|
54
78
|
|
|
79
|
+
/* call-seq:
|
|
80
|
+
* inner_angle=(value) -> Float
|
|
81
|
+
*
|
|
82
|
+
* Sets the inner cone angle in degrees.
|
|
83
|
+
*
|
|
84
|
+
* @return [Float] +value+
|
|
85
|
+
*/
|
|
55
86
|
static VALUE SoundSourceCone_set_inner_angle(VALUE self, VALUE rb_value) {
|
|
56
|
-
((SoundSourceCone
|
|
87
|
+
((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.innerAngle =
|
|
88
|
+
(float)NUM2DBL(rb_value);
|
|
57
89
|
return rb_value;
|
|
58
90
|
}
|
|
59
91
|
|
|
92
|
+
/* call-seq:
|
|
93
|
+
* outer_angle=(value) -> Float
|
|
94
|
+
*
|
|
95
|
+
* Sets the outer cone angle in degrees.
|
|
96
|
+
*
|
|
97
|
+
* @return [Float] +value+
|
|
98
|
+
*/
|
|
60
99
|
static VALUE SoundSourceCone_set_outer_angle(VALUE self, VALUE rb_value) {
|
|
61
|
-
((SoundSourceCone
|
|
100
|
+
((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.outerAngle =
|
|
101
|
+
(float)NUM2DBL(rb_value);
|
|
62
102
|
return rb_value;
|
|
63
103
|
}
|
|
64
104
|
|
|
105
|
+
/* call-seq:
|
|
106
|
+
* outer_gain=(value) -> Float
|
|
107
|
+
*
|
|
108
|
+
* Sets the gain applied outside the outer cone.
|
|
109
|
+
*
|
|
110
|
+
* @return [Float] +value+
|
|
111
|
+
*/
|
|
65
112
|
static VALUE SoundSourceCone_set_outer_gain(VALUE self, VALUE rb_value) {
|
|
66
|
-
((SoundSourceCone
|
|
113
|
+
((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone.outerGain = (float)NUM2DBL(rb_value);
|
|
67
114
|
return rb_value;
|
|
68
115
|
}
|
|
69
116
|
|
|
117
|
+
/* call-seq: to_a -> [Float, Float, Float]
|
|
118
|
+
*
|
|
119
|
+
* Returns the cone's three components as an Array.
|
|
120
|
+
*
|
|
121
|
+
* @return [Array<Float>] +[inner_angle, outer_angle, outer_gain]+
|
|
122
|
+
*/
|
|
70
123
|
static VALUE SoundSourceCone_to_a(VALUE self) {
|
|
71
|
-
sfSoundSourceCone cone = ((SoundSourceCone
|
|
124
|
+
sfSoundSourceCone cone = ((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone;
|
|
72
125
|
|
|
73
126
|
return rb_ary_new_from_args(3, DBL2NUM(cone.innerAngle), DBL2NUM(cone.outerAngle),
|
|
74
127
|
DBL2NUM(cone.outerGain));
|
|
75
128
|
}
|
|
76
129
|
|
|
130
|
+
/* call-seq:
|
|
131
|
+
* self == other -> true or false
|
|
132
|
+
*
|
|
133
|
+
* Returns +true+ if +other+ is a cone with the same angles and gain.
|
|
134
|
+
*
|
|
135
|
+
* @return [Boolean]
|
|
136
|
+
*/
|
|
77
137
|
static VALUE SoundSourceCone_eql(VALUE self, VALUE rb_other) {
|
|
78
|
-
sfSoundSourceCone a = ((SoundSourceCone
|
|
138
|
+
sfSoundSourceCone a = ((SoundSourceCone*)Get_SoundSourceCone_Struct(self))->cone;
|
|
79
139
|
sfSoundSourceCone b;
|
|
80
140
|
|
|
81
141
|
if (!rb_obj_is_kind_of(rb_other, rb_cSoundSourceCone)) {
|
|
82
142
|
return Qfalse;
|
|
83
143
|
}
|
|
84
144
|
|
|
85
|
-
b = ((SoundSourceCone
|
|
145
|
+
b = ((SoundSourceCone*)Get_SoundSourceCone_Struct(rb_other))->cone;
|
|
86
146
|
|
|
87
147
|
return BOOL2RB(a.innerAngle == b.innerAngle && a.outerAngle == b.outerAngle &&
|
|
88
148
|
a.outerGain == b.outerGain);
|
|
89
149
|
}
|
|
90
150
|
|
|
91
|
-
|
|
92
|
-
|
|
151
|
+
/* Document-class: SFML::SoundSourceCone
|
|
152
|
+
* A directional attenuation cone for a SoundSource (SoundSource#cone) or the
|
|
153
|
+
* Listener (Listener.cone): within +inner_angle+ degrees of the facing
|
|
154
|
+
* direction the source is heard at full volume; beyond +outer_angle+
|
|
155
|
+
* degrees it is heard at +outer_gain+ volume, with a smooth transition in
|
|
156
|
+
* between.
|
|
157
|
+
*
|
|
158
|
+
* @!attribute inner_angle
|
|
159
|
+
* Angle, in degrees, of the inner cone within which the source is heard at
|
|
160
|
+
* full volume.
|
|
161
|
+
* @return [Float] angle, in degrees, of the inner cone within which the
|
|
162
|
+
* source is heard at full volume
|
|
163
|
+
* @!attribute outer_angle
|
|
164
|
+
* Angle, in degrees, of the outer cone beyond which the source is heard at
|
|
165
|
+
* +outer_gain+ volume.
|
|
166
|
+
* @return [Float] angle, in degrees, of the outer cone beyond which the
|
|
167
|
+
* source is heard at +outer_gain+ volume
|
|
168
|
+
* @!attribute outer_gain
|
|
169
|
+
* Volume factor applied outside the outer cone.
|
|
170
|
+
* @return [Float] volume factor applied outside the outer cone
|
|
171
|
+
*/
|
|
172
|
+
void Init_SoundSourceCone(VALUE rb_mSFML) {
|
|
173
|
+
rb_cSoundSourceCone = rb_define_class_under(rb_mSFML, "SoundSourceCone", rb_cObject);
|
|
93
174
|
|
|
94
175
|
rb_define_singleton_method(rb_cSoundSourceCone, "new", SoundSourceCone_new, 3);
|
|
95
176
|
|
|
@@ -107,30 +188,28 @@ VALUE Get_Klass_SoundSourceCone(void) {
|
|
|
107
188
|
return rb_cSoundSourceCone;
|
|
108
189
|
}
|
|
109
190
|
|
|
110
|
-
void
|
|
111
|
-
SoundSourceCone
|
|
191
|
+
void* Get_SoundSourceCone_Struct(VALUE self) {
|
|
192
|
+
SoundSourceCone* ptr;
|
|
112
193
|
TypedData_Get_Struct(self, SoundSourceCone, &SoundSourceCone_data_type, ptr);
|
|
113
194
|
return ptr;
|
|
114
195
|
}
|
|
115
196
|
|
|
116
197
|
sfSoundSourceCone sound_source_cone_from_rb(VALUE rb_cone) {
|
|
117
198
|
if (rb_obj_is_kind_of(rb_cone, rb_cSoundSourceCone)) {
|
|
118
|
-
return ((SoundSourceCone
|
|
199
|
+
return ((SoundSourceCone*)Get_SoundSourceCone_Struct(rb_cone))->cone;
|
|
119
200
|
}
|
|
120
201
|
|
|
121
202
|
if (RB_TYPE_P(rb_cone, T_ARRAY) && RARRAY_LEN(rb_cone) == 3) {
|
|
122
|
-
sfSoundSourceCone cone = {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.outerGain = (float) NUM2DBL(rb_ary_entry(rb_cone, 2))
|
|
126
|
-
};
|
|
203
|
+
sfSoundSourceCone cone = {.innerAngle = (float)NUM2DBL(rb_ary_entry(rb_cone, 0)),
|
|
204
|
+
.outerAngle = (float)NUM2DBL(rb_ary_entry(rb_cone, 1)),
|
|
205
|
+
.outerGain = (float)NUM2DBL(rb_ary_entry(rb_cone, 2))};
|
|
127
206
|
|
|
128
207
|
return cone;
|
|
129
208
|
}
|
|
130
209
|
|
|
131
210
|
raise_invalid_argument_class(rb_cSoundSourceCone);
|
|
132
211
|
|
|
133
|
-
return (sfSoundSourceCone)
|
|
212
|
+
return (sfSoundSourceCone){0.0f, 0.0f, 0.0f};
|
|
134
213
|
}
|
|
135
214
|
|
|
136
215
|
VALUE sound_source_cone_to_rb(sfSoundSourceCone cone) {
|