ruby-sdl2 0.1.0 → 0.2.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.
data/mixer.c CHANGED
@@ -1,3 +1,4 @@
1
+ /* -*- mode: C -*- */
1
2
  #ifdef HAVE_SDL_MIXER_H
2
3
  #include "rubysdl2_internal.h"
3
4
  #include <SDL_mixer.h>
@@ -232,6 +233,9 @@ static VALUE Channels_s_allocate(VALUE self, VALUE num_channels)
232
233
 
233
234
  /*
234
235
  * @overload reserve(num)
236
+ * Reserve channel from 0 to num-1 and reserved channels are not used by
237
+ * {Channels.play} and {Channels.fade_in} with **channels**==-1.
238
+ *
235
239
  * @param num [Integer]
236
240
  * @return [Integer]
237
241
  */
@@ -520,29 +524,73 @@ static VALUE Channels_s_playing_chunk(VALUE self, VALUE channel)
520
524
  return rb_ary_entry(playing_chunks, NUM2INT(channel));
521
525
  }
522
526
 
527
+ /*
528
+ * Document-class: SDL2::Mixer::Channels::Group
529
+ *
530
+ * This class represents a channel group. A channel group is
531
+ * a set of channels and you can stop playing and fade out playing
532
+ * channels of an group at the same time.
533
+ *
534
+ * Each channel group is identified by an integer called tag.
535
+ */
536
+
537
+ /*
538
+ * Initialize the channel with given **tag**.
539
+ *
540
+ * Groups with a common tag are identified.
541
+ */
523
542
  static VALUE Group_initialize(VALUE self, VALUE tag)
524
543
  {
525
544
  rb_iv_set(self, "@tag", tag);
526
545
  return Qnil;
527
546
  }
528
547
 
548
+ /*
549
+ * Get the default channel group.
550
+ *
551
+ * The default channel group refers all channels in the mixer system.
552
+ *
553
+ * @return [SDL2::Mixer::Channels::Group]
554
+ */
529
555
  static VALUE Group_s_default(VALUE self)
530
556
  {
531
557
  VALUE tag = INT2FIX(-1);
532
558
  return rb_class_new_instance(1, &tag, self);
533
559
  }
534
560
 
561
+ /*
562
+ * Get the tag of the group.
563
+ *
564
+ * @return [Integer]
565
+ */
535
566
  inline static int Group_tag(VALUE group)
536
567
  {
537
568
  return NUM2INT(rb_iv_get(group, "@tag"));
538
569
  }
539
570
 
571
+ /*
572
+ * @overload ==(other)
573
+ * Return true if **self** and **other** are same.
574
+ *
575
+ * **self** and **other** are considered to be same
576
+ * if they have the same tag.
577
+ *
578
+ * @param other [SDL2::Mixer::Channel::Group] a compared object
579
+ * @return [Boolean]
580
+ */
540
581
  static VALUE Group_eq(VALUE self, VALUE other)
541
582
  {
542
583
  return INT2BOOL(rb_obj_is_instance_of(other, cGroup) &&
543
584
  Group_tag(self) == Group_tag(other));
544
585
  }
545
586
 
587
+ /*
588
+ * @overload add(which)
589
+ * Add a channel to the group.
590
+ *
591
+ * @param which [Integer] a channel id
592
+ * @return [nil]
593
+ */
546
594
  static VALUE Group_add(VALUE self, VALUE which)
547
595
  {
548
596
  if (!Mix_GroupChannel(NUM2INT(which), Group_tag(self))) {
@@ -552,37 +600,85 @@ static VALUE Group_add(VALUE self, VALUE which)
552
600
  return Qnil;
553
601
  }
554
602
 
603
+ /*
604
+ * Get the number of channels belong to the group.
605
+ *
606
+ * @return [Integer]
607
+ */
555
608
  static VALUE Group_count(VALUE self)
556
609
  {
557
610
  return INT2NUM(Mix_GroupCount(Group_tag(self)));
558
611
  }
559
612
 
613
+ /*
614
+ * Return the first available channel in the group.
615
+ *
616
+ * Return -1 if no channel is available.
617
+ *
618
+ * @return [Integer]
619
+ */
560
620
  static VALUE Group_available(VALUE self)
561
621
  {
562
622
  return INT2NUM(Mix_GroupAvailable(Group_tag(self)));
563
623
  }
564
624
 
625
+ /*
626
+ * Return the oldest cahnnel in the group.
627
+ *
628
+ * Return -1 if no channel is available.
629
+ *
630
+ * @return [Integer]
631
+ */
565
632
  static VALUE Group_oldest(VALUE self)
566
633
  {
567
634
  return INT2NUM(Mix_GroupOldest(Group_tag(self)));
568
635
  }
569
636
 
637
+ /*
638
+ * Return the newer cahnnel in the group.
639
+ *
640
+ * Return -1 if no channel is available.
641
+ *
642
+ * @return [Integer]
643
+ */
570
644
  static VALUE Group_newer(VALUE self)
571
645
  {
572
646
  return INT2NUM(Mix_GroupNewer(Group_tag(self)));
573
647
  }
574
648
 
649
+ /*
650
+ * @overload fade_out(ms)
651
+ * Halt playing of all channels in the group with fade-out effect.
652
+ *
653
+ * @param ms [Integer] milliseconds of fade-out effect
654
+ * @return [Integer] the number of channels affected by this method
655
+ * @see Channels.fade_out
656
+ * @see .halt
657
+ */
575
658
  static VALUE Group_fade_out(VALUE self, VALUE ms)
576
659
  {
577
660
  return INT2NUM(Mix_FadeOutGroup(Group_tag(self), NUM2INT(ms)));
578
661
  }
579
662
 
663
+ /*
664
+ * Halt playing of all channels in the group.
665
+ *
666
+ * @return [nil]
667
+ * @see Channels.halt
668
+ * @see .fade_out
669
+ */
580
670
  static VALUE Group_halt(VALUE self)
581
671
  {
582
672
  Mix_HaltGroup(Group_tag(self));
583
673
  return Qnil;
584
674
  }
585
675
 
676
+ /*
677
+ * Document-module: SDL2::Mixer::MusicChannel
678
+ *
679
+ * This module provides the functions to play {SDL2::Mixer::Music}.
680
+ */
681
+
586
682
  /*
587
683
  * @overload play(music, loops)
588
684
  * Play **music** **loops** times.
@@ -596,7 +692,7 @@ static VALUE Group_halt(VALUE self)
596
692
  *
597
693
  * @return [nil]
598
694
  *
599
- * @see {.fade_in}
695
+ * @see .fade_in
600
696
  *
601
697
  */
602
698
  static VALUE MusicChannel_s_play(VALUE self, VALUE music, VALUE loops)
@@ -622,7 +718,7 @@ static VALUE MusicChannel_s_play(VALUE self, VALUE music, VALUE loops)
622
718
  *
623
719
  * @return [nil]
624
720
  *
625
- * @see {.play}
721
+ * @see .play
626
722
  */
627
723
  static VALUE MusicChannel_s_fade_in(int argc, VALUE* argv, VALUE self)
628
724
  {
@@ -970,31 +1066,50 @@ void rubysdl2_init_mixer(void)
970
1066
  rb_define_module_function(mMixer, "close", Mixer_s_close, 0);
971
1067
  rb_define_module_function(mMixer, "query", Mixer_s_query, 0);
972
1068
 
973
- #define DEFINE_MIX_INIT(t) \
974
- rb_define_const(mMixer, "INIT_" #t, UINT2NUM(MIX_INIT_##t))
975
- DEFINE_MIX_INIT(FLAC);
976
- DEFINE_MIX_INIT(MOD);
977
- DEFINE_MIX_INIT(MODPLUG);
978
- DEFINE_MIX_INIT(MP3);
979
- DEFINE_MIX_INIT(OGG);
980
- DEFINE_MIX_INIT(FLUIDSYNTH);
981
-
982
- #define DEFINE_MIX_FORMAT(t) \
983
- rb_define_const(mMixer, "FORMAT_" #t, UINT2NUM(AUDIO_##t))
984
- DEFINE_MIX_FORMAT(U8);
985
- DEFINE_MIX_FORMAT(S8);
986
- DEFINE_MIX_FORMAT(U16LSB);
987
- DEFINE_MIX_FORMAT(S16LSB);
988
- DEFINE_MIX_FORMAT(U16MSB);
989
- DEFINE_MIX_FORMAT(S16MSB);
990
- DEFINE_MIX_FORMAT(U16SYS);
991
- DEFINE_MIX_FORMAT(S16SYS);
1069
+ /* */
1070
+ /* Initialize Ogg flac loader */
1071
+ rb_define_const(mMixer, "INIT_FLAC", UINT2NUM(MIX_INIT_FLAC));
1072
+ /* Initialize MOD loader */
1073
+ rb_define_const(mMixer, "INIT_MOD", UINT2NUM(MIX_INIT_MOD));
1074
+ /* Initialize libmodplug */
1075
+ rb_define_const(mMixer, "INIT_MODPLUG", UINT2NUM(MIX_INIT_MODPLUG));
1076
+ /* Initialize MP3 loader */
1077
+ rb_define_const(mMixer, "INIT_MP3", UINT2NUM(MIX_INIT_MP3));
1078
+ /* Initialize Ogg vorbis loader */
1079
+ rb_define_const(mMixer, "INIT_OGG", UINT2NUM(MIX_INIT_OGG));
1080
+ /* Initialize fluidsynth */
1081
+ rb_define_const(mMixer, "INIT_FLUIDSYNTH", UINT2NUM(MIX_INIT_FLUIDSYNTH));
1082
+
1083
+ /* */
1084
+ /* Unsiged 8-bit sample format. Used by {Mixer.open} */
1085
+ rb_define_const(mMixer, "FORMAT_U8", UINT2NUM(AUDIO_U8));
1086
+ /* Siged 8-bit sample format. Used by {Mixer.open} */
1087
+ rb_define_const(mMixer, "FORMAT_S8", UINT2NUM(AUDIO_S8));
1088
+ /* Unsiged 16-bit little-endian sample format. Used by {Mixer.open} */
1089
+ rb_define_const(mMixer, "FORMAT_U16LSB", UINT2NUM(AUDIO_U16LSB));
1090
+ /* Siged 16-bit little-endian sample format. Used by {Mixer.open} */
1091
+ rb_define_const(mMixer, "FORMAT_S16LSB", UINT2NUM(AUDIO_S16LSB));
1092
+ /* Unsiged 16-bit big-endian sample format. Used by {Mixer.open} */
1093
+ rb_define_const(mMixer, "FORMAT_U16MSB", UINT2NUM(AUDIO_U16MSB));
1094
+ /* Unsiged 16-bit big-endian sample format. Used by {Mixer.open} */
1095
+ rb_define_const(mMixer, "FORMAT_S16MSB", UINT2NUM(AUDIO_S16MSB));
1096
+ /* Unsiged 16-bit sample format. Endian is same as system byte order. Used by {Mixer.open} */
1097
+ rb_define_const(mMixer, "FORMAT_U16SYS", UINT2NUM(AUDIO_U16SYS));
1098
+ /* Siged 16-bit sample format. Endian is same as system byte order. Used by {Mixer.open} */
1099
+ rb_define_const(mMixer, "FORMAT_S16SYS", UINT2NUM(AUDIO_S16SYS));
1100
+ /* Default frequency. 22050 (Hz) */
992
1101
  rb_define_const(mMixer, "DEFAULT_FREQUENCY", UINT2NUM(MIX_DEFAULT_FREQUENCY));
1102
+ /* Default sample format. Same as {Mixer::FORMAT_S16SYS}. */
993
1103
  rb_define_const(mMixer, "DEFAULT_FORMAT", UINT2NUM(MIX_DEFAULT_FORMAT));
1104
+ /* Default number of channels. 2. */
994
1105
  rb_define_const(mMixer, "DEFAULT_CHANNELS", INT2FIX(MIX_DEFAULT_CHANNELS));
1106
+ /* Max volume value. 128. */
995
1107
  rb_define_const(mMixer, "MAX_VOLUME", INT2FIX(MIX_MAX_VOLUME));
1108
+ /* This constants represents that the channel is not fading in and fading out. */
996
1109
  rb_define_const(mMixer, "NO_FADING", INT2FIX(MIX_NO_FADING));
1110
+ /* This constants represents that the channel is fading out. */
997
1111
  rb_define_const(mMixer, "FADING_OUT", INT2FIX(MIX_FADING_OUT));
1112
+ /* This constants represents that the channel is fading in. */
998
1113
  rb_define_const(mMixer, "FADING_IN", INT2FIX(MIX_FADING_IN));
999
1114
 
1000
1115
 
@@ -1007,6 +1122,7 @@ void rubysdl2_init_mixer(void)
1007
1122
  rb_define_method(cChunk, "volume", Chunk_volume, 0);
1008
1123
  rb_define_method(cChunk, "volume=", Chunk_set_volume, 1);
1009
1124
  rb_define_method(cChunk, "inspect", Chunk_inspect, 0);
1125
+ /* @return [String] The file name of the file from which the sound is loaded. */
1010
1126
  rb_define_attr(cChunk, "filename", 1, 0);
1011
1127
 
1012
1128
 
@@ -1040,6 +1156,7 @@ void rubysdl2_init_mixer(void)
1040
1156
  cGroup = rb_define_class_under(mChannels, "Group", rb_cObject);
1041
1157
  rb_define_method(cGroup, "initialize", Group_initialize, 1);
1042
1158
  rb_define_singleton_method(cGroup, "default", Group_s_default, 0);
1159
+ /* @return [Integer] tag id */
1043
1160
  rb_define_attr(cGroup, "tag", 1, 0);
1044
1161
  rb_define_method(cGroup, "==", Group_eq, 1);
1045
1162
  rb_define_method(cGroup, "add", Group_add, 1);
@@ -0,0 +1,1196 @@
1
+ /* -*- mode: C -*- */
2
+ #ifdef HAVE_SDL_MIXER_H
3
+ #include "rubysdl2_internal.h"
4
+ #include <SDL_mixer.h>
5
+
6
+ static VALUE mMixer;
7
+ static VALUE cChunk;
8
+ static VALUE cMusic;
9
+ static VALUE mChannels;
10
+ static VALUE cGroup;
11
+ static VALUE mMusicChannel;
12
+
13
+ static VALUE playing_chunks = Qnil;
14
+ static VALUE playing_music = Qnil;
15
+
16
+ #define MIX_ERROR() do { HANDLE_ERROR(SDL_SetError(Mix_GetError())); } while(0)
17
+ #define HANDLE_MIX_ERROR(code) \
18
+ do { if ((code) < 0) { MIX_ERROR(); } } while (0)
19
+
20
+ typedef struct Chunk {
21
+ Mix_Chunk* chunk;
22
+ } Chunk;
23
+
24
+ typedef struct Music {
25
+ Mix_Music* music;
26
+ } Music;
27
+
28
+ static void Chunk_free(Chunk* c)
29
+ {
30
+ if (rubysdl2_is_active() && c->chunk)
31
+ Mix_FreeChunk(c->chunk);
32
+ free(c);
33
+ }
34
+
35
+ static VALUE Chunk_new(Mix_Chunk* chunk)
36
+ {
37
+ Chunk* c = ALLOC(Chunk);
38
+ c->chunk = chunk;
39
+ return Data_Wrap_Struct(cChunk, 0, Chunk_free, c);
40
+ }
41
+
42
+ DEFINE_WRAPPER(Mix_Chunk, Chunk, chunk, cChunk, "SDL2::Mixer::Chunk");
43
+
44
+ static void Music_free(Music* m)
45
+ {
46
+ if (rubysdl2_is_active() && m->music)
47
+ Mix_FreeMusic(m->music);
48
+ free(m);
49
+ }
50
+
51
+ static VALUE Music_new(Mix_Music* music)
52
+ {
53
+ Music* c = ALLOC(Music);
54
+ c->music = music;
55
+ return Data_Wrap_Struct(cMusic, 0, Music_free, c);
56
+ }
57
+
58
+ DEFINE_WRAPPER(Mix_Music, Music, music, cMusic, "SDL2::Mixer::Music");
59
+
60
+ /*
61
+ * Document-module: SDL2::Mixer
62
+ *
63
+ * Sound mixing module.
64
+ *
65
+ * With this module, you can play many kinds of sound files such as:
66
+ *
67
+ * * WAVE/RIFF (.wav)
68
+ * * AIFF (.aiff)
69
+ * * VOC (.voc)
70
+ * * MOD (.mod .xm .s3m .669 .it .med etc.)
71
+ * * MIDI (.mid)
72
+ * * OggVorbis (.ogg)
73
+ * * MP3 (.mp3)
74
+ * * FLAC (.flac)
75
+ *
76
+ * Before playing sounds,
77
+ * you need to initialize this module by {.init} and
78
+ * open a sound device by {.open}.
79
+ *
80
+ * This module mixes multiple sound sources in parallel.
81
+ * To play a sound source, you assign the source to a "channel"
82
+ * and this module mixes all sound sources assigned to the channels.
83
+ *
84
+ * In this module, there are two types of sound sources:
85
+ * {SDL2::Mixer::Chunk} and {SDL2::Mixer::Music}.
86
+ * And there are two corresponding types of channels:
87
+ * {SDL2::Mixer::Channels} and {SDL2::Mixer::MusicChannel}.
88
+ *
89
+ * {SDL2::Mixer::Channels} module plays {SDL2::Mixer::Chunk} objects,
90
+ * through multiple (default eight) channels. This module is suitable
91
+ * for the sound effects.
92
+ * The number of channels is variable with {SDL2::Mixer::Channels.allocate}.
93
+ *
94
+ * {SDL2::Mixer::MusicChannel} module plays {SDL2::Mixer::Music} objects.
95
+ * This module has only one playing channel, and you cannot play
96
+ * multiple music in parallel. However an {SDL2::Mixer::Music} object
97
+ * is more efficient for memory, and this module supports more file formats
98
+ * than {SDL2::Mixer::Channels}.
99
+ * This module is suitable for playing "BGMs" of your application.
100
+ *
101
+ */
102
+
103
+ /*
104
+ * @overload init(flags)
105
+ * Initialize the mixer library.
106
+ *
107
+ * This module function load dynamically-linked libraries for sound file
108
+ * formats such as ogg and flac.
109
+ *
110
+ * You can give the initialized libraries (file formats) with OR'd bits of the
111
+ * following constants:
112
+ *
113
+ * * SDL2::Mixer::INIT_FLAC
114
+ * * SDL2::Mixer::INIT_MOD
115
+ * * SDL2::Mixer::INIT_MODPLUG
116
+ * * SDL2::Mixer::INIT_MP3
117
+ * * SDL2::Mixer::INIT_OGG
118
+ * * SDL2::Mixer::INIT_FLUIDSYNTH
119
+ *
120
+ * @param flags [Integer] intialized sublibraries
121
+ * @return [nil]
122
+ *
123
+ */
124
+ static VALUE Mixer_s_init(VALUE self, VALUE f)
125
+ {
126
+ int flags = NUM2INT(f);
127
+ if (Mix_Init(flags) & flags != flags)
128
+ rb_raise(eSDL2Error, "Couldn't initialize SDL_mixer");
129
+
130
+ return Qnil;
131
+ }
132
+
133
+ static void check_channel(VALUE ch, int allow_minus_1)
134
+ {
135
+ int channel = NUM2INT(ch);
136
+ if (channel >= Mix_AllocateChannels(-1))
137
+ rb_raise(rb_eArgError, "too large number of channel (%d)", channel);
138
+ if (channel == -1 && !allow_minus_1 || channel < -1)
139
+ rb_raise(rb_eArgError, "negative number of channel is not allowed");
140
+ }
141
+
142
+ /*
143
+ * @overload open(freq=22050, format=SDL2::Mixer::DEFAULT_FORMAT, channels=2, chunksize=1024)
144
+ * Open a sound device.
145
+ *
146
+ * Before calling loading/playing methods in the mixer module,
147
+ * this method must be called.
148
+ * Before calling this method,
149
+ * {SDL2.init} must be called with SDL2::INIT_AUDIO.
150
+ *
151
+ * @param freq [Integer] output sampling frequency in Hz.
152
+ * Normally 22050 or 44100 is used.
153
+ * 44100 is CD audio rate. SDL2::Mixer::DEFAULT_FREQUENCY(22050) is best for
154
+ * many kinds of game because 44100 requires too much CPU power on older computers.
155
+ * @param format [Integer] output sample format
156
+ * @param channels 1 is for mono, and 2 is for stereo.
157
+ * @param chunksize bytes used per output sample
158
+ *
159
+ * @return [nil]
160
+ *
161
+ * @raise [SDL2::Error] raised when a device cannot be opened
162
+ *
163
+ * @see .init
164
+ * @see .close
165
+ * @see .query
166
+ */
167
+ static VALUE Mixer_s_open(int argc, VALUE* argv, VALUE self)
168
+ {
169
+ VALUE freq, format, channels, chunksize;
170
+ rb_scan_args(argc, argv, "04", &freq, &format, &channels, &chunksize);
171
+ HANDLE_MIX_ERROR(Mix_OpenAudio((freq == Qnil) ? MIX_DEFAULT_FREQUENCY : NUM2INT(freq),
172
+ (format == Qnil) ? MIX_DEFAULT_FORMAT : NUM2UINT(format),
173
+ (channels == Qnil) ? 2 : NUM2INT(channels),
174
+ (chunksize == Qnil) ? 1024 : NUM2INT(chunksize)));
175
+ playing_chunks = rb_ary_new();
176
+ return Qnil;
177
+ }
178
+
179
+ /*
180
+ * Close the audio device.
181
+ *
182
+ * @return [nil]
183
+ */
184
+ static VALUE Mixer_s_close(VALUE self)
185
+ {
186
+ Mix_CloseAudio();
187
+ return Qnil;
188
+ }
189
+
190
+
191
+ /*
192
+ * Query a sound device spec.
193
+ *
194
+ * This method returns the most suitable setting for {.open} the device.
195
+ *
196
+ * @return [[Integer, Integer, Integer, Integer]]
197
+ * the suitable frequency in Hz, the suitable format,
198
+ * the suitable number of channels (1 for mono, 2 for stereo),
199
+ * and the number of call of {.open}.
200
+ *
201
+ */
202
+ static VALUE Mixer_s_query(VALUE self)
203
+ {
204
+ int frequency = 0, channels = 0, num_opened;
205
+ Uint16 format = 0;
206
+
207
+ num_opened = Mix_QuerySpec(&frequency, &format, &channels);
208
+ return rb_ary_new3(4, INT2NUM(frequency), UINT2NUM(format),
209
+ INT2NUM(channels), INT2NUM(num_opened));
210
+ }
211
+
212
+ /*
213
+ * Document-module: SDL2::Mixer::Channels
214
+ *
215
+ * This module plays {SDL2::Mixer::Chunk} objects in parallel.
216
+ *
217
+ * Each virtual sound output device is called channel, and
218
+ * the number of channels determines the f
219
+ */
220
+
221
+ /*
222
+ * @overload allocate(num_channels)
223
+ * Set the number of channels being mixed.
224
+ *
225
+ * @param num_channels [Integer] Number of channels prepared for mixing.
226
+ *
227
+ * @return [Integer] the number of prepared channels.
228
+ */
229
+ static VALUE Channels_s_allocate(VALUE self, VALUE num_channels)
230
+ {
231
+ return INT2NUM(Mix_AllocateChannels(NUM2INT(num_channels)));
232
+ }
233
+
234
+ /*
235
+ * @overload reserve(num)
236
+ * Reserve channel from 0 to num-1 and reserved channels are not used by
237
+ * {Channels.play} and {Channels.fade_in} with **channels**==-1.
238
+ *
239
+ * @param num [Integer]
240
+ * @return [Integer]
241
+ */
242
+ static VALUE Channels_s_reserve(VALUE self, VALUE num)
243
+ {
244
+ return INT2NUM(Mix_ReserveChannels(NUM2INT(num)));
245
+ }
246
+
247
+ /*
248
+ * @overload volume(channel)
249
+ * Get the volume of specified channel.
250
+ *
251
+ * @param channel [Integer] the channel to get volume for.
252
+ * If the specified channel is -1, this method returns
253
+ * the average volume of all channels.
254
+ * @return [Integer] the volume, 0-128
255
+ *
256
+ * @see .set_volume
257
+ */
258
+ static VALUE Channels_s_volume(VALUE self, VALUE channel)
259
+ {
260
+ return INT2NUM(Mix_Volume(NUM2INT(channel), -1));
261
+ }
262
+
263
+ /*
264
+ * @overload set_volume(channel, volume)
265
+ * Set the volume of specified channel.
266
+ *
267
+ * The volume should be from 0 to {SDL2::Mixer::MAX_VOLUME}(128).
268
+ * If the specified channel is -1, set volume for all channels.
269
+ *
270
+ * @param channel [Integer] the channel to set volume for.
271
+ * @param volume [Integer] the volume to use
272
+ * @return [void]
273
+ *
274
+ * @see .volume
275
+ */
276
+ static VALUE Channels_s_set_volume(VALUE self, VALUE channel, VALUE volume)
277
+ {
278
+ return INT2NUM(Mix_Volume(NUM2INT(channel), NUM2INT(volume)));
279
+ }
280
+
281
+ static void protect_playing_chunk_from_gc(int channel, VALUE chunk)
282
+ {
283
+ rb_ary_store(playing_chunks, channel, chunk);
284
+ }
285
+
286
+ /*
287
+ * @overload play(channel, chunk, loops, ticks = -1)
288
+ * Play a {SDL2::Mixer::Chunk} on **channel**.
289
+ *
290
+ * @param channel [Integer] the channel to play, or -1 for the first free unreserved
291
+ * channel
292
+ * @param chunk [SDL2::Mixer::Chunk] the chunk to play
293
+ * @param loops [Integer] the number of loops, or -1 for infite loops.
294
+ * passing 1 plays the sample twice (1 loop).
295
+ * @param ticks [Integer] milliseconds limit to play, at most.
296
+ * If the chunk is long enough and **loops** is large enough,
297
+ * the play will stop after **ticks** milliseconds.
298
+ * Otherwise, the play will stop when the loop ends.
299
+ * -1 means infinity.
300
+ * @return [Integer] the channel that plays the chunk.
301
+ *
302
+ * @raise [SDL2::Error] raised on a playing error. For example,
303
+ * **channel** is out of the allocated channels, or
304
+ * there is no free channels when **channel** is -1.
305
+ *
306
+ * @see .fade_in
307
+ */
308
+ static VALUE Channels_s_play(int argc, VALUE* argv, VALUE self)
309
+ {
310
+ VALUE channel, chunk, loops, ticks;
311
+ int ch;
312
+ rb_scan_args(argc, argv, "31", &channel, &chunk, &loops, &ticks);
313
+ if (ticks == Qnil)
314
+ ticks = INT2FIX(-1);
315
+ check_channel(channel, 1);
316
+ ch = Mix_PlayChannelTimed(NUM2INT(channel), Get_Mix_Chunk(chunk),
317
+ NUM2INT(loops), NUM2INT(ticks));
318
+ HANDLE_MIX_ERROR(ch);
319
+ protect_playing_chunk_from_gc(ch, chunk);
320
+ return INT2FIX(ch);
321
+ }
322
+
323
+ /*
324
+ * @overload fade_in(channel, chunk, loops, ms, ticks = -1)
325
+ * Play a {SDL2::Mixer::Chunk} on **channel** with fading in.
326
+ *
327
+ * @param channel [Integer] the channel to play, or -1 for the first free unreserved
328
+ * channel
329
+ * @param chunk [SDL2::Mixer::Chunk] the chunk to play
330
+ * @param loops [Integer] the number of loops, or -1 for infite loops.
331
+ * passing 1 plays the sample twice (1 loop).
332
+ * @param ms [Integer] milliseconds of time of fade-in effect.
333
+ * @param ticks [Integer] milliseconds limit to play, at most.
334
+ * If the chunk is long enough and **loops** is large enough,
335
+ * the play will stop after **ticks** milliseconds.
336
+ * Otherwise, the play will stop when the loop ends.
337
+ * -1 means infinity.
338
+ * @return [Integer] the channel that plays the chunk.
339
+ *
340
+ * @raise [SDL2::Error] raised on a playing error. For example,
341
+ * **channel** is out of the allocated channels, or
342
+ * there is no free channels when **channel** is -1.
343
+ *
344
+ * @see .play
345
+ * @see .fade_out
346
+ */
347
+ static VALUE Channels_s_fade_in(int argc, VALUE* argv, VALUE self)
348
+ {
349
+ VALUE channel, chunk, loops, ms, ticks;
350
+ int ch;
351
+ rb_scan_args(argc, argv, "41", &channel, &chunk, &loops, &ms, &ticks);
352
+ if (ticks == Qnil)
353
+ ticks = INT2FIX(-1);
354
+ check_channel(channel, 1);
355
+ ch = Mix_FadeInChannelTimed(NUM2INT(channel), Get_Mix_Chunk(chunk),
356
+ NUM2INT(loops), NUM2INT(ms), NUM2INT(ticks));
357
+ HANDLE_MIX_ERROR(ch);
358
+ protect_playing_chunk_from_gc(ch, chunk);
359
+ return INT2FIX(ch);
360
+ }
361
+
362
+ /*
363
+ * @overload pause(channel)
364
+ * Pause a specified channel.
365
+ *
366
+ * @param channel [Integer] the channel to pause, or -1 for all channels.
367
+ * @return [nil]
368
+ *
369
+ * @see .resume
370
+ * @see .pause?
371
+ */
372
+ static VALUE Channels_s_pause(VALUE self, VALUE channel)
373
+ {
374
+ check_channel(channel, 1);
375
+ Mix_Pause(NUM2INT(channel));
376
+ return Qnil;
377
+ }
378
+
379
+ /*
380
+ * @overload resume(channel)
381
+ * Resume a specified channel that already pauses.
382
+ *
383
+ * @note This method has no effect to unpaused channels.
384
+ * @param channel [Integer] the channel to be resumed, or -1 for all channels.
385
+ * @return [nil]
386
+ *
387
+ * @see .pause
388
+ * @see .pause?
389
+ */
390
+ static VALUE Channels_s_resume(VALUE self, VALUE channel)
391
+ {
392
+ check_channel(channel, 1);
393
+ Mix_Resume(NUM2INT(channel));
394
+ return Qnil;
395
+ }
396
+
397
+ /*
398
+ * @overload halt(channel)
399
+ * Halt playing of a specified channel.
400
+ *
401
+ * @param channel [Integer] the channel to be halted, or -1 for all channels.
402
+ * @return [nil]
403
+ *
404
+ * @see .expire
405
+ * @see .fade_out
406
+ * @see .play?
407
+ */
408
+ static VALUE Channels_s_halt(VALUE self, VALUE channel)
409
+ {
410
+ check_channel(channel, 1);
411
+ Mix_HaltChannel(NUM2INT(channel));
412
+ return Qnil;
413
+ }
414
+
415
+ /*
416
+ * @overload expire(channel, ticks)
417
+ * Halt playing of a specified channel after **ticks** milliseconds.
418
+ *
419
+ * @param channel [Integer] the channel to be halted, or -1 for all channels.
420
+ * @param ticks [Integer] milliseconds untils the channel halts playback.
421
+ * @return [nil]
422
+ *
423
+ * @see .halt
424
+ * @see .fade_out
425
+ * @see .play?
426
+ */
427
+ static VALUE Channels_s_expire(VALUE self, VALUE channel, VALUE ticks)
428
+ {
429
+ check_channel(channel, 1);
430
+ Mix_ExpireChannel(NUM2INT(channel), NUM2INT(ticks));
431
+ return Qnil;
432
+ }
433
+
434
+ /*
435
+ * @overload fade_out(channel, ms)
436
+ * Halt playing of a specified channel with fade-out effect.
437
+ *
438
+ * @param channel [Integer] the channel to be halted, or -1 for all channels.
439
+ * @param ms [Integer] milliseconds of fade-out effect
440
+ * @return [nil]
441
+ *
442
+ * @see .halt
443
+ * @see .expire
444
+ * @see .play?
445
+ * @see .fade_in
446
+ */
447
+ static VALUE Channels_s_fade_out(VALUE self, VALUE channel, VALUE ms)
448
+ {
449
+ check_channel(channel, 1);
450
+ Mix_FadeOutChannel(NUM2INT(channel), NUM2INT(ms));
451
+ return Qnil;
452
+ }
453
+
454
+ /*
455
+ * @overload play?(channel)
456
+ * Return true if a specified channel is playing.
457
+ *
458
+ * @param channel [Integer] channel to test
459
+ * @see .pause?
460
+ * @see .fading
461
+ */
462
+ static VALUE Channels_s_play_p(VALUE self, VALUE channel)
463
+ {
464
+ check_channel(channel, 0);
465
+ return INT2BOOL(Mix_Playing(NUM2INT(channel)));
466
+ }
467
+
468
+ /*
469
+ * @overload pause?(channel)
470
+ * Return true if a specified channel is paused.
471
+ *
472
+ * @note This method returns true if a paused channel is halted by {.halt}, or any
473
+ * other halting methods.
474
+ *
475
+ * @param channel [Integer] channel to test
476
+ *
477
+ * @see .play?
478
+ * @see .fading
479
+ */
480
+ static VALUE Channels_s_pause_p(VALUE self, VALUE channel)
481
+ {
482
+ check_channel(channel, 0);
483
+ return INT2BOOL(Mix_Paused(NUM2INT(channel)));
484
+ }
485
+
486
+ /*
487
+ * @overload fading(channel)
488
+ * Return the fading state of a specified channel.
489
+ *
490
+ * The return value is one of the following:
491
+ *
492
+ * * {SDL2::Mixer::NO_FADING} - **channel** is not fading in, and fading out
493
+ * * {SDL2::Mixer::FADING_IN} - **channel** is fading in
494
+ * * {SDL2::Mixer::FADING_OUT} - **channel** is fading out
495
+ *
496
+ * @param channel [Integer] channel to test
497
+ *
498
+ * @return [Integer]
499
+ *
500
+ * @see .play?
501
+ * @see .pause?
502
+ * @see .fade_in
503
+ * @see .fade_out
504
+ */
505
+ static VALUE Channels_s_fading(VALUE self, VALUE which)
506
+ {
507
+ check_channel(which, 0);
508
+ return INT2FIX(Mix_FadingChannel(NUM2INT(which)));
509
+ }
510
+
511
+ /*
512
+ * @overload playing_chunk(channel)
513
+ * Get the {SDL2::Mixer::Chunk} object most recently playing on **channel**.
514
+ *
515
+ * If **channel** is out of allocated channels, or
516
+ * no chunk is played yet on **channel**, this method returns nil.
517
+ *
518
+ * @param channel [Integer] the channel to get the chunk object
519
+ * @return [SDL2::Mixer::Chunk,nil]
520
+ */
521
+ static VALUE Channels_s_playing_chunk(VALUE self, VALUE channel)
522
+ {
523
+ check_channel(channel, 0);
524
+ return rb_ary_entry(playing_chunks, NUM2INT(channel));
525
+ }
526
+
527
+ /*
528
+ * Document-class: SDL2::Mixer::Channels::Group
529
+ *
530
+ * This class represents a channel group. A channel group is
531
+ * a set of channels and you can stop playing and fade out playing
532
+ * channels of an group at the same time.
533
+ *
534
+ * Each channel group is identified by an integer called tag.
535
+ */
536
+
537
+ /*
538
+ * Initialize the channel with given **tag**.
539
+ *
540
+ * Groups with a common tag are identified.
541
+ */
542
+ static VALUE Group_initialize(VALUE self, VALUE tag)
543
+ {
544
+ rb_iv_set(self, "@tag", tag);
545
+ return Qnil;
546
+ }
547
+
548
+ /*
549
+ * Get the default channel group.
550
+ *
551
+ * The default channel group refers all channels in the mixer system.
552
+ *
553
+ * @return [SDL2::Mixer::Channels::Group]
554
+ */
555
+ static VALUE Group_s_default(VALUE self)
556
+ {
557
+ VALUE tag = INT2FIX(-1);
558
+ return rb_class_new_instance(1, &tag, self);
559
+ }
560
+
561
+ /*
562
+ * Get the tag of the group.
563
+ *
564
+ * @return [Integer]
565
+ */
566
+ inline static int Group_tag(VALUE group)
567
+ {
568
+ return NUM2INT(rb_iv_get(group, "@tag"));
569
+ }
570
+
571
+ /*
572
+ * @overload ==(other)
573
+ * Return true if **self** and **other** are same.
574
+ *
575
+ * **self** and **other** are considered to be same
576
+ * if they have the same tag.
577
+ *
578
+ * @param other [SDL2::Mixer::Channel::Group] a compared object
579
+ * @return [Boolean]
580
+ */
581
+ static VALUE Group_eq(VALUE self, VALUE other)
582
+ {
583
+ return INT2BOOL(rb_obj_is_instance_of(other, cGroup) &&
584
+ Group_tag(self) == Group_tag(other));
585
+ }
586
+
587
+ /*
588
+ * @overload add(which)
589
+ * Add a channel to the group.
590
+ *
591
+ * @param which [Integer] a channel id
592
+ * @return [nil]
593
+ */
594
+ static VALUE Group_add(VALUE self, VALUE which)
595
+ {
596
+ if (!Mix_GroupChannel(NUM2INT(which), Group_tag(self))) {
597
+ SDL_SetError("Cannot add channel %d", NUM2INT(which));
598
+ SDL_ERROR();
599
+ }
600
+ return Qnil;
601
+ }
602
+
603
+ /*
604
+ * Get the number of channels belong to the group.
605
+ *
606
+ * @return [Integer]
607
+ */
608
+ static VALUE Group_count(VALUE self)
609
+ {
610
+ return INT2NUM(Mix_GroupCount(Group_tag(self)));
611
+ }
612
+
613
+ /*
614
+ * Return the first available channel in the group.
615
+ *
616
+ * Return -1 if no channel is available.
617
+ *
618
+ * @return [Integer]
619
+ */
620
+ static VALUE Group_available(VALUE self)
621
+ {
622
+ return INT2NUM(Mix_GroupAvailable(Group_tag(self)));
623
+ }
624
+
625
+ /*
626
+ * Return the oldest cahnnel in the group.
627
+ *
628
+ * Return -1 if no channel is available.
629
+ *
630
+ * @return [Integer]
631
+ */
632
+ static VALUE Group_oldest(VALUE self)
633
+ {
634
+ return INT2NUM(Mix_GroupOldest(Group_tag(self)));
635
+ }
636
+
637
+ /*
638
+ * Return the newer cahnnel in the group.
639
+ *
640
+ * Return -1 if no channel is available.
641
+ *
642
+ * @return [Integer]
643
+ */
644
+ static VALUE Group_newer(VALUE self)
645
+ {
646
+ return INT2NUM(Mix_GroupNewer(Group_tag(self)));
647
+ }
648
+
649
+ /*
650
+ * @overload fade_out(ms)
651
+ * Halt playing of all channels in the group with fade-out effect.
652
+ *
653
+ * @param ms [Integer] milliseconds of fade-out effect
654
+ * @return [Integer] the number of channels affected by this method
655
+ * @see Channels.fade_out
656
+ * @see .halt
657
+ */
658
+ static VALUE Group_fade_out(VALUE self, VALUE ms)
659
+ {
660
+ return INT2NUM(Mix_FadeOutGroup(Group_tag(self), NUM2INT(ms)));
661
+ }
662
+
663
+ /*
664
+ * Halt playing of all channels in the group.
665
+ *
666
+ * @return [nil]
667
+ * @see Channels.halt
668
+ * @see .fade_out
669
+ */
670
+ static VALUE Group_halt(VALUE self)
671
+ {
672
+ Mix_HaltGroup(Group_tag(self));
673
+ return Qnil;
674
+ }
675
+
676
+ /*
677
+ * Document-module: SDL2::Mixer::MusicChannel
678
+ *
679
+ * This module provides the functions to play {SDL2::Mixer::Music}.
680
+ */
681
+
682
+ /*
683
+ * @overload play(music, loops)
684
+ * Play **music** **loops** times.
685
+ *
686
+ * @note the meaning of **loop** is different from {SDL2::Mixer::Channels.play}.
687
+ *
688
+ * @param music [SDL2::Mixer::Music] music to play
689
+ * @param loops [Integer] number of times to play the music.
690
+ * 0 plays the music zero times.
691
+ * -1 plays the music forever.
692
+ *
693
+ * @return [nil]
694
+ *
695
+ * @see .fade_in
696
+ *
697
+ */
698
+ static VALUE MusicChannel_s_play(VALUE self, VALUE music, VALUE loops)
699
+ {
700
+ HANDLE_MIX_ERROR(Mix_PlayMusic(Get_Mix_Music(music), NUM2INT(loops)));
701
+ playing_music = music;
702
+ return Qnil;
703
+ }
704
+
705
+ /*
706
+ * @overload fade_in(music, loops, ms, pos=0)
707
+ * Play **music** **loops** times with fade-in effect.
708
+ *
709
+ * @note the meaning of **loop** is different from {SDL2::Mixer::Channels.play}.
710
+ *
711
+ * @param music [SDL2::Mixer::Music] music to play
712
+ * @param loops [Integer] number of times to play the music.
713
+ * 0 plays the music zero times.
714
+ * -1 plays the music forever.
715
+ * @param ms [Integer] milliseconds for the fade-in effect
716
+ * @param pos [Float] the position to play from.
717
+ * The meaning of "position" is different for the type of music sources.
718
+ *
719
+ * @return [nil]
720
+ *
721
+ * @see .play
722
+ */
723
+ static VALUE MusicChannel_s_fade_in(int argc, VALUE* argv, VALUE self)
724
+ {
725
+ VALUE music, loops, fade_in_ms, pos;
726
+ rb_scan_args(argc, argv, "31", &music, &loops, &fade_in_ms, &pos);
727
+ HANDLE_MIX_ERROR(Mix_FadeInMusicPos(Get_Mix_Music(music), NUM2INT(loops),
728
+ NUM2INT(fade_in_ms),
729
+ pos == Qnil ? 0 : NUM2DBL(pos)));
730
+ playing_music = music;
731
+ return Qnil;
732
+ }
733
+
734
+ /*
735
+ * Get the volume of the music channel.
736
+ *
737
+ * @return [Integer]
738
+ *
739
+ * @see .volume=
740
+ */
741
+ static VALUE MusicChannel_s_volume(VALUE self)
742
+ {
743
+ return INT2FIX(Mix_VolumeMusic(-1));
744
+ }
745
+
746
+ /*
747
+ * @overload volume=(vol)
748
+ * Set the volume of the music channel.
749
+ *
750
+ * @param vol [Integer] the volume for mixing,
751
+ * from 0 to {SDL2::Mixer::MAX_VOLUME}(128).
752
+ * @return [vol]
753
+ *
754
+ * @see .volume
755
+ */
756
+ static VALUE MusicChannel_s_set_volume(VALUE self, VALUE volume)
757
+ {
758
+ Mix_VolumeMusic(NUM2INT(volume));
759
+ return volume;
760
+ }
761
+
762
+ /*
763
+ * Pause the playback of the music channel.
764
+ *
765
+ * @return [nil]
766
+ *
767
+ * @see .resume
768
+ * @see .pause?
769
+ */
770
+ static VALUE MusicChannel_s_pause(VALUE self)
771
+ {
772
+ Mix_PauseMusic(); return Qnil;
773
+ }
774
+
775
+ /*
776
+ * Resume the playback of the music channel.
777
+ *
778
+ * @return [nil]
779
+ *
780
+ * @see .pause
781
+ * @see .pause?
782
+ */
783
+ static VALUE MusicChannel_s_resume(VALUE self)
784
+ {
785
+ Mix_ResumeMusic(); return Qnil;
786
+ }
787
+
788
+ /*
789
+ * Rewind the music to the start.
790
+ *
791
+ * @return [nil]
792
+ */
793
+ static VALUE MusicChannel_s_rewind(VALUE self)
794
+ {
795
+ Mix_RewindMusic(); return Qnil;
796
+ }
797
+
798
+ /*
799
+ * @overload set_position(position)
800
+ * Set the position of the currently playing music.
801
+ *
802
+ * @param position [Float] the position to play from.
803
+ * @return [nil]
804
+ */
805
+ static VALUE MusicChannel_s_set_position(VALUE self, VALUE position)
806
+ {
807
+ HANDLE_MIX_ERROR(Mix_SetMusicPosition(NUM2DBL(position)));
808
+ return Qnil;
809
+ }
810
+
811
+ /*
812
+ * Halt the music playback.
813
+ *
814
+ * @return [nil]
815
+ */
816
+ static VALUE MusicChannel_s_halt(VALUE self)
817
+ {
818
+ Mix_HaltMusic(); return Qnil;
819
+ }
820
+
821
+ /*
822
+ * @overload fade_out(ms)
823
+ * Halt the music playback with fade-out effect.
824
+ *
825
+ * @return [nil]
826
+ */
827
+ static VALUE MusicChannel_s_fade_out(VALUE self, VALUE fade_out_ms)
828
+ {
829
+ Mix_FadeOutMusic(NUM2INT(fade_out_ms)); return Qnil;
830
+ }
831
+
832
+ /*
833
+ * Return true if a music is playing.
834
+ */
835
+ static VALUE MusicChannel_s_play_p(VALUE self)
836
+ {
837
+ return INT2BOOL(Mix_PlayingMusic());
838
+ }
839
+
840
+ /*
841
+ * Return true if a music playback is paused.
842
+ */
843
+ static VALUE MusicChannel_s_pause_p(VALUE self)
844
+ {
845
+ return INT2BOOL(Mix_PausedMusic());
846
+ }
847
+
848
+ /*
849
+ * Get the fading state of the music playback.
850
+ *
851
+ * The return value is one of the following:
852
+ *
853
+ * * {SDL2::Mixer::NO_FADING} - not fading in, and fading out
854
+ * * {SDL2::Mixer::FADING_IN} - fading in
855
+ * * {SDL2::Mixer::FADING_OUT} - fading out
856
+ *
857
+ * @return [Integer]
858
+ *
859
+ * @see .fade_in
860
+ * @see .fade_out
861
+ *
862
+ */
863
+ static VALUE MusicChannel_s_fading(VALUE self)
864
+ {
865
+ return INT2NUM(Mix_FadingMusic());
866
+ }
867
+
868
+ /*
869
+ * Get the {SDL2::Mixer::Music} object that most recently played.
870
+ *
871
+ * Return nil if no music object is played yet.
872
+ *
873
+ * @return [SDL2::Mixer::Music,nil]
874
+ */
875
+ static VALUE MusicChannel_s_playing_music(VALUE self)
876
+ {
877
+ return playing_music;
878
+ }
879
+
880
+ /*
881
+ * Document-class: SDL2::Mixer::Chunk
882
+ *
883
+ * This class represents a sound sample, a kind of sound sources.
884
+ *
885
+ * Chunk objects is playable on {SDL2::Mixer::Channels}.
886
+ *
887
+ * @!method destroy?
888
+ * Return true if the memory is deallocated by {#destroy}.
889
+ */
890
+
891
+ /*
892
+ * @overload load(path)
893
+ * Load a sample from file.
894
+ *
895
+ * This can load WAVE, AIFF, RIFF, OGG, and VOC files.
896
+ *
897
+ * @note {SDL2::Mixer.open} must be called before calling this method.
898
+ *
899
+ * @param path [String] the fine name
900
+ * @return [SDL2::Mixer::Chunk]
901
+ *
902
+ * @raise [SDL2::Error] raised when failing to load
903
+ */
904
+ static VALUE Chunk_s_load(VALUE self, VALUE fname)
905
+ {
906
+ Mix_Chunk* chunk = Mix_LoadWAV(StringValueCStr(fname));
907
+ VALUE c;
908
+ if (!chunk)
909
+ MIX_ERROR();
910
+ c = Chunk_new(chunk);
911
+ rb_iv_set(c, "@filename", fname);
912
+ return c;
913
+ }
914
+
915
+ /*
916
+ * Get the names of the sample decoders.
917
+ *
918
+ * @return [Array<String>] the names of decoders, such as: "WAVE", "OGG", etc.
919
+ */
920
+ static VALUE Chunk_s_decoders(VALUE self)
921
+ {
922
+ int i;
923
+ int num_decoders = Mix_GetNumChunkDecoders();
924
+ VALUE ary = rb_ary_new();
925
+ for (i=0; i < num_decoders; ++i)
926
+ rb_ary_push(ary, rb_usascii_str_new_cstr(Mix_GetChunkDecoder(i)));
927
+ return ary;
928
+ }
929
+
930
+ /*
931
+ * Deallocate the sample memory.
932
+ *
933
+ * Normally, the memory is deallocated by ruby's GC, but
934
+ * you can surely deallocate the memory with this method at any time.
935
+ *
936
+ * @return [nil]
937
+ */
938
+ static VALUE Chunk_destroy(VALUE self)
939
+ {
940
+ Chunk* c = Get_Chunk(self);
941
+ if (c->chunk) Mix_FreeChunk(c->chunk);
942
+ c->chunk = NULL;
943
+ return Qnil;
944
+ }
945
+
946
+ /*
947
+ * Get the volume of the sample.
948
+ *
949
+ * @return [Integer] the volume from 0 to {SDL2::Mixer::MAX_VOLUME}.
950
+ *
951
+ * @see #volume=
952
+ */
953
+ static VALUE Chunk_volume(VALUE self)
954
+ {
955
+ return INT2NUM(Mix_VolumeChunk(Get_Mix_Chunk(self), -1));
956
+ }
957
+
958
+ /*
959
+ * @overload volume=(vol)
960
+ * Set the volume of the sample.
961
+ *
962
+ * @param vol [Integer] the new volume
963
+ * @return [vol]
964
+ *
965
+ * @see #volume
966
+ */
967
+ static VALUE Chunk_set_volume(VALUE self, VALUE vol)
968
+ {
969
+ return INT2NUM(Mix_VolumeChunk(Get_Mix_Chunk(self), NUM2INT(vol)));
970
+ }
971
+
972
+ /* @return [String] inspection string */
973
+ static VALUE Chunk_inspect(VALUE self)
974
+ {
975
+ VALUE filename = rb_iv_get(self, "@filename");
976
+ if (RTEST(Chunk_destroy_p(self)))
977
+ return rb_sprintf("<%s: destroyed>", rb_obj_classname(self));
978
+
979
+ return rb_sprintf("<%s: filename=\"%s\" volume=%d>",
980
+ rb_obj_classname(self),
981
+ StringValueCStr(filename),
982
+ Mix_VolumeChunk(Get_Mix_Chunk(self), -1));
983
+ }
984
+
985
+ /*
986
+ * Document-class: SDL2::Mixer::Music
987
+ *
988
+ * This class represents music, a kind of sound sources.
989
+ *
990
+ * Music is playable on {SDL2::Mixer::MusicChannel}, not on {SDL2::Mixer::Channels}.
991
+ *
992
+ * @!method destroy?
993
+ * Return true if the memory is deallocated by {#destroy}.
994
+ */
995
+
996
+ /*
997
+ * Get the names of music decoders.
998
+ *
999
+ * @return [Array<String>] the names of decorders (supported sound formats),
1000
+ * such as: "OGG", "WAVE", "MP3"
1001
+ */
1002
+ static VALUE Music_s_decoders(VALUE self)
1003
+ {
1004
+ int num_decoders = Mix_GetNumMusicDecoders();
1005
+ int i;
1006
+ VALUE decoders = rb_ary_new2(num_decoders);
1007
+ for (i=0; i<num_decoders; ++i)
1008
+ rb_ary_push(decoders, utf8str_new_cstr(Mix_GetMusicDecoder(i)));
1009
+ return decoders;
1010
+ }
1011
+
1012
+ /*
1013
+ * @overload load(path)
1014
+ * Load a music from file.
1015
+ *
1016
+ * @param path [String] the file path
1017
+ * @return [SDL2::Mixer::Music]
1018
+ *
1019
+ * @raise [SDL2::Error] raised when failing to load.
1020
+ */
1021
+ static VALUE Music_s_load(VALUE self, VALUE fname)
1022
+ {
1023
+ Mix_Music* music = Mix_LoadMUS(StringValueCStr(fname));
1024
+ VALUE mus;
1025
+ if (!music) MIX_ERROR();
1026
+ mus = Music_new(music);
1027
+ rb_iv_set(mus, "@filename", fname);
1028
+ return mus;
1029
+ }
1030
+
1031
+ /*
1032
+ * Deallocate the music memory.
1033
+ *
1034
+ * Normally, the memory is deallocated by ruby's GC, but
1035
+ * you can surely deallocate the memory with this method at any time.
1036
+ *
1037
+ * @return [nil]
1038
+ */
1039
+ static VALUE Music_destroy(VALUE self)
1040
+ {
1041
+ Music* c = Get_Music(self);
1042
+ if (c) Mix_FreeMusic(c->music);
1043
+ c->music = NULL;
1044
+ return Qnil;
1045
+ }
1046
+
1047
+ /* @return [String] inspection string */
1048
+ static VALUE Music_inspect(VALUE self)
1049
+ {
1050
+ VALUE filename = rb_iv_get(self, "@filename");
1051
+ if (RTEST(Music_destroy_p(self)))
1052
+ return rb_sprintf("<%s: destroyed>", rb_obj_classname(self));
1053
+
1054
+ return rb_sprintf("<%s: filename=\"%s\" type=%d>",
1055
+ rb_obj_classname(self), StringValueCStr(filename),
1056
+ Mix_GetMusicType(Get_Mix_Music(self)));
1057
+ }
1058
+
1059
+
1060
+ void rubysdl2_init_mixer(void)
1061
+ {
1062
+ mMixer = rb_define_module_under(mSDL2, "Mixer");
1063
+
1064
+ rb_define_module_function(mMixer, "init", Mixer_s_init, 1);
1065
+ rb_define_module_function(mMixer, "open", Mixer_s_open, -1);
1066
+ rb_define_module_function(mMixer, "close", Mixer_s_close, 0);
1067
+ rb_define_module_function(mMixer, "query", Mixer_s_query, 0);
1068
+
1069
+ /* define(`DEFINE_MIX_INIT',`rb_define_const(mMixer, "INIT_$1", UINT2NUM(MIX_INIT_$1))') */
1070
+ /* Initialize Ogg flac loader */
1071
+ DEFINE_MIX_INIT(FLAC);
1072
+ /* Initialize MOD loader */
1073
+ DEFINE_MIX_INIT(MOD);
1074
+ /* Initialize libmodplug */
1075
+ DEFINE_MIX_INIT(MODPLUG);
1076
+ /* Initialize MP3 loader */
1077
+ DEFINE_MIX_INIT(MP3);
1078
+ /* Initialize Ogg vorbis loader */
1079
+ DEFINE_MIX_INIT(OGG);
1080
+ /* Initialize fluidsynth */
1081
+ DEFINE_MIX_INIT(FLUIDSYNTH);
1082
+
1083
+ /* define(`DEFINE_MIX_FORMAT',`rb_define_const(mMixer, "FORMAT_$1", UINT2NUM(AUDIO_$1))') */
1084
+ /* Unsiged 8-bit sample format. Used by {Mixer.open} */
1085
+ DEFINE_MIX_FORMAT(U8);
1086
+ /* Siged 8-bit sample format. Used by {Mixer.open} */
1087
+ DEFINE_MIX_FORMAT(S8);
1088
+ /* Unsiged 16-bit little-endian sample format. Used by {Mixer.open} */
1089
+ DEFINE_MIX_FORMAT(U16LSB);
1090
+ /* Siged 16-bit little-endian sample format. Used by {Mixer.open} */
1091
+ DEFINE_MIX_FORMAT(S16LSB);
1092
+ /* Unsiged 16-bit big-endian sample format. Used by {Mixer.open} */
1093
+ DEFINE_MIX_FORMAT(U16MSB);
1094
+ /* Unsiged 16-bit big-endian sample format. Used by {Mixer.open} */
1095
+ DEFINE_MIX_FORMAT(S16MSB);
1096
+ /* Unsiged 16-bit sample format. Endian is same as system byte order. Used by {Mixer.open} */
1097
+ DEFINE_MIX_FORMAT(U16SYS);
1098
+ /* Siged 16-bit sample format. Endian is same as system byte order. Used by {Mixer.open} */
1099
+ DEFINE_MIX_FORMAT(S16SYS);
1100
+ /* Default frequency. 22050 (Hz) */
1101
+ rb_define_const(mMixer, "DEFAULT_FREQUENCY", UINT2NUM(MIX_DEFAULT_FREQUENCY));
1102
+ /* Default sample format. Same as {Mixer::FORMAT_S16SYS}. */
1103
+ rb_define_const(mMixer, "DEFAULT_FORMAT", UINT2NUM(MIX_DEFAULT_FORMAT));
1104
+ /* Default number of channels. 2. */
1105
+ rb_define_const(mMixer, "DEFAULT_CHANNELS", INT2FIX(MIX_DEFAULT_CHANNELS));
1106
+ /* Max volume value. 128. */
1107
+ rb_define_const(mMixer, "MAX_VOLUME", INT2FIX(MIX_MAX_VOLUME));
1108
+ /* This constants represents that the channel is not fading in and fading out. */
1109
+ rb_define_const(mMixer, "NO_FADING", INT2FIX(MIX_NO_FADING));
1110
+ /* This constants represents that the channel is fading out. */
1111
+ rb_define_const(mMixer, "FADING_OUT", INT2FIX(MIX_FADING_OUT));
1112
+ /* This constants represents that the channel is fading in. */
1113
+ rb_define_const(mMixer, "FADING_IN", INT2FIX(MIX_FADING_IN));
1114
+
1115
+
1116
+ cChunk = rb_define_class_under(mMixer, "Chunk", rb_cObject);
1117
+ rb_undef_alloc_func(cChunk);
1118
+ rb_define_singleton_method(cChunk, "load", Chunk_s_load, 1);
1119
+ rb_define_singleton_method(cChunk, "decoders", Chunk_s_decoders, 0);
1120
+ rb_define_method(cChunk, "destroy", Chunk_destroy, 0);
1121
+ rb_define_method(cChunk, "destroy?", Chunk_destroy_p, 0);
1122
+ rb_define_method(cChunk, "volume", Chunk_volume, 0);
1123
+ rb_define_method(cChunk, "volume=", Chunk_set_volume, 1);
1124
+ rb_define_method(cChunk, "inspect", Chunk_inspect, 0);
1125
+ /* @return [String] The file name of the file from which the sound is loaded. */
1126
+ rb_define_attr(cChunk, "filename", 1, 0);
1127
+
1128
+
1129
+ cMusic = rb_define_class_under(mMixer, "Music", rb_cObject);
1130
+ rb_undef_alloc_func(cMusic);
1131
+ rb_define_singleton_method(cMusic, "decoders", Music_s_decoders, 0);
1132
+ rb_define_singleton_method(cMusic, "load", Music_s_load, 1);
1133
+ rb_define_method(cMusic, "destroy", Music_destroy, 0);
1134
+ rb_define_method(cMusic, "destroy?", Music_destroy_p, 0);
1135
+ rb_define_method(cMusic, "inspect", Music_inspect, 0);
1136
+
1137
+
1138
+ mChannels = rb_define_module_under(mMixer, "Channels");
1139
+ rb_define_module_function(mChannels, "allocate", Channels_s_allocate, 1);
1140
+ rb_define_module_function(mChannels, "reserve", Channels_s_reserve, 1);
1141
+ rb_define_module_function(mChannels, "volume", Channels_s_volume, 1);
1142
+ rb_define_module_function(mChannels, "set_volume", Channels_s_set_volume, 2);
1143
+ rb_define_module_function(mChannels, "play", Channels_s_play, -1);
1144
+ rb_define_module_function(mChannels, "fade_in", Channels_s_fade_in, -1);
1145
+ rb_define_module_function(mChannels, "pause", Channels_s_pause, 1);
1146
+ rb_define_module_function(mChannels, "resume", Channels_s_resume, 1);
1147
+ rb_define_module_function(mChannels, "halt", Channels_s_halt, 1);
1148
+ rb_define_module_function(mChannels, "expire", Channels_s_expire, 1);
1149
+ rb_define_module_function(mChannels, "fade_out", Channels_s_fade_out, 2);
1150
+ rb_define_module_function(mChannels, "play?", Channels_s_play_p, 1);
1151
+ rb_define_module_function(mChannels, "pause?", Channels_s_pause_p, 1);
1152
+ rb_define_module_function(mChannels, "fading", Channels_s_fading, 1);
1153
+ rb_define_module_function(mChannels, "playing_chunk", Channels_s_playing_chunk, 1);
1154
+
1155
+
1156
+ cGroup = rb_define_class_under(mChannels, "Group", rb_cObject);
1157
+ rb_define_method(cGroup, "initialize", Group_initialize, 1);
1158
+ rb_define_singleton_method(cGroup, "default", Group_s_default, 0);
1159
+ /* @return [Integer] tag id */
1160
+ rb_define_attr(cGroup, "tag", 1, 0);
1161
+ rb_define_method(cGroup, "==", Group_eq, 1);
1162
+ rb_define_method(cGroup, "add", Group_add, 1);
1163
+ rb_define_method(cGroup, "count", Group_count, 0);
1164
+ rb_define_method(cGroup, "available", Group_available, 0);
1165
+ rb_define_method(cGroup, "newer", Group_newer, 0);
1166
+ rb_define_method(cGroup, "oldest", Group_oldest, 0);
1167
+ rb_define_method(cGroup, "fade_out", Group_fade_out, 1);
1168
+ rb_define_method(cGroup, "halt", Group_halt, 0);
1169
+
1170
+
1171
+ mMusicChannel = rb_define_module_under(mMixer, "MusicChannel");
1172
+ rb_define_module_function(mMusicChannel, "play", MusicChannel_s_play, 2);
1173
+ rb_define_module_function(mMusicChannel, "fade_in", MusicChannel_s_fade_in, -1);
1174
+ rb_define_module_function(mMusicChannel, "volume", MusicChannel_s_volume, 0);
1175
+ rb_define_module_function(mMusicChannel, "volume=", MusicChannel_s_set_volume, 1);
1176
+ rb_define_module_function(mMusicChannel, "pause", MusicChannel_s_pause, 0);
1177
+ rb_define_module_function(mMusicChannel, "resume", MusicChannel_s_resume, 0);
1178
+ rb_define_module_function(mMusicChannel, "rewind", MusicChannel_s_rewind, 0);
1179
+ rb_define_module_function(mMusicChannel, "set_position", MusicChannel_s_set_position, 1);
1180
+ rb_define_module_function(mMusicChannel, "halt", MusicChannel_s_halt, 0);
1181
+ rb_define_module_function(mMusicChannel, "fade_out", MusicChannel_s_fade_out, 1);
1182
+ rb_define_module_function(mMusicChannel, "play?", MusicChannel_s_play_p, 0);
1183
+ rb_define_module_function(mMusicChannel, "pause?", MusicChannel_s_pause_p, 0);
1184
+ rb_define_module_function(mMusicChannel, "fading", MusicChannel_s_fading, 0);
1185
+ rb_define_module_function(mMusicChannel, "playing_music", MusicChannel_s_playing_music, 0);
1186
+
1187
+
1188
+ rb_gc_register_address(&playing_chunks);
1189
+ rb_gc_register_address(&playing_music);
1190
+ }
1191
+
1192
+ #else /* HAVE_SDL_MIXER_H */
1193
+ void rubysdl2_init_mixer(void)
1194
+ {
1195
+ }
1196
+ #endif