1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
12 */
13
14
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: ds.c,v 1.1.1.1 2001/01/19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
18
19 #define WIN32_LEAN_AND_MEAN
20 #define _WIN32
21 #define WIN95
22 #include <windows.h>
23 #include <mmsystem.h>
24
25 #include <stdlib.h>
26 #include <math.h>
27 #include <mem.h>
28
29 #include "fix.h"
30 #include "ds.h"
31 #include "mono.h"
32
33
34 // Samir's Hacked Musical Interface (HMI) mixer
35
36 struct SSMixerObject {
37 LPDIRECTSOUND lpds;
38 DWORD old_master_vol;
39 int active;
40 int ch_num;
41 int ch_cur;
42 SSoundBuffer *ch_list;
43 } SSMixer = { NULL, 0, 0, 0, NULL };
44
45
46 long XlatSSToDSPan(unsigned short pan);
47 long XlatSSToDSVol(unsigned vol);
48 DWORD XlatSSToWAVVol(unsigned short vol);
49 unsigned short XlatWAVToSSVol(DWORD vol);
50
51
52
53 // Functions
54 // ----------------------------------------------------------------------------
55
SSInit(HWND hWnd,int channels,unsigned flags)56 BOOL SSInit(HWND hWnd, int channels, unsigned flags)
57 {
58 LPDIRECTSOUNDBUFFER lpPrimaryBuffer;
59 LPDIRECTSOUND lpDS;
60 DSBUFFERDESC dsbd;
61
62 if (SSMixer.lpds) return TRUE;
63
64 // Perform Direct Sound Initialization
65 if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK)
66 return FALSE;
67
68 SSMixer.lpds = lpDS;
69
70 if (IDirectSound_SetCooperativeLevel(lpDS, hWnd, DSSCL_NORMAL) != DS_OK) {
71 SSDestroy();
72 return FALSE;
73 }
74
75 // Start Mixer
76 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
77 dsbd.dwSize = sizeof(DSBUFFERDESC);
78 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
79 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &lpPrimaryBuffer, NULL) == DS_OK) {
80 if (IDirectSoundBuffer_Play(lpPrimaryBuffer, 0, 0, DSBPLAY_LOOPING) != DS_OK) {
81 IDirectSoundBuffer_Release(lpPrimaryBuffer);
82 SSDestroy();
83 return FALSE;
84 }
85 IDirectSoundBuffer_Release(lpPrimaryBuffer);
86 }
87 else {
88 SSDestroy();
89 return FALSE;
90 }
91
92
93 // Finish initializing SSMixer.
94 SSMixer.ch_cur = 0;
95 SSMixer.ch_list = (SSoundBuffer *)malloc(sizeof(SSoundBuffer)*channels);
96 if (!SSMixer.ch_list) return FALSE;
97
98 memset(SSMixer.ch_list, 0, sizeof(SSoundBuffer)*channels);
99
100 SSMixer.ch_num = channels;
101
102 // Determine Sound technology and volume caps
103 waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, (LPDWORD)&SSMixer.old_master_vol);
104 // waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, 0x40004000);
105 return TRUE;
106 }
107
108
SSDestroy()109 void SSDestroy()
110 {
111 int i;
112 int j = 0;
113
114 if (!SSMixer.lpds) return;
115
116 // Free sound buffers currently allocated.
117 for (i=0; i<SSMixer.ch_num; i++)
118 if (SSMixer.ch_list[i].obj) {
119 j++;
120 IDirectSoundBuffer_Release(SSMixer.ch_list[i].obj);
121 }
122
123 if (j) mprintf((1, "SS: Releasing %d sound buffers!\n", j));
124 free(SSMixer.ch_list);
125
126 // Restore old WAV volume
127 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, SSMixer.old_master_vol);
128
129 // Turn off DirectSound
130 if (SSMixer.lpds) IDirectSound_Release(SSMixer.lpds);
131
132 memset(&SSMixer, 0, sizeof(SSMixer));
133 }
134
135
SSGetObject()136 LPDIRECTSOUND SSGetObject()
137 {
138 return SSMixer.lpds;
139 }
140
141
SSGetCaps(SSCaps * caps)142 void SSGetCaps(SSCaps *caps)
143 {
144 DSCAPS dscaps;
145
146 dscaps.dwSize = sizeof(DSCAPS);
147 IDirectSound_GetCaps(SSMixer.lpds, &dscaps);
148
149 if ((dscaps.dwFlags&DSCAPS_SECONDARY16BIT)) caps->bits_per_sample = 16;
150 else caps->bits_per_sample = 8;
151
152 caps->sample_rate = dscaps.dwMaxSecondarySampleRate;
153 }
154
155
SSSetVolume(DWORD vol)156 void SSSetVolume(DWORD vol)
157 {
158 vol = XlatSSToWAVVol((WORD)vol);
159 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, vol);
160 }
161
162
SSGetVolume()163 WORD SSGetVolume()
164 {
165 DWORD vol;
166
167 waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &vol);
168
169 return XlatWAVToSSVol(vol);
170 }
171
172
173
174 // SSInitBuffer
175 // Must Create a DirectSound Secondary Buffer for the sound info.
176
SSInitBuffer(SSoundBuffer * sample)177 BOOL SSInitBuffer(SSoundBuffer *sample)
178 {
179
180 DSBUFFERDESC dsbd;
181 WAVEFORMATEX wav;
182 HRESULT dsresult;
183 LPVOID databuf;
184 LPVOID databuf2;
185 DWORD writesize1, writesize2;
186 char *data;
187 char *auxdata, *aux2data;
188 int length;
189 int auxlength, aux2length;
190
191 data = sample->data;
192 length = sample->length;
193
194 // Separate buffer into two for looping effects.
195 if (sample->looping) {
196 if (sample->loop_start > -1) {
197 auxdata = sample->data + sample->loop_start;
198 length = sample->loop_start;
199 auxlength = sample->loop_end - sample->loop_start;
200 aux2data = sample->data + sample->loop_end;
201 aux2length = sample->length - sample->loop_end;
202 }
203 }
204
205 // Create sound buffer
206 sample->obj = NULL;
207 sample->auxobj = NULL;
208 sample->auxobj2 = NULL;
209
210 wav.wFormatTag = WAVE_FORMAT_PCM;
211 wav.nChannels = sample->channels;
212 wav.nSamplesPerSec = sample->rate;
213 wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
214 wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
215 wav.wBitsPerSample = sample->bits_per_sample;
216
217 memset(&dsbd, 0, sizeof(dsbd));
218 dsbd.dwSize = sizeof(dsbd);
219 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
220 dsbd.lpwfxFormat = &wav;
221 dsbd.dwBufferBytes = length;
222
223 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->obj, NULL)
224 != DS_OK) {
225 return FALSE;
226 }
227
228 // Copy main data to buffer
229 if (data) {
230 dsresult = IDirectSoundBuffer_Lock(sample->obj, 0, length, &databuf,
231 &writesize1, &databuf2, &writesize2, 0);
232 {
233 if (dsresult != DS_OK) return FALSE;
234 memcpy(databuf, data, writesize1);
235 if (databuf2) memcpy(databuf2, data+writesize1, writesize2);
236 }
237 IDirectSoundBuffer_Unlock(sample->obj, databuf, writesize1, databuf2, writesize2);
238 }
239
240 // Take care of looping buffer
241 if (sample->looping && sample->loop_start>-1) {
242 memset(&dsbd, 0, sizeof(dsbd));
243
244 wav.wFormatTag = WAVE_FORMAT_PCM;
245 wav.nChannels = sample->channels;
246 wav.nSamplesPerSec = sample->rate;
247 wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
248 wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
249 wav.wBitsPerSample = sample->bits_per_sample;
250
251 dsbd.dwSize = sizeof(dsbd);
252 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
253 dsbd.lpwfxFormat = &wav;
254 dsbd.dwBufferBytes = auxlength;
255
256 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj, NULL)
257 != DS_OK) {
258 mprintf((1, "SS: Unable to create aux-buffer.\n"));
259 return FALSE;
260 }
261
262 dsresult = IDirectSoundBuffer_Lock(sample->auxobj, 0, auxlength, &databuf,
263 &writesize1, &databuf2, &writesize2, 0);
264 {
265 if (dsresult != DS_OK) return FALSE;
266 memcpy(databuf, auxdata, writesize1);
267 if (databuf2) memcpy(databuf2, auxdata+writesize1, writesize2);
268 }
269 IDirectSoundBuffer_Unlock(sample->auxobj, databuf, writesize1, databuf2, writesize2);
270
271 //@@ memset(&dsbd, 0, sizeof(dsbd));
272 //@@
273 //@@ wav.wFormatTag = WAVE_FORMAT_PCM;
274 //@@ wav.nChannels = sample->channels;
275 //@@ wav.nSamplesPerSec = sample->rate;
276 //@@ wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
277 //@@ wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
278 //@@ wav.wBitsPerSample = sample->bits_per_sample;
279 //@@
280 //@@ dsbd.dwSize = sizeof(dsbd);
281 //@@ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
282 //@@ dsbd.lpwfxFormat = &wav;
283 //@@ dsbd.dwBufferBytes = aux2length;
284 //@@
285 //@@ if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj2, NULL)
286 //@@ != DS_OK) {
287 //@@ mprintf((1, "SS: Unable to create aux-buffer.\n"));
288 //@@ return FALSE;
289 //@@ }
290 //@@
291 //@@ dsresult = IDirectSoundBuffer_Lock(sample->auxobj2, 0, aux2length, &databuf,
292 //@@ &writesize1, &databuf2, &writesize2, 0);
293 //@@ {
294 //@@ if (dsresult != DS_OK) return FALSE;
295 //@@ memcpy(databuf, aux2data, writesize1);
296 //@@ if (databuf2) memcpy(databuf2, aux2data+writesize1, writesize2);
297 //@@ }
298 //@@ IDirectSoundBuffer_Unlock(sample->auxobj2, databuf, writesize1, databuf2, writesize2);
299
300 }
301
302 return TRUE;
303 }
304
305
SSDestroyBuffer(SSoundBuffer * sample)306 void SSDestroyBuffer(SSoundBuffer *sample)
307 {
308 if (sample->obj) IDirectSoundBuffer_Release(sample->obj);
309 if (sample->auxobj) IDirectSoundBuffer_Release(sample->auxobj);
310 if (sample->auxobj2) IDirectSoundBuffer_Release(sample->auxobj2);
311 sample->obj = NULL;
312 sample->auxobj = NULL;
313 sample->auxobj2 = NULL;
314 }
315
316
SSInitChannel(SSoundBuffer * sample)317 int SSInitChannel(SSoundBuffer *sample)
318 {
319 HRESULT dsresult;
320 int start_channel, this_channel;
321 LPDIRECTSOUNDBUFFER lpdsb;
322 DWORD flags;
323
324 // Find Free channel
325 start_channel = SSMixer.ch_cur;
326
327 while (1)
328 {
329 if (!SSMixer.ch_list[SSMixer.ch_cur].obj)
330 break;
331 else if (!SSChannelPlaying(SSMixer.ch_cur)) {
332 SSDestroyBuffer(&SSMixer.ch_list[SSMixer.ch_cur]);
333 break;
334 }
335 SSMixer.ch_cur++;
336 if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur=0;
337 if (SSMixer.ch_cur == start_channel) return -1;
338 }
339
340 // Create sound object for mixer.
341 flags = 0;
342
343 if (sample->looping) {
344 if (sample->loop_start == -1) {
345 flags = DSBPLAY_LOOPING;
346 // mprintf((0,"SS: looping sample (%d).\n", sample->loop_start));
347 }
348 }
349
350 if (!SSInitBuffer(sample)) return -1;
351
352 // Set up mixing parameters
353 lpdsb = sample->obj;
354 IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol));
355 IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan));
356
357 // Mix in main sound object.
358 dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags);
359 if (dsresult != DS_OK) return -1;
360
361 // Mix in auxillary object (loop portion)
362 lpdsb = sample->auxobj;
363 if (lpdsb) {
364 if (sample->looping) flags = DSBPLAY_LOOPING;
365 IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol));
366 IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan));
367
368 dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags);
369 if (dsresult != DS_OK) return -1;
370 mprintf((0, "SS: looping midsample (%d).\n", sample->loop_start));
371 }
372
373 // Add to mixer list.
374 this_channel = SSMixer.ch_cur;
375 memcpy(&SSMixer.ch_list[SSMixer.ch_cur++], sample, sizeof(SSoundBuffer));
376 if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur = 0;
377
378 return this_channel;
379 }
380
381
SSChannelPlaying(int channel)382 BOOL SSChannelPlaying(int channel)
383 {
384 HRESULT dsresult;
385 DWORD status;
386 int i;
387
388 i = channel;
389
390 if (SSMixer.ch_list[i].obj) {
391 dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].obj,
392 &status);
393 if (dsresult != DS_OK) return FALSE;
394 if (status & DSBSTATUS_PLAYING) {
395 return TRUE;
396 }
397
398 if (SSMixer.ch_list[i].auxobj) {
399 dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].auxobj,
400 &status);
401 if (dsresult != DS_OK) return FALSE;
402 if (status & DSBSTATUS_PLAYING) {
403 return TRUE;
404 }
405 }
406 }
407 return FALSE;
408 }
409
410
SSStopChannel(int channel)411 BOOL SSStopChannel(int channel)
412 {
413 if (SSMixer.ch_list[channel].obj) {
414 if (SSMixer.ch_list[channel].auxobj) {
415 IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].auxobj);
416 mprintf((0, "DS: stopping midsample looping!\n"));
417 }
418
419 if (IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].obj) != DS_OK) {
420 return TRUE;
421 }
422
423 SSDestroyBuffer(&SSMixer.ch_list[channel]);
424 }
425
426 return TRUE;
427 }
428
429
SSSetChannelPan(int channel,unsigned short pan)430 BOOL SSSetChannelPan(int channel, unsigned short pan)
431 {
432 HRESULT dsresult;
433 int i;
434
435 i = channel;
436
437 if (SSMixer.ch_list[i].obj) {
438 dsresult = IDirectSoundBuffer_SetPan(SSMixer.ch_list[i].obj,
439 XlatSSToDSPan(pan));
440 if (dsresult != DS_OK) return FALSE;
441 return TRUE;
442
443 }
444 return FALSE;
445 }
446
447
SSSetChannelVolume(int channel,unsigned short vol)448 BOOL SSSetChannelVolume(int channel, unsigned short vol)
449 {
450 HRESULT dsresult;
451 int i;
452
453 i = channel;
454
455 if (SSMixer.ch_list[i].obj) {
456 dsresult = IDirectSoundBuffer_SetVolume(SSMixer.ch_list[i].obj,
457 XlatSSToDSVol(vol));
458 if (dsresult != DS_OK) return FALSE;
459 return TRUE;
460
461 }
462 return FALSE;
463 }
464
465
466 // ----------------------------------------------------------------------------
467
XlatSSToDSPan(unsigned short pan)468 long XlatSSToDSPan(unsigned short pan)
469 {
470 fix pan1, pan2;
471 long panr;
472
473 pan1 = fixdiv(pan,0x8000);
474 pan2 = fixmul(pan1, i2f(10000));
475
476 panr = (long)f2i(pan2);
477 panr = -10000+panr;
478
479 return panr;
480 }
481
482
XlatSSToDSVol(unsigned vol)483 long XlatSSToDSVol(unsigned vol)
484 {
485 float atten;
486 float fvol;
487
488 atten = 32768.0 / ((float)(vol));
489 fvol = log(atten) / log(2.0);
490 fvol = -1.0 * (fvol * 1000.0);
491
492 if (fvol < -10000.0) fvol = -10000.0;
493 if (fvol > 0.0) fvol = 0.0;
494
495 return (int)(fvol);
496 }
497
498
XlatSSToWAVVol(unsigned short vol)499 DWORD XlatSSToWAVVol(unsigned short vol)
500 {
501 DWORD dw;
502 vol=vol*2;
503 dw = (vol<<16)+vol;
504 return (long)dw;
505 }
506
507
XlatWAVToSSVol(DWORD vol)508 unsigned short XlatWAVToSSVol(DWORD vol)
509 {
510 WORD wvol;
511 wvol = (WORD)vol;
512 return (WORD)(wvol/2);
513 }
514