Class: SFML::Sound

Inherits:
Object
  • Object
show all
Defined in:
lib/sfml/audio/sound.rb

Overview

A short sound that plays from a SoundBuffer held entirely in memory. Cheap to create, suitable for game SFX (blips, hits, footsteps).

buffer = SFML::SoundBuffer.load("blip.wav")
sound  = SFML::Sound.new(buffer, volume: 80, pitch: 1.2, looping: true)
sound.play

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer, volume: 100.0, pitch: 1.0, looping: false) ⇒ Sound

Returns a new instance of Sound.

Raises:

  • (ArgumentError)


9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/sfml/audio/sound.rb', line 9

def initialize(buffer, volume: 100.0, pitch: 1.0, looping: false)
  raise ArgumentError, "Sound requires a SFML::SoundBuffer" unless buffer.is_a?(SoundBuffer)

  ptr = C::Audio.sfSound_create(buffer.handle)
  raise AudioError, "sfSound_create returned NULL" if ptr.null?
  @handle = FFI::AutoPointer.new(ptr, C::Audio.method(:sfSound_destroy))
  @buffer  = buffer # keep alive
  # @looping mirrors the loop flag because SFML 3's isLooping reads
  # through an OpenAL source that may be unallocated on systems
  # without an audio device (some CI runners). Caching on the Ruby
  # side keeps observable behaviour deterministic regardless.
  @looping = false

  self.volume  = volume
  self.pitch   = pitch
  self.looping = looping
end

Instance Attribute Details

#buffer ⇒ Object

The buffer this Sound is currently bound to (the one passed to .new, or whoever last called buffer=). Returns nil if the underlying source has none.



28
29
30
# File 'lib/sfml/audio/sound.rb', line 28

def buffer
  @buffer
end

Instance Method Details

#attenuation ⇒ Object

Falloff sharpness with distance. 0 = no falloff, 1 = realistic (1/distance), higher = steeper.



193
# File 'lib/sfml/audio/sound.rb', line 193

def attenuation = C::Audio.sfSound_getAttenuation(@handle)

#attenuation=(value) ⇒ Object

Set the attenuation — see #attenuation.



196
197
198
# File 'lib/sfml/audio/sound.rb', line 196

def attenuation=(value)
  C::Audio.sfSound_setAttenuation(@handle, value.to_f)
end

#cone ⇒ Object

Directional-attenuation cone — see SFML::SoundCone.



108
109
110
# File 'lib/sfml/audio/sound.rb', line 108

def cone
  SoundCone.from_native(C::Audio.sfSound_getCone(@handle))
end

#cone=(value) ⇒ Object

Set the cone. Accepts a SoundCone or a Hash with inner_angle, outer_angle, outer_gain.



114
115
116
117
118
119
120
121
122
123
# File 'lib/sfml/audio/sound.rb', line 114

def cone=(value)
  cone =
    case value
    when SoundCone then value
    when Hash      then SoundCone.new(**value)
    else
      raise ArgumentError, "Sound#cone= expects SoundCone or Hash; got #{value.class}"
    end
  C::Audio.sfSound_setCone(@handle, cone.to_native)
end

#direction ⇒ Object

The direction the sound's cone points. Used together with #cone= for directional attenuation.



94
95
96
97
# File 'lib/sfml/audio/sound.rb', line 94

def direction
  v = C::Audio.sfSound_getDirection(@handle)
  Vector3.new(v[:x], v[:y], v[:z])
end

#direction=(value) ⇒ Object

Set the direction vector — accepts Vector3 or [x, y, z].



100
101
102
103
104
105
# File 'lib/sfml/audio/sound.rb', line 100

def direction=(value)
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
  packed = C::System::Vector3f.new
  packed[:x] = vec.x.to_f; packed[:y] = vec.y.to_f; packed[:z] = vec.z.to_f
  C::Audio.sfSound_setDirection(@handle, packed)
end

#directional_attenuation_factor ⇒ Object

Multiplier on the Listener's directional attenuation cone. 0 = source ignores the listener's facing direction (no cone falloff); 1 = full cone effect.



274
275
276
# File 'lib/sfml/audio/sound.rb', line 274

