ray 0.0.0.pre2 → 0.0.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.
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