tung-tea 0.3.1 → 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/README.rdoc CHANGED
@@ -69,11 +69,11 @@ What's working:
69
69
 
70
70
  * Events/Input - done
71
71
  * Graphics - done
72
+ * Sound - done
72
73
 
73
74
  What isn't done yet:
74
75
 
75
76
  * Fonts - support bitmap and TrueType fonts in ASCII
76
- * Sound - support loading and playing sound files
77
77
 
78
78
 
79
79
  == More information
@@ -0,0 +1,101 @@
1
+ # A demo that attempts to test all of Tea::Sound's functionality.
2
+
3
+ require 'tea'
4
+
5
+ puts <<TEST
6
+ This is a simple sound demo. Up to 2 sounds can play simultaneously.
7
+
8
+ Keys:
9
+
10
+ [ - Switch to tone 1 (default)
11
+ ] - Switch to tone 2
12
+
13
+ Right - Play tone
14
+ Left - Stop
15
+ Down - Pause
16
+ Up - Resume (unpause)
17
+
18
+ Enter - Print tone's status (stopped/playing/paused)
19
+
20
+ p - Pause all
21
+ r - Resume (unpause) all
22
+ s - Stop all
23
+
24
+ = - Tone volume +1/8
25
+ - - Tone volume -1/8
26
+ + - Master volume +1/8
27
+ _ - Master volume -1/8
28
+
29
+ Esc - Exit demo
30
+ --
31
+ TEST
32
+
33
+ Tea.init
34
+ Tea::Screen.set_mode 100, 100
35
+
36
+ tone_sound = Tea::Sound.new('tone.wav')
37
+ tones = [tone_sound, tone_sound.clone]
38
+
39
+ which_tone = 0
40
+
41
+ done = false
42
+ until done
43
+ e = Tea::Event.get(true)
44
+ case e
45
+ when Tea::Kbd::Down
46
+ case e.key
47
+
48
+ when Tea::Kbd::OPEN_SQUARE_BRACKET
49
+ which_tone -= 1 if which_tone > 0
50
+ puts "Switched to tone ##{which_tone + 1}"
51
+ when Tea::Kbd::CLOSE_SQUARE_BRACKET
52
+ which_tone += 1 if which_tone < tones.length - 1
53
+ puts "Switched to tone ##{which_tone + 1}"
54
+
55
+ when Tea::Kbd::RIGHT
56
+ tones[which_tone].play
57
+ puts "Playing tone ##{which_tone + 1}"
58
+ when Tea::Kbd::LEFT
59
+ tones[which_tone].stop
60
+ puts "Stopping tone ##{which_tone + 1}"
61
+ when Tea::Kbd::DOWN
62
+ tones[which_tone].pause
63
+ puts "Pausing tone ##{which_tone + 1}"
64
+ when Tea::Kbd::UP
65
+ tones[which_tone].resume
66
+ puts "Resuming tone ##{which_tone + 1}"
67
+
68
+ when Tea::Kbd::ENTER
69
+ puts "Tone ##{which_tone + 1} is #{tones[which_tone].state.to_s}"
70
+
71
+ when Tea::Kbd::P
72
+ Tea::Sound.pause_all
73
+ puts "Pausing all sounds"
74
+ when Tea::Kbd::R
75
+ Tea::Sound.resume_all
76
+ puts "Resuming all sounds"
77
+ when Tea::Kbd::S
78
+ Tea::Sound.stop_all
79
+ puts "Stopping all sounds"
80
+
81
+ when Tea::Kbd::EQUALS
82
+ tones[which_tone].volume += 16
83
+ puts "Volume of tone ##{which_tone + 1} raised to #{tones[which_tone].volume} / 128"
84
+ when Tea::Kbd::MINUS
85
+ tones[which_tone].volume -= 16
86
+ puts "Volume of tone ##{which_tone + 1} lowered to #{tones[which_tone].volume} / 128"
87
+ when Tea::Kbd::PLUS
88
+ Tea::Sound.volume += 16
89
+ puts "Master volume raised to #{Tea::Sound.volume} / 128"
90
+ when Tea::Kbd::UNDERSCORE
91
+ Tea::Sound.volume -= 16
92
+ puts "Master volume lowered to #{Tea::Sound.volume} / 128"
93
+
94
+ when Tea::Kbd::ESCAPE
95
+ done = true
96
+
97
+ end
98
+ when Tea::App::Exit
99
+ done = true
100
+ end
101
+ end
@@ -286,7 +286,63 @@ Returns true when the right mouse button is held down.
286
286
 