def directional_attenuation_factor
  C::Audio.sfSound_getDirectionalAttenuationFactor(@handle)
end

#directional_attenuation_factor=(v) ⇒ Object

Set the directional-attenuation factor — see #directional_attenuation_factor.



280
281
282
# File 'lib/sfml/audio/sound.rb', line 280

def directional_attenuation_factor=(v)
  C::Audio.sfSound_setDirectionalAttenuationFactor(@handle, v.to_f)
end

#doppler_factor ⇒ Object

Per-source Doppler scale. 1.0 is realistic; bump it up for an exaggerated Doppler shift, drop to 0 to disable per-source.



88
89
# File 'lib/sfml/audio/sound.rb', line 88

def doppler_factor    = C::Audio.sfSound_getDopplerFactor(@handle)
# Set the per-source Doppler scale. See `#doppler_factor`.

#doppler_factor=(v) ⇒ Object

Set the per-source Doppler scale. See #doppler_factor.



90
# File 'lib/sfml/audio/sound.rb', line 90

def doppler_factor=(v) C::Audio.sfSound_setDopplerFactor(@handle, v.to_f); end

#dup ⇒ Object Also known as: clone

Independent copy — same buffer (buffers are shareable), independent transport state (volume/pan/spatialisation/etc).

Raises:



286
287
288
289
290
291
292
293
294
295
# File 'lib/sfml/audio/sound.rb', line 286

def dup
  ptr = C::Audio.sfSound_copy(@handle)
  raise AudioError, "sfSound_copy returned NULL" if ptr.null?

  copy = self.class.allocate
  copy.instance_variable_set(:@handle,
    FFI::AutoPointer.new(ptr, C::Audio.method(:sfSound_destroy)))
  copy.instance_variable_set(:@buffer, @buffer)
  copy
end

#effect_processor=(callable) ⇒ Object

Install a real-time DSP filter. The callable is invoked from the CSFML audio thread once per audio frame batch with:

* `input` — Array<Float> of interleaved samples (signed [-1, 1])
* `channels` — Integer channel count (e.g. 2 for stereo)

and should return an Array of the same length (or shorter if the effect produces fewer frames). Pass nil to remove an installed processor.

CAVEAT: the callback runs on a real-time audio thread and is called every few milliseconds. Ruby + GVL is rarely fast enough for non-trivial DSP — expect glitches for anything heavier than a constant-gain or simple IIR. For real DSP, do it offline.



137
138
139
140
# File 'lib/sfml/audio/sound.rb', line 137

def effect_processor=(callable)
  @effect_cb = callable.nil? ? nil : Audio._build_effect_processor(callable)
  C::Audio.sfSound_setEffectProcessor(@handle, @effect_cb, nil)
end

#looping=(value) ⇒ Object

Toggle looping playback. With true, the sound restarts from the start after every play-through.



149
150
151
152
# File 'lib/sfml/audio/sound.rb', line 149

def looping=(value)
  @looping = value ? true : false
  C::Audio.sfSound_setLooping(@handle, @looping)
end

#looping? ⇒ Boolean

true if the sound restarts after reaching the end.

Returns:

  • (Boolean)


143
144
145
# File 'lib/sfml/audio/sound.rb', line 143

def looping?
  @looping
end

#max_distance ⇒ Object

The distance beyond which the source is fully attenuated.



255
# File 'lib/sfml/audio/sound.rb', line 255

def max_distance = C::Audio.sfSound_getMaxDistance(@handle)

#max_distance=(v) ⇒ Object

Set the max-distance — see #max_distance.



258
259
260
# File 'lib/sfml/audio/sound.rb', line 258

def max_distance=(v)
  C::Audio.sfSound_setMaxDistance(@handle, v.to_f)
end

#max_gain ⇒ Object

The upper gain bound — see #min_gain.



247
# File 'lib/sfml/audio/sound.rb', line 247

def max_gain = C::Audio.sfSound_getMaxGain(@handle)

#max_gain=(v) ⇒ Object

Set the max-gain cap — see #max_gain.



250
251
252
# File 'lib/sfml/audio/sound.rb', line 250

def max_gain=(v)
  C::Audio.sfSound_setMaxGain(@handle, v.to_f)
