sfml3-rb 0.0.1 → 0.2.1
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/CHANGELOG.md +321 -0
- data/README.md +44 -14
- data/TODO.md +199 -0
- data/ext/audio/audio_enums.c +131 -0
- data/ext/audio/audio_enums.h +18 -0
- data/ext/audio/effect_processor.c +233 -0
- data/ext/audio/effect_processor.h +25 -0
- data/ext/audio/listener.c +83 -0
- data/ext/audio/listener.h +8 -0
- data/ext/audio/music.c +174 -0
- data/ext/audio/music.h +14 -0
- data/ext/audio/sound.c +139 -0
- data/ext/audio/sound.h +14 -0
- data/ext/audio/sound_buffer.c +274 -0
- data/ext/audio/sound_buffer.h +18 -0
- data/ext/audio/sound_buffer_recorder.c +109 -0
- data/ext/audio/sound_buffer_recorder.h +14 -0
- data/ext/audio/sound_recorder.c +268 -0
- data/ext/audio/sound_recorder.h +14 -0
- data/ext/audio/sound_source.h +13 -0
- data/ext/audio/sound_source.inc +271 -0
- data/ext/audio/sound_source_cone.c +138 -0
- data/ext/audio/sound_source_cone.h +20 -0
- data/ext/audio/sound_stream.c +294 -0
- data/ext/audio/sound_stream.h +14 -0
- data/ext/{exceptions.c → core/exceptions.c} +10 -8
- data/ext/{ext → core}/exceptions.h +3 -3
- data/ext/core/foreign_thread.c +149 -0
- data/ext/core/foreign_thread.h +31 -0
- data/ext/core/macros.h +8 -0
- data/ext/{ext → core}/sfml.h +5 -3
- data/ext/core/unicode.c +46 -0
- data/ext/core/unicode.h +25 -0
- data/ext/ext.c +125 -14
- data/ext/extconf.rb +51 -6
- data/ext/graphics/blend_mode.c +261 -0
- data/ext/graphics/blend_mode.h +18 -0
- data/ext/graphics/circle.c +319 -0
- data/ext/{ext/klass/drawable → graphics}/circle.h +3 -3
- data/ext/graphics/color.c +318 -0
- data/ext/graphics/color.h +37 -0
- data/ext/{drawable.c → graphics/drawable.c} +11 -11
- data/ext/graphics/drawable.h +10 -0
- data/ext/graphics/enums.c +123 -0
- data/ext/graphics/enums.h +20 -0
- data/ext/graphics/font.c +148 -0
- data/ext/graphics/font.h +14 -0
- data/ext/graphics/glyph.c +60 -0
- data/ext/graphics/glyph.h +14 -0
- data/ext/graphics/image.c +205 -0
- data/ext/graphics/image.h +16 -0
- data/ext/graphics/polygon.c +300 -0
- data/ext/graphics/polygon.h +10 -0
- data/ext/graphics/rect.c +287 -0
- data/ext/graphics/rect.h +30 -0
- data/ext/graphics/rectangle.c +302 -0
- data/ext/graphics/rectangle.h +10 -0
- data/ext/graphics/render_state.c +204 -0
- data/ext/graphics/render_state.h +18 -0
- data/ext/graphics/render_target.inc +181 -0
- data/ext/graphics/render_texture.c +182 -0
- data/ext/graphics/render_texture.h +14 -0
- data/ext/graphics/shader.c +540 -0
- data/ext/graphics/shader.h +14 -0
- data/ext/graphics/shape.c +311 -0
- data/ext/graphics/shape.h +10 -0
- data/ext/graphics/sprite.c +249 -0
- data/ext/graphics/sprite.h +10 -0
- data/ext/graphics/stencil_mode.c +211 -0
- data/ext/graphics/stencil_mode.h +18 -0
- data/ext/graphics/target.c +133 -0
- data/ext/graphics/target.h +40 -0
- data/ext/graphics/text.c +344 -0
- data/ext/graphics/text.h +10 -0
- data/ext/graphics/texture.c +379 -0
- data/ext/graphics/texture.h +16 -0
- data/ext/graphics/transform.c +372 -0
- data/ext/graphics/transform.h +35 -0
- data/ext/{transformable.c → graphics/transformable.c} +168 -144
- data/ext/{ext/klass → graphics}/transformable.h +3 -3
- data/ext/graphics/vertex.c +179 -0
- data/ext/graphics/vertex.h +23 -0
- data/ext/graphics/vertex_array.c +127 -0
- data/ext/graphics/vertex_array.h +10 -0
- data/ext/graphics/vertex_buffer.c +211 -0
- data/ext/graphics/vertex_buffer.h +14 -0
- data/ext/{view.c → graphics/view.c} +168 -169
- data/ext/{ext/klass → graphics}/view.h +3 -3
- data/ext/network/ftp.c +405 -0
- data/ext/network/ftp.h +20 -0
- data/ext/network/http.c +243 -0
- data/ext/network/http.h +18 -0
- data/ext/network/ip_address.c +164 -0
- data/ext/network/ip_address.h +20 -0
- data/ext/network/network_enums.c +298 -0
- data/ext/network/network_enums.h +26 -0
- data/ext/network/packet.c +189 -0
- data/ext/network/packet.h +14 -0
- data/ext/network/socket_selector.c +142 -0
- data/ext/network/socket_selector.h +14 -0
- data/ext/network/tcp_listener.c +115 -0
- data/ext/network/tcp_listener.h +14 -0
- data/ext/network/tcp_socket.c +199 -0
- data/ext/network/tcp_socket.h +17 -0
- data/ext/network/udp_socket.c +190 -0
- data/ext/network/udp_socket.h +14 -0
- data/ext/ports.rb +88 -21
- data/ext/system/buffer.c +77 -0
- data/ext/system/buffer.h +14 -0
- data/ext/system/clock.c +100 -0
- data/ext/{ext/klass → system}/clock.h +3 -3
- data/ext/system/input_stream.c +229 -0
- data/ext/system/input_stream.h +23 -0
- data/ext/system/sleep.c +16 -0
- data/ext/system/sleep.h +8 -0
- data/ext/system/time.c +218 -0
- data/ext/system/time.h +18 -0
- data/ext/system/vec2.c +251 -0
- data/ext/system/vec2.h +55 -0
- data/ext/system/vec3.c +219 -0
- data/ext/system/vec3.h +18 -0
- data/ext/window/clipboard.c +89 -0
- data/ext/window/clipboard.h +8 -0
- data/ext/window/context.c +70 -0
- data/ext/window/context.h +8 -0
- data/ext/window/context_settings.c +220 -0
- data/ext/window/context_settings.h +18 -0
- data/ext/window/cursor.c +56 -0
- data/ext/window/cursor.h +14 -0
- data/ext/window/event.c +216 -0
- data/ext/window/event.h +14 -0
- data/ext/{event_name.c → window/event_name.c} +2 -2
- data/ext/window/event_name.h +8 -0
- data/ext/window/input_enums.c +261 -0
- data/ext/window/input_enums.h +36 -0
- data/ext/window/joystick.c +60 -0
- data/ext/window/joystick.h +8 -0
- data/ext/{keyboard.c → window/keyboard.c} +74 -2
- data/ext/window/keyboard.h +12 -0
- data/ext/window/mouse.c +70 -0
- data/ext/window/mouse.h +8 -0
- data/ext/window/sensor.c +30 -0
- data/ext/window/sensor.h +8 -0
- data/ext/window/touch.c +49 -0
- data/ext/window/touch.h +8 -0
- data/ext/window/video_mode.c +133 -0
- data/ext/window/video_mode.h +14 -0
- data/ext/window/vulkan.c +44 -0
- data/ext/window/vulkan.h +8 -0
- data/ext/window/window.c +414 -0
- data/ext/{ext/klass → window}/window.h +3 -3
- data/lib/sfml/version.rb +4 -2
- data/lib/sfml.rb +2 -0
- metadata +163 -56
- data/ext/circle.c +0 -198
- data/ext/clock.c +0 -65
- data/ext/color.c +0 -43
- data/ext/event.c +0 -148
- data/ext/ext/klass/color.h +0 -26
- data/ext/ext/klass/drawable/image.h +0 -4
- data/ext/ext/klass/drawable/polygon.h +0 -4
- data/ext/ext/klass/drawable/rectangle.h +0 -4
- data/ext/ext/klass/drawable/sprite.h +0 -4
- data/ext/ext/klass/drawable/texture.h +0 -4
- data/ext/ext/klass/event/event_name.h +0 -8
- data/ext/ext/klass/event.h +0 -12
- data/ext/ext/klass/keyboard.h +0 -8
- data/ext/ext/klass/render_state.h +0 -16
- data/ext/ext/klass/target.h +0 -18
- data/ext/ext/klass/transform.h +0 -17
- data/ext/ext/klass/video_mode.h +0 -12
- data/ext/ext/module/drawable/drawable.h +0 -10
- data/ext/ext/module/transform.h +0 -18
- data/ext/ext/module.h +0 -10
- data/ext/ext/rect.h +0 -16
- data/ext/ext/style_name.h +0 -11
- data/ext/ext/vec2.h +0 -38
- data/ext/image.c +0 -5
- data/ext/polygon.c +0 -5
- data/ext/rect.c +0 -26
- data/ext/rectangle.c +0 -5
- data/ext/render_state.c +0 -109
- data/ext/sprite.c +0 -5
- data/ext/style_name.c +0 -15
- data/ext/target.c +0 -106
- data/ext/texture.c +0 -5
- data/ext/transform.c +0 -107
- data/ext/vec2.c +0 -42
- data/ext/video_mode.c +0 -78
- data/ext/window.c +0 -274
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#include "audio/audio_enums.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
static const char *sound_status_names[] = {"stopped", "paused", "playing"};
|
|
7
|
+
|
|
8
|
+
/* Designated initializers, indexed by the enum constant rather than by
|
|
9
|
+
position: CSFML 3 defines the channel order, and a positional table would
|
|
10
|
+
silently return the wrong name if a future release inserted a value. */
|
|
11
|
+
static const char *sound_channel_names[] = {
|
|
12
|
+
[sfSoundChannelUnspecified] = "unspecified",
|
|
13
|
+
[sfSoundChannelMono] = "mono",
|
|
14
|
+
[sfSoundChannelFrontLeft] = "front_left",
|
|
15
|
+
[sfSoundChannelFrontRight] = "front_right",
|
|
16
|
+
[sfSoundChannelFrontCenter] = "front_center",
|
|
17
|
+
[sfSoundChannelFrontLeftOfCenter] = "front_left_of_center",
|
|
18
|
+
[sfSoundChannelFrontRightOfCenter] = "front_right_of_center",
|
|
19
|
+
[sfSoundChannelLowFrequencyEffects] = "low_frequency_effects",
|
|
20
|
+
[sfSoundChannelBackLeft] = "back_left",
|
|
21
|
+
[sfSoundChannelBackRight] = "back_right",
|
|
22
|
+
[sfSoundChannelBackCenter] = "back_center",
|
|
23
|
+
[sfSoundChannelSideLeft] = "side_left",
|
|
24
|
+
[sfSoundChannelSideRight] = "side_right",
|
|
25
|
+
[sfSoundChannelTopCenter] = "top_center",
|
|
26
|
+
[sfSoundChannelTopFrontLeft] = "top_front_left",
|
|
27
|
+
[sfSoundChannelTopFrontRight] = "top_front_right",
|
|
28
|
+
[sfSoundChannelTopFrontCenter] = "top_front_center",
|
|
29
|
+
[sfSoundChannelTopBackLeft] = "top_back_left",
|
|
30
|
+
[sfSoundChannelTopBackRight] = "top_back_right",
|
|
31
|
+
[sfSoundChannelTopBackCenter] = "top_back_center"
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
static int symbol_index(VALUE rb_symbol, const char *const *names, size_t count) {
|
|
35
|
+
const char *name;
|
|
36
|
+
size_t i;
|
|
37
|
+
|
|
38
|
+
if (!SYMBOL_P(rb_symbol)) {
|
|
39
|
+
return -1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
name = rb_id2name(SYM2ID(rb_symbol));
|
|
43
|
+
|
|
44
|
+
for (i = 0; i < count; i++) {
|
|
45
|
+
if (names[i] != NULL && strcmp(name, names[i]) == 0) {
|
|
46
|
+
return (int) i;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return -1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const char *sound_status_name(sfSoundStatus status) {
|
|
54
|
+
if (status >= sfStopped && status <= sfPlaying) {
|
|
55
|
+
return sound_status_names[status];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return "stopped";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
sfSoundStatus sound_status_from_rb(VALUE rb_status) {
|
|
62
|
+
int index;
|
|
63
|
+
|
|
64
|
+
if (RB_INTEGER_TYPE_P(rb_status)) {
|
|
65
|
+
return (sfSoundStatus) NUM2INT(rb_status);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
index = symbol_index(rb_status, sound_status_names, 3);
|
|
69
|
+
|
|
70
|
+
if (index < 0) {
|
|
71
|
+
rb_raise(rb_eArgError, "unknown sound status");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return (sfSoundStatus) index;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const char *sound_channel_name(sfSoundChannel channel) {
|
|
78
|
+
if (channel >= sfSoundChannelUnspecified && channel <= sfSoundChannelTopBackCenter &&
|
|
79
|
+
sound_channel_names[channel] != NULL) {
|
|
80
|
+
return sound_channel_names[channel];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return "unspecified";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
sfSoundChannel sound_channel_from_rb(VALUE rb_channel) {
|
|
87
|
+
int index;
|
|
88
|
+
|
|
89
|
+
if (RB_INTEGER_TYPE_P(rb_channel)) {
|
|
90
|
+
return (sfSoundChannel) NUM2INT(rb_channel);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
index = symbol_index(rb_channel, sound_channel_names,
|
|
94
|
+
sizeof(sound_channel_names) / sizeof(sound_channel_names[0]));
|
|
95
|
+
|
|
96
|
+
if (index < 0) {
|
|
97
|
+
rb_raise(rb_eArgError, "unknown sound channel");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return (sfSoundChannel) index;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void Init_AudioEnums(VALUE rb_module) {
|
|
104
|
+
VALUE rb_mSoundStatus = rb_define_module_under(rb_module, "SoundStatus");
|
|
105
|
+
VALUE rb_mSoundChannel = rb_define_module_under(rb_module, "SoundChannel");
|
|
106
|
+
|
|
107
|
+
rb_define_const(rb_mSoundStatus, "STOPPED", INT2NUM(sfStopped));
|
|
108
|
+
rb_define_const(rb_mSoundStatus, "PAUSED", INT2NUM(sfPaused));
|
|
109
|
+
rb_define_const(rb_mSoundStatus, "PLAYING", INT2NUM(sfPlaying));
|
|
110
|
+
|
|
111
|
+
rb_define_const(rb_mSoundChannel, "UNSPECIFIED", INT2NUM(sfSoundChannelUnspecified));
|
|
112
|
+
rb_define_const(rb_mSoundChannel, "MONO", INT2NUM(sfSoundChannelMono));
|
|
113
|
+
rb_define_const(rb_mSoundChannel, "FRONT_LEFT", INT2NUM(sfSoundChannelFrontLeft));
|
|
114
|
+
rb_define_const(rb_mSoundChannel, "FRONT_RIGHT", INT2NUM(sfSoundChannelFrontRight));
|
|
115
|
+
rb_define_const(rb_mSoundChannel, "FRONT_CENTER", INT2NUM(sfSoundChannelFrontCenter));
|
|
116
|
+
rb_define_const(rb_mSoundChannel, "FRONT_LEFT_OF_CENTER", INT2NUM(sfSoundChannelFrontLeftOfCenter));
|
|
117
|
+
rb_define_const(rb_mSoundChannel, "FRONT_RIGHT_OF_CENTER", INT2NUM(sfSoundChannelFrontRightOfCenter));
|
|
118
|
+
rb_define_const(rb_mSoundChannel, "LOW_FREQUENCY_EFFECTS", INT2NUM(sfSoundChannelLowFrequencyEffects));
|
|
119
|
+
rb_define_const(rb_mSoundChannel, "BACK_LEFT", INT2NUM(sfSoundChannelBackLeft));
|
|
120
|
+
rb_define_const(rb_mSoundChannel, "BACK_RIGHT", INT2NUM(sfSoundChannelBackRight));
|
|
121
|
+
rb_define_const(rb_mSoundChannel, "BACK_CENTER", INT2NUM(sfSoundChannelBackCenter));
|
|
122
|
+
rb_define_const(rb_mSoundChannel, "SIDE_LEFT", INT2NUM(sfSoundChannelSideLeft));
|
|
123
|
+
rb_define_const(rb_mSoundChannel, "SIDE_RIGHT", INT2NUM(sfSoundChannelSideRight));
|
|
124
|
+
rb_define_const(rb_mSoundChannel, "TOP_CENTER", INT2NUM(sfSoundChannelTopCenter));
|
|
125
|
+
rb_define_const(rb_mSoundChannel, "TOP_FRONT_LEFT", INT2NUM(sfSoundChannelTopFrontLeft));
|
|
126
|
+
rb_define_const(rb_mSoundChannel, "TOP_FRONT_RIGHT", INT2NUM(sfSoundChannelTopFrontRight));
|
|
127
|
+
rb_define_const(rb_mSoundChannel, "TOP_FRONT_CENTER", INT2NUM(sfSoundChannelTopFrontCenter));
|
|
128
|
+
rb_define_const(rb_mSoundChannel, "TOP_BACK_LEFT", INT2NUM(sfSoundChannelTopBackLeft));
|
|
129
|
+
rb_define_const(rb_mSoundChannel, "TOP_BACK_RIGHT", INT2NUM(sfSoundChannelTopBackRight));
|
|
130
|
+
rb_define_const(rb_mSoundChannel, "TOP_BACK_CENTER", INT2NUM(sfSoundChannelTopBackCenter));
|
|
131
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#ifndef SFML_RB_AUDIO_AUDIO_ENUMS_H
|
|
2
|
+
#define SFML_RB_AUDIO_AUDIO_ENUMS_H
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
|
|
6
|
+
#include "core/sfml.h"
|
|
7
|
+
|
|
8
|
+
void Init_AudioEnums(VALUE rb_module);
|
|
9
|
+
|
|
10
|
+
const char *sound_status_name(sfSoundStatus status);
|
|
11
|
+
|
|
12
|
+
sfSoundStatus sound_status_from_rb(VALUE rb_status);
|
|
13
|
+
|
|
14
|
+
const char *sound_channel_name(sfSoundChannel channel);
|
|
15
|
+
|
|
16
|
+
sfSoundChannel sound_channel_from_rb(VALUE rb_channel);
|
|
17
|
+
|
|
18
|
+
#endif //SFML_RB_AUDIO_AUDIO_ENUMS_H
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#include "audio/effect_processor.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
|
|
6
|
+
#include "core/foreign_thread.h"
|
|
7
|
+
|
|
8
|
+
/* Slots are process-global because a C callback cannot carry context. Each
|
|
9
|
+
entry is either Qnil (free) or the Proc assigned to that slot. */
|
|
10
|
+
static VALUE effect_processors[EFFECT_PROCESSOR_SLOTS];
|
|
11
|
+
|
|
12
|
+
typedef struct {
|
|
13
|
+
int slot;
|
|
14
|
+
const float* input;
|
|
15
|
+
unsigned int input_count;
|
|
16
|
+
float* output;
|
|
17
|
+
unsigned int output_count;
|
|
18
|
+
unsigned int requested_output_count;
|
|
19
|
+
unsigned int channels;
|
|
20
|
+
} EffectContext;
|
|
21
|
+
|
|
22
|
+
/* Fills the output buffer with silence for the full frame count the audio
|
|
23
|
+
engine asked for. Used whenever the processor cannot produce real output
|
|
24
|
+
(an exception, or a timed-out worker): reporting output_count 0 instead of
|
|
25
|
+
this was observed to make miniaudio's node graph re-invoke this callback
|
|
26
|
+
in an immediate, unbounded retry loop (tens of thousands of calls/second)
|
|
27
|
+
rather than treat it as one completed (silent) buffer - which in turn
|
|
28
|
+
starved SFML's AudioDevice::waitForReadingComplete() on the main thread,
|
|
29
|
+
since the audio thread never stopped re-acquiring its internal mutex. */
|
|
30
|
+
static void effect_output_silence(EffectContext* ctx) {
|
|
31
|
+
unsigned int i;
|
|
32
|
+
|
|
33
|
+
for (i = 0; i < ctx->requested_output_count * ctx->channels; i++) {
|
|
34
|
+
ctx->output[i] = 0.0f;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
ctx->output_count = ctx->requested_output_count;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#define EFFECT_JOB_TIMEOUT_MS 50
|
|
41
|
+
|
|
42
|
+
void Init_EffectProcessor(void) {
|
|
43
|
+
int i;
|
|
44
|
+
|
|
45
|
+
for (i = 0; i < EFFECT_PROCESSOR_SLOTS; i++) {
|
|
46
|
+
effect_processors[i] = Qnil;
|
|
47
|
+
rb_gc_register_address(&effect_processors[i]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static VALUE effect_yield(VALUE raw) {
|
|
52
|
+
EffectContext* ctx = (EffectContext*)raw;
|
|
53
|
+
VALUE rb_input;
|
|
54
|
+
VALUE rb_result;
|
|
55
|
+
unsigned int i;
|
|
56
|
+
unsigned int c;
|
|
57
|
+
long produced;
|
|
58
|
+
|
|
59
|
+
rb_input = rb_ary_new_capa((long)ctx->input_count);
|
|
60
|
+
|
|
61
|
+
for (i = 0; i < ctx->input_count; i++) {
|
|
62
|
+
VALUE frame = rb_ary_new_capa((long)ctx->channels);
|
|
63
|
+
|
|
64
|
+
for (c = 0; c < ctx->channels; c++) {
|
|
65
|
+
rb_ary_push(frame, DBL2NUM((double)ctx->input[i * ctx->channels + c]));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
rb_ary_push(rb_input, frame);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
rb_result = rb_funcall(effect_processors[ctx->slot], rb_intern("call"), 2, rb_input,
|
|
72
|
+
UINT2NUM(ctx->channels));
|
|
73
|
+
|
|
74
|
+
if (!RB_TYPE_P(rb_result, T_ARRAY)) {
|
|
75
|
+
rb_raise(rb_eTypeError, "effect processor must return an Array of frames");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
produced = RARRAY_LEN(rb_result);
|
|
79
|
+
|
|
80
|
+
if (produced > (long)ctx->output_count) {
|
|
81
|
+
produced = (long)ctx->output_count;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (i = 0; i < (unsigned int)produced; i++) {
|
|
85
|
+
VALUE frame = rb_ary_entry(rb_result, (long)i);
|
|
86
|
+
|
|
87
|
+
if (!RB_TYPE_P(frame, T_ARRAY)) {
|
|
88
|
+
rb_raise(rb_eTypeError, "effect processor frames must be Arrays");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (c = 0; c < ctx->channels; c++) {
|
|
92
|
+
ctx->output[i * ctx->channels + c] = (float)NUM2DBL(rb_ary_entry(frame, (long)c));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
ctx->output_count = (unsigned int)produced;
|
|
97
|
+
|
|
98
|
+
return Qnil;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Runs on the shared foreign-thread worker, which holds the GVL. */
|
|
102
|
+
static void effect_run(void* raw) {
|
|
103
|
+
EffectContext* ctx = (EffectContext*)raw;
|
|
104
|
+
int state = 0;
|
|
105
|
+
|
|
106
|
+
rb_protect(effect_yield, (VALUE)ctx, &state);
|
|
107
|
+
|
|
108
|
+
if (state) {
|
|
109
|
+
/* An exception must not unwind through the audio engine: drop the
|
|
110
|
+
output and let playback continue silently. */
|
|
111
|
+
rb_set_errinfo(Qnil);
|
|
112
|
+
effect_output_silence(ctx);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
static void effect_invoke(int slot, const float* input, unsigned int* input_count, float* output,
|
|
117
|
+
unsigned int* output_count, unsigned int channels) {
|
|
118
|
+
EffectContext ctx;
|
|
119
|
+
|
|
120
|
+
if (slot < 0 || slot >= EFFECT_PROCESSOR_SLOTS || NIL_P(effect_processors[slot]) ||
|
|
121
|
+
*output_count == 0) {
|
|
122
|
+
*output_count = 0;
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
ctx.slot = slot;
|
|
127
|
+
ctx.input = input;
|
|
128
|
+
ctx.input_count = (input != NULL) ? *input_count : 0;
|
|
129
|
+
ctx.output = output;
|
|
130
|
+
ctx.output_count = *output_count;
|
|
131
|
+
ctx.requested_output_count = *output_count;
|
|
132
|
+
ctx.channels = channels;
|
|
133
|
+
|
|
134
|
+
if (!run_on_ruby_thread(effect_run, &ctx, EFFECT_JOB_TIMEOUT_MS)) {
|
|
135
|
+
/* Timed out before the worker even claimed the job (e.g. GVL
|
|
136
|
+
contention): degrade to silence for this callback rather than
|
|
137
|
+
stall the audio thread. */
|
|
138
|
+
effect_output_silence(&ctx);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* The processor consumed every input frame it was offered. */
|
|
142
|
+
*input_count = ctx.input_count;
|
|
143
|
+
*output_count = ctx.output_count;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
#define EFFECT_THUNK(n) \
|
|
147
|
+
static void effect_thunk_##n(const float* input, unsigned int* input_count, float* output, \
|
|
148
|
+
unsigned int* output_count, unsigned int channels) { \
|
|
149
|
+
effect_invoke(n, input, input_count, output, output_count, channels); \
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
EFFECT_THUNK(0)
|
|
153
|
+
EFFECT_THUNK(1)
|
|
154
|
+
EFFECT_THUNK(2)
|
|
155
|
+
EFFECT_THUNK(3)
|
|
156
|
+
EFFECT_THUNK(4)
|
|
157
|
+
EFFECT_THUNK(5)
|
|
158
|
+
EFFECT_THUNK(6)
|
|
159
|
+
EFFECT_THUNK(7)
|
|
160
|
+
EFFECT_THUNK(8)
|
|
161
|
+
EFFECT_THUNK(9)
|
|
162
|
+
EFFECT_THUNK(10)
|
|
163
|
+
EFFECT_THUNK(11)
|
|
164
|
+
EFFECT_THUNK(12)
|
|
165
|
+
EFFECT_THUNK(13)
|
|
166
|
+
EFFECT_THUNK(14)
|
|
167
|
+
EFFECT_THUNK(15)
|
|
168
|
+
EFFECT_THUNK(16)
|
|
169
|
+
EFFECT_THUNK(17)
|
|
170
|
+
EFFECT_THUNK(18)
|
|
171
|
+
EFFECT_THUNK(19)
|
|
172
|
+
EFFECT_THUNK(20)
|
|
173
|
+
EFFECT_THUNK(21)
|
|
174
|
+
EFFECT_THUNK(22)
|
|
175
|
+
EFFECT_THUNK(23)
|
|
176
|
+
EFFECT_THUNK(24)
|
|
177
|
+
EFFECT_THUNK(25)
|
|
178
|
+
EFFECT_THUNK(26)
|
|
179
|
+
EFFECT_THUNK(27)
|
|
180
|
+
EFFECT_THUNK(28)
|
|
181
|
+
EFFECT_THUNK(29)
|
|
182
|
+
EFFECT_THUNK(30)
|
|
183
|
+
EFFECT_THUNK(31)
|
|
184
|
+
|
|
185
|
+
static sfEffectProcessor effect_thunks[EFFECT_PROCESSOR_SLOTS] = {
|
|
186
|
+
effect_thunk_0, effect_thunk_1, effect_thunk_2, effect_thunk_3, effect_thunk_4,
|
|
187
|
+
effect_thunk_5, effect_thunk_6, effect_thunk_7, effect_thunk_8, effect_thunk_9,
|
|
188
|
+
effect_thunk_10, effect_thunk_11, effect_thunk_12, effect_thunk_13, effect_thunk_14,
|
|
189
|
+
effect_thunk_15, effect_thunk_16, effect_thunk_17, effect_thunk_18, effect_thunk_19,
|
|
190
|
+
effect_thunk_20, effect_thunk_21, effect_thunk_22, effect_thunk_23, effect_thunk_24,
|
|
191
|
+
effect_thunk_25, effect_thunk_26, effect_thunk_27, effect_thunk_28, effect_thunk_29,
|
|
192
|
+
effect_thunk_30, effect_thunk_31};
|
|
193
|
+
|
|
194
|
+
sfEffectProcessor effect_processor_acquire(VALUE rb_proc, int* slot) {
|
|
195
|
+
int i;
|
|
196
|
+
|
|
197
|
+
/* Replacing the processor on a source that already has one reuses its
|
|
198
|
+
slot, so a source never leaks slots across repeated assignment. */
|
|
199
|
+
if (*slot >= 0 && *slot < EFFECT_PROCESSOR_SLOTS) {
|
|
200
|
+
if (NIL_P(rb_proc)) {
|
|
201
|
+
effect_processors[*slot] = Qnil;
|
|
202
|
+
return NULL;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
effect_processors[*slot] = rb_proc;
|
|
206
|
+
|
|
207
|
+
return effect_thunks[*slot];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (NIL_P(rb_proc)) {
|
|
211
|
+
*slot = -1;
|
|
212
|
+
return NULL;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
for (i = 0; i < EFFECT_PROCESSOR_SLOTS; i++) {
|
|
216
|
+
if (NIL_P(effect_processors[i])) {
|
|
217
|
+
effect_processors[i] = rb_proc;
|
|
218
|
+
*slot = i;
|
|
219
|
+
|
|
220
|
+
return effect_thunks[i];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
rb_raise(rb_eRuntimeError, "all %d effect-processor slots are in use", EFFECT_PROCESSOR_SLOTS);
|
|
225
|
+
|
|
226
|
+
return NULL;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void effect_processor_release(int slot) {
|
|
230
|
+
if (slot >= 0 && slot < EFFECT_PROCESSOR_SLOTS) {
|
|
231
|
+
effect_processors[slot] = Qnil;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#ifndef SFML_RB_AUDIO_EFFECT_PROCESSOR_H
|
|
2
|
+
#define SFML_RB_AUDIO_EFFECT_PROCESSOR_H
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
|
|
6
|
+
#include "core/sfml.h"
|
|
7
|
+
|
|
8
|
+
/* sfEffectProcessor carries no userData, so a single C callback cannot tell
|
|
9
|
+
which sound source invoked it. Instead the binding keeps a fixed pool of
|
|
10
|
+
identical C thunks, each hard-wired to one slot; assigning a processor to a
|
|
11
|
+
source hands it the thunk for that source's slot. Slots are bounded, and
|
|
12
|
+
exceeding the pool raises rather than silently sharing one callback. */
|
|
13
|
+
#define EFFECT_PROCESSOR_SLOTS 32
|
|
14
|
+
|
|
15
|
+
/* Registers every slot as a GC root. Must run before any acquire. */
|
|
16
|
+
void Init_EffectProcessor(void);
|
|
17
|
+
|
|
18
|
+
/* Stores rb_proc in a free slot, writes its index to *slot and returns the
|
|
19
|
+
matching thunk. Passing nil returns NULL (no processor). */
|
|
20
|
+
sfEffectProcessor effect_processor_acquire(VALUE rb_proc, int *slot);
|
|
21
|
+
|
|
22
|
+
/* Frees a slot previously handed out, clearing the Ruby reference. */
|
|
23
|
+
void effect_processor_release(int slot);
|
|
24
|
+
|
|
25
|
+
#endif //SFML_RB_AUDIO_EFFECT_PROCESSOR_H
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#include "audio/listener.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
|
|
5
|
+
#include "audio/sound_source_cone.h"
|
|
6
|
+
#include "system/vec3.h"
|
|
7
|
+
|
|
8
|
+
static VALUE Listener_global_volume(VALUE module) {
|
|
9
|
+
return DBL2NUM(sfListener_getGlobalVolume());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
static VALUE Listener_set_global_volume(VALUE module, VALUE rb_value) {
|
|
13
|
+
sfListener_setGlobalVolume((float) NUM2DBL(rb_value));
|
|
14
|
+
return rb_value;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static VALUE Listener_position(VALUE module) {
|
|
18
|
+
return vec3f_to_rb(sfListener_getPosition());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
static VALUE Listener_set_position(VALUE module, VALUE rb_value) {
|
|
22
|
+
sfListener_setPosition(vec3f_from_rb(rb_value));
|
|
23
|
+
return rb_value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
static VALUE Listener_direction(VALUE module) {
|
|
27
|
+
return vec3f_to_rb(sfListener_getDirection());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static VALUE Listener_set_direction(VALUE module, VALUE rb_value) {
|
|
31
|
+
sfListener_setDirection(vec3f_from_rb(rb_value));
|
|
32
|
+
return rb_value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static VALUE Listener_velocity(VALUE module) {
|
|
36
|
+
return vec3f_to_rb(sfListener_getVelocity());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static VALUE Listener_set_velocity(VALUE module, VALUE rb_value) {
|
|
40
|
+
sfListener_setVelocity(vec3f_from_rb(rb_value));
|
|
41
|
+
return rb_value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
static VALUE Listener_up_vector(VALUE module) {
|
|
45
|
+
return vec3f_to_rb(sfListener_getUpVector());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static VALUE Listener_set_up_vector(VALUE module, VALUE rb_value) {
|
|
49
|
+
sfListener_setUpVector(vec3f_from_rb(rb_value));
|
|
50
|
+
return rb_value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static VALUE Listener_cone(VALUE module) {
|
|
54
|
+
sfListenerCone cone = sfListener_getCone();
|
|
55
|
+
|
|
56
|
+
return sound_source_cone_to_rb((sfSoundSourceCone) {cone.innerAngle, cone.outerAngle,
|
|
57
|
+
cone.outerGain});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
static VALUE Listener_set_cone(VALUE module, VALUE rb_value) {
|
|
61
|
+
sfSoundSourceCone cone = sound_source_cone_from_rb(rb_value);
|
|
62
|
+
|
|
63
|
+
sfListener_setCone((sfListenerCone) {cone.innerAngle, cone.outerAngle, cone.outerGain});
|
|
64
|
+
|
|
65
|
+
return rb_value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void Init_Listener(VALUE rb_module) {
|
|
69
|
+
VALUE rb_mListener = rb_define_module_under(rb_module, "Listener");
|
|
70
|
+
|
|
71
|
+
rb_define_module_function(rb_mListener, "global_volume", Listener_global_volume, 0);
|
|
72
|
+
rb_define_module_function(rb_mListener, "global_volume=", Listener_set_global_volume, 1);
|
|
73
|
+
rb_define_module_function(rb_mListener, "position", Listener_position, 0);
|
|
74
|
+
rb_define_module_function(rb_mListener, "position=", Listener_set_position, 1);
|
|
75
|
+
rb_define_module_function(rb_mListener, "direction", Listener_direction, 0);
|
|
76
|
+
rb_define_module_function(rb_mListener, "direction=", Listener_set_direction, 1);
|
|
77
|
+
rb_define_module_function(rb_mListener, "velocity", Listener_velocity, 0);
|
|
78
|
+
rb_define_module_function(rb_mListener, "velocity=", Listener_set_velocity, 1);
|
|
79
|
+
rb_define_module_function(rb_mListener, "up_vector", Listener_up_vector, 0);
|
|
80
|
+
rb_define_module_function(rb_mListener, "up_vector=", Listener_set_up_vector, 1);
|
|
81
|
+
rb_define_module_function(rb_mListener, "cone", Listener_cone, 0);
|
|
82
|
+
rb_define_module_function(rb_mListener, "cone=", Listener_set_cone, 1);
|
|
83
|
+
}
|
data/ext/audio/music.c
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#include "audio/music.h"
|
|
2
|
+
|
|
3
|
+
#include <ruby.h>
|
|
4
|
+
#include <ruby/thread.h>
|
|
5
|
+
#include <stdlib.h>
|
|
6
|
+
|
|
7
|
+
#include "audio/audio_enums.h"
|
|
8
|
+
#include "audio/effect_processor.h"
|
|
9
|
+
#include "audio/sound_source.h"
|
|
10
|
+
#include "core/exceptions.h"
|
|
11
|
+
#include "system/input_stream.h"
|
|
12
|
+
#include "system/time.h"
|
|
13
|
+
|
|
14
|
+
typedef struct {
|
|
15
|
+
SoundSource source;
|
|
16
|
+
/* Music streams from the InputStream lazily, so unlike Font/Image/Shader
|
|
17
|
+
the stream has to outlive the create call. The VALUE is both marked and
|
|
18
|
+
registered as a GC root: the root is what guarantees the InputStream's
|
|
19
|
+
sfInputStream is still alive when sfMusic_destroy runs in dfree, even if
|
|
20
|
+
the Music and the stream become unreachable in the same GC cycle. */
|
|
21
|
+
VALUE rb_stream;
|
|
22
|
+
} Music;
|
|
23
|
+
|
|
24
|
+
static VALUE rb_cMusic;
|
|
25
|
+
|
|
26
|
+
static void Music_mark(void* ptr) {
|
|
27
|
+
Music* music = ptr;
|
|
28
|
+
|
|
29
|
+
rb_gc_mark(music->rb_stream);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* sfMusic_destroy() calls Music::~Music(), which explicitly calls stop() and
|
|
33
|
+
can block waiting on the audio thread; release the GVL for the same reason
|
|
34
|
+
as Sound_free/SS_METHOD(stop). */
|
|
35
|
+
static void* Music_destroy_without_gvl(void* handle) {
|
|
36
|
+
sfMusic_destroy(handle);
|
|
37
|
+
return NULL;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
static void Music_free(void* ptr) {
|
|
41
|
+
Music* music = ptr;
|
|
42
|
+
|
|
43
|
+
effect_processor_release(music->source.effect_slot);
|
|
44
|
+
rb_thread_call_without_gvl(Music_destroy_without_gvl, music->source.handle, RUBY_UBF_IO, NULL);
|
|
45
|
+
rb_gc_unregister_address(&music->rb_stream);
|
|
46
|
+
free(music);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static const rb_data_type_t Music_data_type = {
|
|
50
|
+
.wrap_struct_name = "SFML::Music",
|
|
51
|
+
.function = {.dmark = Music_mark, .dfree = Music_free, .dsize = NULL},
|
|
52
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY};
|
|
53
|
+
|
|
54
|
+
static VALUE Music_wrap(VALUE klass, sfMusic* handle, VALUE rb_stream) {
|
|
55
|
+
Music* ptr;
|
|
56
|
+
|
|
57
|
+
if (handle == NULL) {
|
|
58
|
+
rb_raise(rb_eRuntimeError, "failed to create music");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ptr = malloc(sizeof(Music));
|
|
62
|
+
ptr->source.handle = handle;
|
|
63
|
+
ptr->source.effect_slot = -1;
|
|
64
|
+
ptr->rb_stream = rb_stream;
|
|
65
|
+
|
|
66
|
+
rb_gc_register_address(&ptr->rb_stream);
|
|
67
|
+
|
|
68
|
+
return TypedData_Wrap_Struct(klass, &Music_data_type, ptr);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
static VALUE Music_from_file(VALUE klass, VALUE rb_path) {
|
|
72
|
+
return Music_wrap(klass, sfMusic_createFromFile(StringValueCStr(rb_path)), Qnil);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static VALUE Music_from_memory(VALUE klass, VALUE rb_data) {
|
|
76
|
+
StringValue(rb_data);
|
|
77
|
+
|
|
78
|
+
return Music_wrap(
|
|
79
|
+
klass, sfMusic_createFromMemory(RSTRING_PTR(rb_data), (size_t)RSTRING_LEN(rb_data)), Qnil);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static VALUE Music_from_stream(VALUE klass, VALUE rb_stream) {
|
|
83
|
+
VALUE holder = Qnil;
|
|
84
|
+
sfInputStream* stream = input_stream_from_rb(rb_stream, &holder);
|
|
85
|
+
|
|
86
|
+
return Music_wrap(klass, sfMusic_createFromStream(stream), holder);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
static VALUE Music_duration(VALUE self) {
|
|
90
|
+
return time_to_rb(sfMusic_getDuration(Get_Music_Struct(self)));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
static VALUE Music_channel_count(VALUE self) {
|
|
94
|
+
return UINT2NUM(sfMusic_getChannelCount(Get_Music_Struct(self)));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static VALUE Music_sample_rate(VALUE self) {
|
|
98
|
+
return UINT2NUM(sfMusic_getSampleRate(Get_Music_Struct(self)));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
static VALUE Music_channel_map(VALUE self) {
|
|
102
|
+
size_t count = 0;
|
|
103
|
+
const sfSoundChannel* map = sfMusic_getChannelMap(Get_Music_Struct(self), &count);
|
|
104
|
+
VALUE rb_array;
|
|
105
|
+
size_t i;
|
|
106
|
+
|
|
107
|
+
if (map == NULL) {
|
|
108
|
+
return rb_ary_new();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
rb_array = rb_ary_new_capa((long)count);
|
|
112
|
+
|
|
113
|
+
for (i = 0; i < count; i++) {
|
|
114
|
+
rb_ary_push(rb_array, ID2SYM(rb_intern(sound_channel_name(map[i]))));
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return rb_array;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Loop points are an offset plus a length, matching sfTimeSpan. Returned as a
|
|
121
|
+
two-element [offset, length] pair of SFML::Time. */
|
|
122
|
+
static VALUE Music_loop_points(VALUE self) {
|
|
123
|
+
sfTimeSpan span = sfMusic_getLoopPoints(Get_Music_Struct(self));
|
|
124
|
+
|
|
125
|
+
return rb_ary_new_from_args(2, time_to_rb(span.offset), time_to_rb(span.length));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static VALUE Music_set_loop_points(VALUE self, VALUE rb_span) {
|
|
129
|
+
sfTimeSpan span;
|
|
130
|
+
|
|
131
|
+
if (!RB_TYPE_P(rb_span, T_ARRAY) || RARRAY_LEN(rb_span) != 2) {
|
|
132
|
+
rb_raise(rb_eArgError, "loop points must be a two-element [offset, length] array");
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
span.offset = time_from_rb(rb_ary_entry(rb_span, 0));
|
|
136
|
+
span.length = time_from_rb(rb_ary_entry(rb_span, 1));
|
|
137
|
+
|
|
138
|
+
sfMusic_setLoopPoints(Get_Music_Struct(self), span);
|
|
139
|
+
|
|
140
|
+
return rb_span;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#define SS_FN(name) sfMusic_##name
|
|
144
|
+
#define SS_METHOD(name) Music_##name
|
|
145
|
+
#include "audio/sound_source.inc"
|
|
146
|
+
#undef SS_FN
|
|
147
|
+
#undef SS_METHOD
|
|
148
|
+
|
|
149
|
+
void Init_Music(VALUE rb_module) {
|
|
150
|
+
rb_cMusic = rb_define_class_under(rb_module, "Music", rb_cObject);
|
|
151
|
+
|
|
152
|
+
rb_define_singleton_method(rb_cMusic, "from_file", Music_from_file, 1);
|
|
153
|
+
rb_define_singleton_method(rb_cMusic, "from_memory", Music_from_memory, 1);
|
|
154
|
+
rb_define_singleton_method(rb_cMusic, "from_stream", Music_from_stream, 1);
|
|
155
|
+
|
|
156
|
+
rb_define_method(rb_cMusic, "duration", Music_duration, 0);
|
|
157
|
+
rb_define_method(rb_cMusic, "channel_count", Music_channel_count, 0);
|
|
158
|
+
rb_define_method(rb_cMusic, "sample_rate", Music_sample_rate, 0);
|
|
159
|
+
rb_define_method(rb_cMusic, "channel_map", Music_channel_map, 0);
|
|
160
|
+
rb_define_method(rb_cMusic, "loop_points", Music_loop_points, 0);
|
|
161
|
+
rb_define_method(rb_cMusic, "loop_points=", Music_set_loop_points, 1);
|
|
162
|
+
|
|
163
|
+
Music_define_sound_source_methods(rb_cMusic);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
VALUE Get_Klass_Music(void) {
|
|
167
|
+
return rb_cMusic;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void* Get_Music_Struct(VALUE self) {
|
|
171
|
+
Music* ptr;
|
|
172
|
+
TypedData_Get_Struct(self, Music, &Music_data_type, ptr);
|
|
173
|
+
return ptr->source.handle;
|
|
174
|
+
}
|
data/ext/audio/music.h
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#ifndef SFML_RB_AUDIO_MUSIC_H
|
|
2
|
+
#define SFML_RB_AUDIO_MUSIC_H
|
|
3
|
+
|
|
4
|
+
#include <ruby.h>
|
|
5
|
+
|
|
6
|
+
#include "core/sfml.h"
|
|
7
|
+
|
|
8
|
+
void Init_Music(VALUE rb_module);
|
|
9
|
+
|
|
10
|
+
VALUE Get_Klass_Music(void);
|
|
11
|
+
|
|
12
|
+
void *Get_Music_Struct(VALUE self);
|
|
13
|
+
|
|
14
|
+
#endif //SFML_RB_AUDIO_MUSIC_H
|