source: trunk/src/dsound/dsmixer.cpp

Last change on this file was 21479, checked in by dmik, 15 years ago

Get rid of dd_obj_base.h which duplicates obj_base.h creating unnecessary mess (symbol/define duplication) and conflicts when both the DDarw and other COM-related headers are included.

File size: 7.5 KB
Line 
1/* $Id: dsmixer.cpp,v 1.5 2001-04-20 13:22:38 phaller Exp $ */
2/*
3 * DirectSound Software Mixer
4 *
5 * Copyright 2000 Michal Necasek
6 * Copyright 2000 Ondrej Necasek
7 *
8 * Project Odin Software License can be found in LICENSE.TXT
9 *
10 */
11
12
13/*@Header***********************************************************************
14* Header Files *
15*******************************************************************************/
16#define INCL_DOSMISC
17#include <os2win.h>
18
19#include <stdlib.h>
20#include <string.h>
21
22#define CINTERFACE
23#include <dsound.h>
24
25#include "os2dsound.h"
26#include "os2sndbuffer.h"
27#include "os2notify.h"
28#include <misc.h>
29
30//@@@ signed long mixbuf[2300*2]; /* enough for 50 ms at 44100Hz stereo */
31
32
33// The internal mixer buffer for sample calculations
34// It's allocated on demand by MixFunc.
35static signed long* mixbuf = NULL; // pointer to the mixer data buffer
36static ULONG ulMixerBufferSize = 0; // current size of the mixer buffer
37
38
39void MixCallback(ULONG cbMix)
40{
41 // Check for priority level here; for DSSCL_WRITEPRIMARY just play directly
42 // from the primary buffer; for all others mix the secondary buffers
43 if (OS2IDirectSoundBuffer::primary->parentDS->GetCoopLevel() != DSSCL_WRITEPRIMARY)
44 MixFunc(OS2IDirectSoundBuffer::dsbroot, OS2IDirectSoundBuffer::primary, cbMix);
45 else
46 {
47 }
48}
49
50
51void MixOneBuffer(OS2IDirectSoundBuffer *inBuf, int tomix, int outrate)
52{
53 unsigned char *data8b;
54 signed short *data16b;
55 int inpos, spd, i, j, sample, len, bytespersample, vol1, vol2;
56 int oldpos;
57
58 bytespersample = inBuf->lpfxFormat->wBitsPerSample *
59 inBuf->lpfxFormat->nChannels / 8;
60 inpos = inBuf->playpos / bytespersample * 1024 + inBuf->frac;
61 spd = 1024 * inBuf->frequency / outrate;
62 if (inBuf->pan <= 0)
63 vol1 = inBuf->volume;
64 else
65 vol1 = inBuf->volume * (256 - inBuf->pan) / 256;
66 if (inBuf->pan >= 0)
67 vol2 = inBuf->volume;
68 else
69 vol2 = inBuf->volume * (256 + inBuf->pan) / 256;
70
71 len = inBuf->bufferdesc.dwBufferBytes / bytespersample * 1024;
72 if ((inBuf->lpfxFormat->nChannels == 2) &&
73 (inBuf->lpfxFormat->wBitsPerSample == 16))
74 {
75 data16b = (signed short *) inBuf->lpBuffer;
76 for (i = 0; i < tomix; i++)
77 {
78 j = inpos / 1024 * 2;
79 mixbuf[i*2] += data16b[j] * vol1 / 256;
80 mixbuf[i*2+1] += data16b[j+1] * vol2 / 256;
81 inpos += spd;
82 if (inpos >= len)
83 {
84 if (inBuf->fLoop) inpos -= len;
85 else
86 {
87 inBuf->fPlaying = FALSE;
88 if (inBuf->notify != NULL)
89 inBuf->notify->CheckStop();
90
91 break;
92 }
93 }
94 }
95 }
96
97 if ((inBuf->lpfxFormat->nChannels == 1) &&
98 (inBuf->lpfxFormat->wBitsPerSample == 16))
99 {
100 data16b = (signed short *) inBuf->lpBuffer;
101 for (i = 0; i < tomix; i++)
102 {
103 j = inpos / 1024;
104 sample = data16b[j];
105 mixbuf[i*2] += sample * vol1 / 256;
106 mixbuf[i*2+1] += sample * vol2 / 256;
107 inpos += spd;
108 if (inpos >= len)
109 {
110 if (inBuf->fLoop) inpos -= len;
111 else
112 {
113 inBuf->fPlaying = FALSE;
114 if (inBuf->notify != NULL)
115 inBuf->notify->CheckStop();
116
117 break;
118 }
119 }
120 }
121 }
122
123 if ((inBuf->lpfxFormat->nChannels == 2) &&
124 (inBuf->lpfxFormat->wBitsPerSample == 8))
125 {
126 data8b = (unsigned char *) inBuf->lpBuffer;
127 for (i = 0; i < tomix; i++)
128 {
129 j = inpos / 1024 * 2;
130 sample = ((int) data8b[j] - 128) * vol1;
131 mixbuf[i*2] += sample;
132 sample = ((int) data8b[j+1] - 128) * vol2;
133 mixbuf[i*2+1] += sample;
134 inpos += spd;
135 if (inpos >= len)
136 {
137 if (inBuf->fLoop) inpos -= len;
138 else
139 {
140 inBuf->fPlaying = FALSE;
141 if (inBuf->notify != NULL)
142 inBuf->notify->CheckStop();
143
144 break;
145 }
146 }
147 }
148 }
149
150 if ((inBuf->lpfxFormat->nChannels == 1) &&
151 (inBuf->lpfxFormat->wBitsPerSample == 8))
152 {
153 data8b = (unsigned char *) inBuf->lpBuffer;
154 for (i = 0; i < tomix; i++)
155 {
156 j = inpos / 1024;
157 sample = (int) data8b[j] - 128;
158 mixbuf[i*2] += sample * vol1;
159 mixbuf[i*2+1] += sample * vol2;
160 inpos += spd;
161 if (inpos >= len)
162 {
163 if (inBuf->fLoop) inpos -= len;
164 else
165 {
166 inBuf->fPlaying = FALSE;
167 if (inBuf->notify != NULL)
168 inBuf->notify->CheckStop();
169
170 break;
171 }
172 }
173 }
174 }
175
176 oldpos = inBuf->playpos;
177 inBuf->playpos = inpos / 1024 * bytespersample;
178 inBuf->frac = inpos % 1024;
179
180 // Check if any notifications are to be signaled
181 if (inBuf->notify != NULL)
182 inBuf->notify->CheckPos(oldpos, inBuf->playpos);
183
184 // keep the write cursor about 15ms ahead of the play cursor
185 inBuf->writepos = inBuf->playpos + inBuf->frequency * bytespersample / 67;
186 inBuf->writepos %= inBuf->bufferdesc.dwBufferBytes;
187}
188
189
190void MixFunc (OS2IDirectSoundBuffer *firstBuf,
191 OS2IDirectSoundBuffer *outBuf,
192 ULONG cbMix)
193{
194 OS2IDirectSoundBuffer *inBuf = firstBuf;
195 int i;
196 int outbits;
197 int outrate;
198 int outnch;
199 int tomix;
200 int outpos;
201 int outlen;
202 unsigned char *data8b;
203 signed short *data16b;
204
205 outbits = outBuf->lpfxFormat->wBitsPerSample;
206 outrate = outBuf->lpfxFormat->nSamplesPerSec;
207 outnch = outBuf->lpfxFormat->nChannels;
208 tomix = cbMix * 8 / outbits / outnch;
209
210 // calculate required size (elements) of mixer buffer
211 ULONG ulRequiredSize = tomix * outnch;
212
213 // dynamically allocate the mixerbuffer as required
214 if (ulMixerBufferSize < ulRequiredSize)
215 {
216 // check if buffer has been allocated at all
217 if (NULL == mixbuf)
218 {
219 // allocate new buffer
220 mixbuf = (signed long*) malloc(ulRequiredSize * sizeof(mixbuf[0]));
221 ulMixerBufferSize = tomix;
222 }
223 else
224 {
225 // reallocate existing buffer
226 mixbuf = (signed long*) realloc(mixbuf, ulRequiredSize * sizeof(mixbuf[0]));
227 ulMixerBufferSize = tomix;
228 }
229 }
230
231
232 /* PH 2001-04-20 PowerDVD 3 comes in with tomix==4096
233 * (ulNumDartBuffers == 1.
234 * So below memset() crashed as the former static
235 * mixer buffer was way to small. The dynamic allocation
236 * is supposed to fix this.
237 *
238 * Also the assumption (?) of outnch == 2 is not met here.
239 * PowerDVD tries with 4 channels, thus requiring an even
240 * larger buffer.
241 */
242 memset(&mixbuf[0], 0, ulRequiredSize * sizeof(mixbuf[0]));
243
244
245 while (inBuf != NULL)
246 {
247 if (inBuf->fPlaying)
248 {
249 MixOneBuffer(inBuf, tomix, outrate);
250 }
251 inBuf = inBuf->next;
252 }
253
254 outpos = outBuf->playpos * 8 / outbits;
255 outlen = outBuf->bufferdesc.dwBufferBytes * 8 / outbits;
256
257 if (outbits == 16)
258 {
259 data16b = (signed short *) outBuf->lpBuffer;
260 for (i = 0; i < tomix * outnch; i++)
261 {
262 if (mixbuf[i] <= -32768)
263 data16b[outpos] = -32768;
264 else
265 if (mixbuf[i] >= 32767)
266 data16b[outpos] = 32767;
267 else
268 data16b[outpos] = (signed short)mixbuf[i];
269
270 outpos++;
271
272 if (outpos >= outlen)
273 outpos = 0;
274 }
275 }
276 else
277 {
278 data8b = (unsigned char *) outBuf->lpBuffer;
279 for (i = 0; i < tomix * outnch; i++)
280 {
281 if (mixbuf[i] <= -32768)
282 data8b[outpos] = 0;
283 else
284 if (mixbuf[i] >= 32767)
285 data8b[outpos] = 255;
286 else
287 data8b[outpos] = (signed short)mixbuf[i] / 256 + 128;
288
289 outpos++;
290 if (outpos >= outlen)
291 outpos = 0;
292 }
293 }
294
295 outBuf->playpos = outpos * outbits / 8;
296}
297
Note: See TracBrowser for help on using the repository browser.