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.
15 #define WIN32_LEAN_AND_MEAN
30 // Samir's Hacked Musical Interface (HMI) mixer
32 struct SSMixerObject {
38 SSoundBuffer *ch_list;
39 } SSMixer = { NULL, 0, 0, 0, NULL };
42 long XlatSSToDSPan(unsigned short pan);
43 long XlatSSToDSVol(unsigned vol);
44 DWORD XlatSSToWAVVol(unsigned short vol);
45 unsigned short XlatWAVToSSVol(DWORD vol);
50 // ----------------------------------------------------------------------------
52 BOOL SSInit(HWND hWnd, int channels, unsigned flags)
54 LPDIRECTSOUNDBUFFER lpPrimaryBuffer;
58 if (SSMixer.lpds) return TRUE;
60 // Perform Direct Sound Initialization
61 if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK)
66 if (IDirectSound_SetCooperativeLevel(lpDS, hWnd, DSSCL_NORMAL) != DS_OK) {
72 memset(&dsbd, 0, sizeof(DSBUFFERDESC));
73 dsbd.dwSize = sizeof(DSBUFFERDESC);
74 dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
75 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &lpPrimaryBuffer, NULL) == DS_OK) {
76 if (IDirectSoundBuffer_Play(lpPrimaryBuffer, 0, 0, DSBPLAY_LOOPING) != DS_OK) {
77 IDirectSoundBuffer_Release(lpPrimaryBuffer);
81 IDirectSoundBuffer_Release(lpPrimaryBuffer);
89 // Finish initializing SSMixer.
91 SSMixer.ch_list = (SSoundBuffer *)malloc(sizeof(SSoundBuffer)*channels);
92 if (!SSMixer.ch_list) return FALSE;
94 memset(SSMixer.ch_list, 0, sizeof(SSoundBuffer)*channels);
96 SSMixer.ch_num = channels;
98 // Determine Sound technology and volume caps
99 waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, (LPDWORD)&SSMixer.old_master_vol);
100 // waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, 0x40004000);
110 if (!SSMixer.lpds) return;
112 // Free sound buffers currently allocated.
113 for (i=0; i<SSMixer.ch_num; i++)
114 if (SSMixer.ch_list[i].obj) {
116 IDirectSoundBuffer_Release(SSMixer.ch_list[i].obj);
119 if (j) mprintf((1, "SS: Releasing %d sound buffers!\n", j));
120 free(SSMixer.ch_list);
122 // Restore old WAV volume
123 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, SSMixer.old_master_vol);
125 // Turn off DirectSound
126 if (SSMixer.lpds) IDirectSound_Release(SSMixer.lpds);
128 memset(&SSMixer, 0, sizeof(SSMixer));
132 LPDIRECTSOUND SSGetObject()
138 void SSGetCaps(SSCaps *caps)
142 dscaps.dwSize = sizeof(DSCAPS);
143 IDirectSound_GetCaps(SSMixer.lpds, &dscaps);
145 if ((dscaps.dwFlags&DSCAPS_SECONDARY16BIT)) caps->bits_per_sample = 16;
146 else caps->bits_per_sample = 8;
148 caps->sample_rate = dscaps.dwMaxSecondarySampleRate;
152 void SSSetVolume(DWORD vol)
154 vol = XlatSSToWAVVol((WORD)vol);
155 waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, vol);
163 waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &vol);
165 return XlatWAVToSSVol(vol);
171 // Must Create a DirectSound Secondary Buffer for the sound info.
173 BOOL SSInitBuffer(SSoundBuffer *sample)
181 DWORD writesize1, writesize2;
183 char *auxdata, *aux2data;
185 int auxlength, aux2length;
188 length = sample->length;
190 // Separate buffer into two for looping effects.
191 if (sample->looping) {
192 if (sample->loop_start > -1) {
193 auxdata = sample->data + sample->loop_start;
194 length = sample->loop_start;
195 auxlength = sample->loop_end - sample->loop_start;
196 aux2data = sample->data + sample->loop_end;
197 aux2length = sample->length - sample->loop_end;
201 // Create sound buffer
203 sample->auxobj = NULL;
204 sample->auxobj2 = NULL;
206 wav.wFormatTag = WAVE_FORMAT_PCM;
207 wav.nChannels = sample->channels;
208 wav.nSamplesPerSec = sample->rate;
209 wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
210 wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
211 wav.wBitsPerSample = sample->bits_per_sample;
213 memset(&dsbd, 0, sizeof(dsbd));
214 dsbd.dwSize = sizeof(dsbd);
215 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
216 dsbd.lpwfxFormat = &wav;
217 dsbd.dwBufferBytes = length;
219 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->obj, NULL)
224 // Copy main data to buffer
226 dsresult = IDirectSoundBuffer_Lock(sample->obj, 0, length, &databuf,
227 &writesize1, &databuf2, &writesize2, 0);
229 if (dsresult != DS_OK) return FALSE;
230 memcpy(databuf, data, writesize1);
231 if (databuf2) memcpy(databuf2, data+writesize1, writesize2);
233 IDirectSoundBuffer_Unlock(sample->obj, databuf, writesize1, databuf2, writesize2);
236 // Take care of looping buffer
237 if (sample->looping && sample->loop_start>-1) {
238 memset(&dsbd, 0, sizeof(dsbd));
240 wav.wFormatTag = WAVE_FORMAT_PCM;
241 wav.nChannels = sample->channels;
242 wav.nSamplesPerSec = sample->rate;
243 wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
244 wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
245 wav.wBitsPerSample = sample->bits_per_sample;
247 dsbd.dwSize = sizeof(dsbd);
248 dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
249 dsbd.lpwfxFormat = &wav;
250 dsbd.dwBufferBytes = auxlength;
252 if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj, NULL)
254 mprintf((1, "SS: Unable to create aux-buffer.\n"));
258 dsresult = IDirectSoundBuffer_Lock(sample->auxobj, 0, auxlength, &databuf,
259 &writesize1, &databuf2, &writesize2, 0);
261 if (dsresult != DS_OK) return FALSE;
262 memcpy(databuf, auxdata, writesize1);
263 if (databuf2) memcpy(databuf2, auxdata+writesize1, writesize2);
265 IDirectSoundBuffer_Unlock(sample->auxobj, databuf, writesize1, databuf2, writesize2);
267 //@@ memset(&dsbd, 0, sizeof(dsbd));
269 //@@ wav.wFormatTag = WAVE_FORMAT_PCM;
270 //@@ wav.nChannels = sample->channels;
271 //@@ wav.nSamplesPerSec = sample->rate;
272 //@@ wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3;
273 //@@ wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec;
274 //@@ wav.wBitsPerSample = sample->bits_per_sample;
276 //@@ dsbd.dwSize = sizeof(dsbd);
277 //@@ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT;
278 //@@ dsbd.lpwfxFormat = &wav;
279 //@@ dsbd.dwBufferBytes = aux2length;
281 //@@ if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj2, NULL)
283 //@@ mprintf((1, "SS: Unable to create aux-buffer.\n"));
287 //@@ dsresult = IDirectSoundBuffer_Lock(sample->auxobj2, 0, aux2length, &databuf,
288 //@@ &writesize1, &databuf2, &writesize2, 0);
290 //@@ if (dsresult != DS_OK) return FALSE;
291 //@@ memcpy(databuf, aux2data, writesize1);
292 //@@ if (databuf2) memcpy(databuf2, aux2data+writesize1, writesize2);
294 //@@ IDirectSoundBuffer_Unlock(sample->auxobj2, databuf, writesize1, databuf2, writesize2);
302 void SSDestroyBuffer(SSoundBuffer *sample)
304 if (sample->obj) IDirectSoundBuffer_Release(sample->obj);
305 if (sample->auxobj) IDirectSoundBuffer_Release(sample->auxobj);
306 if (sample->auxobj2) IDirectSoundBuffer_Release(sample->auxobj2);
308 sample->auxobj = NULL;
309 sample->auxobj2 = NULL;
313 int SSInitChannel(SSoundBuffer *sample)
316 int start_channel, this_channel;
317 LPDIRECTSOUNDBUFFER lpdsb;
321 start_channel = SSMixer.ch_cur;
325 if (!SSMixer.ch_list[SSMixer.ch_cur].obj)
327 else if (!SSChannelPlaying(SSMixer.ch_cur)) {
328 SSDestroyBuffer(&SSMixer.ch_list[SSMixer.ch_cur]);
332 if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur=0;
333 if (SSMixer.ch_cur == start_channel) return -1;
336 // Create sound object for mixer.
339 if (sample->looping) {
340 if (sample->loop_start == -1) {
341 flags = DSBPLAY_LOOPING;
342 // mprintf((0,"SS: looping sample (%d).\n", sample->loop_start));
346 if (!SSInitBuffer(sample)) return -1;
348 // Set up mixing parameters
350 IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol));
351 IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan));
353 // Mix in main sound object.
354 dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags);
355 if (dsresult != DS_OK) return -1;
357 // Mix in auxillary object (loop portion)
358 lpdsb = sample->auxobj;
360 if (sample->looping) flags = DSBPLAY_LOOPING;
361 IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol));
362 IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan));
364 dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags);
365 if (dsresult != DS_OK) return -1;
366 mprintf((0, "SS: looping midsample (%d).\n", sample->loop_start));
369 // Add to mixer list.
370 this_channel = SSMixer.ch_cur;
371 memcpy(&SSMixer.ch_list[SSMixer.ch_cur++], sample, sizeof(SSoundBuffer));
372 if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur = 0;
378 BOOL SSChannelPlaying(int channel)
386 if (SSMixer.ch_list[i].obj) {
387 dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].obj,
389 if (dsresult != DS_OK) return FALSE;
390 if (status & DSBSTATUS_PLAYING) {
394 if (SSMixer.ch_list[i].auxobj) {
395 dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].auxobj,
397 if (dsresult != DS_OK) return FALSE;
398 if (status & DSBSTATUS_PLAYING) {
407 BOOL SSStopChannel(int channel)
409 if (SSMixer.ch_list[channel].obj) {
410 if (SSMixer.ch_list[channel].auxobj) {
411 IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].auxobj);
412 mprintf((0, "DS: stopping midsample looping!\n"));
415 if (IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].obj) != DS_OK) {
419 SSDestroyBuffer(&SSMixer.ch_list[channel]);
426 BOOL SSSetChannelPan(int channel, unsigned short pan)
433 if (SSMixer.ch_list[i].obj) {
434 dsresult = IDirectSoundBuffer_SetPan(SSMixer.ch_list[i].obj,
436 if (dsresult != DS_OK) return FALSE;
444 BOOL SSSetChannelVolume(int channel, unsigned short vol)
451 if (SSMixer.ch_list[i].obj) {
452 dsresult = IDirectSoundBuffer_SetVolume(SSMixer.ch_list[i].obj,
454 if (dsresult != DS_OK) return FALSE;
462 // ----------------------------------------------------------------------------
464 long XlatSSToDSPan(unsigned short pan)
469 pan1 = fixdiv(pan,0x8000);
470 pan2 = fixmul(pan1, i2f(10000));
472 panr = (long)f2i(pan2);
479 long XlatSSToDSVol(unsigned vol)
484 atten = 32768.0 / ((float)(vol));
485 fvol = log(atten) / log(2.0);
486 fvol = -1.0 * (fvol * 1000.0);
488 if (fvol < -10000.0) fvol = -10000.0;
489 if (fvol > 0.0) fvol = 0.0;
495 DWORD XlatSSToWAVVol(unsigned short vol)
504 unsigned short XlatWAVToSSVol(DWORD vol)
508 return (WORD)(wvol/2);