ray 0.0.0.pre2 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/.gitignore +1 -0
  2. data/.rspec +3 -0
  3. data/README.md +62 -0
  4. data/Rakefile +33 -23
  5. data/VERSION +1 -1
  6. data/ext/audio.c +473 -0
  7. data/ext/color.c +4 -4
  8. data/ext/event.c +25 -3
  9. data/ext/extconf.rb +35 -22
  10. data/ext/font.c +287 -0
  11. data/ext/image.c +682 -33
  12. data/ext/joystick.c +9 -9
  13. data/ext/ray.c +166 -55
  14. data/ext/ray.h +120 -9
  15. data/ext/ray_osx.m +161 -0
  16. data/ext/rect.c +31 -4
  17. data/lib/ray/audio.rb +52 -0
  18. data/lib/ray/color.rb +16 -0
  19. data/lib/ray/dsl.rb +1 -3
  20. data/lib/ray/dsl/event.rb +1 -39
  21. data/lib/ray/dsl/event_listener.rb +38 -0
  22. data/lib/ray/dsl/event_runner.rb +3 -1
  23. data/lib/ray/dsl/event_translator.rb +74 -8
  24. data/lib/ray/dsl/handler.rb +3 -33
  25. data/lib/ray/dsl/matcher.rb +129 -23
  26. data/lib/ray/font.rb +108 -0
  27. data/lib/ray/font_set.rb +37 -0
  28. data/lib/ray/game.rb +171 -34
  29. data/lib/ray/helper.rb +43 -5
  30. data/lib/ray/image.rb +90 -3
  31. data/lib/ray/image_set.rb +35 -0
  32. data/lib/ray/joystick.rb +30 -0
  33. data/lib/ray/music_set.rb +35 -0
  34. data/lib/ray/ray.rb +17 -9
  35. data/lib/ray/rect.rb +51 -0
  36. data/lib/ray/resource_set.rb +92 -0
  37. data/lib/ray/scene.rb +220 -51
  38. data/lib/ray/sound_set.rb +35 -0
  39. data/lib/ray/sprite.rb +184 -0
  40. data/psp/ext.c +4 -0
  41. data/samples/hello_world/hello.rb +35 -0
  42. data/samples/hello_world/hello_dsl.rb +24 -0
  43. data/samples/pong/pong.rb +128 -0
  44. data/samples/sokoban/level_1 +7 -0
  45. data/samples/sokoban/sokoban.rb +370 -0
  46. data/spec/ray/audio_spec.rb +146 -0
  47. data/spec/ray/color_spec.rb +13 -0
  48. data/spec/ray/event_spec.rb +57 -168
  49. data/spec/ray/font_spec.rb +93 -0
  50. data/spec/ray/image_set_spec.rb +48 -0
  51. data/spec/ray/image_spec.rb +130 -44
  52. data/spec/ray/joystick_spec.rb +13 -9
  53. data/spec/ray/matcher_spec.rb +32 -55
  54. data/spec/ray/ray_spec.rb +33 -31
  55. data/spec/ray/rect_spec.rb +80 -0
  56. data/spec/ray/resource_set_spec.rb +105 -0
  57. data/spec/ray/sprite_spec.rb +163 -0
  58. data/spec/res/VeraMono.ttf +0 -0
  59. data/spec/res/aqua2.bmp +0 -0
  60. data/spec/res/pop.wav +0 -0
  61. data/spec/spec.opts +4 -0
  62. data/spec/spec_helper.rb +8 -0
  63. data/yard_ext.rb +91 -0
  64. metadata +104 -38
  65. data/bin/ray +0 -5
  66. data/bin/ray_irb +0 -4
  67. data/ext/SDLMain.h +0 -17
  68. data/ext/SDLMain.m +0 -381
  69. data/lib/ray/config.rb +0 -84
  70. data/lib/ray/dsl/converter.rb +0 -65
  71. data/lib/ray/dsl/listener.rb +0 -30
  72. data/lib/ray/dsl/type.rb +0 -58
  73. data/spec/ray/config_spec.rb +0 -90
  74. data/spec/ray/conversion_spec.rb +0 -43
  75. data/spec/ray/type_spec.rb +0 -17
  76. data/spec_runner.rb +0 -27
