Class: Rubygame::Sound
- Inherits:
-
Object
- Object
- Rubygame::Sound
- Includes:
- NamedResource
- Defined in:
- lib/rubygame/sound.rb
Overview
IMPORTANT: this class only exists if SDL_mixer is available! Your code should check “defined?(Rubygame::Sound) != nil” to see if you can use this class, or be prepared to rescue from NameError.
Sound holds a sound effect, loaded from an audio file (see #load for supported formats).
Sound can #play, #pause/#unpause, #stop, adjust #volume, and #fade_out (you can fade in by passing an option to #play).
Sound can create duplicates (with #dup or #clone) in a memory-efficient way – the new Sound instance refers back to the same audio data, so having 100 duplicates of a sound uses only slightly more memory than having the first sound. Duplicates can different volume levels, too!
Sound includes the Rubygame::NamedResource mixin module, which can perform autoloading of sounds on demand, among other things.
Class Method Summary collapse
-
.autoload(filename) ⇒ Object
Searches each directory in Sound.autoload_dirs for a file with the given filename.
-
.load(filename) ⇒ Object
Load the given audio file.
Instance Method Summary collapse
-
#fade_out(fade_time) ⇒ Object
Fade out to silence over the given number of seconds.
-
#fading?(direction = :either) ⇒ Boolean
True if the Sound is currently fading in or out.
-
#initialize(sound = nil) ⇒ Sound
constructor
call-seq: new.
-
#initialize_copy(other) ⇒ Object
call-seq: clone( other ) -> sound dup( other ) -> sound.
-
#pause ⇒ Object
Pause the Sound.
-
#paused? ⇒ Boolean
True if the Sound is currently paused (not playing and not stopped).
-
#play(options = {}) ⇒ Object
call-seq: play( options==> 0, :repeats => 0, :stop_after => nil ).
-
#playing? ⇒ Boolean
True if the Sound is currently playing (not paused and not stopped).
-
#stop ⇒ Object
Stop the Sound.
-
#stopped? ⇒ Boolean
True if the Sound is currently stopped (not playing and not paused).
-
#unpause ⇒ Object
Unpause the Sound, if it is currently paused.
-
#volume ⇒ Object
Return the volume level of the sound.
-
#volume=(new_vol) ⇒ Object
Set the new #volume level of the sound.
Methods included from NamedResource
Constructor Details
#initialize(sound = nil) ⇒ Sound
call-seq:
new
NOTE: Don’t use this method. Use Sound.load.
Raises NotImplementedError.
96 97 98 99 100 101 102 103 104 105 |
# File 'lib/rubygame/sound.rb', line 96 def initialize( sound=nil ) if( sound.instance_of? SDL::Mixer::Chunk ) @struct = sound @volume = 1 @channel = -1 else raise( NotImplementedError, "Sound.new is not implemented. "+ "Use Sound.load to load a sound file." ) end end |
Class Method Details
.autoload(filename) ⇒ Object
Searches each directory in Sound.autoload_dirs for a file with the given filename. If it finds that file, loads it and returns a Sound instance. If it doesn’t find the file, returns nil.
See Rubygame::NamedResource for more information about this functionality.
54 55 56 57 58 59 60 61 62 |
# File 'lib/rubygame/sound.rb', line 54 def autoload( filename ) path = find_file( filename ) if( path ) return load( path ) else return nil end end |
.load(filename) ⇒ Object
Load the given audio file. Supported file formats are WAVE, MOD, MIDI, OGG, and MP3.
- filename
-
Full or relative path to the file. (String, required)
- Returns
-
The new Sound instance. (Sound)
- May raise
-
SDLError, if the sound file could not be loaded.
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/rubygame/sound.rb', line 73 def load( filename ) Rubygame.open_audio sound = SDL::Mixer.LoadWAV( filename ) if( sound.pointer.null? ) raise( Rubygame::SDLError, "Could not load Sound file '%s': %s"% [filename, SDL.GetError()] ) end return new( sound ) end |
Instance Method Details
#fade_out(fade_time) ⇒ Object
Fade out to silence over the given number of seconds. Once the sound is silent, it is automatically stopped.
- Returns
-
The receiver (self).
NOTE: If the sound is currently paused, the fade will start, but you won’t be able to hear it happening unless you #unpause during the fade.
Does nothing if the sound is currently stopped.
346 347 348 349 350 351 352 353 354 355 356 |
# File 'lib/rubygame/sound.rb', line 346 def fade_out( fade_time ) if( fade_time < 0 ) raise ArgumentError, "fade time cannot be negative (got %.2f)"%fade_time end if channel_active? SDL::Mixer.FadeOutChannel( @channel, (fade_time * 1000).to_i ) end return self end |
#fading?(direction = :either) ⇒ Boolean
True if the Sound is currently fading in or out. See also #play and #fade_out.
- direction
-
Check if it is fading :in, :out, or :either. (Symbol, required)
365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/rubygame/sound.rb', line 365 def fading?( direction=:either ) return false unless channel_active? case direction when :in SDL::Mixer.FadingChannel( @channel ) == SDL::Mixer::FADING_IN when :out SDL::Mixer.FadingChannel( @channel ) == SDL::Mixer::FADING_OUT else SDL::Mixer.FadingChannel( @channel ) != SDL::Mixer::NO_FADING end end |
#initialize_copy(other) ⇒ Object
call-seq:
clone( other ) -> sound
dup( other ) -> sound
Create a copy of the given Sound instance. More efficient than using #load to load the sound file again.
- other
-
An existing Sound instance. (Sound, required)
- Returns
-
The new Sound instance. (Sound)
NOTE: #clone and #dup do slightly different things; #clone will copy the ‘frozen’ state of the object, while #dup will create a fresh, un-frozen object.
127 128 129 130 131 |
# File 'lib/rubygame/sound.rb', line 127 def initialize_copy( other ) @struct = other.struct @volume = other.volume @channel = -1 end |
#pause ⇒ Object
Pause the Sound. Unlike #stop, it can be unpaused later to resume from where it was paused. See also #unpause and #paused?.
- Returns
-
The receiver (self).
NOTE: Does nothing if the sound is not currently playing.
274 275 276 277 278 279 280 |
# File 'lib/rubygame/sound.rb', line 274 def pause if channel_active? SDL::Mixer.Pause( @channel ) end return self end |
#paused? ⇒ Boolean
True if the Sound is currently paused (not playing and not stopped). See also #playing? and #stopped?.
302 303 304 305 306 |
# File 'lib/rubygame/sound.rb', line 302 def paused? channel_active? and SDL::Mixer.Playing( @channel ) == 1 and SDL::Mixer.Paused( @channel ) == 1 end |
#play(options = {}) ⇒ Object
call-seq:
play( ={:fade_in => 0, :repeats => 0, :stop_after => nil} )
Play the Sound, optionally fading in, repeating a certain number of times (or forever), and/or stopping automatically after a certain time.
See also #pause and #stop.
- options
-
Hash of options, listed below. (Hash, required)
- :fade_in
-
Fade in from silence over the given number of seconds. Default: 0. (Numeric, optional)
- :repeats
-
Repeat the sound the given number of times, or forever (or until stopped) if -1. Default: 0. (Integer, optional)
- :stop_after
-
Automatically stop playing after playing for the given number of seconds. Use nil to disable this behavior. (Numeric or nil, optional)
- Returns
-
The receiver (self).
- May raise
-
SDLError, if the audio device could not be opened, or if the sound file could not be played.
NOTE: If the sound is already playing (or paused), it will be stopped and played again from the beginning.
Example:
# Fade in over 2 seconds, play 4 times (1 + 3 repeats),
# but stop playing after 5 seconds.
sound.play( :fade_in => 2, :repeats => 3, :stop_after => 5 );
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/rubygame/sound.rb', line 168 def play( ={} ) fade_in = ([:fade_in] or 0) repeats = ([:repeats] or 0) stop_after = ([:stop_after] or nil) fade_in = if( fade_in < 0 ) raise ArgumentError, ":fade_in cannot be negative (got %.2f)"%fade_in elsif( fade_in < 0.05 ) # Work-around for a bug with SDL_mixer not working with small # non-zero fade-ins 0 else (fade_in * 1000).to_i end repeats = if( repeats < -1 ) raise( ArgumentError, ":repeats cannot be negative, except -1 (got #{repeats})" ) else repeats end stop_after = if( stop_after.nil? ) -1 elsif( stop_after < 0 ) raise( ArgumentError, ":stop_after cannot be negative, (got %.2f)"%stop_after ) else (stop_after * 1000).to_i end Rubygame.open_audio # If it's already playing on a channel, stop it first. if channel_active? SDL::Mixer.HaltChannel( @channel ) end # Find first available channel @channel = SDL::Mixer.GroupAvailable(-1) if @channel == -1 # No channels were available, so make one more than there are now. # (Mix_AllocateChannels(-1) returns the current number of channels) SDL::Mixer.AllocateChannels( SDL::Mixer.AllocateChannels(-1) + 1 ) # Try again @channel = SDL::Mixer.GroupAvailable(-1) end # Set sound channel volume before we play SDL::Mixer.Volume( @channel, (SDL::Mixer::MAX_VOLUME * @volume).to_i ) result = if( fade_in <= 0 ) # Play sound without fading in SDL::Mixer.PlayChannelTimed( @channel, @struct, repeats, stop_after ) else # Play sound with fading in SDL::Mixer.FadeInChannelTimed( @channel, @struct, repeats, fade_in, stop_after ) end if( result == -1 ) raise Rubygame::SDLError, "Could not play Sound: #{SDL.GetError()}" end return self end |
#playing? ⇒ Boolean
True if the Sound is currently playing (not paused and not stopped). See also #paused? and #stopped?.
259 260 261 262 263 |
# File 'lib/rubygame/sound.rb', line 259 def channel_active? and SDL::Mixer.Playing(@channel) == 1 and SDL::Mixer.Paused(@channel) == 0 end |
#stop ⇒ Object
Stop the Sound. Unlike #pause, the sound must be played again from the beginning, it cannot be resumed from it was stopped.
- Returns
-
The receiver (self).
NOTE: Does nothing if the sound is not currently playing or paused.
317 318 319 320 321 322 323 |
# File 'lib/rubygame/sound.rb', line 317 def stop if channel_active? SDL::Mixer.HaltChannel( @channel ) end return self end |
#stopped? ⇒ Boolean
True if the Sound is currently stopped (not playing and not paused). See also #playing? and #paused?.
329 330 331 |
# File 'lib/rubygame/sound.rb', line 329 def stopped? (not channel_active?) or (SDL::Mixer.Playing(@channel) == 0) end |
#unpause ⇒ Object
Unpause the Sound, if it is currently paused. Resumes from where it was paused. See also #pause and #paused?.
- Returns
-
The receiver (self).
NOTE: Does nothing if the sound is not currently paused.
290 291 292 293 294 295 296 |
# File 'lib/rubygame/sound.rb', line 290 def unpause if channel_active? SDL::Mixer.Resume( @channel ) end return self end |
#volume ⇒ Object
Return the volume level of the sound. 0.0 is totally silent, 1.0 is full volume.
NOTE: Ignores fading in or out.
385 386 387 |
# File 'lib/rubygame/sound.rb', line 385 def volume @volume end |
#volume=(new_vol) ⇒ Object
Set the new #volume level of the sound. 0.0 is totally silent, 1.0 is full volume. The new volume will be clamped to this range if it is too small or too large.
Volume cannot be set while the sound is fading in or out. Be sure to check #fading? or rescue from SDLError when using this method.
- May raise
-
SDLError if the sound is fading in or out.
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/rubygame/sound.rb', line 401 def volume=( new_vol ) # Clamp it to valid range new_vol = if new_vol < 0.0; 0.0 elsif new_vol > 1.0; 1.0 else; new_vol end if channel_active? if fading? raise Rubygame::SDLError, "cannot set Sound volume while fading" else SDL::Mixer.Volume( @channel, (SDL::Mixer::MAX_VOLUME * new_vol).to_i ) end end @volume = new_vol end |