/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #pragma off (unreferenced) static char rcsid[] = "$Id: ds.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $"; #pragma on (unreferenced) #define WIN32_LEAN_AND_MEAN #define _WIN32 #define WIN95 #include #include #include #include #include #include "fix.h" #include "ds.h" #include "mono.h" // Samir's Hacked Musical Interface (HMI) mixer struct SSMixerObject { LPDIRECTSOUND lpds; DWORD old_master_vol; int active; int ch_num; int ch_cur; SSoundBuffer *ch_list; } SSMixer = { NULL, 0, 0, 0, NULL }; long XlatSSToDSPan(unsigned short pan); long XlatSSToDSVol(unsigned vol); DWORD XlatSSToWAVVol(unsigned short vol); unsigned short XlatWAVToSSVol(DWORD vol); // Functions // ---------------------------------------------------------------------------- BOOL SSInit(HWND hWnd, int channels, unsigned flags) { LPDIRECTSOUNDBUFFER lpPrimaryBuffer; LPDIRECTSOUND lpDS; DSBUFFERDESC dsbd; if (SSMixer.lpds) return TRUE; // Perform Direct Sound Initialization if (DirectSoundCreate(NULL, &lpDS, NULL) != DS_OK) return FALSE; SSMixer.lpds = lpDS; if (IDirectSound_SetCooperativeLevel(lpDS, hWnd, DSSCL_NORMAL) != DS_OK) { SSDestroy(); return FALSE; } // Start Mixer memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &lpPrimaryBuffer, NULL) == DS_OK) { if (IDirectSoundBuffer_Play(lpPrimaryBuffer, 0, 0, DSBPLAY_LOOPING) != DS_OK) { IDirectSoundBuffer_Release(lpPrimaryBuffer); SSDestroy(); return FALSE; } IDirectSoundBuffer_Release(lpPrimaryBuffer); } else { SSDestroy(); return FALSE; } // Finish initializing SSMixer. SSMixer.ch_cur = 0; SSMixer.ch_list = (SSoundBuffer *)malloc(sizeof(SSoundBuffer)*channels); if (!SSMixer.ch_list) return FALSE; memset(SSMixer.ch_list, 0, sizeof(SSoundBuffer)*channels); SSMixer.ch_num = channels; // Determine Sound technology and volume caps waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, (LPDWORD)&SSMixer.old_master_vol); // waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, 0x40004000); return TRUE; } void SSDestroy() { int i; int j = 0; if (!SSMixer.lpds) return; // Free sound buffers currently allocated. for (i=0; ibits_per_sample = 16; else caps->bits_per_sample = 8; caps->sample_rate = dscaps.dwMaxSecondarySampleRate; } void SSSetVolume(DWORD vol) { vol = XlatSSToWAVVol((WORD)vol); waveOutSetVolume((HWAVEOUT)WAVE_MAPPER, vol); } WORD SSGetVolume() { DWORD vol; waveOutGetVolume((HWAVEOUT)WAVE_MAPPER, &vol); return XlatWAVToSSVol(vol); } // SSInitBuffer // Must Create a DirectSound Secondary Buffer for the sound info. BOOL SSInitBuffer(SSoundBuffer *sample) { DSBUFFERDESC dsbd; WAVEFORMATEX wav; HRESULT dsresult; LPVOID databuf; LPVOID databuf2; DWORD writesize1, writesize2; char *data; char *auxdata, *aux2data; int length; int auxlength, aux2length; data = sample->data; length = sample->length; // Separate buffer into two for looping effects. if (sample->looping) { if (sample->loop_start > -1) { auxdata = sample->data + sample->loop_start; length = sample->loop_start; auxlength = sample->loop_end - sample->loop_start; aux2data = sample->data + sample->loop_end; aux2length = sample->length - sample->loop_end; } } // Create sound buffer sample->obj = NULL; sample->auxobj = NULL; sample->auxobj2 = NULL; wav.wFormatTag = WAVE_FORMAT_PCM; wav.nChannels = sample->channels; wav.nSamplesPerSec = sample->rate; wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3; wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec; wav.wBitsPerSample = sample->bits_per_sample; memset(&dsbd, 0, sizeof(dsbd)); dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT; dsbd.lpwfxFormat = &wav; dsbd.dwBufferBytes = length; if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->obj, NULL) != DS_OK) { return FALSE; } // Copy main data to buffer if (data) { dsresult = IDirectSoundBuffer_Lock(sample->obj, 0, length, &databuf, &writesize1, &databuf2, &writesize2, 0); { if (dsresult != DS_OK) return FALSE; memcpy(databuf, data, writesize1); if (databuf2) memcpy(databuf2, data+writesize1, writesize2); } IDirectSoundBuffer_Unlock(sample->obj, databuf, writesize1, databuf2, writesize2); } // Take care of looping buffer if (sample->looping && sample->loop_start>-1) { memset(&dsbd, 0, sizeof(dsbd)); wav.wFormatTag = WAVE_FORMAT_PCM; wav.nChannels = sample->channels; wav.nSamplesPerSec = sample->rate; wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3; wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec; wav.wBitsPerSample = sample->bits_per_sample; dsbd.dwSize = sizeof(dsbd); dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT; dsbd.lpwfxFormat = &wav; dsbd.dwBufferBytes = auxlength; if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj, NULL) != DS_OK) { mprintf((1, "SS: Unable to create aux-buffer.\n")); return FALSE; } dsresult = IDirectSoundBuffer_Lock(sample->auxobj, 0, auxlength, &databuf, &writesize1, &databuf2, &writesize2, 0); { if (dsresult != DS_OK) return FALSE; memcpy(databuf, auxdata, writesize1); if (databuf2) memcpy(databuf2, auxdata+writesize1, writesize2); } IDirectSoundBuffer_Unlock(sample->auxobj, databuf, writesize1, databuf2, writesize2); //@@ memset(&dsbd, 0, sizeof(dsbd)); //@@ //@@ wav.wFormatTag = WAVE_FORMAT_PCM; //@@ wav.nChannels = sample->channels; //@@ wav.nSamplesPerSec = sample->rate; //@@ wav.nBlockAlign = (sample->channels * sample->bits_per_sample) >> 3; //@@ wav.nAvgBytesPerSec = wav.nBlockAlign * wav.nSamplesPerSec; //@@ wav.wBitsPerSample = sample->bits_per_sample; //@@ //@@ dsbd.dwSize = sizeof(dsbd); //@@ dsbd.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLDEFAULT; //@@ dsbd.lpwfxFormat = &wav; //@@ dsbd.dwBufferBytes = aux2length; //@@ //@@ if (IDirectSound_CreateSoundBuffer(SSMixer.lpds, &dsbd, &sample->auxobj2, NULL) //@@ != DS_OK) { //@@ mprintf((1, "SS: Unable to create aux-buffer.\n")); //@@ return FALSE; //@@ } //@@ //@@ dsresult = IDirectSoundBuffer_Lock(sample->auxobj2, 0, aux2length, &databuf, //@@ &writesize1, &databuf2, &writesize2, 0); //@@ { //@@ if (dsresult != DS_OK) return FALSE; //@@ memcpy(databuf, aux2data, writesize1); //@@ if (databuf2) memcpy(databuf2, aux2data+writesize1, writesize2); //@@ } //@@ IDirectSoundBuffer_Unlock(sample->auxobj2, databuf, writesize1, databuf2, writesize2); } return TRUE; } void SSDestroyBuffer(SSoundBuffer *sample) { if (sample->obj) IDirectSoundBuffer_Release(sample->obj); if (sample->auxobj) IDirectSoundBuffer_Release(sample->auxobj); if (sample->auxobj2) IDirectSoundBuffer_Release(sample->auxobj2); sample->obj = NULL; sample->auxobj = NULL; sample->auxobj2 = NULL; } int SSInitChannel(SSoundBuffer *sample) { HRESULT dsresult; int start_channel, this_channel; LPDIRECTSOUNDBUFFER lpdsb; DWORD flags; // Find Free channel start_channel = SSMixer.ch_cur; while (1) { if (!SSMixer.ch_list[SSMixer.ch_cur].obj) break; else if (!SSChannelPlaying(SSMixer.ch_cur)) { SSDestroyBuffer(&SSMixer.ch_list[SSMixer.ch_cur]); break; } SSMixer.ch_cur++; if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur=0; if (SSMixer.ch_cur == start_channel) return -1; } // Create sound object for mixer. flags = 0; if (sample->looping) { if (sample->loop_start == -1) { flags = DSBPLAY_LOOPING; // mprintf((0,"SS: looping sample (%d).\n", sample->loop_start)); } } if (!SSInitBuffer(sample)) return -1; // Set up mixing parameters lpdsb = sample->obj; IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol)); IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan)); // Mix in main sound object. dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags); if (dsresult != DS_OK) return -1; // Mix in auxillary object (loop portion) lpdsb = sample->auxobj; if (lpdsb) { if (sample->looping) flags = DSBPLAY_LOOPING; IDirectSoundBuffer_SetVolume(lpdsb, XlatSSToDSVol(sample->vol)); IDirectSoundBuffer_SetPan(lpdsb, XlatSSToDSPan(sample->pan)); dsresult = IDirectSoundBuffer_Play(lpdsb, 0, 0, flags); if (dsresult != DS_OK) return -1; mprintf((0, "SS: looping midsample (%d).\n", sample->loop_start)); } // Add to mixer list. this_channel = SSMixer.ch_cur; memcpy(&SSMixer.ch_list[SSMixer.ch_cur++], sample, sizeof(SSoundBuffer)); if (SSMixer.ch_cur >= SSMixer.ch_num) SSMixer.ch_cur = 0; return this_channel; } BOOL SSChannelPlaying(int channel) { HRESULT dsresult; DWORD status; int i; i = channel; if (SSMixer.ch_list[i].obj) { dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].obj, &status); if (dsresult != DS_OK) return FALSE; if (status & DSBSTATUS_PLAYING) { return TRUE; } if (SSMixer.ch_list[i].auxobj) { dsresult = IDirectSoundBuffer_GetStatus(SSMixer.ch_list[i].auxobj, &status); if (dsresult != DS_OK) return FALSE; if (status & DSBSTATUS_PLAYING) { return TRUE; } } } return FALSE; } BOOL SSStopChannel(int channel) { if (SSMixer.ch_list[channel].obj) { if (SSMixer.ch_list[channel].auxobj) { IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].auxobj); mprintf((0, "DS: stopping midsample looping!\n")); } if (IDirectSoundBuffer_Stop(SSMixer.ch_list[channel].obj) != DS_OK) { return TRUE; } SSDestroyBuffer(&SSMixer.ch_list[channel]); } return TRUE; } BOOL SSSetChannelPan(int channel, unsigned short pan) { HRESULT dsresult; int i; i = channel; if (SSMixer.ch_list[i].obj) { dsresult = IDirectSoundBuffer_SetPan(SSMixer.ch_list[i].obj, XlatSSToDSPan(pan)); if (dsresult != DS_OK) return FALSE; return TRUE; } return FALSE; } BOOL SSSetChannelVolume(int channel, unsigned short vol) { HRESULT dsresult; int i; i = channel; if (SSMixer.ch_list[i].obj) { dsresult = IDirectSoundBuffer_SetVolume(SSMixer.ch_list[i].obj, XlatSSToDSVol(vol)); if (dsresult != DS_OK) return FALSE; return TRUE; } return FALSE; } // ---------------------------------------------------------------------------- long XlatSSToDSPan(unsigned short pan) { fix pan1, pan2; long panr; pan1 = fixdiv(pan,0x8000); pan2 = fixmul(pan1, i2f(10000)); panr = (long)f2i(pan2); panr = -10000+panr; return panr; } long XlatSSToDSVol(unsigned vol) { float atten; float fvol; atten = 32768.0 / ((float)(vol)); fvol = log(atten) / log(2.0); fvol = -1.0 * (fvol * 1000.0); if (fvol < -10000.0) fvol = -10000.0; if (fvol > 0.0) fvol = 0.0; return (int)(fvol); } DWORD XlatSSToWAVVol(unsigned short vol) { DWORD dw; vol=vol*2; dw = (vol<<16)+vol; return (long)dw; } unsigned short XlatWAVToSSVol(DWORD vol) { WORD wvol; wvol = (WORD)vol; return (WORD)(wvol/2); }