win32-sound 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES ADDED
@@ -0,0 +1,33 @@
1
+ == 0.4.0 - 26-Feb-2006
2
+ * Now pure Ruby only.
3
+ * Documentation updates and reorganization.
4
+ * Added a gemspec.
5
+ * Minor test suite changes.
6
+
7
+ == 0.3.0 - 29-May-2005
8
+ * Changed the Sound.volume= method (which didn't work) to
9
+ Sound.set_wave_volume because it takes up to two values and only affects
10
+ the wave volume, not the master volume.
11
+ * Renamed the Sound.volume method to Sound.wave_volume.
12
+ * Fixed a bug in the Sound.wave_volume method.
13
+ * Created the Sound.get_wave_volume alias for Sound.wave_volume.
14
+ * Fixed the Sound.set_wave_volume method.
15
+ * Test adjustments and additions to reflect API changes.
16
+ * Now Unicode friendly.
17
+ * Removed the sound.rd file. The sound.txt file is now rdoc friendly.
18
+
19
+ == 0.2.1 - 1-Mar-2005
20
+ * Moved the 'examples' directory to the toplevel directory
21
+ * Made the CHANGES and README files rdoc friendly
22
+ * Some cleanup in sound.h.
23
+
24
+ == 0.2.0 - 13-Jul-2004
25
+ * Moved the SoundError class under the Win32 module namespace
26
+ * Replaced the deprecated STR2CSTR() function with the StringValuePtr()
27
+ function. This means that as of version 0.2.0, this package requires
28
+ Ruby 1.8.0 or later.
29
+ * Moved the test.rb script to doc/examples
30
+ * Added the README file (oops).
31
+
32
+ == 0.1.0 - 14-Feb-2004
33
+ * Initial release
data/MANIFEST ADDED
@@ -0,0 +1,11 @@
1
+ MANIFEST
2
+ CHANGES
3
+ README
4
+ install.rb
5
+ win32-sound.gempsec
6
+
7
+ examples/sound_test.rb
8
+
9
+ lib/win32/sound.rb
10
+
11
+ test/tc_sound.rb
data/README ADDED
@@ -0,0 +1,69 @@
1
+ == Description
2
+ A package for playing with sound on Windows.
3
+
4
+ == Prerequisites
5
+ This package requires Ruby 1.8.0 or later.
6
+
7
+ == Installation instructions
8
+ === Gem installation
9
+ ruby win32-sound.gemspect
10
+ gem install win32-sound-X.X.X.gem
11
+
12
+ === Manual installation
13
+ ruby install.rb
14
+ ri lib\win32\sound.rb (to generate documentation)
15
+
16
+ == Synopsis
17
+ require "win32/sound"
18
+ include Win32
19
+
20
+ # Get the current volume of the waveform-audio output device.
21
+ p Sound.volume.join(", ") # left channel, right channel
22
+
23
+ # Play a system sound
24
+ Sound.play("SystemAsterisk",Sound::ALIAS)
25
+
26
+ # Play a wav file
27
+ Sound.play("somefile.wav")
28
+
29
+ == Acknowledgements
30
+ API ideas derived (or not) from Perl's Win32::Sound module and Python's
31
+ winsound package.
32
+
33
+ == Known Bugs
34
+ None that I'm aware of. Please report any bugs on the Win32 Utils home
35
+ page at http://rubyforge.org/projects/win32utils.
36
+
37
+ == Questions and Comments
38
+ Please post questions and/or comments on one of the forums on the project
39
+ page at http://rubyforge.org/projects/win32utils. Click the 'Forums' tab.
40
+
41
+ == Future Plans
42
+ Add ability to retrieve information about WAV files.
43
+ Add MIDI support?
44
+
45
+ == Developer's Notes
46
+ The MessageBeep() function, which the Python "winsound" module contains,
47
+ is intentionally omitted here. I felt it was redundant, because you can
48
+ achieve the same effect with something like
49
+ Sound.play("SystemAsterisk", Sound::ALIAS).
50
+
51
+ == License
52
+ Ruby's
53
+
54
+ == Copyright
55
+ (C) 2004-2006, Daniel J. Berger, All Rights Reserved
56
+
57
+ == Warranty
58
+ This package is provided "as is" and without any express or
59
+ implied warranties, including, without limitation, the implied
60
+ warranties of merchantability and fitness for a particular purpose.
61
+
62
+ == Author(s)
63
+ Daniel Berger
64
+ djberg96 at gmail dot com
65
+ imperator/mok on IRC (irc.freenode.net)
66
+
67
+ Park Heesob
68
+ phasis at nownuri dot net
69
+ phasis68 on IRC (irc.freenode.net)
@@ -0,0 +1,50 @@
1
+ ##############################################################
2
+ # sound_test.rb (win32-sound)
3
+ #
4
+ # A test script for general futzing. Modify as you see fit.
5
+ ##############################################################
6
+ if File.basename(Dir.pwd) == "examples"
7
+ Dir.chdir ".."
8
+ $LOAD_PATH.unshift Dir.pwd + '/lib'
9
+ end
10
+
11
+ require "win32/sound"
12
+ include Win32
13
+
14
+ wav = "c:\\windows\\media\\chimes.wav"
15
+
16
+ puts "VERSION: " + Sound::VERSION
17
+ #puts "Devices: " + Sound.devices.join(", ")
18
+
19
+ #Sound.volume = [77,128] # my personal settings
20
+
21
+ orig_left, orig_right = Sound.wave_volume
22
+ puts "Volume was: #{orig_left}, #{orig_right}"
23
+
24
+ #Sound.volume = 140
25
+ #puts "Volume is now: " + Sound.volume.join(", ")
26
+
27
+ #Sound.volume = [orig_left,orig_right]
28
+ #puts "Volume is now: " + Sound.volume.join(", ")
29
+
30
+ puts "Playing 'SystemAsterisk' sound"
31
+ sleep 1
32
+ Sound.play("SystemAsterisk",Sound::ALIAS)
33
+
34
+ puts "Playing 'chimes' sound once"
35
+ sleep 1
36
+ Sound.play(wav)
37
+
38
+ puts "Playing 'chimes' sound in a loop for 3 seconds"
39
+ sleep 1
40
+ Sound.play(wav,Sound::ASYNC|Sound::LOOP)
41
+ sleep 3
42
+ Sound.stop
43
+
44
+ puts "Playing default sound"
45
+ sleep 1
46
+ Sound.play("Foofoo",Sound::ALIAS)
47
+
48
+ puts "Playing a beep"
49
+ sleep 1
50
+ Sound.beep(500,10000)
@@ -0,0 +1,202 @@
1
+ require 'Win32API'
2
+ module Win32
3
+ class SoundError < StandardError; end
4
+ class Sound
5
+ VERSION = '0.4.0'
6
+ LOW_FREQUENCY = 37
7
+ HIGH_FREQUENCY = 32767
8
+ MAX_VOLUME = 0xFFFF
9
+
10
+ SYNC = 0x0000 # play synchronously (default)
11
+ ASYNC = 0x0001 # play asynchronously
12
+ NODEFAULT = 0x0002 # silence (!default) if sound not found
13
+ MEMORY = 0x0004 # pszSound points to a memory file
14
+ LOOP = 0x0008 # loop the sound until next sndPlaySound
15
+ NOSTOP = 0x0010 # don't stop any currently playing sound
16
+ NOWAIT = 8192 # don't wait if the driver is busy
17
+ ALIAS = 65536 # name is a registry alias
18
+ ALIAS_ID = 1114112 # alias is a predefined ID
19
+ FILENAME = 131072 # name is file name
20
+ RESOURCE = 262148 # name is resource name or atom
21
+ PURGE = 0x0040 # purge non-static events for task
22
+ APPLICATION = 0x0080 # look for application specific association
23
+
24
+ @@Beep = Win32API.new('kernel32', 'Beep', 'LL', 'I')
25
+ @@PlaySound = Win32API.new('winmm', 'PlaySound', 'PPL', 'I')
26
+ @@waveOutSetVolume = Win32API.new('winmm', 'waveOutSetVolume', 'PL', 'I')
27
+ @@waveOutGetVolume = Win32API.new('winmm', 'waveOutGetVolume', 'IP', 'I')
28
+ @@waveOutGetNumDevs = Win32API.new('winmm', 'waveOutGetNumDevs', 'V', 'I')
29
+ @@waveInGetNumDevs = Win32API.new('winmm', 'waveInGetNumDevs', 'V', 'I')
30
+ @@midiOutGetNumDevs = Win32API.new('winmm', 'midiOutGetNumDevs', 'V', 'I')
31
+ @@midiInGetNumDevs = Win32API.new('winmm', 'midiInGetNumDevs', 'V', 'I')
32
+ @@auxGetNumDevs = Win32API.new('winmm', 'auxGetNumDevs', 'V', 'I')
33
+ @@mixerGetNumDevs = Win32API.new('winmm', 'mixerGetNumDevs', 'V', 'I')
34
+
35
+ @@GetLastError = Win32API.new('kernel32', 'GetLastError', '', 'L')
36
+ @@FormatMessage = Win32API.new('kernel32', 'FormatMessage', 'LPLLPLP', 'L')
37
+
38
+ # Returns an array of all the available sound devices; their names contain
39
+ # the type of the device and a zero-based ID number. Possible return values
40
+ # are WAVEOUT, WAVEIN, MIDIOUT, MIDIIN, AUX or MIXER.
41
+ def self.devices
42
+ devs = []
43
+
44
+ begin
45
+ 0.upto(@@waveOutGetNumDevs.call){ |i| devs << "WAVEOUT#{i}" }
46
+ 0.upto(@@waveInGetNumDevs.call){ |i| devs << "WAVEIN#{i}" }
47
+ 0.upto(@@midiOutGetNumDevs.call){ |i| devs << "MIDIOUT#{i}" }
48
+ 0.upto(@@midiInGetNumDevs.call){ |i| devs << "MIDIIN#{i}" }
49
+ 0.upto(@@auxGetNumDevs.call){ |i| devs << "AUX#{i}" }
50
+ 0.upto(@@mixerGetNumDevs.call){ |i| devs << "MIXER#{i}" }
51
+ rescue Exception => err
52
+ raise SoundError, get_last_error
53
+ end
54
+
55
+ devs
56
+ end
57
+
58
+ # Generates simple tones on the speaker. The function is synchronous; it
59
+ # does not return control to its caller until the sound finishes.
60
+ #
61
+ # The frequency (in Hertz) must be between 37 and 32767.
62
+ # The duration is in milliseconds.
63
+ def self.beep(frequency, duration)
64
+ if frequency > HIGH_FREQUENCY || frequency < LOW_FREQUENCY
65
+ raise SoundError, 'invalid frequency'
66
+ end
67
+
68
+ if 0 == @@Beep.call(frequency, duration)
69
+ raise SoundError, get_last_error
70
+ end
71
+ self
72
+ end
73
+
74
+ # Stops any currently playing waveform sound. If +purge+ is set to
75
+ # true, then *all* sounds are stopped. The default is false.
76
+ def self.stop(purge = false)
77
+ if purge && purge != 0
78
+ flags = PURGE
79
+ else
80
+ flags = 0
81
+ end
82
+
83
+ if 0 == @@PlaySound.call(0, 0, flags)
84
+ raise SoundError, get_last_error
85
+ end
86
+ self
87
+ end
88
+
89
+ # Plays the specified sound. The sound can be a wave file or a system
90
+ # sound, when used in conjunction with the ALIAS flag.
91
+ #
92
+ # Valid flags:
93
+ #
94
+ # Sound::ALIAS
95
+ # The sound parameter is a system-event alias in the registry or the
96
+ # WIN.INI file. If the registry contains no such name, it plays the
97
+ # system default sound unless the NODEFAULT value is also specified.
98
+ # Do not use with FILENAME.
99
+ #
100
+ # Sound::APPLICATION
101
+ # The sound is played using an application-specific association.
102
+ #
103
+ # Sound::ASYNC
104
+ # The sound is played asynchronously and the function returns
105
+ # immediately after beginning the sound.
106
+ #
107
+ # Sound::FILENAME
108
+ # The sound parameter is the name of a WAV file. Do not use with
109
+ # ALIAS.
110
+ #
111
+ # Sound::LOOP
112
+ # The sound plays repeatedly until Sound.stop() is called. You must
113
+ # also specify the ASYNC flag to loop sounds.
114
+ #
115
+ # Sound::MEMORY
116
+ # The sound points to an image of a waveform sound in memory.
117
+ #
118
+ # Sound::NODEFAULT
119
+ # If the sound cannot be found, the function returns silently without
120
+ # playing the default sound.
121
+ #
122
+ # Sound::NOSTOP
123
+ # If a sound is currently playing, the function immediately returns
124
+ # false without playing the requested sound.
125
+ #
126
+ # Sound::NOWAIT
127
+ # If the driver is busy, return immediately without playing the sound.
128
+ #
129
+ # Sound::PURGE
130
+ # Stop playing all instances of the specified sound.
131
+ #
132
+ # Sound::SYNC
133
+ # The sound is played synchronously and the function does not return
134
+ # until the sound ends.
135
+ def self.play(sound, flags = 0)
136
+ if 0 == @@PlaySound.call(sound, 0, flags)
137
+ raise SoundError, get_last_error
138
+ end
139
+ self
140
+ end
141
+
142
+ # Sets the volume for the left and right channel. If the +right_channel+
143
+ # is omitted, the volume is set for *both* channels.
144
+ #
145
+ # You may optionally pass a single Integer rather than an Array, in which
146
+ # case it is assumed you are setting both channels to the same value.
147
+ def self.set_wave_volume(left_channel, right_channel = nil)
148
+ right_channel ||= left_channel
149
+
150
+ lvolume = left_channel > MAX_VOLUME ? MAX_VOLUME : left_channel
151
+ rvolume = right_channel > MAX_VOLUME ? MAX_VOLUME : right_channel
152
+
153
+ volume = lvolume | rvolume << 16
154
+
155
+ if @@waveOutSetVolume.call(-1, volume) != 0
156
+ raise SoundError, get_last_error
157
+ end
158
+ self
159
+ end
160
+
161
+ # Returns a 2-element array that contains the volume for the left channel
162
+ # and right channel, respectively.
163
+ def self.wave_volume
164
+ volume = [0].pack('L')
165
+ if @@waveOutGetVolume.call(-1, volume) != 0
166
+ raise SoundError, get_last_error
167
+ end
168
+ volume = volume.unpack('L').first
169
+ [low_word(volume), high_word(volume)]
170
+ end
171
+
172
+ # Alias for Sound.wave_volume
173
+ def self.get_wave_volume
174
+ self.wave_volume
175
+ end
176
+
177
+ private
178
+
179
+ def self.low_word(num)
180
+ num & 0xFFFF
181
+ end
182
+
183
+ def self.high_word(num)
184
+ num >> 16
185
+ end
186
+
187
+ # Convenience method that wraps FormatMessage with some sane defaults.
188
+ def self.get_last_error(err_num = @@GetLastError.call)
189
+ buf = 0.chr * 260
190
+ @@FormatMessage.call(
191
+ 12288,
192
+ 0,
193
+ err_num,
194
+ 0,
195
+ buf,
196
+ buf.length,
197
+ 0
198
+ )
199
+ buf.split(0.chr).first.chomp
200
+ end
201
+ end
202
+ end
data/test/tc_sound.rb ADDED
@@ -0,0 +1,95 @@
1
+ ###########################################
2
+ # tc_sound.rb
3
+ #
4
+ # Test suite for the win32-sound package.
5
+ ############################################
6
+ base = File.basename(Dir.pwd)
7
+
8
+ if base == "test" || base =~ /win32-sound/
9
+ Dir.chdir("..") if base == "test"
10
+ $LOAD_PATH.unshift Dir.pwd + '/lib'
11
+ Dir.chdir("test") if base =~ /win32-sound/
12
+ end
13
+
14
+ puts "You may hear some funny noises - don't panic"
15
+ sleep 1
16
+
17
+ require "test/unit"
18
+ require "win32/sound"
19
+ include Win32
20
+
21
+ class TC_Sound < Test::Unit::TestCase
22
+ def setup
23
+ @wav = "c:\\windows\\media\\chimes.wav"
24
+ end
25
+
26
+ def test_version
27
+ assert_equal("0.4.0", Sound::VERSION)
28
+ end
29
+
30
+ def test_beep
31
+ assert_respond_to(Sound, :beep)
32
+ assert_nothing_raised{ Sound.beep(55,100) }
33
+
34
+ assert_raises(SoundError){ Sound.beep(0,100) }
35
+ assert_raises(ArgumentError){ Sound.beep }
36
+ assert_raises(ArgumentError){ Sound.beep(500) }
37
+ assert_raises(ArgumentError){ Sound.beep(500,500,5) }
38
+ end
39
+
40
+ def test_devices
41
+ assert_respond_to(Sound, :devices)
42
+ assert_nothing_raised{ Sound.devices }
43
+
44
+ assert_kind_of(Array,Sound.devices)
45
+ end
46
+
47
+ def test_stop
48
+ assert_respond_to(Sound, :stop)
49
+ assert_nothing_raised{ Sound.stop }
50
+ assert_nothing_raised{ Sound.stop(true) }
51
+ end
52
+
53
+ def test_get_volume
54
+ assert_respond_to(Sound, :wave_volume)
55
+ assert_respond_to(Sound, :get_wave_volume)
56
+ assert_nothing_raised{ Sound.get_wave_volume }
57
+
58
+ assert_kind_of(Array, Sound.get_wave_volume)
59
+ assert_equal(2, Sound.get_wave_volume.length)
60
+ end
61
+
62
+ def test_set_volume
63
+ assert_respond_to(Sound, :set_wave_volume)
64
+ assert_nothing_raised{ Sound.set_wave_volume(30000) } # About half
65
+ assert_nothing_raised{ Sound.set_wave_volume(30000, 30000) }
66
+ end
67
+
68
+ def test_play
69
+ assert_respond_to(Sound, :play)
70
+ assert_nothing_raised{ Sound.play(@wav) }
71
+ assert_nothing_raised{ Sound.play("SystemAsterisk", Sound::ALIAS) }
72
+ end
73
+
74
+ def test_expected_errors
75
+ assert_raises(SoundError){ Sound.beep(-1, 1) }
76
+ end
77
+
78
+ def test_constants
79
+ assert_not_nil(Sound::ALIAS)
80
+ assert_not_nil(Sound::APPLICATION)
81
+ assert_not_nil(Sound::ASYNC)
82
+ assert_not_nil(Sound::FILENAME)
83
+ assert_not_nil(Sound::LOOP)
84
+ assert_not_nil(Sound::MEMORY)
85
+ assert_not_nil(Sound::NODEFAULT)
86
+ assert_not_nil(Sound::NOSTOP)
87
+ assert_not_nil(Sound::NOWAIT)
88
+ assert_not_nil(Sound::PURGE)
89
+ assert_not_nil(Sound::SYNC)
90
+ end
91
+
92
+ def teardown
93
+ @wav = nil
94
+ end
95
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.11
3
+ specification_version: 1
4
+ name: win32-sound
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.4.0
7
+ date: 2006-02-26 00:00:00 -07:00
8
+ summary: A package for playing with sound on Windows.
9
+ require_paths:
10
+ - lib
11
+ email: djberg96@gmail.com
12
+ homepage: http://www.rubyforge.org/projects/win32utils
13
+ rubyforge_project: win32utils
14
+ description: A package for playing with sound on Windows.
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ authors:
29
+ - Daniel J. Berger
30
+ files:
31
+ - examples/sound_test.rb
32
+ - lib/win32/sound.rb
33
+ - test/tc_sound.rb
34
+ - CHANGES
35
+ - MANIFEST
36
+ - README
37
+ test_files:
38
+ - test/tc_sound.rb
39
+ rdoc_options: []
40
+
41
+ extra_rdoc_files:
42
+ - CHANGES
43
+ - README
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ requirements: []
49
+
50
+ dependencies: []
51
+