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

📄 snd_dma.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 3 页
字号:
  s_pendingplays.prev := @s_pendingplays;

	for i := 0 to MAX_PLAYSOUNDS-1 do
	begin
		s_playsounds[i].prev := @s_freeplays;
		s_playsounds[i].next := s_freeplays.next;
		s_playsounds[i].prev^.next := @s_playsounds[i];
		s_playsounds[i].next^.prev := @s_playsounds[i];
	end;

	// clear all the channels
	FillChar(channels, sizeof(channels), 0);

	S_ClearBuffer ();
end;

(*
==================
S_AddLoopSounds

Entities with a ->sound field will generated looped sounds
that are automatically started, stopped, and merged together
as the entities are sent to the client
==================
*)
procedure S_AddLoopSounds;
var
  i, j, num: Integer;
  sounds: array[0..MAX_EDICTS-1] of Integer;
  left, right, left_total, right_total: Integer;
  ch: channel_p;
  sfx: sfx_p;
  sc: sfxcache_p;
  ent: entity_state_p;
begin
	if (cl_paused^.value <> 0) then
		exit;

	if (cls.state <> ca_active) then
		exit;

	if (not cl.sound_prepped) then
		exit;

	for i := 0 to cl.frame.num_entities-1 do
	begin
		num := (cl.frame.parse_entities + i) and (MAX_PARSE_ENTITIES-1);
		ent := @cl_parse_entities[num];
		sounds[i] := ent^.sound;
	end;

	for i := 0 to cl.frame.num_entities-1 do
	begin
		if (sounds[i] = 0) then
			continue;

		sfx := @cl.sound_precache[sounds[i]];
		if (sfx = nil) then
			continue;		// bad sound effect
		sc := sfx^.cache;
		if (sc = nil) then
			continue;

		num := (cl.frame.parse_entities + i) and (MAX_PARSE_ENTITIES-1);
		ent := @cl_parse_entities[num];

		// find the total contribution of all sounds of this type
		S_SpatializeOrigin (ent^.origin, 255.0, SOUND_LOOPATTENUATE,
			left_total, right_total);
		for j := i+1 to cl.frame.num_entities-1 do
		begin
			if (sounds[j] <> sounds[i]) then
				continue;
			sounds[j] := 0;	// don't check this again later

			num := (cl.frame.parse_entities + j) and (MAX_PARSE_ENTITIES-1);
			ent := @cl_parse_entities[num];

			S_SpatializeOrigin (ent^.origin, 255.0, SOUND_LOOPATTENUATE,
				left, right);
			left_total := left_total + left;
			right_total := right_total + right;
		end;

		if ((left_total = 0) and (right_total = 0)) then
			continue;		// not audible

		// allocate a channel
		ch := S_PickChannel(0, 0);
		if (ch = nil) then
			exit;

		if (left_total > 255) then
			left_total := 255;
		if (right_total > 255) then
			right_total := 255;
		ch^.leftvol := left_total;
		ch^.rightvol := right_total;
		ch^.autosound := true;	// remove next frame
		ch^.sfx := sfx;
		ch^.pos := paintedtime mod sc^.length;
		ch^._end := paintedtime + sc^.length - ch^.pos;
	end;
end;

//=============================================================================

(*
============
S_RawSamples

Cinematic streaming and voice over network
============
*)
procedure S_RawSamples(samples, rate, width, channels: Integer; data: PByte);
var
  i, src, dst: Integer;
  scale: Single;
begin
	if (sound_started = 0) then
		exit;

	if (s_rawend < paintedtime) then
		s_rawend := paintedtime;
	scale := rate / dma.speed;

//Com_Printf ("%d < %d < %d"#10, soundtime, paintedtime, s_rawend);
	if ((channels = 2) and (width = 2)) then
	begin
		if (scale = 1.0) then
		begin	// optimized case
			for i := 0 to samples-1  do
			begin
				dst := s_rawend and (MAX_RAW_SAMPLES-1);
				Inc(s_rawend);
				s_rawsamples_[dst].left :=
				    LittleShort(PSmallIntArray(data)[i*2]) shl 8;
				s_rawsamples_[dst].right :=
				    LittleShort(PSmallIntArray(data)[i*2+1]) shl 8;
			end;
		end
		else
		begin
      i := 0;
      while (True) do
			begin
				src := Trunc(i*scale);
				if (src >= samples) then
          break;
     		dst := s_rawend and (MAX_RAW_SAMPLES-1);
			  Inc(s_rawend);
			  s_rawsamples_[dst].left :=
			     LittleShort(PSmallIntArray(data)[src*2]) shl 8;
			  s_rawsamples_[dst].right :=
			     LittleShort(PSmallIntArray(data)[src*2+1]) shl 8;
        Inc(i);
			end;
		end;
	end
	else if ((channels = 1) and (width = 2)) then
	begin
    i := 0;
		while (True) do
		begin
			src := Trunc(i*scale);
			if (src >= samples) then
				break;
			dst := s_rawend and (MAX_RAW_SAMPLES-1);
			Inc(s_rawend);
			s_rawsamples_[dst].left :=
			    LittleShort(PSmallIntArray(data)[src]) shl 8;
			s_rawsamples_[dst].right :=
			    LittleShort(PSmallIntArray(data)[src]) shl 8;
      Inc(i);
		end;
	end
	else if ((channels = 2) and (width = 1)) then
	begin
		i := 0;
    while (True) do
		begin
			src := Trunc(i*scale);
			if (src >= samples) then
				break;
			dst := s_rawend and (MAX_RAW_SAMPLES-1);
			Inc(s_rawend);
			s_rawsamples_[dst].left :=
			    PShortIntArray(data)[src*2] shl 16;
			s_rawsamples_[dst].right :=
			    PShortIntArray(data)[src*2+1] shl 16;
      Inc(i);
		end;
	end
	else if ((channels = 1) and (width = 1)) then
	begin
		i := 0;
    while (True) do
		begin
			src := Trunc(i*scale);
			if (src >= samples) then
				break;
			dst := s_rawend and (MAX_RAW_SAMPLES-1);
			Inc(s_rawend);
			s_rawsamples_[dst].left :=
			    (PByteArray(data)[src]-128) shl 16;
			s_rawsamples_[dst].right:=
          (PByteArray(data)[src]-128) shl 16;
      Inc(i);
		end;
	end;
end;

//=============================================================================

(*
============
S_Update

Called once each time through the main loop
============
*)
procedure S_Update(origin, _forward, right, up : vec3_t);
var
  i, total: Integer;
  ch, combine: channel_p;
label
  continue_;