end

#min_distance ⇒ Object

Distance below which volume is not attenuated.



201
# File 'lib/sfml/audio/sound.rb', line 201

def min_distance = C::Audio.sfSound_getMinDistance(@handle)

#min_distance=(value) ⇒ Object

Set the min-distance — see #min_distance.



204
205
206
# File 'lib/sfml/audio/sound.rb', line 204

def min_distance=(value)
  C::Audio.sfSound_setMinDistance(@handle, value.to_f)
end

#min_gain ⇒ Object

Output gain clamping. min_gain floors the attenuated gain; max_gain caps it. Useful when you want a sound to always be at least faintly audible (or never louder than the listener's local SFX volume).



239
# File 'lib/sfml/audio/sound.rb', line 239

def min_gain = C::Audio.sfSound_getMinGain(@handle)

#min_gain=(v) ⇒ Object

Set the min-gain floor — see #min_gain.



242
243
244
# File 'lib/sfml/audio/sound.rb', line 242

def min_gain=(v)
  C::Audio.sfSound_setMinGain(@handle, v.to_f)
end

#pan ⇒ Object

Stereo pan in [-1.0, 1.0]: -1 = full left, 0 = centre, 1 = full right.



228
# File 'lib/sfml/audio/sound.rb', line 228

def pan = C::Audio.sfSound_getPan(@handle)

#pan=(v) ⇒ Object

Set the stereo pan — see #pan.



231
232
233
# File 'lib/sfml/audio/sound.rb', line 231

def pan=(v)
  C::Audio.sfSound_setPan(@handle, v.to_f)
end

#pause ⇒ Object

Pause playback. #play resumes from this point; #stop rewinds.



42
43
# File 'lib/sfml/audio/sound.rb', line 42

def pause  = C::Audio.sfSound_pause(@handle)
# Stop playback and rewind to the start.

#paused? ⇒ Boolean

Convenience predicate for status == :paused.

Returns:

  • (Boolean)


51
52
# File 'lib/sfml/audio/sound.rb', line 51

def paused?     = status == :paused
# Convenience predicate for `status == :stopped`.

#pitch ⇒ Object

Pitch multiplier. 1.0 = normal, 2.0 = octave up, 0.5 = octave down. Also shifts playback duration proportionally.



164
# File 'lib/sfml/audio/sound.rb', line 164

def pitch       = C::Audio.sfSound_getPitch(@handle)

#pitch=(value) ⇒ Object

Set the pitch multiplier — see #pitch.



167
168
169
# File 'lib/sfml/audio/sound.rb', line 167

def pitch=(value)
  C::Audio.sfSound_setPitch(@handle, value.to_f)
end

#play ⇒ Object

Start playback. If the sound was paused, resumes from there. If it was already playing, restarts from the beginning.



40
41
# File 'lib/sfml/audio/sound.rb', line 40

def play   = C::Audio.sfSound_play(@handle)
# Pause playback. `#play` resumes from this point; `#stop` rewinds.

#playing? ⇒ Boolean

Convenience predicate for status == :playing.

Returns:

  • (Boolean)


49
50
# File 'lib/sfml/audio/sound.rb', line 49

def playing?    = status == :playing
# Convenience predicate for `status == :paused`.

#playing_offset ⇒ Object

Current playback head as a SFML::Time. Reads from the underlying OpenAL source — only meaningful while the sound is playing or paused (not after #stop).



58
59
60
# File 'lib/sfml/audio/sound.rb', line 58

def playing_offset
  Time.from_native(C::Audio.sfSound_getPlayingOffset(@handle))
end

#playing_offset=(value) ⇒ Object

Seek to value (a SFML::Time, or seconds as a Numeric). Works while the sound is playing, paused, or stopped — calling #play afterwards resumes from the new offset.



65
66
67
68
# File 'lib/sfml/audio/sound.rb', line 65

def playing_offset=(value)
  t = value.is_a?(Time) ? value : Time.seconds(value.to_f)
  C::Audio.sfSound_setPlayingOffset(@handle, t.to_native)
end

#position ⇒ Object

---- 3D positional audio ----

Sounds have a 3D position; the SFML::Listener acts as the "ear". Volume falls off with distance from min_distance outward, scaled by attenuation (0 = no falloff, 1 = realistic, higher = sharper). By default a Sound's position is in world coordinates; flip relative_to_listener = true and the position becomes relative to the listener — useful for "stuck to the camera" UI sounds.

For 2D games, set z = 0 and listener.position to your camera.



181
182
183
# File 'lib/sfml/audio/sound.rb', line 181

def position
  Vector3.from_native(C::Audio.sfSound_getPosition(@handle))
end

#position=(value) ⇒ Object

Set the 3D position — accepts Vector3 or [x, y, z].



186
187
188
189
# File 'lib/sfml/audio/sound.rb', line 186

def position=(value)
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
  C::Audio.sfSound_setPosition(@handle, vec.to_native_f)
end

#relative_to_listener=(value) ⇒ Object

Toggle listener-relative positioning.



214
215
216
# File 'lib/sfml/audio/sound.rb', line 214

def relative_to_listener=(value)
  C::Audio.sfSound_setRelativeToListener(@handle, value ? true : false)
end

#relative_to_listener? ⇒ Boolean

If true, #position is interpreted relative to the listener (useful for HUD/UI sounds that should stay glued to the camera).

Returns:

  • (Boolean)


211
# File 'lib/sfml/audio/sound.rb', line 211

def relative_to_listener? = C::Audio.sfSound_isRelativeToListener(@handle)

#spatialization_enabled=(v) ⇒ Object

Toggle 3D spatialisation — see #spatialization_enabled?.



267
268
269
# File 'lib/sfml/audio/sound.rb', line 267

def spatialization_enabled=(v)
  C::Audio.sfSound_setSpatializationEnabled(@handle, v ? true : false)
end

#spatialization_enabled? ⇒ Boolean

Whether 3D-positional / Doppler / cone math is applied at mix time. Off → the sound plays as a simple stereo source.

Returns:

  • (Boolean)


264
# File 'lib/sfml/audio/sound.rb', line 264

def spatialization_enabled? = C::Audio.sfSound_isSpatializationEnabled(@handle)

#status ⇒ Object

Playback state — one of :stopped, :paused, :playing.



47
48
# File 'lib/sfml/audio/sound.rb', line 47

def status      = C::Audio::STATUSES[C::Audio.sfSound_getStatus(@handle)]
# Convenience predicate for `status == :playing`.

#stop ⇒ Object

Stop playback and rewind to the start.



44
# File 'lib/sfml/audio/sound.rb', line 44

def stop   = C::Audio.sfSound_stop(@handle)

#stopped? ⇒ Boolean

Convenience predicate for status == :stopped.

Returns:

  • (Boolean)


53
# File 'lib/sfml/audio/sound.rb', line 53

def stopped?    = status == :stopped

#velocity ⇒ Object

3D velocity in world units / second — used by the Doppler effect to shift pitch as the source approaches or recedes from the listener.



73
74
75
76
# File 'lib/sfml/audio/sound.rb', line 73

def velocity
  v = C::Audio.sfSound_getVelocity(@handle)
  Vector3.new(v[:x], v[:y], v[:z])
end

#velocity=(value) ⇒ Object

Set the 3D velocity — accepts a Vector3 or [x, y, z].



79
80
81
82
83
84
# File 'lib/sfml/audio/sound.rb', line 79

def velocity=(value)
  vec = value.is_a?(Vector3) ? value : Vector3.new(*value)
  packed = C::System::Vector3f.new
  packed[:x] = vec.x.to_f; packed[:y] = vec.y.to_f; packed[:z] = vec.z.to_f
  C::Audio.sfSound_setVelocity(@handle, packed)
end

#volume ⇒ Object

Playback volume in [0, 100] — 100 = unattenuated.



155
# File 'lib/sfml/audio/sound.rb', line 155

def volume      = C::Audio.sfSound_getVolume(@handle)

#volume=(value) ⇒ Object

Set the playback volume in [0, 100].



158
159
160
# File 'lib/sfml/audio/sound.rb', line 158

def volume=(value)
  C::Audio.sfSound_setVolume(@handle, value.to_f)
end