win32-sound 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+