📄 snd_dma.pas
字号:
*)
function S_PickChannel(entnum, entchannel : Integer):channel_p;
var
ch_idx,
first_to_die,
life_left: Integer;
ch: channel_p;
begin
if (entchannel<0) then
Com_Error (ERR_DROP, 'S_PickChannel: entchannel<0', []);
// Check for replacement sound, or find the best one to replace
first_to_die := -1;
life_left := $7fffffff;
for ch_idx := 0 to MAX_CHANNELS-1 do
begin
if ((entchannel <> 0) and // channel 0 never overrides
(channels[ch_idx].entnum = entnum) and
(channels[ch_idx].entchannel = entchannel)) then
begin // always override sound from same entity
first_to_die := ch_idx;
break;
end;
// don't let monster sounds override player sounds
if ((channels[ch_idx].entnum = cl.playernum+1) and
(entnum <> cl.playernum+1) and
(channels[ch_idx].sfx<>nil)) then
continue;
if (channels[ch_idx]._end - paintedtime < life_left) then
begin
life_left := channels[ch_idx]._end - paintedtime;
first_to_die := ch_idx;
end;
end;
if (first_to_die = -1) then
begin
Result := nil;
Exit;
end;
ch := @channels[first_to_die];
FillChar(ch^, sizeof(channel_t), 0);
Result := ch;
end;
(*
=================
S_SpatializeOrigin
Used for spatializing channels and autosounds
=================
*)
procedure S_SpatializeOrigin (origin: vec3_t; master_vol, dist_mult: Single; var left_vol: Integer; var right_vol: Integer);
var
dot,
dist,
lscale, rscale, scale: vec_t;
source_vec : vec3_t;
begin
if (cls.state <> ca_active) then
begin
left_vol := 255;
right_vol := 255;
exit;
end;
// calculate stereo seperation and distance attenuation
VectorSubtract(origin, listener_origin, source_vec);
dist := VectorNormalize(source_vec);
dist := dist - SOUND_FULLVOLUME;
if (dist < 0) then
dist := 0; // close enough to be at full volume
dist := dist * dist_mult; // different attenuation levels
dot := DotProduct(listener_right, source_vec);
if ((dma.channels = 1) or (dist_mult=0)) then
begin // no attenuation:=no spatialization
rscale := 1.0;
lscale := 1.0;
end
else
begin
rscale := 0.5 * (1.0 + dot);
lscale := 0.5 * (1.0 - dot);
end;
// add in distance effect
scale := (1.0 - dist) * rscale;
right_vol := Trunc(master_vol * scale);
if (right_vol < 0) then
right_vol := 0;
scale := (1.0 - dist) * lscale;
left_vol := Trunc(master_vol * scale);
if (left_vol < 0) then
left_vol := 0;
end;
(*
=================
S_Spatialize
=================
*)
procedure S_Spatialize(ch : channel_p);
var
origin: vec3_t;
begin
// anything coming from the view entity will always be full volume
if (ch^.entnum = cl.playernum+1) then
begin
ch^.leftvol := ch^.master_vol;
ch^.rightvol := ch^.master_vol;
exit;
end;
if (ch^.fixed_origin) then
begin
VectorCopy (ch^.origin, origin);
end
else
CL_GetEntitySoundOrigin (ch^.entnum, origin);
S_SpatializeOrigin (origin, ch^.master_vol, ch^.dist_mult, ch^.leftvol, ch^.rightvol);
end;
(*
=================
S_AllocPlaysound
=================
*)
function S_AllocPlaysound : playsound_p;
var
ps: playsound_p;
begin
ps := s_freeplays.next;
if (ps = @s_freeplays) then
begin
Result := nil; // no free playsounds
Exit;
end;
// unlink from freelist
ps^.prev^.next := ps^.next;
ps^.next^.prev := ps^.prev;
Result := ps;
end;
(*
=================
S_FreePlaysound
=================
*)
procedure S_FreePlaysound(ps: playsound_p);
begin
// unlink from channel
ps^.prev^.next := ps^.next;
ps^.next^.prev := ps^.prev;
// add to free list
ps^.next := s_freeplays.next;
s_freeplays.next^.prev := ps;
ps^.prev := @s_freeplays;
s_freeplays.next := ps;
end;
(*
===============
S_IssuePlaysound
Take the next playsound and begin it on the channel
This is never called directly by S_Play*, but only
by the update loop.
===============
*)
procedure S_IssuePlaysound(ps: playsound_p);
var
ch: channel_p;
sc: sfxcache_p;
begin
if (s_show^.value<>0) then
Com_Printf ('Issue %d'#10,[ps^._begin]);
// pick a channel to play on
ch := S_PickChannel(ps^.entnum, ps^.entchannel);
if (ch = nil) then
begin
S_FreePlaysound (ps);
exit;
end;
// spatialize
if (ps^.attenuation = ATTN_STATIC) then
ch^.dist_mult := ps^.attenuation * 0.001
else
ch^.dist_mult := ps^.attenuation * 0.0005;
ch^.master_vol := Trunc(ps^.volume);
ch^.entnum := ps^.entnum;
ch^.entchannel := ps^.entchannel;
ch^.sfx := ps^.sfx;
VectorCopy (ps^.origin, ch^.origin);
ch^.fixed_origin := ps^.fixed_origin;
S_Spatialize(ch);
ch^.pos := 0;
sc := S_LoadSound (ch^.sfx);
ch^._end := paintedtime + sc^.length;
// free the playsound
S_FreePlaysound (ps);
end;
//struct sfx_s *S_RegisterSexedSound (entity_state_t *ent, char *base);
function S_RegisterSexedSound (ent:entity_state_p;base:PChar):sfx_p;
var
n: Integer;
p: PChar;
sfx: sfx_p;//struct sfx_s *sfx;
f: integer;
model: array[0..MAX_QPATH-1] of Char;
sexedFilename: array[0..MAX_QPATH-1] of Char;
maleFilename: array[0..MAX_QPATH-1] of Char;
begin
// determine what model the client is using
model[0] := #0;
n := CS_PLAYERSKINS + ent^.number - 1;
if (cl.configstrings[n][0]<>#0) then
begin
p := strchr(cl.configstrings[n], Byte('\'));
if (p <> nil) then
begin
p := p + 1;
strcpy(model, p);
p := strchr(model, Byte('/'));
if (p<>nil) then
p^ := #0;
end;
end;
// if we can't figure it out, they're male
if (model[0] = #0) then
strcpy(model, 'male');
// see if we already know of the model specific sound
Com_sprintf (sexedFilename, sizeof(sexedFilename), '#players/%s/%s',[model, base+1]);
sfx := S_FindName (sexedFilename, false);
if (sfx = nil) then
begin
// no, so see if it exists
if FS_FOpenFile (@sexedFilename[1], f)>0 then
begin
// yes, close the file and register it
FS_FCloseFile(f);
sfx := S_RegisterSound (sexedFilename);
end
else
begin
// no, revert to the male sound in the pak0.pak
Com_sprintf (maleFilename, sizeof(maleFilename), 'player/%s/%s', ['male', base+1]);
sfx := S_AliasName (sexedFilename, maleFilename);
end;
end;
Result := sfx;
end;
// =======================================================================
// Start a sound effect
// =======================================================================
(*
====================
S_StartSound
Validates the parms and ques the sound up
if pos is nil, the sound will be dynamically sourced from the entity
Entchannel 0 will never override a playing sound
====================
*)
procedure S_StartSound(origin: vec3_p; entnum, entchannel: Integer; sfx: sfx_p; fvol, attenuation, timeofs: Single);
var
sc: sfxcache_p;
vol, start: Integer;
ps, sort: playsound_p;
begin
if (sound_started = 0) then
exit;
if (sfx = nil) then
exit;
if (sfx^.name[0] = '*') then
sfx := S_RegisterSexedSound(@cl_entities[entnum].current, sfx^.name);
// make sure the sound is loaded
sc := S_LoadSound (sfx);
if (sc = nil) then
exit; // couldn't load the sound's data
vol := Trunc(fvol*255);
// make the playsound_t
ps := S_AllocPlaysound ();
if (ps = nil) then
exit;
if (origin <> nil) then
begin
VectorCopy(origin^, ps^.origin);
ps^.fixed_origin := true;
end
else
ps^.fixed_origin := false;
ps^.entnum := entnum;
ps^.entchannel := entchannel;
ps^.attenuation := attenuation;
ps^.volume := vol;
ps^.sfx := sfx;
// drift s_beginofs
start := Trunc(cl.frame.servertime * 0.001 * dma.speed) + s_beginofs;
if (start < paintedtime) then
begin
start := paintedtime;
s_beginofs := start - Trunc(cl.frame.servertime * 0.001 * dma.speed);
end
else if (start > paintedtime + 0.3 * dma.speed) then
begin
start := paintedtime + Trunc(0.1 * dma.speed);
s_beginofs := start - Trunc(cl.frame.servertime * 0.001 * dma.speed);
end
else
begin
s_beginofs := s_beginofs - 10;
end;
if (timeofs = 0) then
ps^._begin := paintedtime
else
ps^._begin := start + Trunc(timeofs * dma.speed);
// sort into the pending sound list
// for (sort:=s_pendingplays.next ;
// sort != &s_pendingplays && sort^._begin < ps^._begin ;
// sort:=sort^.next);
sort := s_pendingplays.next;
while ((sort<>@s_pendingplays) and (sort^._begin < ps^._begin)) do
begin
sort := sort^.next;
end;
ps^.next := sort;
ps^.prev := sort^.prev;
ps^.next^.prev := ps;
ps^.prev^.next := ps;
end;
(*
==================
S_StartLocalSound
==================
*)
procedure S_StartLocalSound (sound: PChar);
var
sfx: sfx_p;
begin
if (sound_started = 0) then
exit;
sfx := S_RegisterSound (sound);
if (sfx = nil) then
begin
Com_Printf ('S_StartLocalSound: can''t cache %s'#10,[sound]);
exit;
end;
S_StartSound (nil, cl.playernum+1, 0, sfx, 1, 1, 0);
end;
(*
==================
S_ClearBuffer
==================
*)
procedure S_ClearBuffer;
var
clear: Integer;
begin
if (sound_started = 0) then
exit;
s_rawend := 0;
if (dma.samplebits = 8) then
clear := $80
else
clear := 0;
SNDDMA_BeginPainting ();
if (dma.buffer<>nil) then
FillChar(dma.buffer^, dma.samples * dma.samplebits div 8, clear);
SNDDMA_Submit ();
end;
(*
==================
S_StopAllSounds
==================
*)
procedure S_StopAllSounds;
var
i: Integer;
begin
if (sound_started = 0) then
exit;
// clear all the playsounds
FillChar(s_playsounds, sizeof(s_playsounds), 0);
s_freeplays.next := @s_freeplays;
s_freeplays.prev := @s_freeplays;
s_pendingplays.next := @s_pendingplays;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -