⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snd_dma.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
*)
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 + -