📄 snd_dma.pas
字号:
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 + -