287
287
  h1. Sound
288
288
 
289
- Nothing yet.
289
+ h2. Tea::Sound
290
+
291
+ A Sound represents a loaded audio file that can be played through the computer's speakers.
292
+
293
+ For now, the supported formats are: OGG, WAV, AIFF, RIFF, VOC.
294
+
295
+ h3. Tea::Sound.volume()
296
+
297
+ Get the master volume. Returns a value between 0 (min) and 128 (max) inclusive.
298
+
299
+ h3. Tea::Sound.volume=(new_volume)
300
+
301
+ Set the master volume. new_volume should be between 0 (min) and 128 (max) inclusive.
302
+
303
+ h3. Tea::Sound.pause_all()
304
+
305
+ Pause all playing sounds.
306
+
307
+ h3. Tea::Sound.resume_all()
308
+
309
+ Resume all paused sounds.
310
+
311
+ h3. Tea::Sound.stop_all()
312
+
313
+ Stop all playing and paused sounds.
314
+
315
+ h3. Tea::Sound.new(path)
316
+
317
+ Load a new sound from an audio file.
318
+
319
+ h3. Tea::Sound#volume()
320
+
321
+ Get the volume of the sound. Returns a value between 0 (min) and 128 (max) inclusive.
322
+
323
+ h3. Tea::Sound#volume=(new_volume)
324
+
325
+ Set the volume of the sound. new_volume should be between 0 (min) and 128 (max) inclusive.
326
+
327
+ h3. Tea::Sound#play(loops=0)
328
+
329
+ Play the sound. If it's already playing, cut it off and start over. loops should be the number of times to repeat the sound; use -1 to repeat it forever.
330
+
331
+ h3. Tea::Sound#pause()
332
+
333
+ Pause the sound if it's playing, otherwise do nothing.
334
+
335
+ h3. Tea::Sound#resume()
336
+
337
+ Resume playing the sound if it was paused, otherwise do nothing.
338
+
339
+ h3. Tea::Sound#stop()
340
+
341
+ Stop the sound if it's playing, otherwise do nothing.
342
+
343
+ h3. Tea::Sound#state()
344
+
345
+ Check if the sound is stopped, playing or paused. Returns one of Tea::Sound::STOPPED, Tea::Sound::PLAYING or Tea::Sound::PAUSED.
290
346
 
291
347
 
292
348
  h1. Fonts
data/lib/tea/c_bitmap.rb CHANGED
@@ -41,6 +41,13 @@ module Tea
41
41
  @buffer.h
42
42
  end
43
43
 
44
+ # Convert the Bitmap's internal format to that of the screen to speed up
45
+ # drawing. Intended for internal use, but calling it manually won't bring
46
+ # any harm.
47
+ def optimize_for_screen
48
+ @buffer = @buffer.display_format_alpha
49
+ end
50
+
44
51
  include Blitting
45
52
  def blitting_buffer
46
53
  @buffer
@@ -78,7 +85,7 @@ module Tea
78
85
  if Tea::Screen.mode_set?
79
86
  @buffer = @buffer.display_format_alpha
80
87
  else
81
- Tea::Screen.on_set_mode lambda { @buffer = @buffer.display_format_alpha }
88
+ Tea::Screen.register_bitmap_for_optimizing self
82
89
  end
83
90
  rescue SDL::Error => e
