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