note description: "[ s_sound.c none ]" license: "[ Copyright (C) 1993-1996 by id Software, Inc. Copyright (C) 2005-2014 Simon Howard Copyright (C) 2021 Ilgiz Mustafin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ]" class S_SOUND create make feature i_main: I_MAIN make (a_i_main: like i_main) do i_main := a_i_main create channels.make_empty snd_sfxvolume := 15 snd_musicvolume := 15 end feature snd_sfxvolume: INTEGER_32 assign set_snd_sfxvolume set_snd_sfxvolume (a_snd_sfxvolume: like snd_sfxvolume) do snd_sfxvolume := a_snd_sfxvolume end s_setsfxvolume (volume: INTEGER_32) require volume >= 0 and volume <= 127 do if volume < 0 or volume > 127 then i_main.i_error ("Attempt to set sfx volume at " + volume.out) end snd_sfxvolume := volume end snd_musicvolume: INTEGER_32 assign set_snd_musicvolume set_snd_musicvolume (a_snd_musicvolume: like snd_musicvolume) do snd_musicvolume := a_snd_musicvolume end s_setmusicvolume (volume: INTEGER_32) require volume >= 0 and volume <= 127 do if volume < 0 or volume > 127 then i_main.i_error ("Attempt to set music volume at " + volume.out + "%N") end i_main.I_sound.i_setmusicvolume (127) i_main.I_sound.i_setmusicvolume (volume) snd_musicvolume := volume end feature mus_paused: BOOLEAN -- whether songs are mus_paused mus_playing: detachable MUSICINFO_T feature -- following is set by the defaults code in M_Misc numchannels: INTEGER_32 assign set_numchannels -- number of channels available set_numchannels (a_numchannels: like numchannels) do numchannels := a_numchannels end feature channels: ARRAY [CHANNEL_T] -- the set of channels available feature -- Adjustible by menu. Norm_pitch: INTEGER_32 = 128 Norm_priority: INTEGER_32 = 64 Norm_sep: INTEGER_32 = 128 S_stereo_swing: INTEGER_32 once Result := 96 * 65536 end S_close_dist: INTEGER_32 -- Distance tp origin when sounds should be maxed out. -- This should relate to movement clipping resolution -- (see BLOCKMAP handling). -- // Originally: (200*0x10000). once Result := 160 * 65536 end S_attenuator: INTEGER_32 once Result := (S_clipping_dist - S_close_dist) |>> {M_FIXED}.fracbits end feature S_clipping_dist: INTEGER_32 -- when to clip out sounds -- Does not fit the large outdoor areas once Result := 1200 * 65536 end feature s_init (sfxvolume: INTEGER_32; musicvolume: INTEGER_32) -- Initializes sound stuff, including volume -- Sets channels, SFX and music volume, -- allocates channel buffer, sets S_sfx lookup. local i: INTEGER_32 do print ("S_Init: default sfx volume " + sfxvolume.out + "%N") i_main.I_sound.i_setchannels s_setsfxvolume (sfxvolume) s_setmusicvolume (musicvolume) create channels.make_filled (create {CHANNEL_T}.make, 0, numchannels - 1) from i := 0 until i >= numchannels loop channels [i] := create {CHANNEL_T}.make channels [i].sfxinfo := Void i := i + 1 end mus_paused := False from i := 1 until i >= {SOUNDS_H}.numsfx loop {SOUNDS_H}.s_sfx [i].lumpnum := -1 {SOUNDS_H}.s_sfx [i].usefulness := -1 i := i + 1 end end feature s_pausesound do if mus_playing /= Void and not mus_paused then i_main.I_sound.i_pausesong mus_paused := True end end s_resumesound do if mus_playing /= Void and mus_paused then i_main.I_sound.i_resumesong mus_paused := False end end feature s_updatesounds (listener: detachable MOBJ_T) -- Updates music & sounds -- from chocolate doom local audible: BOOLEAN cnum: INTEGER_32 volume: INTEGER_32_REF sep: INTEGER_32_REF c: CHANNEL_T l_stopped: BOOLEAN do i_main.I_sound.i_updatesound from cnum := 0 until cnum >= numchannels loop l_stopped := False c := channels [cnum] if attached c.sfxinfo as sfx then if i_main.I_sound.i_soundisplaying (c.handle) then volume := snd_sfxvolume sep := Norm_sep if attached sfx.link then volume := volume + sfx.volume if volume < 1 then s_stopchannel (cnum) l_stopped := True elseif volume > snd_sfxvolume then volume := snd_sfxvolume end end if not l_stopped then if attached c.origin as origin and then listener /= origin then check attached listener as l then audible := s_adjustsoundparams (l, origin, volume, sep) end if not audible then s_stopchannel (cnum) else i_main.I_sound.i_updatesoundparams (c.handle, create {INTEGER_32}.make_from_reference (volume), create {INTEGER_32}.make_from_reference (sep)) end end end else s_stopchannel (cnum) end end cnum := cnum + 1 end end s_startsound (origin_p: detachable ANY; sfx_id: INTEGER_32) local sfx: SFXINFO_T origin: MOBJ_T rc: BOOLEAN sep, pitch, cnum, volume: INTEGER_32 ignore: BOOLEAN do {NOT_IMPLEMENTED}.not_implemented ("S_StartSound", False) volume := snd_sfxvolume if sfx_id < 1 or sfx_id > {SOUNDS_H}.numsfx then {I_MAIN}.i_error ("Bad sfx #:" + sfx_id.out) end sfx := {SOUNDS_H}.s_sfx [sfx_id] pitch := Norm_pitch if attached sfx.link as link then volume := volume + sfx.volume pitch := sfx.pitch if volume < 1 then ignore := True else if volume > snd_sfxvolume then volume := snd_sfxvolume end end end if not ignore then if attached origin and then origin /= i_main.G_game.Players [i_main.G_game.consoleplayer].mo then check attached i_main.G_game.Players [i_main.G_game.consoleplayer].mo as mo then rc := s_adjustsoundparams (mo, origin, volume, sep) if origin.x = mo.x and origin.y = mo.y then sep := Norm_sep end end if not rc then ignore := True end else sep := Norm_sep end end if not ignore then if sfx_id >= {SOUNDS_H}.sfx_sawup and sfx_id <= {SOUNDS_H}.sfx_sawhit then pitch := pitch + 8 - (i_main.M_random.m_random & 15) elseif sfx_id /= {SOUNDS_H}.sfx_itemup and sfx_id /= {SOUNDS_H}.sfx_tink then pitch := pitch + 16 - (i_main.M_random.m_random & 31) end pitch := pitch.min (255).max (0) s_stopsound (origin) cnum := s_getchannel (origin, sfx) if cnum < 0 then ignore := True end end if not ignore then sfx.usefulness := (sfx.usefulness + 1).max (1) if sfx.lumpnum < 0 then sfx.lumpnum := i_main.I_sound.i_getsfxlumpnum (sfx) end channels [cnum].pitch := pitch channels [cnum].handle := i_main.I_sound.i_startsound (sfx, cnum, volume, sep, channels [cnum].pitch) end end s_getchannel (origin: detachable MOBJ_T; sfxinfo: SFXINFO_T): INTEGER_32 -- If none available, return -1. Otherwise channel #. local c: CHANNEL_T found: BOOLEAN do from Result := 0 until found or Result > channels.upper loop if channels [Result].sfxinfo = Void then found := True elseif attached origin and then channels [Result].origin = origin then s_stopchannel (Result) found := True else Result := Result + 1 end end if Result > channels.upper then from Result := 0 found := False until found or Result > channels.upper loop if attached channels [Result].sfxinfo as csfxinfo and then csfxinfo.priority >= sfxinfo.priority then found := True else Result := Result + 1 end end if Result > channels.upper then Result := -1 else s_stopchannel (Result) end end if Result /= -1 then c := channels [Result] c.sfxinfo := sfxinfo c.origin := origin end end s_stopsound (origin: detachable MOBJ_T) local cnum: INTEGER_32 done: BOOLEAN do from cnum := 0 until not done or cnum > channels.upper loop if channels [cnum].sfxinfo /= Void and channels [cnum].origin = origin then s_stopchannel (cnum) done := True end cnum := cnum + 1 end end s_startmusic (m_id: INTEGER_32) do s_changemusic (m_id, False) end s_changemusic (a_musicnum: INTEGER_32; looping: BOOLEAN) local music: MUSICINFO_T musicnum: INTEGER_32 handle: ANY do musicnum := a_musicnum if musicnum = {SOUNDS_H}.mus_intro and (i_main.I_sound.snd_musicdevice = {I_SOUND}.snddevice_adlib or i_main.I_sound.snd_musicdevice = {I_SOUND}.snddevice_sb) and i_main.W_wad.w_checknumforname ("D_INTROA") >= 0 then musicnum := {SOUNDS_H}.mus_introa end if musicnum <= {SOUNDS_H}.mus_none or musicnum >= {SOUNDS_H}.nummusic then {I_MAIN}.i_error ("Bad music number " + musicnum.out) else music := {SOUNDS_H}.s_music [musicnum] end if mus_playing = music then else s_stopmusic if music.lumpnum = 0 then music.lumpnum := i_main.W_wad.w_getnumforname ("d_" + music.name) end music.data := i_main.W_wad.w_cachelumpnum (music.lumpnum) handle := i_main.I_sound.i_registersong (music.data, i_main.W_wad.w_lumplength (music.lumpnum)) music.handle := handle i_main.I_sound.i_playsong (handle, looping) mus_playing := music end end s_stopmusic do if attached mus_playing as m then if mus_paused then i_main.I_sound.i_resumesong end i_main.I_sound.i_stopsong i_main.I_sound.i_unregistersong (m.handle) i_main.W_wad.w_releaselumpnum (m.lumpnum) m.data := Void mus_playing := Void end end s_stopchannel (cnum: INTEGER_32) -- from chocolate doom local c: CHANNEL_T i: INTEGER_32 do c := channels [cnum] if attached c.sfxinfo as sfxinfo then if i_main.I_sound.i_soundisplaying (c.handle) then i_main.I_sound.i_stopsound (c.handle) end from i := 0 until i > channels.upper or else (cnum /= i and c.sfxinfo = channels [i].sfxinfo) loop i := i + 1 end if attached c.sfxinfo as si then si.usefulness := si.usefulness - 1 end c.sfxinfo := Void c.origin := Void end end s_adjustsoundparams (listener: MOBJ_T; source: MOBJ_T; vol, sep: INTEGER_32_REF): BOOLEAN -- (originally returned int) -- Changes volume, stereo-separation, and pith variables -- from the norm of a sound effect to be played. -- If the sound is not audible, returns False (originally 0). -- Otherwise, modifies parameters and returns True (originally 1). local approx_dist: FIXED_T adx: FIXED_T ady: FIXED_T angle: ANGLE_T do adx := create {FIXED_T}.from_integer ((listener.x - source.x).abs) ady := create {FIXED_T}.from_integer ((listener.y - source.y).abs) approx_dist := adx + ady - (adx.min (ady) |>> 1) if i_main.G_game.gamemap /= 8 and approx_dist > create {FIXED_T}.from_integer (S_clipping_dist) then Result := False else angle := i_main.R_main.r_pointtoangle2 (listener.x, listener.y, source.x, source.y) if angle > listener.angle then angle := angle - listener.angle else angle := angle + (create {ANGLE_T}.from_natural (({NATURAL_32} 4294967295)) - listener.angle) end angle := angle |>> {TABLES}.angletofineshift sep.set_item ((128 - ({M_FIXED}.fixedmul (create {FIXED_T}.from_integer (S_stereo_swing), create {FIXED_T}.from_integer ({TABLES}.finesine [angle.as_integer_32]))) |>> {M_FIXED}.fracbits.as_integer_32).as_integer_32) if approx_dist < create {FIXED_T}.from_integer (S_close_dist) then vol.set_item (snd_sfxvolume) elseif i_main.G_game.gamemap = 8 then if approx_dist > create {FIXED_T}.from_integer (S_clipping_dist) then approx_dist := create {FIXED_T}.from_integer (S_clipping_dist) end vol.set_item ((vol * (15 + ((snd_sfxvolume - 15) * ((S_clipping_dist - approx_dist.as_integer_32) |>> {M_FIXED}.fracbits)) // S_attenuator)).as_integer_32) else vol.set_item ((vol * ((snd_sfxvolume * ((S_clipping_dist - approx_dist.as_integer_32) |>> {M_FIXED}.fracbits)) // S_attenuator)).as_integer_32) end Result := vol > 0 end end s_start -- Per level startup code. -- Kills playing sounds at start of level, -- determines music if any, changes music. local cnum: INTEGER_32 mnum: INTEGER_32 spmus: ARRAY [INTEGER_32] do from cnum := 0 until cnum >= numchannels loop if channels [cnum].sfxinfo /= Void then s_stopchannel (cnum) end cnum := cnum + 1 end mus_paused := False if i_main.Doomstat_h.gamemode = {GAME_MODE_T}.commercial then mnum := {SOUNDS_H}.mus_runnin + i_main.G_game.gamemap - 1 else spmus := <<{SOUNDS_H}.mus_e3m4, {SOUNDS_H}.mus_e3m2, {SOUNDS_H}.mus_e3m3, {SOUNDS_H}.mus_e1m5, {SOUNDS_H}.mus_e2m7, {SOUNDS_H}.mus_e2m4, {SOUNDS_H}.mus_e2m6, {SOUNDS_H}.mus_e2m5, {SOUNDS_H}.mus_e1m9>> if i_main.G_game.gameepisode < 4 then mnum := {SOUNDS_H}.mus_e1m1 + (i_main.G_game.gameepisode - 1) * 9 + i_main.G_game.gamemap - 1 else mnum := spmus [i_main.G_game.gamemap - 1] end end s_changemusic (mnum, True) end end -- class S_SOUND
Generated by ISE EiffelStudio