Class: Win32::Sound

Inherits:
Object
  • Object
show all
Extended by:
Windows::SoundFunctions
Includes:
Windows::SoundStructs
Defined in:
lib/win32/sound.rb

Overview

The Sound class encapsulates various methods for playing sound as well as querying or configuring sound related properties.

Constant Summary collapse

VERSION =

The version of the win32-sound library

'0.6.2'.freeze
SYNC =

play synchronously (default)

0x00000000
ASYNC =

play asynchronously

0x00000001
NODEFAULT =

silence (!default) if sound not found

0x00000002
MEMORY =

pszSound points to a memory file

0x00000004
LOOP =

loop the sound until next sndPlaySound

0x00000008
NOSTOP =

don’t stop any currently playing sound

0x00000010
NOWAIT =

don’t wait if the driver is busy

8192
ALIAS =

name is a registry alias

65536
ALIAS_ID =

alias is a predefined ID

1114112
FILENAME =

name is file name

131072
RESOURCE =

name is resource name or atom

262148
PURGE =

purge non-static events for task

0x00000040
APPLICATION =

look for app specific association

0x00000080

Class Method Summary collapse

Class Method Details

.beep(frequency, duration) ⇒ Object

Generates simple tones on the speaker. The function is synchronous; it does not return control to its caller until the sound finishes.

The frequency (in Hertz) must be between 37 and 32767. The duration is in milliseconds.



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

def self.beep(frequency, duration)
  if frequency > HIGH_FREQUENCY || frequency < LOW_FREQUENCY
    raise ArgumentError, 'invalid frequency'
  end

  if 0 == Beep(frequency, duration)
    raise SystemCallError, FFI.errno, "Beep"
  end

  self
end

.devicesObject

Returns an array of all the available sound devices; their names contain the type of the device and a zero-based ID number. Possible return values are WAVEOUT, WAVEIN, MIDIOUT, MIDIIN, AUX or MIXER.



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/win32/sound.rb', line 91

def self.devices
  devs = []

  begin
    0.upto(waveOutGetNumDevs()){ |i| devs << "WAVEOUT#{i}" }
    0.upto(waveInGetNumDevs()){ |i| devs << "WAVEIN#{i}" }
    0.upto(midiOutGetNumDevs()){ |i| devs << "MIDIOUT#{i}" }
    0.upto(midiInGetNumDevs()){ |i| devs << "MIDIIN#{i}" }
    0.upto(auxGetNumDevs()){ |i| devs << "AUX#{i}" }
    0.upto(mixerGetNumDevs()){ |i| devs << "MIXER#{i}" }
  rescue Exception
    raise SystemCallError, FFI.errno, "GetNumDevs"
  end

  devs
end

.play(sound, flags = 0) ⇒ Object

Plays the specified sound. The sound can be a wave file or a system sound, when used in conjunction with the ALIAS flag.

Valid flags:

Sound::ALIAS

The sound parameter is a system-event alias in the registry or the
WIN.INI file. If the registry contains no such name, it plays the
system default sound unless the NODEFAULT value is also specified.
Do not use with FILENAME.

Sound::APPLICATION

The sound is played using an application-specific association.

Sound::ASYNC

The sound is played asynchronously and the function returns
immediately after beginning the sound.

Sound::FILENAME

The sound parameter is the name of a WAV file.  Do not use with
ALIAS.

Sound::LOOP

The sound plays repeatedly until Sound.stop() is called. You must
also specify the ASYNC flag to loop sounds.

Sound::MEMORY

The sound points to an image of a waveform sound in memory.

Sound::NODEFAULT

If the sound cannot be found, the function returns silently without
playing the default sound.

Sound::NOSTOP

If a sound is currently playing, the function immediately returns
false without playing the requested sound.

Sound::NOWAIT

If the driver is busy, return immediately without playing the sound.

Sound::PURGE

Stop playing all instances of the specified sound.

Sound::SYNC

The sound is played synchronously and the function does not return
until the sound ends.

