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

📄 snd_dma.pas

📁 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(const 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, 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;

⌨️ 快捷键说明

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