84
91
  raise Tea::Error, e.message, e.backtrace
@@ -106,7 +113,7 @@ module Tea
106
113
  if Tea::Screen.mode_set?
107
114
  @buffer = @buffer.display_format_alpha
108
115
  else
109
- Tea::Screen.on_set_mode lambda { @buffer = @buffer.display_format_alpha }
116
+ Tea::Screen.register_bitmap_for_optimizing self
110
117
  end
111
118
  rescue SDL::Error => e
112
119
  raise Tea::Error, e.message, e.backtrace
@@ -0,0 +1,145 @@
1
+ # This file contains the Sound class.
2
+
3
+ require 'sdl'
4
+
5
+ require 'tea/c_error'
6
+
7
+ #
8
+ module Tea
9
+
10
+ # The Sound class allows loading and playing of audio files.
11
+ #
12
+ # Currently supported formats: OGG, WAV, AIFF, RIFF, VOC.
13
+ class Sound
14
+
15
+ # Sound states returned by Tea::Sound#state.
16
+ STOPPED = :STOPPED
17
+ PLAYING = :PLAYING
18
+ PAUSED = :PAUSED
19
+
20
+ # As per Ruby/SDL's mixer API.
21
+ VOLUME_MAX = 128
22
+
23
+ # Tracked because Ruby/SDL's mixer API can't get the channel volumes.
24
+ @@volume = VOLUME_MAX
25
+
26
+ # Tracks which Sound objects are playing in which channels, to report
27
+ # accurate playing state info.
28
+ @@channel_sound_ids = []
29
+
30
+ # Get the master volume. Volume ranges from 0..128 inclusive.
31
+ def Sound.volume
32
+ @@volume
33
+ end
34
+
35
+ # Set the master volume. new_volume should be between 0..128 inclusive.
36
+ def Sound.volume=(new_volume)
37
+ v = (new_volume >= 0) ? (new_volume <= VOLUME_MAX ? new_volume : VOLUME_MAX) : 0
38
+ SDL::Mixer.set_volume -1, new_volume
39
+ @@volume = v
40
+ end
41
+
42
+ # Pause all sound.
43
+ def Sound.pause_all
44
+ SDL::Mixer.pause -1
45
+ end
46
+
47
+ # Resume playing all paused sound.
48
+ def Sound.resume_all
49
+ SDL::Mixer.resume -1
50
+ end
51
+
52
+ # Stop all sounds, playing or paused.
53
+ def Sound.stop_all
54
+ SDL::Mixer.halt -1
55
+ end
56
+
57
+
58
+ # Load a sound file.
59
+ #
60
+ # May raise Tea::Error on failure.
61
+ def initialize(path)
62
+ @wave = SDL::Mixer::Wave.load(path)
63
+ @channel = -1
64
+
65
+ # Tracked because Ruby/SDL's mixer API can't get sound volumes.
66
+ @volume = VOLUME_MAX
67
+ rescue SDL::Error => e
68
+ raise Tea::Error, e.message, e.backtrace
69
+ end
70
+
71
+ # Get the sound's volume. Volume ranges from 0..128 inclusive.
72
+ def volume
73
+ @volume
74
+ end
75
+
76
+ # Set the sound's volume. new_volume should be between 0..128 inclusive.
77
+ def volume=(new_volume)
78
+ v = (new_volume >= 0) ? (new_volume <= VOLUME_MAX ? new_volume : VOLUME_MAX) : 0
79
+ @wave.set_volume v
80
+ @volume = v
81
+ end
82
+
83
+ # Play the sound. If this sound is still playing, cut it off and start
84
+ # playing it from the start.
85
+ #
86
+ # loops should be the number of times to repeat playing the sound. Use -1
87
+ # to loop the sound forever.
88
+ def play(loops=0)
89
+ # Cut off the sound if it's already playing.
90
+ SDL::Mixer.halt(@channel) if channel_valid?
91
+
92
+ @channel = SDL::Mixer.play_channel(-1, @wave, loops)
93
+ @@channel_sound_ids[@channel] = object_id
94
+ end
95
+
96
+ # Pause the sound if it's playing, otherwise do nothing.
97
+ def pause
98
+ SDL::Mixer.pause(@channel) if channel_valid?
99
+ end
100
+
101
+ # Resume the sound if it's paused, otherwise do nothing.
102
+ def resume
103
+ SDL::Mixer.resume(@channel) if channel_valid?
104
+ end
105
+
106
+ # Stop the sound if it's playing or paused, otherwise do nothing.
107
+ def stop
108
+ SDL::Mixer.halt(@channel) if channel_valid?
109
+ end
110
+
111
+ # Check if the sound is stopped, playing or paused. Returns one of
112
+ # Tea::Sound::STOPPED, Tea::Sound::PLAYING or Tea::Sound::PAUSED. A sound
113
+ # that isn't playing or paused is considered stopped.
114
+ def state
115
+ if channel_valid?
116
+ if SDL::Mixer.play?(@channel)
117
+ # For some reason, pause? returns 0 and 1 instead of true and false.
118
+ if SDL::Mixer.pause?(@channel) != 0
119
+ PAUSED
120
+ else
121
+ PLAYING
122
+ end
123
+ else
124
+ STOPPED
125
+ end
126
+ else
127
+ STOPPED
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ # Check if @channel really maps to this sound. Returns the channel number
134
+ # if so, otherwise nil.
135
+ def channel_valid?
136
+ if @channel >= 0 && @@channel_sound_ids[@channel] == object_id
137
+ @channel
138
+ else
139
+ nil
140
+ end
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -199,14 +199,19 @@ module Tea
199
199
  @key = sdl_keysym_to_key(sdl_event.sym)
