Class: Doom::Wad::SoundManager
- Inherits:
-
Object
- Object
- Doom::Wad::SoundManager
- Defined in:
- lib/doom/wad/sound.rb
Overview
Loads DOOM sound effects from WAD and converts to WAV for Gosu playback. DOOM sound format: 8-byte header (2 format, 2 sample_rate, 4 num_samples) followed by unsigned 8-bit PCM samples.
Instance Method Summary collapse
-
#[](name) ⇒ Object
Get or load a sound effect.
- #cleanup ⇒ Object
-
#initialize(wad) ⇒ SoundManager
constructor
A new instance of SoundManager.
Constructor Details
#initialize(wad) ⇒ SoundManager
Returns a new instance of SoundManager.
12 13 14 15 16 17 18 19 20 21 |
# File 'lib/doom/wad/sound.rb', line 12 def initialize(wad) @wad = wad @cache = {} # name => Gosu::Sample @temp_dir = File.join(Dir.tmpdir, "doom_rb_sounds_#{Process.pid}") Dir.mkdir(@temp_dir) unless Dir.exist?(@temp_dir) # Sounds are decoded into a per-process temp dir; clean it up when the # process exits so repeated runs do not leak WAV files. at_exit { cleanup } end |
Instance Method Details
#[](name) ⇒ Object
Get or load a sound effect. Returns a Gosu::Sample or nil.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/doom/wad/sound.rb', line 24 def [](name) return @cache[name] if @cache.key?(name) lump_name = name.start_with?('DS') ? name : "DS#{name}" entry = @wad.find_lump(lump_name) return @cache[name] = nil unless entry data = @wad.read_lump_at(entry) return @cache[name] = nil if data.size < 8 # Parse DOOM sound header _format = data[0, 2].unpack1('v') sample_rate = data[2, 2].unpack1('v') num_samples = data[4, 4].unpack1('V') # PCM data starts at offset 8, skip 16 padding bytes at start and end pcm_start = 8 + 16 pcm_end = 8 + num_samples - 16 pcm_data = data[pcm_start...pcm_end] return @cache[name] = nil unless pcm_data && pcm_data.size > 0 # Convert to WAV file for Gosu wav_path = File.join(@temp_dir, "#{lump_name}.wav") write_wav(wav_path, pcm_data, sample_rate) unless File.exist?(wav_path) @cache[name] = Gosu::Sample.new(wav_path) rescue StandardError => e # A bad or unplayable lump should silence that one sound, not crash the # game -- but say so rather than swallowing the error entirely. warn "SoundManager: could not load '#{name}': #{e.class}: #{e.message}" @cache[name] = nil end |
#cleanup ⇒ Object
57 58 59 |
# File 'lib/doom/wad/sound.rb', line 57 def cleanup FileUtils.rm_rf(@temp_dir) if @temp_dir && Dir.exist?(@temp_dir) end |