data/.gitignore CHANGED
@@ -20,3 +20,4 @@ ext/ray
20
20
  /ext/mkmf.log
21
21
  ruby-1.8.*/
22
22
  ruby_stdlib/
23
+ autotest/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format html:report.html
2
+ --format p
3
+ -c
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # Hello world!
2
+ ## Subclassing Ray::Game or Ray::Scene
3
+ require 'ray'
4
+
5
+ class HelloScene < Ray::Scene
6
+ scene_name :hello
7
+
8
+ def setup
9
+ @font = font(path_of("VeraMono.ttf"), 12)
10
+ end
11
+
12
+ def render(win)
13
+ @font.draw("Hello world!", :on => win, :at => [0, 0])
14
+ end
15
+ end
16
+
17
+ class HelloWorld < Ray::Game
18
+ def initialize
19
+ super("Hello world!")
20
+
21
+ HelloScene.bind(self)
22
+ push_scene :hello
23
+ end
24
+
25
+ def register
26
+ add_hook :quit, method(:exit!)
27
+ end
28
+ end
29
+
30
+ HelloWorld.new.run
31
+ ## DSL
32
+ require 'ray'
33
+
34
+ Ray::Game.new("Hello world!") do
35
+ register do
36
+ add_hook :quit, method(:exit!)
37
+ end
38
+
39
+ scene :hello do
40
+ @font = font(path_of("VeraMono.ttf"), 12)
41
+
42
+ render do |win|
43
+ @font.draw("Hello world", :on => win, :at => [0, 0])
44
+ end
45
+ end
46
+
47
+ push_scene :hello
48
+ end
49
+ # Installation
50
+ Run the following command:
51
+
52
+ gem install ray
53
+
54
+ This requires the SDL to be installed. SDL_TTF, SDL_image, SDL_gfx, and
55
+ SDL_mixer are also needed for several features, though you can install ray
56
+ without them.
57
+ # Features
58
+ * Hides the event loop where registred blocks or methods are run when something
59
+ happens.
60
+ * Provides a cache for resources like images, fonts, sounds, ...
61
+ * Documented, using YARD. You can check the documentation on
62
+ [rubydoc.info](http://rubydoc.info/github/Mon-Ouie/ray/master/frames)
data/Rakefile CHANGED
@@ -2,22 +2,9 @@
2
2
  begin
3
3
  require 'yard'
4
4
 
5
- class MatcherHandler < YARD::Handlers::Ruby::Base
6
- handles method_call(:describe_matcher)
7
-
8
- def process
9
- src = statement.parameters.children.first.source[1..-1]
10
- MethodObject.new(Proxy.new(nil, "Ray::Matchers"), src) do |o|
11
- o.source = statement.source
12
- o.docstring = statement.comments
13
- o.visibility = :private
14
- end
15
- end
16
- end
17
-
18
5
  YARD::Rake::YardocTask.new do |t|
19
6
  t.files = ['lib/**/*.rb', 'ext/**/*.c', 'psp/*.c']
20
- t.options |= ["--private"]
7
+ t.options |= ["--private", "-e", "./yard_ext.rb"]
21
8
  end
22
9
  rescue LoadError
23
10
  $stderr.puts("YARD is not installed. Please install it " +
@@ -30,7 +17,8 @@ begin
30
17
  Jeweler::Tasks.new do |s|
31
18
  s.name = "ray"
32
19
 
33
- s.summary = ""
20
+ s.summary = "A library to write games (or to play with) in Ruby"
21
+ s.description = "Written to play with Ruby"
34
22
  s.homepage = "http://github.com/Mon-Ouie/ray"
35
23
 
36
24
  s.email = "mon.ouie@gmail.com"
@@ -38,20 +26,39 @@ begin
38
26
 
39
27
  s.files |= FileList["lib/**/*.rb"]
40
28
  s.files |= FileList["ext/**/*.{c,h,m}"]
41
- s.files |= FileList["bin/ray{,_irb}"]
42
29
 
43
- s.extensions << "ext/extconf.rb"
30
+ s.has_rdoc = "yard"
44
31
 
45
- s.executables << "ray" << "ray_irb"
32
+ s.extensions = ["ext/extconf.rb"]
33
+
34
+ s.add_development_dependency "jeweler"
35
+ s.add_development_dependency "yard"
36
+ s.add_development_dependency "rspec"
37
+ s.add_development_dependency "psp_task"
46
38
  end
47
39
  rescue LoadError
48
40
  $stderr.puts("Jeweler is not installed. Please install it " +
49
41
  "with the following command: gem intall jeweler")
50
42
  end
51
43
 
52
- desc "Run specs"
53
- task :spec do
54
- load "spec_runner.rb"
44
+ begin
45
+ begin
46
+ require 'spec/rake/spectask'
47
+
48
+ Spec::Rake::SpecTask.new(:spec) do |t|
49
+ t.spec_files = FileList['spec/**/*_spec\.rb']
50
+ t.fail_on_error = false
51
+ end
52
+ rescue LoadError
53
+ require 'rspec/core/rake_task'
54
+
55
+ RSpec::Core::RakeTask.new(:spec) do |t|
56
+ t.fail_on_error = false
57
+ end
58
+ end
59
+ rescue LoadError
60
+ $stderr.puts("RSpec is not installed. Please install it " +
61
+ "with the following command: gem install rspec")
55
62
  end
56
63
 
57
64
  namespace :ext do
@@ -95,12 +102,15 @@ begin
95
102
  syck/token.c syck/emitter.c syck/handler.c syck/node.c syck/syck.c
96
103
  syck/yaml2byte.c).map { |i| "psp/#{i}" }
97
104
 
98
- static_libs = ["-lSDL_image", "-lSDL", "-lGL", "-lpspvfpu",
105
+ static_libs = ["-lSDL_ttf", "-lSDL_mixer", "-lSDL_gfx", "-lSDL_image",
106
+ "-lSDL", "-lGL", "-lpspvfpu", "-lfreetype", "-lvorbisfile",
107
+ "-lvorbis", "-lmikmod", "-logg",
99
108
  "-lpspgu", "-lpspaudio", "-lpsprtc", "-lpsphprm", "-lpspwlan",
100
109
  "-lruby", "-lpng", "-ljpeg", "-lz","-lm", "-lc"]
101
110
 
102
111
  flags = ["-Wall", "-Wno-unused-parameter", "-D_PSP_ -DHAVE_STRUCT_TIMESPEC",
103
- "-DHAVE_SDL_IMAGE", "-G0"]
112
+ "-DHAVE_SDL_SDL_IMAGE_H", "-G0", "-DHAVE_SDL_SDL_ROTOZOOM_H",
113
+ "-DHAVE_SDL_SDL_TTF_H", "-DHAVE_SDL_SDL_MIXER_H", "-DUSE_RWOPS"]
104
114
 
105
115
  begin
106
116
  PSPTask.new do |t|
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.0.pre2
1
+ 0.0.1
data/ext/audio.c ADDED
@@ -0,0 +1,473 @@
1
+ #include "ray.h"
2
+
3
+ #ifdef HAVE_SDL_MIXER
4
+
5
+ VALUE ray_mAudio = Qnil;
6
+ VALUE ray_cSound = Qnil;
7
+ VALUE ray_cMusic = Qnil;
8
+
9
+ /* @return [Integer] The audio frequency */
10
+ VALUE ray_audio_frequency() {
11
+ int freq = 0, channels = 0;
12
+ uint16_t format = 0;
13
+ Mix_QuerySpec(&freq, &format, &channels);
14
+
15
+ return INT2FIX(freq);
16
+ }
17
+
18
+ /* @return [Integer] The audio format */
19
+ VALUE ray_audio_format() {
20
+ int freq = 0, channels = 0;
21
+ uint16_t format = 0;
22
+ Mix_QuerySpec(&freq, &format, &channels);
23
+
24
+ return INT2FIX(format);
25
+ }
26
+
27
+ /* @return [true, false] true if mono is used */
28
+ VALUE ray_audio_mono() {
29
+ int freq = 0, channels = 0;
30
+ uint16_t format = 0;
31
+ Mix_QuerySpec(&freq, &format, &channels);
32
+
33
+ return channels == 1 ? Qtrue : Qfalse;
34
+ }
35
+
36
+ /* @return [true, false] true if stereo is used */
37
+ VALUE ray_audio_stereo() {
38
+ int freq = 0, channels = 0;
39
+ uint16_t format = 0;
40
+ Mix_QuerySpec(&freq, &format, &channels);
41
+
42
+ return channels == 1 ? Qfalse : Qtrue;
43
+ }
44
+
45
+ /*
46
+ @return [Float] The volume for the song which is currently being played.
47
+ 0 is the minimum volume, whereas 100 is the maximum.
48
+ */
49
+ VALUE ray_audio_volume(VALUE self) {
50
+ int volume = Mix_VolumeMusic(-1);
51
+ return rb_float_new((volume / 128.0f) * 100.0f);
52
+ }
53
+
54
+ /* Sets the volume of the song which is currently being played */
55
+ VALUE ray_audio_set_volume(VALUE self, VALUE value) {
56
+ float volume = (float)NUM2DBL(value);
57
+ Mix_VolumeMusic((int)((volume / 100.0f) * 128.0f));
58
+
59
+ return value;
60
+ }
61
+
62
+ /*
63
+ @overload playing?(channel = nil)
64
+ @return [true, false] If channel is set, true if something is playing on
65
+ that channel. If it isn't, true if a music is currently being played.
66
+ */
67
+ VALUE ray_audio_playing(int argc, VALUE *argv, VALUE self) {
68
+ VALUE channel = Qnil;
69
+ rb_scan_args(argc, argv, "01", &channel);
70
+
71
+ if (NIL_P(channel))
72
+ return Mix_PlayingMusic() ? Qtrue : Qfalse;
73
+ return Mix_Playing(NUM2INT(channel)) ? Qtrue: Qfalse;
74
+ }
75
+
76
+ /*
77
+ @overload stop(channel = nil)
78
+ If channel is set, stops playback on a channel. Stops playing
79
+ the current music otherwise.
80
+ */
81
+ VALUE ray_audio_stop(int argc, VALUE *argv, VALUE self) {
82
+ VALUE channel;
83
+ rb_scan_args(argc, argv, "01", &channel);
84
+
85
+ if (!NIL_P(channel)) {
86
+ Mix_HaltChannel(NUM2INT(channel));
87
+ return channel;
88
+ }
89
+
90
+ Mix_HaltMusic();
91
+ return Qnil;
92
+ }
93
+
94
+ /*
95
+ @overload pause(channel = nil)
96
+ If channel is set, pauses a channel. Pauses the current music otherwise.
97
+ */
98
+ VALUE ray_audio_pause(int argc, VALUE *argv, VALUE self) {
99
+ VALUE channel;
100
+ rb_scan_args(argc, argv, "01", &channel);
101
+
102
+ if (!NIL_P(channel)) {
103
+ Mix_Pause(NUM2INT(channel));
104
+ return channel;
105
+ }
106
+
107
+ Mix_PauseMusic();
108
+ return Qnil;
109
+ }
110
+
111
+ /*
112
+ @overload resume(channel = nil)
113
+ If channel is set, resumes a paused channel from pause. Resumes the music
114
+ otherwise.
115
+ */
116
+ VALUE ray_audio_resume(int argc, VALUE *argv, VALUE self) {
117
+ VALUE channel;
118
+ rb_scan_args(argc, argv, "01", &channel);
119
+
120
+ if (!NIL_P(channel)) {
121
+ Mix_Resume(NUM2INT(channel));
122
+ return channel;
123
+ }
124
+
125
+ Mix_ResumeMusic();
126
+ return Qnil;
127
+ }
128
+
129
+ /*
130
+ @overload paused?(channel = nil)
131
+ @return [true, false] True if the channel is paused. If channel isn't set,
132
+ returns true if the current music isn't paused.
133
+ */
134
+ VALUE ray_audio_paused(int argc, VALUE *argv, VALUE self) {
135
+ VALUE channel;
136
+ rb_scan_args(argc, argv, "01", &channel);
137
+
138
+ if (!NIL_P(channel))
139
+ return Mix_Paused(NUM2INT(channel)) ? Qtrue : Qfalse;
140
+ return Mix_PausedMusic() ? Qtrue : Qfalse;
141
+ }
142
+
143
+ /*
144
+ @overload music_pos=(val)
145
+ Sets the position in the current music. May not be implemented for some
146
+ formats.
147
+ */
148
+ VALUE ray_audio_set_music_pos(VALUE self, VALUE val) {
149
+ Mix_SetMusicPosition(NUM2DBL(val));
150
+ return val;
151
+ }
152
+
153
+ Mix_Chunk *ray_rb2chunk(VALUE object) {
154
+ if (!RAY_IS_A(object, ray_cSound)) {
155
+ rb_raise(rb_eTypeError, "Can't convert %s into Ray::Sound",
156
+ RAY_OBJ_CLASSNAME(object));
157
+ }
158
+
159
+ ray_sound *ptr = NULL;
160
+ Data_Get_Struct(object, ray_sound, ptr);
161
+
162
+ return ptr->sound;
163
+ }
164
+
165
+ void ray_free_sound(ray_sound *sound) {
166
+ if (sound->sound) Mix_FreeChunk(sound->sound);
167
+ free(sound);
168
+ }
169
+
170
+ VALUE ray_alloc_sound(VALUE self) {
171
+ ray_sound *ptr = malloc(sizeof(ray_sound));
172
+ ptr->sound = NULL;
173
+
174
+ VALUE ret = Data_Wrap_Struct(self, 0, ray_free_sound, ptr);
175
+
176
+ return ret;
177
+ }
178
+
179
+ void ray_init_sound_with_filename(VALUE self, VALUE filename) {
180
+ char *c_filename = StringValuePtr(filename);
181
+ ray_sound *sound = NULL;
182
+ Data_Get_Struct(self, ray_sound, sound);
183
+
184
+ sound->sound = Mix_LoadWAV(c_filename);
185
+ if (!sound->sound) {
186
+ rb_raise(rb_eRuntimeError, "Could not load sound (%s)",
187
+ Mix_GetError());
188
+ }
189
+ }
190
+
191
+ void ray_init_sound_with_io(VALUE self, VALUE io) {
192
+ ray_sound *sound = NULL;
193
+ Data_Get_Struct(self, ray_sound, sound);
194
+
195
+ VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
196
+ char *content = StringValuePtr(string);
197
+ SDL_RWops *data = SDL_RWFromMem(content, (int)RSTRING_LEN(string));
198
+
199
+ if (!data) {
200
+ rb_raise(rb_eRuntimeError, "Could not create music data (%s)",
201
+ SDL_GetError());
202
+ }
203
+
204
+ sound->sound = Mix_LoadWAV_RW(data, 1);
205
+ if (!sound->sound) {
206
+ rb_raise(rb_eRuntimeError, "Could not load sound (%s)",
207
+ Mix_GetError());
208
+ }
209
+ }
210
+
211
+ /*
212
+ Creates a new sound from an IO object or a filename.
213
+ */
214
+ VALUE ray_init_sound(VALUE self, VALUE arg) {
215
+ if (rb_respond_to(arg, RAY_METH("to_str")))
216
+ ray_init_sound_with_filename(self, rb_String(arg));
217
+ else if (rb_respond_to(arg, RAY_METH("read")))
218
+ ray_init_sound_with_io(self, arg);
219
+ else {
220
+ rb_raise(rb_eTypeError, "Can't convert %s into String",
221
+ RAY_OBJ_CLASSNAME(arg));
222
+ }
223
+
224
+ return Qnil;
225
+ }
226
+
227
+ /*
228
+ @overload play(channel = 0, times = 1)
229
+ Plays a sound on the given channel a given number of times.
230
+ @param [Integer, :forever] times How many times the sound should be played.
231
+ Can also be :forever or 0 to play it forever.
232
+ */
233
+ VALUE ray_sound_play(int argc, VALUE *argv, VALUE self) {
234
+ VALUE channel, times;
235
+ rb_scan_args(argc, argv, "02", &channel, &times);
236
+
237
+ if (NIL_P(channel)) channel = INT2FIX(0);
238
+ if (NIL_P(times)) times = INT2FIX(1);
239
+
240
+ int c_channel = NUM2INT(channel), c_times = 0;
241
+ if (times == RAY_SYM("forever"))
242
+ c_times = 0;
243
+ else
244
+ c_times = NUM2INT(times);
245
+
246
+ Mix_Chunk *chunk = ray_rb2chunk(self);
247
+ Mix_PlayChannel(c_channel, chunk, c_times - 1);
248
+
249
+ return self;
250
+ }
251
+
252
+ /*
253
+ @overload fade(duration, channel = 0, times = 1)
254
+ Same as play, but fades for a given number of a seconds.
255
+ @param [Float] duration Duration of the fade, in seconds.
256
+ @see Ray::Sound#play
257
+ */
258
+ VALUE ray_sound_fade(int argc, VALUE *argv, VALUE self) {
259
+ VALUE duration, channel, times;
260
+ rb_scan_args(argc, argv, "12", &duration, &channel, &times);
261
+
262
+ if (NIL_P(channel)) channel = INT2FIX(0);
263
+ if (NIL_P(times)) times = INT2FIX(1);
264
+
265
+ int c_channel = NUM2INT(channel), c_times = 0;
266
+ if (times == RAY_SYM("forever"))
267
+ c_times = 0;
268
+ else
269
+ c_times = NUM2INT(times);
270
+
271
+ Mix_Chunk *chunk = ray_rb2chunk(self);
272
+ Mix_FadeInChannel(c_channel, chunk, c_times - 1,
273
+ (int)(NUM2DBL(duration) * 1000));
274
+
275
+ return self;
276
+ }
277
+
278
+ /* @return [Float] Volume of the sound, between 0 and 100. */
279
+ VALUE ray_sound_volume(VALUE self) {
280
+ Mix_Chunk *chunk = ray_rb2chunk(self);
281
+ int volume = Mix_VolumeChunk(chunk, -1);
282
+
283
+ return rb_float_new((volume / 128.0f) * 100.0f);
284
+ }
285
+
286
+ /* Sets the volume of the sound. */
287
+ VALUE ray_sound_set_volume(VALUE self, VALUE value) {
288
+ Mix_Chunk *chunk = ray_rb2chunk(self);
289
+ float volume = (float)NUM2DBL(value);
290
+ Mix_VolumeChunk(chunk, (int)((volume / 100.0f) * 128.0f));
291
+
292
+ return value;
293
+ }
294
+
295
+ Mix_Music *ray_rb2music(VALUE object) {
296
+ if (!RAY_IS_A(object, ray_cMusic)) {
297
+ rb_raise(rb_eTypeError, "Can't convert %s into Ray::Music",
298
+ RAY_OBJ_CLASSNAME(object));
299
+ }
300
+
301
+ ray_music *ptr = NULL;
302
+ Data_Get_Struct(object, ray_music, ptr);
303
+
304
+ return ptr->music;
305
+ }
306
+
307
+ void ray_free_music(ray_music *music) {
308
+ if (music->music) Mix_FreeMusic(music->music);
309
+ free(music);
310
+ }
311
+
312
+ VALUE ray_alloc_music(VALUE self) {
313
+ ray_music *ptr = malloc(sizeof(ray_music));
314
+ ptr->music = NULL;
315
+
316
+ VALUE ret = Data_Wrap_Struct(self, 0, ray_free_music, ptr);
317
+
318
+ return ret;
319
+ }
320
+
321
+ void ray_init_music_with_filename(VALUE self, VALUE filename) {
322
+ char *c_filename = StringValuePtr(filename);
323
+ ray_music *music = NULL;
324
+ Data_Get_Struct(self, ray_music, music);
325
+
326
+ music->music = Mix_LoadMUS(c_filename);
327
+ if (!music->music) {
328
+ rb_raise(rb_eRuntimeError, "Could not load music (%s)",
329
+ Mix_GetError());
330
+ }
331
+ }
332
+
333
+ void ray_init_music_with_io(VALUE self, VALUE io) {
334
+ ray_music *music = NULL;
335
+ Data_Get_Struct(self, ray_music, music);
336
+
337
+ VALUE string = rb_funcall2(io, RAY_METH("read"), 0, NULL);
338
+ char *content = StringValuePtr(string);
339
+ SDL_RWops *data = SDL_RWFromMem(content, (int)RSTRING_LEN(string));
340
+
341
+ if (!data) {
342
+ rb_raise(rb_eRuntimeError, "Could not create music data (%s)",
343
+ SDL_GetError());
344
+ }
345
+
346
+ music->music = Mix_LoadMUS_RW(data);
347
+ if (!music->music) {
348
+ rb_raise(rb_eRuntimeError, "Could not load music (%s)",
349
+ Mix_GetError());
350
+ }
351
+
352
+ SDL_FreeRW(data);
353
+ }
354
+
355
+ /*
356
+ Creates a new music from an IO object or a filename.
357
+ */
358
+ VALUE ray_init_music(VALUE self, VALUE arg) {
359
+ if (rb_respond_to(arg, RAY_METH("to_str")))
360
+ ray_init_music_with_filename(self, rb_String(arg));
361
+ else if (rb_respond_to(arg, RAY_METH("read")))
362
+ ray_init_music_with_io(self, arg);
363
+ else {
364
+ rb_raise(rb_eTypeError, "Can't convert %s into String",
365
+ RAY_OBJ_CLASSNAME(arg));
366
+ }
367
+
368
+ return Qnil;
369
+ }
370
+
371
+ /* @return [Integer] The type of the music */
372
+ VALUE ray_music_type(VALUE self) {
373
+ Mix_Music *music = ray_rb2music(self);
374
+ Mix_MusicType ret = Mix_GetMusicType(music);
375
+
376
+ return INT2FIX(ret);
377
+ }
378
+
379
+ /*
380
+ @overload play(times = 1)
381
+ Plays the music a given number of times.
382
+ @param [Integer, :forever] times How many times the music should be played.
383
+ Can also be :forever or 0 to play it forever.
384
+ */
385
+ VALUE ray_music_play(int argc, VALUE *argv, VALUE self) {
386
+ VALUE times;
387
+ rb_scan_args(argc, argv, "01", &times);
388
+
389
+ if (NIL_P(times)) times = INT2FIX(1);
390
+
391
+ int c_times = 0;
392
+ if (times == RAY_SYM("forever"))
393
+ c_times = 0;
394
+ else
395
+ c_times = NUM2INT(times);
396
+
397
+ Mix_Music *music = ray_rb2music(self);
398
+ Mix_PlayMusic(music, c_times);
399
+
400
+ return self;
401
+ }
402
+
403
+ /*
404
+ Document-class: Ray::Music
405
+
406
+ Class used to play music. Notice only one music can be played at the
407
+ same time.
408
+ */
409
+
410
+ /*
411
+ Document-class: Ray::Sound
412
+
413
+ Class used to represent short sounds. You can play one sound per channel.
414
+ */
415
+
416
+ void Init_ray_audio() {
417
+ ray_mAudio = rb_define_module_under(ray_mRay, "Audio");
418
+
419
+ rb_define_const(ray_mAudio, "FORMAT_U8", INT2FIX(AUDIO_U8));
420
+ rb_define_const(ray_mAudio, "FORMAT_S8", INT2FIX(AUDIO_S8));
421
+ rb_define_const(ray_mAudio, "FORMAT_U16LSB", INT2FIX(AUDIO_U16LSB));
422
+ rb_define_const(ray_mAudio, "FORMAT_S16LSB", INT2FIX(AUDIO_S16LSB));
423
+ rb_define_const(ray_mAudio, "FORMAT_U16MSB", INT2FIX(AUDIO_U16MSB));
424
+ rb_define_const(ray_mAudio, "FORMAT_S16MSB", INT2FIX(AUDIO_S16MSB));
425
+ rb_define_const(ray_mAudio, "FORMAT_U16", INT2FIX(AUDIO_U16));
426
+ rb_define_const(ray_mAudio, "FORMAT_S16", INT2FIX(AUDIO_S16));
427
+ rb_define_const(ray_mAudio, "FORMAT_U16SYS", INT2FIX(AUDIO_U16SYS));
428
+ rb_define_const(ray_mAudio, "FORMAT_S16SYS", INT2FIX(AUDIO_S16SYS));
429
+
430
+ rb_define_module_function(ray_mAudio, "frequency", ray_audio_frequency, 0);
431
+ rb_define_module_function(ray_mAudio, "format", ray_audio_format, 0);
432
+ rb_define_module_function(ray_mAudio, "mono?", ray_audio_mono, 0);
433
+ rb_define_module_function(ray_mAudio, "stereo?", ray_audio_stereo, 0);
434
+
435
+ rb_define_module_function(ray_mAudio, "volume", ray_audio_volume, 0);
436
+ rb_define_module_function(ray_mAudio, "volume=", ray_audio_set_volume, 1);
437
+
438
+ rb_define_module_function(ray_mAudio, "stop", ray_audio_stop, -1);
439
+ rb_define_module_function(ray_mAudio, "pause", ray_audio_pause, -1);
440
+ rb_define_module_function(ray_mAudio, "resume", ray_audio_resume, -1);
441
+ rb_define_module_function(ray_mAudio, "paused?", ray_audio_paused, -1);
442
+ rb_define_module_function(ray_mAudio, "playing?", ray_audio_playing, -1);
443
+
444
+ rb_define_module_function(ray_mAudio, "music_pos=", ray_audio_set_music_pos, 1);
445
+
446
+ ray_cSound = rb_define_class_under(ray_mRay, "Sound", rb_cObject);
447
+ rb_define_alloc_func(ray_cSound, ray_alloc_sound);
448
+ rb_define_method(ray_cSound, "initialize", ray_init_sound, 1);
449
+ rb_define_method(ray_cSound, "play", ray_sound_play, -1);
450
+ rb_define_method(ray_cSound, "fade", ray_sound_fade, -1);
451
+ rb_define_method(ray_cSound, "volume", ray_sound_volume, 0);
452
+ rb_define_method(ray_cSound, "volume=", ray_sound_set_volume, 1);
453
+
454
+ ray_cMusic = rb_define_class_under(ray_mRay, "Music", rb_cObject);
455
+ rb_define_alloc_func(ray_cMusic, ray_alloc_music);
456
+ rb_define_method(ray_cMusic, "initialize", ray_init_music, 1);
457
+ rb_define_method(ray_cMusic, "type", ray_music_type, 0);
458
+ rb_define_method(ray_cMusic, "play", ray_music_play, -1);
459
+
460
+ rb_define_const(ray_cMusic, "TYPE_NONE", INT2FIX(MUS_NONE));
461
+ rb_define_const(ray_cMusic, "TYPE_CMD", INT2FIX(MUS_CMD));
462
+ rb_define_const(ray_cMusic, "TYPE_WAV", INT2FIX(MUS_WAV));
463
+ rb_define_const(ray_cMusic, "TYPE_MOD", INT2FIX(MUS_MOD));
464
+ rb_define_const(ray_cMusic, "TYPE_MID", INT2FIX(MUS_MID));
465
+ rb_define_const(ray_cMusic, "TYPE_OGG", INT2FIX(MUS_OGG));
466
+ rb_define_const(ray_cMusic, "TYPE_MP3", INT2FIX(MUS_MP3));
467
+ #ifndef PSP
468
+ rb_define_const(ray_cMusic, "TYPE_MP3_MAD", INT2FIX(MUS_MP3_MAD));
469
+ rb_define_const(ray_cMusic, "TYPE_FLAC", INT2FIX(MUS_FLAC));
470
+ #endif
471
+ }
472
+
473
+ #endif