200
200
  @mods = sdl_keymod_to_mods(sdl_event.mod)
201
201
 
202
- # Ruby 1.9 uses UTF-8 Unicode encoding. Below this, who knows how
203
- # Unicode code points are interpreted?
204
202
  if sdl_event.unicode != 0
205
203
  unicode_field = "%c"
206
- ruby_minor = RUBY_VERSION.match(/\.(\d+)\./)
207
- if ruby_minor && ruby_minor[1].to_i >= 9
208
- unicode_field = unicode_field.encode('utf-8')
204
+
205
+ # Ruby 1.9 uses UTF-8 Unicode encoding. Otherwise, who knows how
206
+ # Unicode code points are interpreted?
207
+ if ruby_version_match = RUBY_VERSION.match(/(\d+)\.(\d+)\.\d+/)
208
+ ruby_major = ruby_version_match[1].to_i
209
+ ruby_minor = ruby_version_match[2].to_i
210
+ if ruby_major >= 1 && ruby_minor >= 9
211
+ unicode_field = unicode_field.encode('utf-8')
212
+ end
209
213
  end
214
+
210
215
  @char = unicode_field % sdl_event.unicode
211
216
  else
212
217
  @char = ''
@@ -32,7 +32,7 @@ module Tea
32
32
  ext = extension_match[0]
33
33
  case ext
34
34
  when '.bmp'
35
- image_saving_buffer.save_bmp(path)
35
+ image_saving_buffer.save_bmp path
36
36
  when '.png'
37
37
  image_saving_cheat_save path
38
38
  else
@@ -70,25 +70,18 @@ module Tea
70
70
 
71
71
  r, g, b, a = primitive_hex_to_rgba(color)
72
72
 
73
- if a < 0xff
74
- if options == nil || options[:mix] == nil
75
- mix = :blend
76
- else
77
- unless [:blend, :replace].include?(options[:mix])
78
- raise Tea::Error, "invalid mix option \"#{options[:mix]}\"", caller
79
- end
80
- mix = options[:mix]
81
- end
73
+ if options == nil || options[:mix] == nil
74
+ mix = (a < 0xff) ? :blend : :replace
82
75
  else
