Cygwin support, using SDL.
[btb/d2x.git] / unused / win95 / ds.c
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
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                 
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
136 LPDIRECTSOUND SSGetObject()
137 {
138         return SSMixer.lpds;
139 }
140
141
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
156 void SSSetVolume(DWORD vol)
157 {
158         vol = XlatSSToWAVVol((WORD)vol);
159         waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, vol);
160 }
161
162
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
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
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
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
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
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
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
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
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
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
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
508 unsigned short XlatWAVToSSVol(DWORD vol)
509 {
510         WORD wvol;
511         wvol = (WORD)vol;
512         return (WORD)(wvol/2);
513 }