/* Copyright (C) 1994-2003 Revolution Software Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ */ //============================================================================= // // Filename : d_sound.c // Created : 3rd December 1996 // By : P.R.Porter // // Summary : This module holds the driver interface to direct sound. // // Version Date By Description // ------- --------- --- ----------------------------------------------- // 1.0 03-Dec-96 PRP The sound buffer can be created, with the // format defined by the game engine, and speech // can be played. // // 1.1 05-Dec-96 PRP Sound effects now done. // // 1.2 19-Dec-96 PRP Added volume and pan to speech and sound // effects. Also, added type to sound effects // so that they can be looped. Implemented // a CloseAllFx function which will clear out // all sound effects. // // 1.3 20-Dec-96 PRP Fixed a bug in the function which clears // spot effects when they have finished playing. // // 1.4 02-Jan-97 PRP Fixed a bug in ClearAllFx which was trying // to close the speech. // // 1.5 08-Apr-97 PRP Added ... to the // InitialiseSound function. // // 1.6 09-Apr-97 PRP Added functions to steam music from CD. // // 1.7 29-May-97 PSJ Added functions to save and restore the state // of the sound drivers. // // 1.8 04-Jun-97 PRP Added bodge to PlayFx routine which registers // a sound effect to remove itself from the list // if it is the tune to leave a sequence. // // 1.9 06-Jun-97 PSJ Expanded volTable from 17 to 241 entries. // Added an fx and a speech master volume level. // Added SetFxVolume and GetFxVolume for fx master // volume. Added SetSpeechVolume and GetSpeechVolume // for speech master volume. // // 1.10 09-Jun-97 PSJ Added SetMusicVolume and GetMusicVolume. // // 1.11 09-Jun-97 PSJ Fixed bug in SetSpeechVolume. // // 1.12 10-Jun-97 PSJ Added MuteMusic, MuteSpeech, MuteFx, IsMusicMute, // IsFxMute and IsSpeechMute. // // 1.13 12-Jun-97 PSJ Added PlayCompSpeech to play compressed speech // from a speech cluster. // // 1.14 19-Jun-97 PSJ Added StreamCompMusic and UpdateCompSampleStreaming // to play compressed music from a music cluster. // Added StopMusic to fade out any music playing. // // 1.15 24-Jun-97 PSJ Changed PlayCompSpeech to physically check for // playing samples rather than using the assuming the // speechStatus flag is correct. // // 1.16 24-Jun-97 PSJ Fixed bug it SetSpeechVolume. // // 1.17 26-Jun-97 PSJ Added AmISpeaking() for lip syncing. // // 1.18 26-Jun-97 PSJ Tweaked the nose of the dread, killer AmISpeaking // function. // // 1.19 26-Jun-97 PSJ Added PauseSpeech and UnpauseSpeech. // // 1.20 26-Jun-97 PSJ Fixed a bug in the muteSpeech routine. // // 1.21 26-Jun-97 PSJ Fixed a bug in the AmISpeaking routine. // // 1.22 26-Jun-97 PSJ PlayCompSpeech loads and pauses the speech // ready to be played by UnpauseSpeech. // // 1.23 01-Jul-97 PSJ Fixed GetSpeechStatus to work when speech is paused // // 1.24 03-Jul-97 PSJ Stopped PlayCompSpeech clicking at the end of samples. // // 1.25 10-Jul-97 PSJ Reduced music volume by 1/4 when playing speech // // 1.26 10-Jul-97 PSJ GetMusicVolume return safeMusicVol if it is set. // // 1.27 15-Jul-97 PRP Added functions to pause and unpause the sound effects. // // 1.28 15-Jul-97 PRP Fixed PauseFx // // 1.29 16-Jul-97 PSJ Added GetCompSpeechSize and PreFetchCompSpeech // // 1.30 16-Jul-97 PRP Fixed setting of sound fx volume. // // 1.31 18-Jul-97 PRP Added speech expansion to get samples to sound the same. // // 1.32 18-Jul-97 PRP Hopefully fixed expansion algorithm. // // 1.33 18-Jul-97 JEL Fixed UnpauseFx() // // 1.34 18-Jul-97 JEL Fixed PlayCompSpeech() // // 1.35 18-Jul-97 JEL Removed speech volume enhancing (now to be done in speech compressor) // // 1.36 21-Jul-97 PRP Added new type of sound effect which is the music lead in. // Also, added function to pause the sound effects // just for sequences. // // 1.37 21-Jul-97 PRP Modified ClearAllFx so that it doesn't kick out // lead in and lead out music for smacker sequences. // // 1.38 21-Jul-97 PRP Tried to fix the bug where the second lead in // music will not play due to a duplicate id. // // 1.39 21-Jul-97 PRP Finally fixed the bug to kick out lead in music // fx when they have finished. // // 1.40 25-Jul-97 JEL Fixed crashing when music paused & unpaused repeatedly // // 1.41 28-Jul-97 PRP Checked to see if fx are looping as well as playing! // // 1.42 30-Jul-97 PSJ Added Music dipping. // // 1.43 30-Jul-97 PSJ Added MusicTimeRemaining. // // 1.44 31-Jul-97 PSJ Adjusted MusicTimeRemaining to include music left in buffer. // // 1.45 06-Aug-97 PSJ Updated Get and Set scroll SoundStatus. // // 1.46 12-Aug-97 PSJ Added ReverseStereo(void) // // 1.47 13-Aug-97 PSJ Updated DipMusic so it fades up after speech has finished. // // 1.48 13-Aug-97 PRP Added IsFxOpen(). // // 1.49 15-Aug-97 PRP Added SetFxVolumePan(). // // 1.50 15-Aug-97 PRP Added SetFxIdVolume() // // 1.51 15-Aug-97 PSJ Fixed bug in PlayCompMusic(); // // 1.52 19-Aug-97 JEL Fixed bug in MusicTimeRemaining() // // WE'VE SCREWED UP THE NUMBERING! // // 1.59 19-Aug-97 JEL Fixed bug in MusicTimeRemaining(), ;) // // 1.60 19-Aug-97 PSJ Updated DipMusic so it fades music a bit more. // // 1.61 21-Aug-97 PSJ Updated StreamCompMusic so if both streams are in use, // the fading stream is stopped and the new tune started. // // 1.62 21-Aug-97 PSJ Updated StreamCompMusic so if the music is unmuted, // the last tune is restarted if it was looping. // // 1.63 22-Aug-97 PSJ Update PlayFx to handle smacker leadouts. // // 1.64 27-Aug-97 PSJ Update PlayFx to record an fx's local volume, // So SetFxVolume can update playing fx's with the // correct volume. // // 1.65 27-Aug-97 PSJ Stopped CloseFX from closing invalid fx's. // // 1.66 01-Sep-97 PRP Cleared the fxPaused flag when closing fx. // // 1.67 01-Sep-97 PRP Fixed the fact that SetFxVolume was still // being done even if the fx were muted. // // 1.68 01-Sep-97 PRP Set zero sound to -10000 // // Functions // --------- // // -------------------------------------------------------------------------- // // int32 InitialiseSound(uint16 freq, uint16 channels, uint16 bitDepth) // // This function initialises DirectSound by specifying the parameters of the // primary buffer. // // Freq is the sample rate - 44100, 22050 or 11025 // Channels should be 1 for mono, 2 for stereo // BitDepth should be either 8 or 16 bits per sample. // // -------------------------------------------------------------------------- // // int32 PlaySpeech(uint8 *data, uint8 vol, int8 pan) // // This function plays the wav file passed into it as speech. An error occurs // if speech is already playing, or directSound comes accross problems. The // volume is 0 for zero volume and 16 for maximum volume. The pan position // is -16 for full left, 0 for central and 16 for full right. // // -------------------------------------------------------------------------- // // int32 PlayCompSpeech(const char *filename, uint32 id, uint8 vol, int8 pan) // // This function loads, decompresses and plays the wav 'id' from the cluster // 'filename'. An error occurs if speech is already playing, or directSound // comes accross problems. 'volume' can be from 0 to 16. 'pan' can be from // -16 (full left) to 16 (full right). // id is the text line id used to reference the speech within the speech // cluster. // // -------------------------------------------------------------------------- // // int32 StopSpeechSword2(void) // // Stops the speech from playing. // // -------------------------------------------------------------------------- // // int32 GetSpeechStatus(void) // // Returns either RDSE_SAMPLEPLAYING or RDSE_SAMPLEFINISHED // // -------------------------------------------------------------------------- // // int32 AmISpeaking(void) // // Returns either RDSE_QUIET or RDSE_SPEAKING // // -------------------------------------------------------------------------- // // int32 PauseSpeech(void) // // Stops the speech dead in it's tracks. // // -------------------------------------------------------------------------- // // int32 UnpauseSpeech(void) // // Re-starts the speech from where it was stopped. // // -------------------------------------------------------------------------- // // int32 OpenFx(int32 id, uint8 *data) // // This function opens a sound effect ready for playing. A unique id should // be passed in so that each effect can be referenced individually. // // WARNING: Zero is not a valid ID. // // -------------------------------------------------------------------------- // // int32 PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type) // // This function plays a sound effect. If the effect has already been opened // then *data should be NULL, and the sound effect will simply be obtained // from the id passed in. If the effect has not been opened, then the wav // data should be passed in data. The sound effect will be closed when it // has finished playing. // // The volume can be between 0 (minimum) and 16 (maximum). The pan defines // the left/right balance of the sample. -16 is full left, and 16 is full // right with 0 in the middle. The sample type can be either RDSE_FXSPOT, or // RDSE_FXLOOP. // // WARNING: Zero is not a valid ID // // -------------------------------------------------------------------------- // // int32 CloseFx(int32 id) // // This function closes a sound effect which has been previously opened for // playing. Sound effects must be closed when they are finished with, // otherwise you will run out of sound effect buffers. // // -------------------------------------------------------------------------- // // int32 ClearAllFx(void) // // This function clears all of the sound effects which are currently open or // playing, irrespective of type. // // -------------------------------------------------------------------------- // // int32 StreamMusic(uint8 *filename, int32 loopFlag) // // Streams music from the file defined by filename. The loopFlag should // be set to RDSE_FXLOOP if the music is to loop back to the start. // Otherwise, it should be RDSE_FXSPOT. // The return value must be checked for any problems. // // -------------------------------------------------------------------------- // // int32 StreamCompMusic(uint8 *filename, uint32 id, int32 loopFlag) // // Streams music 'id' from the cluster file 'filename'. The loopFlag should // be set to RDSE_FXLOOP if the music is to loop back to the start. // Otherwise, it should be RDSE_FXSPOT. // The return value must be checked for any problems. // // StreamCompMusic should not be used inconjunction with StreamMusic. // // -------------------------------------------------------------------------- // // void StopMusic(void) // // Fades out and stops the music. // // -------------------------------------------------------------------------- // // int32 PauseMusic(void) // // Stops the music dead in it's tracks. // // -------------------------------------------------------------------------- // // int32 UnpauseMusic(void) // // Re-starts the music from where it was stopped. // // --------------------------------------------------------------------------- // // int32 MusicTimeRemaining(void) // // Returns the time left for the current tune. // // ---------------------------------------------------------------------------- // // int32 ReverseStereo(void) // // This function reverse the pan table, thus reversing the stereo. // //============================================================================= #define WIN32_LEAN_AND_MEAN //#include //#include #include #include "stdafx.h" #include "driver96.h" #include "rdwin.h" // for hwnd. #include "d_sound.h" // Decompression macros #define MakeCompressedByte(shift,sign,amplitude) (((shift)<<4) + ((sign)<<3) + (amplitude)) #define GetCompressedShift(byte) ((byte)>>4) #define GetCompressedSign(byte) (((byte)>>3) & 1) #define GetCompressedAmplitude(byte) ((byte) & 7) #define GetdAPower(dA,power) for (power = 15;power>0 && !((dA) & (1< 32767.0) result = 32767.0; } return (int16) result; } #endif */ // -------------------------------------------------------------------------- // This function reverse the pan table, thus reversing the stereo. // -------------------------------------------------------------------------- int32 Sword2Sound::ReverseStereo(void) { int32 i,j; for (i = 0; i<16; i++) { j = panTable[i]; panTable[i] = panTable[32-i]; panTable[32-i] = j; } return (RD_OK); } // -------------------------------------------------------------------------- // This function returns the index of the sound effect with the ID passed in. // -------------------------------------------------------------------------- int32 Sword2Sound::GetFxIndex(int32 id) { int32 i = 0; while (i < MAXFX) { if (fxId[i] == id) break; i++; } return(i); } int32 Sword2Sound::IsFxOpen(int32 id) { int32 i = 0; while (i < MAXFX) { if (fxId[i] == id) break; i++; } if (i == MAXFX) return 1; else return 0; } // -------------------------------------------------------------------------- // This function checks the status of all current sound effects, and clears // out the ones which are no longer required in a buffer. It is called on // a slow timer from rdwin.c // -------------------------------------------------------------------------- void Sword2Sound::FxServer(void) { warning("stub FxServer"); /* int32 i; int32 status; if (!soundOn) return; if (musicPaused[0] + musicPaused[1] == 0) { if (compressedMusic == 1) UpdateCompSampleStreaming(); else if (compressedMusic == 2) UpdateSampleStreaming(); } if (fxPaused) { for (i=0; i> 3; pf.nAvgBytesPerSec = pf.nBlockAlign * pf.nSamplesPerSec; pf.cbSize = 0; hrz = IDirectSoundBuffer_SetFormat(dsbPrimary, (LPWAVEFORMATEX) &pf); if (hrz != DS_OK) { // We have not been able to set the primary format to the format requested!!! // But carry on anyway, the mixer will just have to work harder :) } // Clear the fx id's for (i=0; ichannels; wf.wf.nSamplesPerSec = wav->samplesPerSec; wf.wBitsPerSample = 8 * wav->blockAlign / (wav->samplesPerSec * wav->channels); wf.wf.nBlockAlign = wf.wf.nChannels * wf.wBitsPerSample / 8; wf.wf.nAvgBytesPerSec = wf.wf.nSamplesPerSec * wf.wf.nBlockAlign; memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); // dsbd.dwFlags = DSBCAPS_CTRLDEFAULT; dsbd.lpwfxFormat = (LPWAVEFORMATEX) &wf; // Set the sample size - search for the size of the data. i = 0; while (i<100) { if (*data == 'd') { data32 = (int32 *) data; if (*data32 == 'atad') break; } i += 1; data++; } if (i == 100) return(RDERR_INVALIDWAV); dsbd.dwBufferBytes = *(data32 + 1); // Create the speech sample buffer hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbSpeech, NULL); if (hr != DS_OK) return(RDERR_CREATESOUNDBUFFER); // Lock the speech buffer, ready to fill it with data hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(dsbSpeech); hr = IDirectSoundBuffer_Lock(dsbSpeech, 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { // Fill the speech buffer with data memcpy((uint8 *) lpv1, (uint8 *) (data32 + 2), dwBytes1); if (dwBytes1 != dsbd.dwBufferBytes) { memcpy((uint8 *) lpv1 + dwBytes1, (uint8 *) (data32 + 2) + dwBytes1, dwBytes2); } // Unlock the buffer now that we've filled it IDirectSoundBuffer_Unlock(dsbSpeech, lpv1, dwBytes1, lpv2, dwBytes2); // Modify the volume according to the master volume if (speechMuted) IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[0]); else IDirectSoundBuffer_SetVolume(dsbSpeech, volTable[vol*speechVol]); IDirectSoundBuffer_SetPan(dsbSpeech, panTable[pan+16]); // Start the speech playing IDirectSoundBuffer_Play(dsbSpeech, 0, 0, 0); speechStatus = 1; } else { IDirectSoundBuffer_Release(dsbSpeech); return(RDERR_LOCKSPEECHBUFFER); } } */ return(RD_OK); } int32 Sword2Sound::AmISpeaking() { warning("stub AmISpeaking"); /* int32 len; // int32 status; int32 readCursor, writeCursor; int32 dwBytes1, dwBytes2; int16 *sample; int32 count = 0; LPVOID lpv1, lpv2; HRESULT hr; #define POSITIVE_THRESHOLD 350 #define NEGATIVE_THRESHOLD -350 if ((!speechMuted) && (!speechPaused) && (dsbSpeech)) { if (IDirectSoundBuffer_GetCurrentPosition(dsbSpeech, &readCursor, &writeCursor) != DS_OK) { return (RDSE_SPEAKING); } len = 44100 / 12; hr = IDirectSoundBuffer_Lock(dsbSpeech, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DS_OK) { for (sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 90) // 20 samples if (*sample>POSITIVE_THRESHOLD || *sample5) // 25% of the samples return (RDSE_SPEAKING); } return (RDSE_QUIET); } return (RDSE_SPEAKING); */ return RDSE_QUIET; } int32 Sword2Sound::GetCompSpeechSize(const char *filename, uint32 speechid) { int32 i; uint32 speechIndex[2]; FILE *fp; // Open the speech cluster and find the data offset & size fp = fopen(filename, "rb"); if (fp == NULL) return(0); if (fseek(fp, (++speechid)*8, SEEK_SET)) { fclose(fp); return (0); } if (fread(speechIndex, sizeof(uint32), 2, fp) != 2) { fclose(fp); return (0); } if (!speechIndex[0] || !speechIndex[1]) { fclose(fp); return (0); } fclose(fp); i = (speechIndex[1]-1)*2 + sizeof(_wavHeader) + 8; return(i); } int32 Sword2Sound::PreFetchCompSpeech(const char *filename, uint32 speechid, uint8 *waveMem) { uint32 i; uint16 *data16; uint8 *data8; uint32 speechIndex[2]; _wavHeader *pwf = (_wavHeader *) waveMem; FILE *fp; // Open the speech cluster and find the data offset & size fp = fopen(filename, "rb"); if (fp == NULL) return(RDERR_INVALIDFILENAME); if (fseek(fp, (++speechid)*8, SEEK_SET)) { fclose(fp); return (RDERR_READERROR); } if (fread(speechIndex, sizeof(uint32), 2, fp) != 2) { fclose(fp); return (RDERR_READERROR); } if (!speechIndex[0] || !speechIndex[1]) { fclose(fp); return (RDERR_INVALIDID); } data16 = (uint16*)(waveMem + sizeof(_wavHeader)); memset(pwf, 0, sizeof(_wavHeader)); *((uint32*)pwf->riff) = 'FFIR'; *((uint32*)pwf->wavID) = 'EVAW'; *((uint32*)pwf->format) = ' tmf'; pwf->formatLen = 0x00000010; pwf->formatTag = 0x0001; pwf->channels = 0x0001; pwf->samplesPerSec = 0x5622; pwf->avgBytesPerSec = 0x0000; pwf->blockAlign = 0xAC44; pwf->unknown1 = 0x0000; pwf->unknown2 = 0x0002; pwf->bitsPerSample = 0x0010; *((uint32*)data16) = 'atad'; data16 += 2; *((uint32*)data16) = (speechIndex[1]-1)*2; data16 += 2; pwf->fileLength = (speechIndex[1]-1)*2 + sizeof(_wavHeader) + 8; // Calculate position in buffer to load compressed sound into data8 = (uint8*)data16 + (speechIndex[1]-1); if (fseek(fp, speechIndex[0], SEEK_SET)) { fclose(fp); return (RDERR_INVALIDID); } if (fread(data8, sizeof(uint8), speechIndex[1], fp) != speechIndex[1]) { fclose(fp); return (RDERR_INVALIDID); } fclose(fp); data16[0] = *((int16*)data8); // Starting Value i=1; while (i<(speechIndex[1]-1)) { if (GetCompressedSign(data8[i+1])) data16[i] = data16[i-1] - (GetCompressedAmplitude(data8[i+1])<channels; wf.wf.nSamplesPerSec = wav->samplesPerSec; wf.wBitsPerSample = 8 * wav->blockAlign / (wav->samplesPerSec * wav->channels); wf.wf.nBlockAlign = wf.wf.nChannels * wf.wBitsPerSample / 8; wf.wf.nAvgBytesPerSec = wf.wf.nSamplesPerSec * wf.wf.nBlockAlign; memset(&dsbd, 0, sizeof(DSBUFFERDESC)); dsbd.dwSize = sizeof(DSBUFFERDESC); // dsbd.dwFlags = DSBCAPS_CTRLDEFAULT; dsbd.lpwfxFormat = (LPWAVEFORMATEX) &wf; // Set the sample size - search for the size of the data. i = 0; while (i<100) { if (*data == 'd') { data32 = (int32 *) data; if (*data32 == 'atad') break; } i += 1; data++; } if (i == 100) return(RDERR_INVALIDWAV); dsbd.dwBufferBytes = *(data32 + 1); // Create the speech sample buffer hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbd, &dsbFx[fxi], NULL); if (hr != DS_OK) return(RDERR_CREATESOUNDBUFFER); // Lock the speech buffer, ready to fill it with data hr = IDirectSoundBuffer_Lock(dsbFx[fxi], 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(dsbFx[fxi]); hr = IDirectSoundBuffer_Lock(dsbFx[fxi], 0, dsbd.dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { // Fill the speech buffer with data memcpy((uint8 *) lpv1, (uint8 *) (data32 + 2), dwBytes1); if (dwBytes1 != dsbd.dwBufferBytes) { memcpy((uint8 *) lpv1 + dwBytes1, (uint8 *) (data32 + 2) + dwBytes1, dwBytes2); } // Unlock the buffer now that we've filled it IDirectSoundBuffer_Unlock(dsbFx[fxi], lpv1, dwBytes1, lpv2, dwBytes2); } else { IDirectSoundBuffer_Release(dsbFx[fxi]); return(RDERR_LOCKSPEECHBUFFER); } fxId[fxi] = id; fxCached[fxi] = RDSE_FXCACHED; } */ return(RD_OK); } int32 Sword2Sound::PlayFx(int32 id, uint8 *data, uint8 vol, int8 pan, uint8 type) { warning("stub PlayFx( %d, %d, %d, %d )", id, vol, pan, type); /* int32 i, loop; HRESULT hr; if (type == RDSE_FXLOOP) loop = DSBPLAY_LOOPING; else loop = 0; if (soundOn) { if (data == NULL) { if (type == RDSE_FXLEADOUT) { id = 0xffffffff; i = GetFxIndex(id); if (i == MAXFX) return(RDERR_FXNOTOPEN); fxLooped[i] = 0; // Start the sound effect playing if (musicMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]); else IDirectSoundBuffer_SetVolume(dsbFx[i], musicVolTable[volMusic[0]]); IDirectSoundBuffer_SetPan(dsbFx[i], 0); IDirectSoundBuffer_Play(dsbFx[i], 0, 0, 0); fxCached[i] = RDSE_FXTOCLEAR; } else { i = GetFxIndex(id); if (i == MAXFX) return(RDERR_FXNOTOPEN); fxLooped[i] = loop; fxVolume[i] = vol; // Start the sound effect playing if (fxMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]); else IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]); IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]); IDirectSoundBuffer_Play(dsbFx[i], 0, 0, loop); if (id == 0xffffffff) fxCached[i] = RDSE_FXTOCLEAR; } } else { if (type == RDSE_FXLEADIN) { id = 0xfffffffe; hr = OpenFx(id, data); if (hr != RD_OK) return hr; i = GetFxIndex(id); if (i == MAXFX) return RDERR_FXFUCKED; fxCached[i] = RDSE_FXTOCLEAR; if (musicMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]); else IDirectSoundBuffer_SetVolume(dsbFx[i], musicVolTable[volMusic[0]]); IDirectSoundBuffer_SetPan(dsbFx[i], 0); IDirectSoundBuffer_Play(dsbFx[i], 0, 0, 0); } else { hr = OpenFx(id, data); if (hr != RD_OK) return(hr); i = GetFxIndex(id); if (i == MAXFX) return(RDERR_FXFUCKED); fxCached[i] = RDSE_FXTOCLEAR; fxLooped[i] = loop; fxVolume[i] = vol; // Start the sound effect playing if (fxMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[0]); else IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]); IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]); IDirectSoundBuffer_Play(dsbFx[i], 0, 0, loop); } } } */ return(RD_OK); } int32 Sword2Sound::SetFxVolumePan(int32 id, uint8 vol, int8 pan) { warning("stub SetFxVolumePan( %d, %d, %d )", id, vol, pan); /* int32 i = GetFxIndex(id); if (i == MAXFX) return RDERR_FXNOTOPEN; fxVolume[i] = vol; if (!fxMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]); IDirectSoundBuffer_SetPan(dsbFx[i], panTable[pan+16]); */ return RD_OK; } int32 Sword2Sound::SetFxIdVolume(int32 id, uint8 vol) { warning("stub SetFxIdVolume( %d, %d )", id, vol); /* int32 i = GetFxIndex(id); if (i == MAXFX) return RDERR_FXNOTOPEN; fxVolume[i] = vol; if (!fxMuted) IDirectSoundBuffer_SetVolume(dsbFx[i], volTable[vol*fxVol]); */ return RD_OK; } int32 Sword2Sound::ClearAllFx(void) { warning("stub ClearAllFx"); /* int32 status; int32 i; if (!soundOn) return(RD_OK); i = 0; while (i < MAXFX) { if ((fxId[i]) && (fxId[i] != 0xfffffffe) && (fxId[i] != 0xffffffff)) { IDirectSoundBuffer_GetStatus(dsbFx[i], &status); if (status & (DSBSTATUS_PLAYING + DSBSTATUS_LOOPING)) { IDirectSoundBuffer_Stop(dsbFx[i]); } IDirectSoundBuffer_Release(dsbFx[i]); fxId[i] = 0; fxiPaused[i] = 0; } i++; } */ return(RD_OK); } int32 Sword2Sound::CloseFx(int32 id) { warning("stub CloseFx( %d )", id); /* int32 i; int32 status; if (!soundOn) return(RD_OK); i = GetFxIndex(id); if (i v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } // Start the sound effect playing IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING); musStreaming[i] = 1; musCounter[i] = 250; strcpy(musFilename[i], filename); // and exit the function. } else { // Pdebug("Failed to lock sound buffer upon creation - (%d)", hr & 0x0000ffff); // DirectSoundDebug("Error - ", hr); fclose(fpMus[i]); return(RDERR_LOCKFAILED); } } else { // Pdebug("Failed to create sound buffer - (%d)", hr & 0x0000ffff); // Pdebug("Error - ", hr); fclose(fpMus[i]); return(RDERR_CREATESOUNDBUFFER); } } else if (musStreaming[0] + musStreaming[1] == 1) { i = musStreaming[0]; musLooping[i] = looping; if (!musFading[1-i]) StartMusicFadeDown(1 - i); fpMus[i] = fopen(filename, "rb"); if (fpMus[i] == NULL) return(RDERR_INVALIDFILENAME); fread(&head, sizeof(_wavHeader), 1, fpMus[i]); streamCursor[i] = 0; memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT)); wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM; wfMus[i].wf.nChannels = head.channels; wfMus[i].wf.nSamplesPerSec = head.samplesPerSec; wfMus[i].wBitsPerSample = 8 * head.blockAlign / (head.samplesPerSec * head.channels); wfMus[i].wf.nBlockAlign = wfMus[i].wf.nChannels * wfMus[i].wBitsPerSample / 8; wfMus[i].wf.nAvgBytesPerSec = wfMus[i].wf.nSamplesPerSec * wfMus[i].wf.nBlockAlign; // Reset the sample format and size memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC)); dsbdMus[i].dwSize = sizeof(DSBUFFERDESC); // dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT; dsbdMus[i].dwBufferBytes = 6 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i]; // Create the sound effect sample buffer hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL); if (hr == DS_OK) { hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(lpDsbMus[i]); hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { // Fill the speech buffer with data bytes = fread(lpv1, 1, dwBytes1, fpMus[i]); // Pdebug("Read %d bytes\n", bytes); // memcpy((uint8 *) lpv1, (uint8 *) wavData + sizeof(_wavHeader), dwBytes1); // Unlock the buffer now that we've filled it IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); // Modify the volume according to the master volume and music mute state if (musicMuted) v0 = v1 = 0; else { v0 = volMusic[0]; v1 = volMusic[1]; } if (v0 > v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } // Start the sound effect playing IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING); musStreaming[i] = 1; musCounter[i] = 250; strcpy(musFilename[i], filename); } else { // Pdebug("Failed to lock sound buffer upon creation - (%d)", hr & 0x0000ffff); // DirectSoundDebug("Error - ", hr); fclose(fpMus[i]); return(RDERR_LOCKFAILED); } } else { // Pdebug("Failed to create sound buffer - (%d)", hr & 0x0000ffff); // Pdebug("Error - ", hr); fclose(fpMus[i]); return(RDERR_CREATESOUNDBUFFER); } } */ return(RD_OK); } void Sword2Sound::UpdateSampleStreaming(void) { warning("stub UpdateSampleStreaming"); /* int32 i; int32 v0, v1; int32 readLen; int32 len; int32 readCursor, writeCursor; int32 dwBytes1, dwBytes2; LPVOID lpv1, lpv2; HRESULT hr; for (i=0; i v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } } } } else { if (IDirectSoundBuffer_GetCurrentPosition(lpDsbMus[i], &readCursor, &writeCursor) != DS_OK) { // Pdebug ("Stopping sample %d cos cant get position", i); IDirectSoundBuffer_Stop(lpDsbMus[i]); } len = readCursor - streamCursor[i]; if (len < 0) { len += dsbdMus[i].dwBufferBytes; } if (len > 0) { hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(lpDsbMus[i]); hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { streamCursor[i] += len; if (streamCursor[i] >= (int32) dsbdMus[i].dwBufferBytes) streamCursor[i] -= dsbdMus[i].dwBufferBytes; if (len > dwBytes1) { readLen = fread(lpv1, 1, dwBytes1, fpMus[i]); if (readLen == dwBytes1) { readLen = fread(lpv2, 1, dwBytes2, fpMus[i]); if (readLen != dwBytes2) { IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); StartMusicFadeDown(i); if (musLooping[i]) { StreamMusic(musFilename[i], musLooping[i]); } } else { IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); } } else { IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); StartMusicFadeDown(i); if (musLooping[i]) { StreamMusic(musFilename[i], musLooping[i]); } } } else { readLen = fread(lpv1, 1, len, fpMus[i]); if (readLen != len) { IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); StartMusicFadeDown(i); if (musLooping[i]) { StreamMusic(musFilename[i], musLooping[i]); } } else { IDirectSoundBuffer_Unlock(lpDsbMus[i], lpv1, dwBytes1, lpv2, dwBytes2); } } } // else // { // DirectSoundDebug("Failed to lock sound buffer to write bytes", hr); // Pdebug("Stream cursor %d", streamCursor[i]); // Pdebug("len %d", len); // } } //} } } } */ } int32 Sword2Sound::StreamCompMusic(const char *filename, uint32 musicId, int32 looping) { warning("stub StreamCompMusic( %s, %d, %d )", filename, musicId, looping); /* HRESULT hr; LPVOID lpv1, lpv2; DWORD dwBytes1, dwBytes2; uint32 i,j; int32 v0, v1; uint16 *data16; uint8 *data8; // Do not allow compressed and uncompressed music to be streamed at the same time. if (compressedMusic == 2) return (RDERR_FXFUCKED); compressedMusic = 1; if (musStreaming[0] + musStreaming[1] == 0) // No music streaming at present. { i = 0; musLooping[i] = looping; // Save looping info strcpy(musFilename[i], filename); // And tune id's musId[i] = musicId; if (IsMusicMute()) // Don't start streaming if the volume is off. return (RD_OK); if (!fpMus[0]) fpMus[0] = fopen(filename, "rb"); // Always use fpMus[0] (all music in one cluster) musFilePos[i] for different pieces of music. if (fpMus[0] == NULL) return(RDERR_INVALIDFILENAME); if (fseek(fpMus[0], (musicId+1)*8, SEEK_SET)) // Seek to music index { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (fread(&musFilePos[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music index { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (fread(&musEnd[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music length { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (!musEnd[i] || !musFilePos[i]) // Check that music is valid (has length & offset) { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_INVALIDID); } musEnd[i] += musFilePos[i]; // Calculate the file position of the end of the music streamCursor[i] = 0; // Reset streaming cursor and store looping flag memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT)); // Set up wave format (no headers in cluster) wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM; wfMus[i].wf.nChannels = 1; wfMus[i].wf.nSamplesPerSec = 22050; wfMus[i].wBitsPerSample = 16; wfMus[i].wf.nBlockAlign = 2; wfMus[i].wf.nAvgBytesPerSec = 44100; // Reset the sample format and size memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC)); dsbdMus[i].dwSize = sizeof(DSBUFFERDESC); // dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT; dsbdMus[i].dwBufferBytes = 3 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i]; // Create a temporary buffer if ((data8 = malloc(dsbdMus[i].dwBufferBytes/2)) == NULL) // Allocate a compressed data buffer { fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_OUTOFMEMORY); } // Seek to start of the compressed music if (fseek(fpMus[0], musFilePos[i], SEEK_SET)) { fclose(fpMus[0]); fpMus[0] = 0; free(data8); return (RDERR_INVALIDID); } // Read the compressed data in to the buffer if (fread(data8, sizeof(uint8), dsbdMus[i].dwBufferBytes/2, fpMus[0]) != dsbdMus[i].dwBufferBytes/2) { fclose(fpMus[0]); fpMus[0] = 0; free(data8); return (RDERR_INVALIDID); } // Store the current position in the file for future streaming musFilePos[i] = ftell(fpMus[0]); // Create the music buffer hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL); if (hr == DS_OK) { hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(lpDsbMus[i]); hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { // decompress the music into the music buffer. data16 = (uint16*)lpv1; data16[0] = *((int16*)data8); // First sample value j=1; while (j<(dwBytes1/2)-1) { if (GetCompressedSign(data8[j+1])) data16[j] = data16[j-1] - (GetCompressedAmplitude(data8[j+1])< v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } // Start the sound effect playing IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING); // Recorder some last variables musStreaming[i] = 1; musCounter[i] = 250; // and exit the function. } else { // Opps Failed to lock the sound buffer fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_LOCKFAILED); } } else { // Opps Failed to create the sound buffer fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_CREATESOUNDBUFFER); } } else { if (musStreaming[0] + musStreaming[1] == 2) // Both streams in use, try to find a fading stream { if (musFading[0]) i = 0; else i = 1; musFading[i] = 0; IDirectSoundBuffer_Stop(lpDsbMus[i]); IDirectSoundBuffer_Release(lpDsbMus[i]); musStreaming[i] = 0; } if (musStreaming[0] + musStreaming[1] == 1) // Some music is already streaming { i = musStreaming[0]; // Set i to the free channel musLooping[i] = looping; // Save looping info strcpy(musFilename[i], filename); // And tune id's musId[i] = musicId; if (IsMusicMute()) // Don't start streaming if the volume is off. return (RD_OK); if (!fpMus[0]) fpMus[0] = fopen(filename, "rb"); // Always use fpMus[0] (all music in one cluster) musFilePos[i] for different pieces of music. if (fpMus[0] == NULL) return(RDERR_INVALIDFILENAME); if (!musFading[1-i]) // Start other music stream fading out musFading[1 - i] = -16; streamCursor[i] = 0; // Reset the streaming cursor for this sample if (fseek(fpMus[0], (musicId+1)*8, SEEK_SET)) // Seek to music index { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (fread(&musFilePos[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music index { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (fread(&musEnd[i], sizeof(uint32), 1, fpMus[0]) != 1) // Read music length { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_READERROR); } if (!musEnd[i] || !musFilePos[i]) // Check that music is valid (has length & offset) { fclose(fpMus[0]); fpMus[0] = 0; return (RDERR_INVALIDID); } musEnd[i] += musFilePos[i]; // Calculate the file position of the end of the music memset(&wfMus[i], 0, sizeof(PCMWAVEFORMAT)); // Set up the music format info wfMus[i].wf.wFormatTag = WAVE_FORMAT_PCM; wfMus[i].wf.nChannels = 1; wfMus[i].wf.nSamplesPerSec = 22050; wfMus[i].wBitsPerSample = 16; wfMus[i].wf.nBlockAlign = 2; wfMus[i].wf.nAvgBytesPerSec = 44100; // Reset the sample format and size memset(&dsbdMus[i], 0, sizeof(DSBUFFERDESC)); dsbdMus[i].dwSize = sizeof(DSBUFFERDESC); // dsbdMus[i].dwFlags = DSBCAPS_CTRLDEFAULT; dsbdMus[i].dwBufferBytes = 3 * wfMus[i].wf.nAvgBytesPerSec; // 3 seconds dsbdMus[i].lpwfxFormat = (LPWAVEFORMATEX) &wfMus[i]; // Allocate a compressed data buffer if ((data8 = malloc(dsbdMus[i].dwBufferBytes/2)) == NULL) { fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_OUTOFMEMORY); } // Seek to start of the compressed music if (fseek(fpMus[0], musFilePos[i], SEEK_SET)) { fclose(fpMus[0]); fpMus[0] = 0; free(data8); return (RDERR_INVALIDID); } // Read the compressed data in to the buffer if (fread(data8, sizeof(uint8), dsbdMus[i].dwBufferBytes/2, fpMus[0]) != dsbdMus[i].dwBufferBytes/2) { fclose(fpMus[0]); fpMus[0] = 0; free(data8); return (RDERR_INVALIDID); } // Store the current position in the file for future streaming musFilePos[i] = ftell(fpMus[0]); // Create the sound effect sample buffer hr = IDirectSound_CreateSoundBuffer(lpDS, &dsbdMus[i], &lpDsbMus[i], NULL); if (hr == DS_OK) { hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(lpDsbMus[i]); hr = IDirectSoundBuffer_Lock(lpDsbMus[i], 0, dsbdMus[i].dwBufferBytes, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { // decompress the music into the music buffer. data16 = (uint16*)lpv1; data16[0] = *((int16*)data8); // First sample value j=1; while (j<(dwBytes1/2)-1) { if (GetCompressedSign(data8[j+1])) data16[j] = data16[j-1] - (GetCompressedAmplitude(data8[j+1])< v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } // Start the sound effect playing IDirectSoundBuffer_Play(lpDsbMus[i], 0, 0, DSBPLAY_LOOPING); // Record the last variables for streaming and looping musStreaming[i] = 1; musCounter[i] = 250; } else { // Opps failed to lock the sound buffer fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_LOCKFAILED); } } else { // Opps failed to create the sound buffer fclose(fpMus[0]); fpMus[0] = 0; return(RDERR_CREATESOUNDBUFFER); } } } */ return(RD_OK); } void Sword2Sound::UpdateCompSampleStreaming(void) { warning("stub UpdateCompSampleStreaming"); /* uint32 i,j,k; int32 v0, v1; int32 len; int32 readCursor, writeCursor; int32 dwBytes1, dwBytes2; LPVOID lpv1, lpv2; HRESULT hr; uint16 *data16; uint8 *data8; int fade; for (i=0; i v1) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v0]); IDirectSoundBuffer_SetPan(lpDsbMus[i], musicVolTable[v1*16/v0]); } else { if (v1 > v0) { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], -musicVolTable[v0*16/v1]); } else { IDirectSoundBuffer_SetVolume(lpDsbMus[i], musicVolTable[v1]); IDirectSoundBuffer_SetPan(lpDsbMus[i], 0); } } } } } else { if (IDirectSoundBuffer_GetCurrentPosition(lpDsbMus[i], &readCursor, &writeCursor) != DS_OK) { // Failed to get read and write positions IDirectSoundBuffer_Stop(lpDsbMus[i]); } // Caluculate the amount of data to load into the sound buffer len = readCursor - streamCursor[i]; if (len < 0) { len += dsbdMus[i].dwBufferBytes; // Wrap around ! } // Reduce length if it requires reading past the end of the music if (musFilePos[i]+len >= musEnd[i]) { len = musEnd[i] - musFilePos[i]; fade = 1; // End of music reaced so we'll need to fade and repeat } else fade = 0; if (len > 0) { hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); if (hr == DSERR_BUFFERLOST) { IDirectSoundBuffer_Restore(lpDsbMus[i]); hr = IDirectSoundBuffer_Lock(lpDsbMus[i], streamCursor[i], len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0); } if (hr == DS_OK) { streamCursor[i] += len; if (streamCursor[i] >= (int32) dsbdMus[i].dwBufferBytes) streamCursor[i] -= dsbdMus[i].dwBufferBytes; // Allocate a compressed data buffer if ((data8 = malloc(len/2)) == NULL) { fclose(fpMus[0]); fpMus[0] = 0; musFading[i] = -16; } // Seek to update position of compressed music when neccassary (probably never occurs) if (ftell(fpMus[0]) != musFilePos[i]) fseek(fpMus[0], musFilePos[i], SEEK_SET); // Read the compressed data in to the buffer if (fread(data8, sizeof(uint8), len/2, fpMus[0]) != (size_t)len/2) { fclose(fpMus[0]); fpMus[0] = 0; free(data8); musFading[i] = -16; return; } // Update the current position in the file for future streaming musFilePos[i] = ftell(fpMus[0]); // decompress the music into the music buffer. data16 = (uint16*)lpv1; // Decompress the first byte using the last decompressed sample if (GetCompressedSign(data8[0])) data16[0] = musLastSample[i] - (GetCompressedAmplitude(data8[0])<2)) { minMusicVol = musicVolTable[volMusic[0] - 3]; if (speechStatus) { IDirectSoundBuffer_GetStatus(dsbSpeech, &status); if ((hr = IDirectSoundBuffer_GetCurrentPosition(dsbMusic, &readCursor, &writeCursor)) != DS_OK) return hr; len = 44100 / 12 ;// 12th of a second if ((hr = IDirectSoundBuffer_Lock(dsbMusic, readCursor, len, &lpv1, &dwBytes1, &lpv2, &dwBytes2, 0)) != DS_OK) return hr; for (i = 0, sample = (int16*)lpv1; sample<(int16*)((int8*)lpv1+dwBytes1); sample+= 30, i++) // 60 samples { if (*sample>0) total += *sample; else total -= *sample; } total /= i; total = minMusicVol + ( ( (currentMusicVol - minMusicVol) * total ) / 8000); if (total > currentMusicVol) total = currentMusicVol; IDirectSoundBuffer_SetVolume(dsbMusic, total); IDirectSoundBuffer_Unlock(dsbMusic,lpv1,dwBytes1,lpv2,dwBytes2); } else { IDirectSoundBuffer_GetVolume(dsbMusic, &total); total += 50; if (total > currentMusicVol) total = currentMusicVol; IDirectSoundBuffer_SetVolume(dsbMusic, total); } } return (hr); */ return RD_OK; } int32 Sword2Sound::MusicTimeRemaining() { warning("stub MusicTimeRemaaining"); /* int32 writeCursor; int32 i; int32 readCursor; for (i=0; ihwnd = hwnd; // s->lpDS = lpDS; // s->dsbPrimary = dsbPrimary; // s->dsbSpeech = dsbSpeech; s->soundOn = soundOn; s->speechStatus = speechStatus; s->fxPaused = fxPaused; s->speechPaused = speechPaused; s->speechVol = speechVol; s->fxVol = fxVol; s->speechMuted = speechMuted; s->fxMuted = fxMuted; s->compressedMusic = compressedMusic; s->musicMuted = musicMuted; memcpy(s->fxId, fxId, sizeof(int32) * MAXFX); memcpy(s->fxCached, fxCached, sizeof(uint8) * MAXFX); // memcpy(s->dsbFx, dsbFx, sizeof(LPDIRECTSOUNDBUFFER) * MAXFX); memcpy(s->fxiPaused, fxiPaused, sizeof(uint8) * MAXFX); memcpy(s->fxLooped, fxLooped, sizeof(uint8) * MAXFX); memcpy(s->musStreaming, musStreaming, sizeof(int16) * MAXMUS); memcpy(s->musicPaused, musicPaused, sizeof(int16) * MAXMUS); memcpy(s->musCounter, musCounter, sizeof(int16) * MAXMUS); memcpy(s->musFading, musFading, sizeof(int16) * MAXMUS); memcpy(s->musLooping, musLooping, sizeof(int16) * MAXMUS); memcpy(s->musLastSample,musLastSample, sizeof(int16) * MAXMUS); memcpy(s->streamCursor, streamCursor, sizeof(int32) * MAXMUS); memcpy(s->musFilePos, musFilePos, sizeof(int32) * MAXMUS); memcpy(s->musEnd, musEnd, sizeof(int32) * MAXMUS); memcpy(s->musId, musId, sizeof(uint32) * MAXMUS); memcpy(s->volMusic, volMusic, sizeof(uint32) * 2); // memcpy(s->dsbdMus, dsbdMus, sizeof(DSBUFFERDESC) * MAXMUS); // memcpy(s->lpDsbMus, lpDsbMus, sizeof(LPDIRECTSOUNDBUFFER) * MAXMUS); memcpy(s->fpMus, fpMus, sizeof(FILE*) * MAXMUS); // memcpy(s->wfMus, wfMus, sizeof(PCMWAVEFORMAT) * MAXMUS); for (i = 0; imusFilename[i], musFilename[i], sizeof(char) * 256); } void Sword2Sound::SetSoundStatus(_drvSoundStatus *s) { int i; // hwnd = s->hwnd; // lpDS = s->lpDS; // dsbPrimary = s->dsbPrimary; // dsbSpeech = s->dsbSpeech; soundOn = s->soundOn; speechStatus = s->speechStatus; fxPaused = s->fxPaused; speechPaused = s->speechPaused; speechVol = s->speechVol; fxVol = s->fxVol; speechMuted = s->speechMuted; fxMuted = s->fxMuted; compressedMusic = s->compressedMusic; musicMuted = s->musicMuted; memcpy(fxId, s->fxId, sizeof(int32) * MAXFX); memcpy(fxCached, s->fxCached, sizeof(uint8) * MAXFX); // memcpy(dsbFx, s->dsbFx, sizeof(LPDIRECTSOUNDBUFFER) * MAXFX); memcpy(fxiPaused, s->fxiPaused, sizeof(uint8) * MAXFX); memcpy(fxLooped, s->fxLooped, sizeof(uint8) * MAXFX); memcpy(musStreaming, s->musStreaming, sizeof(int16) * MAXMUS); memcpy(musicPaused, s->musicPaused, sizeof(int16) * MAXMUS); memcpy(musCounter, s->musCounter, sizeof(int16) * MAXMUS); memcpy(musFading, s->musFading, sizeof(int16) * MAXMUS); memcpy(musLooping, s->musLooping, sizeof(int16) * MAXMUS); memcpy(musLastSample,s->musLastSample, sizeof(int16) * MAXMUS); memcpy(streamCursor, s->streamCursor, sizeof(int32) * MAXMUS); memcpy(musFilePos, s->musFilePos, sizeof(int32) * MAXMUS); memcpy(musEnd, s->musEnd, sizeof(int32) * MAXMUS); memcpy(musId, s->musId, sizeof(uint32) * MAXMUS); memcpy(volMusic, s->volMusic, sizeof(uint32) * 2); // memcpy(dsbdMus, s->dsbdMus, sizeof(DSBUFFERDESC) * MAXMUS); // memcpy(lpDsbMus, s->lpDsbMus, sizeof(LPDIRECTSOUNDBUFFER) * MAXMUS); // memcpy(fpMus, s->fpMus, sizeof(FILE*) * MAXMUS); // memcpy(wfMus, s->wfMus, sizeof(PCMWAVEFORMAT) * MAXMUS); for (i = 0; imusFilename[i], sizeof(char) * 256); }