83
- mix = :replace
76
+ unless [:blend, :replace].include?(options[:mix])
77
+ raise Tea::Error, "invalid mix option \"#{options[:mix]}\"", caller
78
+ end
79
+ mix = (a < 0xff) ? options[:mix] : :replace
84
80
  end
85
81
 
86
82
  case mix
87
83
  when :blend
88
- if a == 0xff
89
- # Same as for mix == :replace
90
- primitive_buffer.fill_rect x, y, w, h, primitive_rgba_to_color(r, g, b, a)
91
- elsif primitive_buffer.class == SDL::Screen
84
+ if primitive_buffer.class == SDL::Screen
92
85
  # SGE's broken alpha blending doesn't matter on the screen, so
93
86
  # optimise for it. rubysdl's draw_rect is off-by-one for width and
94
87
  # height, so compensate for that.
@@ -118,12 +111,13 @@ module Tea
118
111
  antialias = false
119
112
  mix = (a < 0xff) ? :blend : :replace
120
113
  else
121
- antialias = options[:antialias] || false
122
- mix = options[:mix] || ((a < 0xff) ? :blend : :replace)
123
-
124
- unless [:blend, :replace].include?(mix)
114
+ if options[:mix] && [:blend, :replace].include?(options[:mix]) == false
125
115
  raise Tea::Error, "invalid mix option \"#{mix}\"", caller
126
116
  end
117
+
118
+ antialias = options[:antialias] || false
119
+ mix = (options[:mix] && a < 0xff) ? options[:mix] : :replace
120
+ mix = (a < 0xff) ? (options[:mix] ? options[:mix] : :blend) : :replace
127
121
  end
128
122
 
129
123
  if primitive_buffer.class == SDL::Screen
@@ -162,13 +156,13 @@ module Tea
162
156
  antialias = false
163
157
  mix = (a < 0xff) ? :blend : :replace
164
158
  else
165
- outline = options[:outline] || false
166
- antialias = options[:antialias] || false
167
- mix = options[:mix] || ((a < 0xff) ? :blend : :replace)
168
-
169
- unless [:blend, :replace].include?(mix)
159
+ if options[:mix] && [:blend, :replace].include?(options[:mix]) == false
170
160
  raise Tea::Error, "invalid mix option \"#{mix}\"", caller
171
161
  end
162
+
163
+ outline = options[:outline] || false
164
+ antialias = options[:antialias] || false
165
+ mix = (a < 0xff) ? (options[:mix] ? options[:mix] : :blend) : :replace
172
166
  end
173
167
 
174
168
  if primitive_buffer.class == SDL::Screen
data/lib/tea/o_screen.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  # This file contains the Screen class.
2
2
 
3
+ require 'weakref'
4
+
3
5
  require 'sdl'
4
6
 
7
+ require 'tea/c_bitmap'
5
8
  require 'tea/mix_blitting'
6
9
  require 'tea/mix_clipping'
7
10
  require 'tea/mix_grabbing'
@@ -20,12 +23,18 @@ module Tea
20
23
 
21
24
  # Set or change the screen video mode, giving a width * height screen buffer.
22
25
  def Screen.set_mode(width, height)
23
- begin
24
- @screen = SDL::Screen.open(width, height, BITS_PER_PIXEL, SDL::SWSURFACE)
25
- @set_mode_callbacks.each { |c| c.call }
26
- rescue SDL::Error => e
27
- raise Tea::Error, e.message, e.backtrace
26
+ @screen = SDL::Screen.open(width, height, BITS_PER_PIXEL, SDL::SWSURFACE)
27
+
28
+ # Optimize Bitmaps that registered for it.
29
+ (0...(@bitmaps_to_optimize.length)).to_a.reverse.each do |opt_index|
30
+ begin
31
+ @bitmaps_to_optimize[opt_index].optimize_for_screen
32
+ rescue WeakRef::RefError
33
+ @bitmaps_to_optimize.delete_at opt_index
34
+ end
28
35
  end
36
+ rescue SDL::Error => e
37
+ raise Tea::Error, e.message, e.backtrace
29
38
  end
30
39
 
31
40
  # Check if Screen.set_mode has been called yet.
@@ -33,14 +42,12 @@ module Tea
33
42
  @screen ? true : false
34
43
  end
35
44
 
36
- # Set a proc to be called when Screen.set_mode is called. The proc will be
37
- # called after the new screen mode is set. The callback ordering is not
38
- # defined, so don't make callbacks that depend on other callbacks being
39
- # called first.
40
- def Screen.on_set_mode(callback)
41
- @set_mode_callbacks << callback
45
+ # Register a Bitmap object to be optimised to the Screen's format when a
46
+ # screen mode is set.
47
+ def Screen.register_bitmap_for_optimizing(bitmap)
48
+ @bitmaps_to_optimize << WeakRef.new(bitmap)
42
49
  end
43
- @set_mode_callbacks = []
50
+ @bitmaps_to_optimize = []
44
51
 
45
52
  # Get the screen width in pixels.
46
53
  def Screen.w
data/lib/tea.rb CHANGED
@@ -4,6 +4,7 @@ require 'sdl'
4
4
 
5
5
  require 'tea/c_bitmap'
6
6
  require 'tea/c_error'
7
+ require 'tea/c_sound'
7
8
  require 'tea/m_event'
8
9
  require 'tea/o_screen'
9
10
 
@@ -16,14 +17,13 @@ module Tea
16
17
  #
17
18
  # May throw Tea::Error if initialisation fails.
18
19
  def Tea.init
19
- begin
20
- SDL.init(SDL::INIT_VIDEO)
20
+ SDL.init(SDL::INIT_VIDEO | SDL::INIT_AUDIO)
21
21
 
22
- # Get typed characters from keys when pressed.
23
- SDL::Event.enable_unicode
24
- rescue SDL::Error => e
25
- raise Tea::Error, e.message, e.backtrace
26
- end
22
+ # Get typed characters from keys when pressed.
23
+ SDL::Event.enable_unicode
24
+ SDL::Mixer.open 44100, SDL::Mixer::DEFAULT_FORMAT, SDL::Mixer::DEFAULT_CHANNELS, 1024
25
+ rescue SDL::Error => e
26
+ raise Tea::Error, e.message, e.backtrace
27
27
  end
28
28
 
29
29
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tung-tea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-29 00:00:00 -07:00
12
+ date: 2009-09-02 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -69,6 +69,7 @@ files:
69
69
  - doc/example/smile_bounce.rb
70
70
  - doc/example/smile_move.rb
71
71
  - doc/example/smile_move_2.rb
72
+ - doc/example/sound.rb
72
73
  - doc/example/state_app.rb
73
74
  - doc/example/state_keyboard.rb
74
75
  - doc/example/state_mouse.rb
@@ -78,6 +79,7 @@ files:
78
79
  - lib/tea.rb
79
80
  - lib/tea/c_bitmap.rb
80
81
  - lib/tea/c_error.rb
82
+ - lib/tea/c_sound.rb
81
83
  - lib/tea/m_event.rb
82
84
  - lib/tea/m_event_app.rb
83
85
  - lib/tea/m_event_dispatch.rb
@@ -91,7 +93,6 @@ files:
91
93
  - lib/tea/o_screen.rb
92
94
  has_rdoc: false
93
95
  homepage: http://github.com/tung/tea
94
- licenses:
95
96
  post_install_message:
96
97
  rdoc_options:
97
98
  - --charset=UTF-8
@@ -113,7 +114,7 @@ requirements:
113
114
  - SDL, SGE
114
115
  - imagemagick
115
116
  rubyforge_project:
116
- rubygems_version: 1.3.5
117
+ rubygems_version: 1.2.0
117
118
  signing_key:
118
119
  specification_version: 3
119
120
  summary: A simple game development library for Ruby.