2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 // snd_mix.c -- portable code to mix sounds for snd_dma.c
27 #define DWORD unsigned long
30 #define PAINTBUFFER_SIZE 512
31 portable_samplepair_t paintbuffer
[PAINTBUFFER_SIZE
];
32 int snd_scaletable
[32][256];
33 int *snd_p
, snd_linear_count
, snd_vol
;
36 void Snd_WriteLinearBlastStereo16 (void);
39 void Snd_WriteLinearBlastStereo16 (void)
44 for (i
=0 ; i
<snd_linear_count
; i
+=2)
46 val
= (snd_p
[i
]*snd_vol
)>>8;
49 else if (val
< (short)0x8000)
50 snd_out
[i
] = (short)0x8000;
54 val
= (snd_p
[i
+1]*snd_vol
)>>8;
56 snd_out
[i
+1] = 0x7fff;
57 else if (val
< (short)0x8000)
58 snd_out
[i
+1] = (short)0x8000;
65 void S_TransferStereo16 (int endtime
)
77 snd_vol
= volume
.value
*256;
79 snd_p
= (int *) paintbuffer
;
80 lpaintedtime
= paintedtime
;
87 while ((hresult
= pDSBuf
->lpVtbl
->Lock(pDSBuf
, 0, gSndBufSize
, &pbuf
, &dwSize
,
88 &pbuf2
, &dwSize2
, 0)) != DS_OK
)
90 if (hresult
!= DSERR_BUFFERLOST
)
92 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
100 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
110 pbuf
= (DWORD
*)shm
->buffer
;
113 while (lpaintedtime
< endtime
)
115 // handle recirculating buffer issues
116 lpos
= lpaintedtime
& ((shm
->samples
>>1)-1);
118 snd_out
= (short *) pbuf
+ (lpos
<<1);
120 snd_linear_count
= (shm
->samples
>>1) - lpos
;
121 if (lpaintedtime
+ snd_linear_count
> endtime
)
122 snd_linear_count
= endtime
- lpaintedtime
;
124 snd_linear_count
<<= 1;
126 // write a linear blast of samples
127 Snd_WriteLinearBlastStereo16 ();
129 snd_p
+= snd_linear_count
;
130 lpaintedtime
+= (snd_linear_count
>>1);
135 pDSBuf
->lpVtbl
->Unlock(pDSBuf
, pbuf
, dwSize
, NULL
, 0);
139 void S_TransferPaintBuffer(int endtime
)
151 DWORD dwSize
,dwSize2
;
156 if (shm
->samplebits
== 16 && shm
->channels
== 2)
158 S_TransferStereo16 (endtime
);
162 p
= (int *) paintbuffer
;
163 count
= (endtime
- paintedtime
) * shm
->channels
;
164 out_mask
= shm
->samples
- 1;
165 out_idx
= paintedtime
* shm
->channels
& out_mask
;
166 step
= 3 - shm
->channels
;
167 snd_vol
= volume
.value
*256;
174 while ((hresult
= pDSBuf
->lpVtbl
->Lock(pDSBuf
, 0, gSndBufSize
, &pbuf
, &dwSize
,
175 &pbuf2
,&dwSize2
, 0)) != DS_OK
)
177 if (hresult
!= DSERR_BUFFERLOST
)
179 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
187 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
197 pbuf
= (DWORD
*)shm
->buffer
;
200 if (shm
->samplebits
== 16)
202 short *out
= (short *) pbuf
;
205 val
= (*p
* snd_vol
) >> 8;
209 else if (val
< (short)0x8000)
212 out_idx
= (out_idx
+ 1) & out_mask
;
215 else if (shm
->samplebits
== 8)
217 unsigned char *out
= (unsigned char *) pbuf
;
220 val
= (*p
* snd_vol
) >> 8;
224 else if (val
< (short)0x8000)
226 out
[out_idx
] = (val
>>8) + 128;
227 out_idx
= (out_idx
+ 1) & out_mask
;
233 DWORD dwNewpos
, dwWrite
;
234 int il
= paintedtime
;
235 int ir
= endtime
- paintedtime
;
239 pDSBuf
->lpVtbl
->Unlock(pDSBuf
, pbuf
, dwSize
, NULL
, 0);
241 pDSBuf
->lpVtbl
->GetCurrentPosition(pDSBuf
, &dwNewpos
, &dwWrite
);
243 // if ((dwNewpos >= il) && (dwNewpos <= ir))
244 // Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
251 ===============================================================================
255 ===============================================================================
258 void SND_PaintChannelFrom8 (channel_t
*ch
, sfxcache_t
*sc
, int endtime
);
259 void SND_PaintChannelFrom16 (channel_t
*ch
, sfxcache_t
*sc
, int endtime
);
261 void S_PaintChannels(int endtime
)
269 while (paintedtime
< endtime
)
271 // if paintbuffer is smaller than DMA buffer
273 if (endtime
- paintedtime
> PAINTBUFFER_SIZE
)
274 end
= paintedtime
+ PAINTBUFFER_SIZE
;
276 // clear the paint buffer
277 Q_memset(paintbuffer
, 0, (end
- paintedtime
) * sizeof(portable_samplepair_t
));
279 // paint in the channels.
281 for (i
=0; i
<total_channels
; i
++, ch
++)
285 if (!ch
->leftvol
&& !ch
->rightvol
)
287 sc
= S_LoadSound (ch
->sfx
);
296 count
= ch
->end
- ltime
;
303 SND_PaintChannelFrom8(ch
, sc
, count
);
305 SND_PaintChannelFrom16(ch
, sc
, count
);
310 // if at end of loop, restart
311 if (ltime
>= ch
->end
)
313 if (sc
->loopstart
>= 0)
315 ch
->pos
= sc
->loopstart
;
316 ch
->end
= ltime
+ sc
->length
- ch
->pos
;
319 { // channel just stopped
328 // transfer out according to DMA format
329 S_TransferPaintBuffer(end
);
334 void SND_InitScaletable (void)
338 for (i
=0 ; i
<32 ; i
++)
339 for (j
=0 ; j
<256 ; j
++)
340 snd_scaletable
[i
][j
] = ((signed char)j
) * i
* 8;
346 void SND_PaintChannelFrom8 (channel_t
*ch
, sfxcache_t
*sc
, int count
)
349 int *lscale
, *rscale
;
353 if (ch
->leftvol
> 255)
355 if (ch
->rightvol
> 255)
358 lscale
= snd_scaletable
[ch
->leftvol
>> 3];
359 rscale
= snd_scaletable
[ch
->rightvol
>> 3];
360 sfx
= (signed char *)sc
->data
+ ch
->pos
;
362 for (i
=0 ; i
<count
; i
++)
365 paintbuffer
[i
].left
+= lscale
[data
];
366 paintbuffer
[i
].right
+= rscale
[data
];
375 void SND_PaintChannelFrom16 (channel_t
*ch
, sfxcache_t
*sc
, int count
)
379 int leftvol
, rightvol
;
383 leftvol
= ch
->leftvol
;
384 rightvol
= ch
->rightvol
;
385 sfx
= (signed short *)sc
->data
+ ch
->pos
;
387 for (i
=0 ; i
<count
; i
++)
390 left
= (data
* leftvol
) >> 8;
391 right
= (data
* rightvol
) >> 8;
392 paintbuffer
[i
].left
+= left
;
393 paintbuffer
[i
].right
+= right
;