Examples:

require 'win32/sound'
include Win32

# Play a wave file once
Sound.play('some_file.wav')

# Play a wave file in an asynchronous loop for 2 seconds
Sound.play('some_file.wav', Sound::ASYNC | Sound::LOOP)
sleep 2
Sound.stop


203
204
205
206
207
208
209
# File 'lib/win32/sound.rb', line 203

def self.play(sound, flags = 0)
  unless PlaySound(sound, 0, flags)
    raise SystemCallError, FFI.errno, "PlaySound"
  end

  self
end

.play_freq(frequency = 440, duration = 1000, volume = 1, immediate_playback = true) ⇒ Object

Plays a frequency for a specified duration at a given volume. Defaults are 440Hz, 1 second, full volume.

The result is a single channel, 44100Hz sampled, 16 bit sine wave. If multiple instances are plays in simultaneous threads, they will be started and played at the same time.

ex.: threads = []

[440, 660].each do |freq|
  threads << Thread.new { Win32::Sound.play_freq(freq) }
end
threads.each { |th| th.join }

The first frequency in this array (440) will wait until the thread for 660 finished calculating its PCM array and they will both start streaming at the same time.

If immediate_playback is set to false, the thread will calculate all pending PCM arrays and wait to be woken up again. This if useful for time-sensitive playback of notes in succession.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/win32/sound.rb', line 63

def self.play_freq(frequency = 440, duration = 1000, volume = 1, immediate_playback = true)

  if frequency > HIGH_FREQUENCY || frequency < LOW_FREQUENCY
    raise ArgumentError, 'invalid frequency'
  end

  if duration < 0 || duration > 5000
    raise ArgumentError, 'invalid duration'
  end

  if volume.abs > 1
    warn("WARNING: Volume greater than 1 will cause audio clipping.")
  end

  stream(immediate_playback) do |wfx|
    data = generate_pcm_integer_array_for_freq(frequency, duration, volume)
    data_buffer = FFI::MemoryPointer.new(:int, data.size)
    data_buffer.write_array_of_int data
    buffer_length = wfx[:nAvgBytesPerSec]*duration/1000
    WAVEHDR.new(data_buffer, buffer_length)
  end

end

.set_wave_volume(left_channel, right_channel = nil) ⇒ Object

Sets the volume for the left and right channel. If the right_channel is omitted, the volume is set for both channels.

You may optionally pass a single Integer rather than an Array, in which case it is assumed you are setting both channels to the same value.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
# File 'lib/win32/sound.rb', line 217

def self.set_wave_volume(left_channel, right_channel = nil)
  right_channel ||= left_channel

  lvolume = left_channel > MAX_VOLUME ? MAX_VOLUME : left_channel
  rvolume = right_channel > MAX_VOLUME ? MAX_VOLUME : right_channel

  volume = lvolume | rvolume << 16

  if waveOutSetVolume(-1, volume) != 0
    raise SystemCallError, FFI.errno, "waveOutSetVolume"
  end

  self
end

.stop(purge = false) ⇒ Object

Stops any currently playing waveform sound. If purge is set to true, then all sounds are stopped. The default is false.



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/win32/sound.rb', line 129

def self.stop(purge = false)
  if purge && purge != 0
    flags = PURGE
  else
    flags = 0
  end

  unless PlaySound(nil, 0, flags)
    raise SystemCallError, FFI.errno, "PlaySound"
  end

  self
end

.wave_volumeObject Also known as: get_wave_volume

Returns a 2-element array that contains the volume for the left channel and right channel, respectively.



235
236
237
238
239
240
241
242
243
244
245
# File 'lib/win32/sound.rb', line 235

def self.wave_volume
  ptr = FFI::MemoryPointer.new(:ulong)

  if waveOutGetVolume(-1, ptr) != 0
    raise SystemCallError, FFI.errno, "waveOutGetVolume"
  end

  volume = ptr.read_long

  [low_word(volume), high_word(volume)]
end