begin
	if (sound_started = 0) then
		exit;

	// if the laoding plaque is up, clear everything
	// out to make sure we aren't looping a dirty
	// dma buffer while loading
	if (cls.disable_screen <> 0) then
	begin
		S_ClearBuffer;
		exit;
	end;

	// rebuild scale tables if volume is modified
	if (s_volume^.modified) then
		S_InitScaletable;

	VectorCopy(origin, listener_origin);
	VectorCopy(_forward, listener_forward);
	VectorCopy(right, listener_right);
	VectorCopy(up, listener_up);

	combine := nil;

	// update spatialization for dynamic sounds
	ch := @channels;
	for i := 0 to MAX_CHANNELS-1 do
	begin
		if (ch^.sfx = nil) then
			goto continue_;
		if (ch^.autosound) then
		begin	// autosounds are regenerated fresh each frame
			FillChar(ch^, sizeof(channel_t), 0);
			goto continue_;
		end;
		S_Spatialize(ch);         // respatialize channel
		if ((ch^.leftvol=0) and (ch^.rightvol=0)) then
		begin
			FillChar (ch^, sizeof(channel_t), 0);
			goto continue_;
		end;
  continue_:
    inc(ch);
	end;

	// add loopsounds
	S_AddLoopSounds;

	//
	// debugging output
	//
	if (s_show^.value <> 0) then
	begin
		total := 0;
		ch := @channels;
		for i := 0 to MAX_CHANNELS-1 do
    begin
			if ((ch^.sfx<>nil) and ((ch^.leftvol<>0) or (ch^.rightvol<>0))) then
			begin
				Com_Printf ('%3d %3d %s'#10, [ch^.leftvol, ch^.rightvol, ch^.sfx^.name]);
				Inc(total);
			end;
      Inc(ch);
    end;
		Com_Printf ('----(%d)---- painted: %d'#10, [total, paintedtime]);
	end;

// mix some sound
	S_Update_();
end;


var
  buffers: Integer;
  oldsamplepos: Integer;

procedure GetSoundtime;
var
  samplepos      : Integer;
  fullsamples    : Integer;
begin
	fullsamples := dma.samples div dma.channels;

// it is possible to miscount buffers if it has wrapped twice between
// calls to S_Update.  Oh well.
	samplepos := SNDDMA_GetDMAPos();

	if (samplepos < oldsamplepos) then
	begin
		Inc(buffers);					// buffer wrapped

		if (paintedtime > $40000000) then
		begin	// time to chop things off to aprocedure 32 bit limits
			buffers := 0;
			paintedtime := fullsamples;
			S_StopAllSounds;
		end;
	end;
	oldsamplepos := samplepos;

	soundtime := buffers*fullsamples + samplepos div dma.channels;
end;


procedure S_Update_;
var
  endtime: Cardinal;
  samps: Integer;
begin
	if (sound_started = 0) then
		exit;

	SNDDMA_BeginPainting;

	if (dma.buffer = nil) then
		exit;

// Updates DMA time
	GetSoundtime();

// check to make sure that we haven't overshot
	if (paintedtime < soundtime) then
	begin
		Com_DPrintf('S_Update_ : overflow'#10, []);
		paintedtime := soundtime;
	end;

// mix ahead of current position
	endtime := Trunc(soundtime + s_mixahead^.value * dma.speed);
//endtime:=(soundtime + 4096) & ~4095;

	// mix to an even submission block size
	endtime := (endtime + dma.submission_chunk-1) and
             not(dma.submission_chunk-1);
	samps := dma.samples shr (dma.channels-1);
	if (endtime - soundtime > samps) then
		endtime := soundtime + samps;

	S_PaintChannels (endtime);

	SNDDMA_Submit ();
end;

(*
===============================================================================

console functions

===============================================================================
*)
procedure S_Play;
var
  i: Integer;
  name: array [0..255] of Char;
  sfx: sfx_p;
begin
	i := 1;
	while (i<Cmd_Argc()) do
	begin
		if not(strchr(Cmd_Argv(i), Byte('.'))<>nil) then
		begin
			strcpy(name, Cmd_Argv(i));
			strcat(name, '.wav');
		end
		else
			strcpy(name, Cmd_Argv(i));
		sfx := S_RegisterSound(name);
		S_StartSound(nil, cl.playernum+1, 0, sfx, 1.0, 1.0, 0);
		Inc(i);
	end;
end;

procedure S_SoundList;
var
  i: Integer;
  sc: sfxcache_p;
  size: Integer;
  total: Integer;
begin
	total := 0;
  for i := 0 to num_sfx-1 do
	begin
		if (known_sfx[i].registration_sequence=0) then
			continue;
		sc := known_sfx[i].cache;
		if (sc <> nil) then
		begin
			size := sc^.length * sc^.width * (sc^.stereo+1);
			total := total + size;
			if (sc^.loopstart >= 0) then
				Com_Printf ('L', [])
			else
				Com_Printf (' ', []);
			Com_Printf('(%2db) %6i : %s'#10, [sc^.width * 8,  size, known_sfx[i].name]);
		end
		else
		begin
			if (known_sfx[i].name[0] = '*') then
				Com_Printf('  placeholder : %s'#10, [known_sfx[i].name])
			else
				Com_Printf('  not loaded  : %s'#10, [known_sfx[i].name]);
		end;
	end;
	Com_Printf ('Total resident: %d'#10, [total]);
end;

end.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -