ruby-sdl2 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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