/*
* Seven Kingdoms: Ancient Adversaries
*
* Copyright 1997,1998 Enlight 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, see .
*
*/
//Filename : OAUDIO.CPP
//Description : Object Midi Audio and Digitized Sound
//Ownership : Gilbert
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//---------------- Define constant ------------------//
//
// DirectSoundBuffer size = LWAV_STREAM_BUFSIZ * LWAV_BANKS
// if it is going to play a high transfer rate wave
// (e.g. 16-bit 44.1kHz Stereo), increase LWAV_STREAM_BUFSIZ
//
//---------------------------------------------------//
#define LWAV_STREAM_BUFSIZ 0x1000
#define LWAV_BANKS 4
#define LOOPWAV_STREAM_BUFSIZ 0x1000
#define LOOPWAV_BANKS 4
#ifndef DSBCAPS_CTRLDEFAULT
#define DSBCAPS_CTRLDEFAULT (DSBCAPS_CTRLFREQUENCY|DSBCAPS_CTRLPAN|DSBCAPS_CTRLVOLUME)
#endif
//---------- Define static variables ---------//
static MCI_PLAY_PARMS mci_play;
static MCI_OPEN_PARMS mci_open;
static MCI_SET_PARMS mci_set;
//--------- Begin of function wavefile_offset -------//
//
// find the "data" tag in a wave file
//
static char * wavefile_data(char *wavfile_buf)
{
//----- position at WAVEfmt tag size ------//
char *p = wavfile_buf+0x10;
DWORD tagSize=*(DWORD *)p;
//-------- go to next tag field -----------//
for( p += sizeof(DWORD)+tagSize; strncmp(p, "data", 4) != 0;
p += sizeof(DWORD)+tagSize)
{
p += 4; // pointing at size of tag field
tagSize = *(DWORD *)p; // get the size of this tage field
if(p - wavfile_buf > 128)
return NULL;
}
//----- p pointing at the start of "data" tag ------//
return p;
}
//--------- End of function wavefile_offset------------//
//--------- Begin of function Audio::Audio ----------//
Audio::Audio()
{
init_flag = 0;
}
//--------- Begin of function Audio::Audio ----------//
//--------- Begin of function Audio::~Audio ----------//
Audio::~Audio()
{
deinit();
}
//--------- Begin of function Audio::~Audio ----------//
//--------- Begin of function Audio::init ----------//
//
// Initialize the mid driver
//
// return : 1 - initialized successfully
// 0 - init fail
//
int Audio::init()
{
//-------- init vars -----------//
run_yield = 0;
mid_init_flag = 0; // the init flag is on when the driver is initialized successfully
wav_init_flag = 0;
cd_init_flag = 0;
mid_flag = 1;
wav_flag = 1;
cd_flag = 1;
mid_buf = NULL;
wav_buf = NULL;
mid_buf_size = 0;
wav_buf_size = 0;
int i;
for(i = 0; i < MAX_WAV_CHANNEL; ++i)
{
lp_wav_ch_dsb[i] = NULL;
wav_serial_no[i] = 0;
}
max_lwav_serial_no = 0;
for(i=0; i < MAX_LONG_WAV_CH; ++i)
{
lp_lwav_ch_dsb[i] = NULL;
lwav_serial_no[i] = 0;
lwav_fileptr[i] = NULL;
}
max_lwav_serial_no = 0;
for(i=0; i < MAX_LOOP_WAV_CH; ++i)
{
lp_loop_ch_dsb[i] = NULL;
loopwav_fileptr[i] = NULL;
}
// wav_volume = 0;
wav_volume = 100; // 0(slient) - 100(loudest)
//--------- init devices ----------//
if( init_wav() )
{
wav_res.init( DIR_RES"A_WAVE2.RES", 0, 0 ); // 2nd 0-don't read all, 3rd 0-don't use vga buffer
wav_buf = mem_add(DEFAULT_WAV_BUF_SIZE);
wav_buf_size = DEFAULT_WAV_BUF_SIZE;
}
/*
if( init_mid() )
{
mid_res.init( DIR_RES"A_MIDI.RES", 0, 0 ); // 2nd 0-don't read all, 3rd 0-don't use vga buffer
mid_buf = mem_add(DEFAULT_MID_BUF_SIZE);
mid_buf_size = DEFAULT_MID_BUF_SIZE;
}
*/
init_cd();
//----------------------------------//
init_flag = wav_init_flag || cd_init_flag;
return 1;
}
//--------- End of function Audio::init ----------//
//--------- Begin of function Audio::deinit ----------//
void Audio::deinit()
{
if( init_flag )
{
//------- deinit vars --------//
run_yield = 0;
init_flag = 0;
//------- deinit devices -------//
deinit_wav();
deinit_mid();
deinit_cd();
}
}
//--------- End of function Audio::deinit ----------//
//--------- Begin of function Audio::init_wav ----------//
//
// Initialize digitized wav driver
//
// return : 1 - initialized successfully
// 0 - init fail
//
int Audio::init_wav()
{
if( wav_init_flag )
return 1;
//-------- create DirectSound object -------//
HRESULT rc=DirectSoundCreate(NULL, &lp_direct_sound, NULL);
//------------------------------------------//
if( rc==DS_OK ) // Create succeeded
{
lp_direct_sound->SetCooperativeLevel(sys.main_hwnd, DSSCL_NORMAL);
wav_init_flag=1;
}
return wav_init_flag;
}
//--------- End of function Audio::init_wav ----------//
//--------- Begin of function Audio::init_mid ----------//
//
// Initialize MIDI mid driver
//
// return : 1 - initialized successfully
// 0 - init fail
//
int Audio::init_mid()
{
if( mid_init_flag )
return 1;
//.. insert code here ...//
mid_init_flag=1;
return 1;
}
//--------- End of function Audio::init_mid ----------//
//--------- Begin of function Audio::init_cd ----------//
//
// Initialize the audio CD player
//
// return : 1 - initialized successfully
// 0 - init fail
//
int Audio::init_cd()
{
mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
if( mciSendCommand( NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,
(DWORD) (LPVOID) &mci_open) == 0 ||
mciSendCommand( NULL, MCI_OPEN, MCI_OPEN_TYPE |
MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
(DWORD) (LPVOID) &mci_open)== 0 )
{
mci_set.dwTimeFormat = MCI_FORMAT_TMSF;
mciSendCommand( mci_open.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
(DWORD) (LPVOID) &mci_set);
cd_init_flag = 1;
return 1;
}
cd_init_flag = 0;
return 0;
}
//--------- End of function Audio::init_cd ----------//
//--------- Begin of function Audio::deinit_cd ----------//
void Audio::deinit_cd()
{
if( cd_init_flag )
{
stop_cd();
mciSendString ("close cdaudio", NULL, 0, NULL);
cd_init_flag = 0;
}
}
//--------- End of function Audio::deinit_cd ----------//
//--------- Begin of function Audio::deinit_wav ----------//
void Audio::deinit_wav()
{
stop_wav();
if( wav_buf )
{
mem_del(wav_buf);
wav_buf = NULL;
}
if(wav_init_flag)
{
lp_direct_sound->Release();
wav_init_flag = 0;
}
}
//--------- End of function Audio::deinit_wav ----------//
//--------- Begin of function Audio::deinit_mid ----------//
void Audio::deinit_mid()
{
if( !mid_init_flag )
return;
stop_mid();
//.. insert code here ...//
mem_del(mid_buf);
mid_buf = NULL;
mid_init_flag = 0;
}
//--------- End of function Audio::deinit_mid ----------//
//------- Begin of function Audio::play_mid -------//
//
// Play a midi mid from the mid resource file
//
// midName = name of the mid in the resource file
//
// return : 1 - mid loaded and is playing
// 0 - mid not played
//
int Audio::play_mid(char* midName)
{
if( !mid_init_flag || !mid_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
stop_mid(); // stop currently playing mid if any
//------ Load mid file -------//
int dataSize;
File* filePtr = mid_res.get_file(midName, dataSize);
if( !filePtr )
return 0;
if( dataSize > mid_buf_size )
{
mid_buf_size = dataSize;
mid_buf = mem_resize( mid_buf, mid_buf_size );
}
if( !filePtr->file_read( mid_buf, dataSize ) )
return 0;
//-------- Play mid file --------//
//.. insert code here ...//
return 1;
}
//------- End of function Audio::play_mid -------//
//------- Begin of function Audio::stop_mid -------//
//
void Audio::stop_mid()
{
if( !mid_init_flag || !mid_flag )
return;
//.. insert code here ...//
mciSendCommand(mci_open.wDeviceID, MCI_STOP, NULL, NULL);
}
//------- End of function Audio::stop_mid -------//
//------- Begin of function Audio::play_wav -------//
//
// Play digitized wav from the wav resource file
//
// wavName = name of the wav in the resource file
// long vol = volume (0 to 100)
// long pan = pan (-10000 to 10000)
//
// return : non-zero - wav loaded and is playing, return a serial no. to be referred in stop_wav and is_wav_playing
// 0 - wav not played
//
int Audio::play_wav(char* wavName, DsVolume dsVolume)
{
/*
//---- redirect to play_long_wav -------//
String str;
str = DIR_SOUND;
str += wavName;
str += ".WAV";
if( m.is_file_exist(str) )
return play_long_wav(str);
else
return 0;
//------------------------------------//
*/
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//-------- Load wav file header-------//
int dataSize;
DWORD wavDataOffset, wavDataLength;
File* filePtr = wav_res.get_file(wavName, dataSize);
if( !filePtr )
return 0;
// load small part of the wave file (first 128 bytes) enough to hold
// the hold header
//#define LOAD_FULL_WAVE
#ifdef LOAD_FULL_WAVE
if( dataSize > wav_buf_size )
{
wav_buf_size = dataSize;
wav_buf = mem_resize( wav_buf, wav_buf_size );
}
if( !filePtr->file_read( wav_buf, dataSize))
#else
if( !filePtr->file_read( wav_buf, 128 ) )
#endif
return 0;
// short-cut to test play_resided_wave()
#ifdef LOAD_FULL_WAVE
return play_resided_wav(wav_buf);
#endif
// determine the wave data offset and length
char * dataTag = wavefile_data(wav_buf);
if (!dataTag)
{
err_now("Invalid wave file format");
return 0; // invalid RIFF WAVE format
}
wavDataOffset = (dataTag - wav_buf) + 4 + sizeof(DWORD);
wavDataLength = *(DWORD *)(dataTag+4);
#ifndef LOAD_FULL_WAVE
// seek to the start of wave data
filePtr->file_seek(wavDataOffset-128,FILE_CURRENT);
#endif
//------- Create DirectSoundBuffer to store a wave ------//
LPDIRECTSOUNDBUFFER lpDsb;
DSBUFFERDESC dsbDesc;
HRESULT hr;
DWORD dsbStatus;
// set up DSBUFFERDESC structure
memset(&dsbDesc, 0, sizeof(DSBUFFERDESC)); // zero it out
dsbDesc.dwSize = sizeof(DSBUFFERDESC);
dsbDesc.dwFlags = DSBCAPS_CTRLDEFAULT; // Need defaul controls (pan, volume, frequency)
dsbDesc.dwBufferBytes = wavDataLength;
dsbDesc.lpwfxFormat = (LPWAVEFORMATEX) (wav_buf+0x14);
// ------- assign buffer to a channel number ----------//
lpDsb = NULL;
int chanNum;
for( chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
if(lp_wav_ch_dsb[chanNum] == NULL || (lp_wav_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)))
{
if(lp_wav_ch_dsb[chanNum])
{
lp_wav_ch_dsb[chanNum]->Release();
lp_wav_ch_dsb[chanNum] = NULL;
}
// found an idle channel, create DirectSoundBuffer
hr = lp_direct_sound->CreateSoundBuffer(&dsbDesc, &lpDsb, NULL);
if (DS_OK != hr)
{
// failed!
err_now("Cannot create DirectSoundBuffer");
return 0;
}
lp_wav_ch_dsb[chanNum] = lpDsb;
break;
}
if( chanNum >= MAX_WAV_CHANNEL)
{
return 0;
}
// Note : if not found, just play the sound, don't play the sound
// increase MAX_WAV_CHANNEL
//------- copy sound data to DirectSoundBuffer--------//
// unlock vga_front
VgaFrontLock vgaLock;
// lock the buffer first
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
hr = lpDsb->Lock(0, wavDataLength, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
return 0;
}
// write to pointers
#ifdef LOAD_FULL_WAVE
memcpy(lpvPtr1, wav_buf+wavDataOffset, dwBytes1);
#else
filePtr->file_read(lpvPtr1, dwBytes1);
#endif
if(lpvPtr2)
{
#ifdef LOAD_FULL_WAVE
memcpy(lpvPtr2, wav_buf+wavDataOffset+dwBytes1, dwBytes2);
#else
filePtr->file_read(lpvPtr2, dwBytes2);
#endif
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
return 0;
}
//------- Set volume and pan -----------//
lpDsb->SetVolume(dsVolume.ds_vol);
lpDsb->SetPan(dsVolume.ds_pan);
//------- Play wav file --------//
if(lpDsb->Play(0, 0, 0) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
return 0;
}
return wav_serial_no[chanNum] = assign_serial(max_wav_serial_no);
}
//------- End of function Audio::play_wav -------//
//------- Begin of function Audio::play_wav -------//
//
// Play digitized wav from the wav resource file
//
// short resIdx = index of wave file in A_WAVE2.RES
// long vol = volume (0 to 100)
// long pan = pan (-10000 to 10000)
//
// return : 1 - wav loaded and is playing
// 0 - wav not played
//
int Audio::play_wav(short resIdx, DsVolume dsVolume)
{
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//-------- Load wav file header-------//
int dataSize;
DWORD wavDataOffset, wavDataLength;
File* filePtr = wav_res.get_file(resIdx, dataSize);
if( !filePtr )
return 0;
// load small part of the wave file (first 128 bytes) enough to hold
// the hold header
#ifdef LOAD_FULL_WAVE
if( dataSize > wav_buf_size )
{
wav_buf_size = dataSize;
wav_buf = mem_resize( wav_buf, wav_buf_size );
}
if( !filePtr->file_read( wav_buf, dataSize))
#else
if( !filePtr->file_read( wav_buf, 128 ) )
#endif
return 0;
// short-cut to test play_resided_wave()
#ifdef LOAD_FULL_WAVE
return play_resided_wav(wav_buf);
#endif
// determine the wave data offset and length
char * dataTag = wavefile_data(wav_buf);
if (!dataTag)
{
err_now("Invalid wave file format");
return 0; // invalid RIFF WAVE format
}
wavDataOffset = (dataTag - wav_buf) + 4 + sizeof(DWORD);
wavDataLength = *(DWORD *)(dataTag+4);
#ifndef LOAD_FULL_WAVE
// seek to the start of wave data
filePtr->file_seek(wavDataOffset-128,FILE_CURRENT);
#endif
//------- Create DirectSoundBuffer to store a wave ------//
LPDIRECTSOUNDBUFFER lpDsb;
DSBUFFERDESC dsbDesc;
HRESULT hr;
DWORD dsbStatus;
// set up DSBUFFERDESC structure
memset(&dsbDesc, 0, sizeof(DSBUFFERDESC)); // zero it out
dsbDesc.dwSize = sizeof(DSBUFFERDESC);
dsbDesc.dwFlags = DSBCAPS_CTRLDEFAULT; // Need defaul controls (pan, volume, frequency)
dsbDesc.dwBufferBytes = wavDataLength;
dsbDesc.lpwfxFormat = (LPWAVEFORMATEX) (wav_buf+0x14);
// ------- assign buffer to a channel number ----------//
lpDsb = NULL;
int chanNum;
for( chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
if(lp_wav_ch_dsb[chanNum] == NULL || (lp_wav_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)))
{
if(lp_wav_ch_dsb[chanNum])
{
lp_wav_ch_dsb[chanNum]->Release();
lp_wav_ch_dsb[chanNum] = NULL;
}
// found an idle channel, create DirectSoundBuffer
hr = lp_direct_sound->CreateSoundBuffer(&dsbDesc, &lpDsb, NULL);
if (DS_OK != hr)
{
// failed!
err_now("Cannot create DirectSoundBuffer");
return 0;
}
lp_wav_ch_dsb[chanNum] = lpDsb;
break;
}
if( chanNum >= MAX_WAV_CHANNEL)
{
return 0;
}
// Note : if not found, just play the sound, don't play the sound
// increase MAX_WAV_CHANNEL
//------- copy sound data to DirectSoundBuffer--------//
// unlock vga_front
VgaFrontLock vgaLock;
// lock the buffer first
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
hr = lpDsb->Lock(0, wavDataLength, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
return 0;
}
// write to pointers
#ifdef LOAD_FULL_WAVE
memcpy(lpvPtr1, wav_buf+wavDataOffset, dwBytes1);
#else
filePtr->file_read(lpvPtr1, dwBytes1);
#endif
if(lpvPtr2)
{
#ifdef LOAD_FULL_WAVE
memcpy(lpvPtr2, wav_buf+wavDataOffset+dwBytes1, dwBytes2);
#else
filePtr->file_read(lpvPtr2, dwBytes2);
#endif
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
return 0;
}
//------- Set volume and pan -----------//
lpDsb->SetVolume(dsVolume.ds_vol);
lpDsb->SetPan(dsVolume.ds_pan);
//------- Play wav file --------//
if(lpDsb->Play(0, 0, 0) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
return 0;
}
return wav_serial_no[chanNum] = assign_serial(max_wav_serial_no);
}
//------- End of function Audio::play_wav -------//
//------- Begin of function Audio::play_resided_wav -------//
//
// Play digitized wav from the wav file in memory
//
// wavBuf = point to the wav in memory
// long vol = volume (0 to 100)
// long pan = pan (-10000 to 10000)
//
// return : 1 - wav loaded and is playing
// 0 - wav not played
//
int Audio::play_resided_wav(char* wavBuf, DsVolume dsVolume)
{
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//-------- Load wav file header-------//
DWORD wavDataOffset, wavDataLength;
// determine the wave data offset and length
char * dataTag = wavefile_data(wavBuf);
if (!dataTag)
{
err_now("Invalid wave file format");
return 0; // invalid RIFF WAVE format
}
wavDataOffset = (dataTag - wavBuf) + 4 + sizeof(DWORD);
wavDataLength = *(DWORD *)(dataTag+4);
//------- Create DirectSoundBuffer to store a wave ------//
LPDIRECTSOUNDBUFFER lpDsb;
DSBUFFERDESC dsbDesc;
HRESULT hr;
DWORD dsbStatus;
// set up DSBUFFERDESC structure
memset(&dsbDesc, 0, sizeof(DSBUFFERDESC)); // zero it out
dsbDesc.dwSize = sizeof(DSBUFFERDESC);
dsbDesc.dwFlags = DSBCAPS_CTRLDEFAULT; // Need defaul controls (pan, volume, frequency)
dsbDesc.dwBufferBytes = wavDataLength;
dsbDesc.lpwfxFormat = (LPWAVEFORMATEX) (wavBuf+0x14);
// ------- assign buffer to a channel number ----------//
lpDsb = NULL;
int chanNum;
for( chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
if(lp_wav_ch_dsb[chanNum] == NULL || (lp_wav_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)))
{
if(lp_wav_ch_dsb[chanNum])
{
lp_wav_ch_dsb[chanNum]->Release();
lp_wav_ch_dsb[chanNum] = NULL;
}
// found an idle channel, create DirectSoundBuffer
hr = lp_direct_sound->CreateSoundBuffer(&dsbDesc, &lpDsb, NULL);
if (DS_OK != hr)
{
// failed!
err_now("Cannot create DirectSoundBuffer");
return 0;
}
lp_wav_ch_dsb[chanNum] = lpDsb;
break;
}
if( chanNum >= MAX_WAV_CHANNEL)
{
return 0;
}
// Note : if not found, just play the sound, don't play the sound
// increase MAX_WAV_CHANNEL
//------- copy sound data to DirectSoundBuffer--------//
// unlock vga_front
VgaFrontLock vgaLock;
// lock the buffer first
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
hr = lpDsb->Lock(0, wavDataLength, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
return 0;
}
// write to pointers
memcpy(lpvPtr1, wavBuf+wavDataOffset, dwBytes1);
if(lpvPtr2)
{
memcpy(lpvPtr2, wavBuf+wavDataOffset+dwBytes1, dwBytes2);
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
return 0;
}
//------- Set volume -----------//
lpDsb->SetVolume(dsVolume.ds_vol);
lpDsb->SetPan(dsVolume.ds_pan);
//------- Play wav file --------//
if(lpDsb->Play(0, 0, 0) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
return 0;
}
return wav_serial_no[chanNum] = assign_serial(max_wav_serial_no);
}
//------- End of function Audio::play_resided_wav -------//
// ###### begin Gilbert 6/12 ########//
//------- Begin of function Audio::get_free_wav_ch --------//
int Audio::get_free_wav_ch()
{
int count = 0;
DWORD dsbStatus;
for( int chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
{
if( lp_wav_ch_dsb[chanNum] != NULL && (lp_wav_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)) )
{
lp_wav_ch_dsb[chanNum]->Release();
lp_wav_ch_dsb[chanNum] = NULL;
}
if( !lp_wav_ch_dsb[chanNum] )
count++;
}
return count;
}
//------- End of function Audio::get_free_wav_ch --------//
// ###### end Gilbert 6/12 ########//
//------- Begin of function Audio::stop_wav ------------//
//
// stop a short sound effect started by play_wav or play_resided_wav
//
// the serial no returned by play_wav or play_resided_wav
//
// return 1 - channel is found and stopped / channel not found
// return 0 - cannot stop the channel
//
int Audio::stop_wav(int serial)
{
for( int chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
{
if(lp_wav_ch_dsb[chanNum] != NULL && wav_serial_no[chanNum] == serial)
{
lp_wav_ch_dsb[chanNum]->Stop();
lp_wav_ch_dsb[chanNum]->Release();
lp_wav_ch_dsb[chanNum] = NULL;
wav_serial_no[chanNum] = 0;
return 1;
}
}
return 0;
}
//------- End of function Audio::stop_wav ------------//
//------- Begin of function Audio::is_wav_playing ------------//
//
// return wheather a short sound effect is stopped
//
// the serial no returned by play_wav or play_resided_wav
//
int Audio::is_wav_playing(int serial)
{
DWORD dsbStatus;
for( int chanNum = 0; chanNum < MAX_WAV_CHANNEL; ++chanNum)
{
if(lp_wav_ch_dsb[chanNum] != NULL && wav_serial_no[chanNum] == serial
&& lp_wav_ch_dsb[chanNum]->GetStatus(&dsbStatus) )
{
return dsbStatus & DSBSTATUS_PLAYING;
}
}
return 0;
}
//------- End of function Audio::is_wav_playing ------------//
//------- Begin of function Audio::play_long_wav --------//
//
// Play digitized wav from the wav file
// suitable for very large wave file
//
// wavName = name of the wave file
//
// return : 1 - wav loaded and is playing
// 0 - wav not played
// note : it uses streaming DirectSoundBuffer
// Audio::yield() keeps on feeding data to it
// Create a DirectSoundBuffer of size lwav_buf_size[c]*LWAV_BANKS
// divide into LWAV_BANKS parts. Each time Audio::yield() is called,
// load wave file into one part. lwav_bank[c] record which part to be
// filled next for channel c.
int Audio::play_long_wav(char *wavName, DsVolume dsVolume)
{
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//-------- Load wav file header-------//
DWORD wavDataOffset,wavDataLength;
if( LWAV_STREAM_BUFSIZ*LWAV_BANKS > wav_buf_size )
{
wav_buf_size = LWAV_STREAM_BUFSIZ*LWAV_BANKS;
wav_buf = mem_resize( wav_buf, wav_buf_size );
}
// File* filePtr = (File *)mem_add(sizeof(File)); // new File;
File* filePtr = new File; // new File;
if(!filePtr->file_open(wavName,0,0))
{
char errmsg[60];
sprintf(errmsg, "Cannot open %s", wavName);
box.msg(errmsg);
delete filePtr;
return 0;
}
if( !filePtr )
{
delete filePtr;
return 0;
}
// load small part of the wave file (first 128 bytes) enough to hold
// the hold header
if( !filePtr->file_read( wav_buf, 128 ) )
{
delete filePtr;
return 0;
}
// determine the wave data offset
char * dataTag = wavefile_data(wav_buf);
if (!dataTag)
{
err_now("Invalid wave file format");
delete filePtr;
return 0; // invalid RIFF WAVE format
}
wavDataOffset = (dataTag - wav_buf) + 4 + sizeof(DWORD);
wavDataLength = *(DWORD *)(dataTag+4);
// seek to the start of wave data
long temp1 = filePtr->file_seek(wavDataOffset,FILE_BEGIN);
WORD OptBufferSize=LWAV_STREAM_BUFSIZ,
MinRemainder =(WORD)(wavDataLength % (OptBufferSize * LWAV_BANKS));
//------- find out the best buffer size -------//
// store it in OptBufferSize
// criteria : below or equal to LWAV_STREAM_BUFSIZ and
// minimize wavDataLength % (OptBufferSize * LWAV_BANKS)
// i.e. minimize the truncation to the wave file
for(WORD TryBufSiz=LWAV_STREAM_BUFSIZ-0x200; TryBufSiz <= LWAV_STREAM_BUFSIZ;
TryBufSiz+=0x20)
{
WORD TryRemainder = (WORD)(wavDataLength % (TryBufSiz * LWAV_BANKS));
if(TryRemainder < MinRemainder)
{
MinRemainder = TryRemainder;
OptBufferSize = TryBufSiz;
}
}
//------- Create DirectSoundBuffer to store a wave ------//
LPDIRECTSOUNDBUFFER lpDsb;
DSBUFFERDESC dsbDesc;
HRESULT hr;
DWORD dsbStatus;
// set up DSBUFFERDESC structure
memset(&dsbDesc, 0, sizeof(DSBUFFERDESC)); // zero it out
dsbDesc.dwSize = sizeof(DSBUFFERDESC);
dsbDesc.dwFlags = DSBCAPS_CTRLDEFAULT; // Need defaul controls (pan, volume, frequency)
dsbDesc.dwBufferBytes = OptBufferSize * LWAV_BANKS;
dsbDesc.lpwfxFormat = (LPWAVEFORMATEX) (wav_buf+0x14);
// ------- assign buffer to a channel number ----------//
lpDsb = NULL;
int chanNum;
for( chanNum = 0; chanNum < MAX_LONG_WAV_CH; ++chanNum)
if(lp_lwav_ch_dsb[chanNum] == NULL || (lp_lwav_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)))
{
if(lp_lwav_ch_dsb[chanNum])
{
lp_lwav_ch_dsb[chanNum]->Release();
lp_lwav_ch_dsb[chanNum] = NULL;
// mem_del(lwav_fileptr[chanNum]); // delete lwav_fileptr[chanNum];
delete lwav_fileptr[chanNum];
lwav_fileptr[chanNum] = NULL;
}
// found an idle channel, create DirectSoundBuffer
hr = lp_direct_sound->CreateSoundBuffer(&dsbDesc, &lpDsb, NULL);
if (DS_OK != hr)
{
// failed!
err_now("Cannot create Stream DirectSoundBuffer");
delete filePtr;
return 0;
}
lp_lwav_ch_dsb[chanNum] = lpDsb;
lwav_fileptr[chanNum] = filePtr; // no need to delete filePtr any more
lwav_bank[chanNum] = 0;
lwav_bufsiz[chanNum] = OptBufferSize;
break;
}
if( chanNum >= MAX_LONG_WAV_CH)
{
delete filePtr;
return 0;
}
// Note : if not found, just play the sound, don't play the sound
// increase MAX_LONG_WAV_CH
//------- copy sound data to DirectSoundBuffer--------//
// unlock vga_front
VgaFrontLock vgaLock;
// lock the buffer first
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
// load wave data into buffer
// load data before lock DirectSoundBuffer in case the wave file
// is very short
DWORD startPos = filePtr->file_pos();
if( !filePtr->file_read(wav_buf, OptBufferSize*LWAV_BANKS))
{
// file error
err_now("Missing wave file");
return 0;
}
DWORD readStreamSize = filePtr->file_pos() - startPos;
DWORD playFlag = DSBPLAY_LOOPING;
hr = lpDsb->Lock(0, OptBufferSize*LWAV_BANKS, &lpvPtr1, &dwBytes1,
&lpvPtr2, &dwBytes2, 0);
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
return 0;
}
// write to pointers
memcpy(lpvPtr1, wav_buf, min(dwBytes1, readStreamSize));
if( dwBytes1 > readStreamSize )
{ // end of file, fill the remaining with zero
memset((char *)lpvPtr1+readStreamSize, 0, dwBytes1 - readStreamSize);
playFlag &= ~DSBPLAY_LOOPING;
}
else
{
readStreamSize -= dwBytes1;
if(lpvPtr2 && dwBytes2 > 0)
{
memcpy(lpvPtr2, wav_buf+dwBytes1, min(dwBytes2, readStreamSize));
if( dwBytes2 > readStreamSize )
{ // end of file, fill the remaining with zero
memset((char *)lpvPtr2+readStreamSize, 0 , dwBytes2 - readStreamSize);
playFlag &= ~DSBPLAY_LOOPING;
}
}
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
return 0;
}
//------- Set volume -----------//
lpDsb->SetVolume(dsVolume.ds_vol);
lpDsb->SetPan(dsVolume.ds_pan);
//------- Play wav file --------//
if(lpDsb->Play(0, 0, playFlag) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
return 0;
}
run_yield = 1;
return lwav_serial_no[chanNum] = assign_serial(max_lwav_serial_no);
}
//------- End of function Audio::play_long_wav ----------//
//------- Begin of function Audio::stop_long_wav ------------//
//
// stop a short sound effect started by play_long_wav
//
// the serial no returned by play_long_wav
//
// return 1 - channel is found and stopped / channel not found
// return 0 - cannot stop the channel
//
int Audio::stop_long_wav(int serial)
{
for( int chanNum = 0; chanNum < MAX_LONG_WAV_CH; ++chanNum)
{
if(lp_lwav_ch_dsb[chanNum] != NULL && lwav_serial_no[chanNum] == serial)
{
lp_lwav_ch_dsb[chanNum]->Stop();
lp_lwav_ch_dsb[chanNum]->Release();
lp_lwav_ch_dsb[chanNum] = NULL;
delete lwav_fileptr[chanNum];
lwav_fileptr[chanNum] = NULL;
lwav_serial_no[chanNum] = 0;
return 1;
}
}
return 0;
}
//------- End of function Audio::stop_long_wav ------------//
//------- Begin of function Audio::is_long_wav_playing ------------//
//
// return wheather a short sound effect is stopped
//
// the serial no returned by play_wav or play_resided_wav
//
int Audio::is_long_wav_playing(int serial)
{
DWORD dsbStatus;
for( int chanNum = 0; chanNum < MAX_LONG_WAV_CH; ++chanNum)
{
if(lp_lwav_ch_dsb[chanNum] != NULL && lwav_serial_no[chanNum] == serial
&& lp_lwav_ch_dsb[chanNum]->GetStatus(&dsbStatus) == DS_OK )
{
return dsbStatus & DSBSTATUS_PLAYING;
}
}
return 0;
}
//------- End of function Audio::is_long_wav_playing ------------//
//--------------- Begin of Audio::vol_multiply --------------//
long Audio::vol_multiply(int relVolume)
{
long dsVolume = (wav_volume * relVolume) - 10000;
if( dsVolume > 0 )
dsVolume = 0;
else if( dsVolume < -10000 )
dsVolume = -10000;
return dsVolume;
}
//--------------- End of Audio::vol_multiply --------------//
//--------------- Begin of Audio::vol_divide --------------//
int Audio::vol_divide(long dsVolume)
{
if( wav_volume == 0)
return 0;
int relVolume = (dsVolume + 10000) / wav_volume;
if( relVolume < 0)
relVolume = 0;
else if( relVolume > 100 )
relVolume = 100;
return relVolume;
}
//--------------- End of Audio::vol_divide --------------//
//------- Begin of function Audio::play_loop_wav -------//
//
// Play digitized wav from the wav resource file
//
// wavName = name of the wav in the resource file
// int repeatOffset = offset of wave data to play on repeat
// i.e. 0 to start of wave data
//
// return : channel number (1 - MAX_LOOP_WAV_CH)
// 0 not played
//
int Audio::play_loop_wav(char *wavName, int repeatOffset, DsVolume dsVolume)
{
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//-------- Load wav file header-------//
DWORD wavDataOffset,wavDataLength;
// File* filePtr = (File *)mem_add(sizeof(File)); // new File;
File* filePtr = new File;
if(!filePtr->file_open(wavName,0,0))
{
char errmsg[60];
sprintf(errmsg, "Cannot open %s", wavName);
box.msg(errmsg);
delete filePtr;
return 0;
}
if( !filePtr )
return 0;
// load small part of the wave file (first 128 bytes) enough to hold
// the hold header
if( !filePtr->file_read( wav_buf, 128 ) )
{
delete filePtr;
return 0;
}
// determine the wave data offset
char * dataTag = wavefile_data(wav_buf);
if (!dataTag)
{
err_now("Invalid wave file format");
delete filePtr;
return 0; // invalid RIFF WAVE format
}
wavDataOffset = (dataTag - wav_buf) + 4 + sizeof(DWORD);
wavDataLength = *(DWORD *)(dataTag+4);
// seek to the start of wave data
long temp1 = filePtr->file_seek(wavDataOffset,FILE_BEGIN);
WORD OptBufferSize=LOOPWAV_STREAM_BUFSIZ;
//------- Create DirectSoundBuffer to store a wave ------//
LPDIRECTSOUNDBUFFER lpDsb;
DSBUFFERDESC dsbDesc;
HRESULT hr;
DWORD dsbStatus;
// set up DSBUFFERDESC structure
memset(&dsbDesc, 0, sizeof(DSBUFFERDESC)); // zero it out
dsbDesc.dwSize = sizeof(DSBUFFERDESC);
dsbDesc.dwFlags = DSBCAPS_CTRLDEFAULT; // Need defaul controls (pan, volume, frequency)
dsbDesc.dwBufferBytes = OptBufferSize * LWAV_BANKS;
dsbDesc.lpwfxFormat = (LPWAVEFORMATEX) (wav_buf+0x14);
// ------- assign buffer to a channel number ----------//
lpDsb = NULL;
int chanNum;
for( chanNum = 0; chanNum < MAX_LOOP_WAV_CH; ++chanNum)
if(lp_loop_ch_dsb[chanNum] == NULL || (lp_loop_ch_dsb[chanNum]->GetStatus(&dsbStatus),
!(dsbStatus & DSBSTATUS_PLAYING)))
{
if(lp_loop_ch_dsb[chanNum])
{
lp_loop_ch_dsb[chanNum]->Release();
lp_loop_ch_dsb[chanNum] = NULL;
// mem_del(loopwav_fileptr[chanNum]); // delete lwav_fileptr[chanNum];
delete loopwav_fileptr[chanNum];
loopwav_fileptr[chanNum] = NULL;
}
// found an idle channel, create DirectSoundBuffer
hr = lp_direct_sound->CreateSoundBuffer(&dsbDesc, &lpDsb, NULL);
if (DS_OK != hr)
{
// failed!
err_now("Cannot create Stream DirectSoundBuffer");
return 0;
}
lp_loop_ch_dsb[chanNum] = lpDsb;
loopwav_fileptr[chanNum] = filePtr; // no need to delete filePtr any more
loopwav_bank[chanNum] = 0;
repeat_offset[chanNum] = wavDataOffset + repeatOffset;
loopwav_fade_rate[chanNum] = 0;
break;
}
if( chanNum >= MAX_LOOP_WAV_CH)
{
delete filePtr;
return 0;
}
// Note : if not found, just play the sound, don't play the sound
//------- copy sound data to DirectSoundBuffer--------//
// unlock vga_front
VgaFrontLock vgaLock;
// lock the buffer first
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
// load wave data into buffer
// load data before lock DirectSoundBuffer in case the wave file
// is very short
DWORD startPos = filePtr->file_pos();
if( !filePtr->file_read(wav_buf, OptBufferSize*LOOPWAV_BANKS))
{
// file error
err_now("Missing wave file");
return 0;
}
DWORD readStreamSize = filePtr->file_pos() - startPos;
DWORD playFlag = DSBPLAY_LOOPING;
hr = lpDsb->Lock(0, OptBufferSize*LOOPWAV_BANKS, &lpvPtr1, &dwBytes1,
&lpvPtr2, &dwBytes2, 0);
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
return 0;
}
// write to pointers, assume wave file repeating size is
// larger than OptBufferSize * LOOPWAV_BANKS
memcpy(lpvPtr1, wav_buf, min(dwBytes1, readStreamSize));
if( dwBytes1 < readStreamSize )
{
readStreamSize -= dwBytes1;
if(lpvPtr2 && dwBytes2 > 0)
{
memcpy(lpvPtr2, wav_buf+dwBytes1, min(dwBytes2, readStreamSize));
}
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
return 0;
}
//------- Set volume -----------//
lpDsb->SetVolume(dsVolume.ds_vol);
lpDsb->SetPan(dsVolume.ds_pan);
//------- Play wav file --------//
if(lpDsb->Play(0, 0, playFlag) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
return 0;
}
run_yield = 1;
return chanNum+1;
}
//------- End of function Audio::play_loop_wav ---------//
//------- Begin of function Audio::volume_loop_wav -------//
void Audio::volume_loop_wav(int ch, DsVolume dsVolume)
{
int chanNum = ch-1;
if( chanNum < 0 || chanNum >= MAX_LOOP_WAV_CH)
return;
if(lp_loop_ch_dsb[chanNum])
{
lp_loop_ch_dsb[chanNum]->SetVolume(dsVolume.ds_vol);
lp_loop_ch_dsb[chanNum]->SetPan(dsVolume.ds_pan);
// stop fading
loopwav_fade_rate[chanNum] = 0;
}
}
//------- End of function Audio::volume_loop_wav -------//
//------- Begin of function Audio::fade_out_loop_wav -------//
//
// fadeRate, time for volume 100 wave drop to slience
//
void Audio::fade_out_loop_wav(int ch, int fadeRate)
{
int chanNum = ch-1;
if( chanNum < 0 || chanNum >= MAX_LOOP_WAV_CH)
return;
if(lp_loop_ch_dsb[chanNum])
{
loopwav_fade_rate[chanNum] = fadeRate;
loopwav_fade_time[chanNum] = m.get_time();
}
}
//------- End of function Audio::fade_out_loop_wav -------//
//------- Begin of function Audio::get_loop_wav_volume -------//
DsVolume Audio::get_loop_wav_volume(int ch)
{
int chanNum = ch-1;
if( chanNum < 0 || chanNum >= MAX_LOOP_WAV_CH)
{
RelVolume rel = RelVolume(0,0);
return DsVolume(rel);
}
LONG volume;
LONG pan;
LPDIRECTSOUNDBUFFER lpDsb= lp_loop_ch_dsb[chanNum];
if( lpDsb && lpDsb->GetVolume(&volume) == DS_OK &&
lpDsb->GetPan(&pan) == DS_OK )
{
return DsVolume(volume, pan);
}
RelVolume rel = RelVolume(0,0);
return DsVolume(rel);
}
//------- End of function Audio::get_loop_wav_volume -------//
//------- Begin of function Audio::is_loop_wav_fading -------//
int Audio::is_loop_wav_fading(int ch)
{
int chanNum = ch-1;
if( chanNum < 0 || chanNum >= MAX_LOOP_WAV_CH)
return 0;
return lp_loop_ch_dsb[chanNum] && loopwav_fade_rate[chanNum];
}
//------- End of function Audio::is_loop_wav_fading -------//
//------- Begin of function Audio::yield ---------------//
void Audio::yield()
{
#ifndef WIN32
// unlock vga_front
VgaFrontLock vgaLock;
#endif
if( !run_yield)
return;
run_yield = 0; // suspend recursive Audio::yield();
#ifdef WIN32
// unlock vga_front
VgaFrontLock vgaLock;
#endif
// set break point beyond this point
int i;
for(i = 0; i < MAX_LONG_WAV_CH; ++i)
{
if( !lp_lwav_ch_dsb[i] )
continue;
// if a wav is not play, or buffer lost, stop it
LPDIRECTSOUNDBUFFER& lpDsb = lp_lwav_ch_dsb[i];
DWORD dsbStatus;
if( lpDsb->GetStatus(&dsbStatus) != DS_OK)
err_here();
if( !(dsbStatus & DSBSTATUS_PLAYING) ||
(dsbStatus & DSBSTATUS_BUFFERLOST) && lpDsb->Restore() != DS_OK )
{
lpDsb->Stop();
lpDsb->Release();
lpDsb = NULL;
// mem_del(lwav_fileptr[i]);
delete lwav_fileptr[i];
lwav_fileptr[i] = NULL;
continue;
}
char writeTooFast = 1;
// buffer lost, succeeded in restoring
if( dsbStatus & DSBSTATUS_BUFFERLOST )
{
writeTooFast = 0;
}
else
{
// perform flow control
DWORD tmpPlayCursor, tmpWriteCursor;
if( lpDsb->GetCurrentPosition(&tmpPlayCursor, &tmpWriteCursor) == DS_OK)
{
writeTooFast = ((short)(tmpPlayCursor / lwav_bufsiz[i]) == lwav_bank[i]);
}
}
if(!writeTooFast)
{
// lock a channel for lwav_bufsiz[i]
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
File *filePtr = lwav_fileptr[i];
HRESULT hr = lpDsb->Lock(lwav_bank[i]*lwav_bufsiz[i], lwav_bufsiz[i],
&lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
lwav_bank[i] = (lwav_bank[i] + 1) % LWAV_BANKS; // next bank to fill
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
run_yield = 1;
return;
}
long startPos;
long readStreamSize;
DWORD playFlag = DSBPLAY_LOOPING;
// write to pointers
startPos = filePtr->file_pos();
// filePtr->file_read(wav_buf, dwBytes1);
// readStreamSize = filePtr->file_pos() - startPos; // bytes read in
// memcpy(lpvPtr1, wav_buf, readStreamSize);
filePtr->file_read(lpvPtr1, dwBytes1);
readStreamSize = filePtr->file_pos() - startPos; // bytes read in
if((long)dwBytes1 > readStreamSize)
{ // end of file, fill the remaining with zero
// memset((char *)lpvPtr1+readStreamSize, 0, dwBytes1 - readStreamSize);
playFlag &= ~DSBPLAY_LOOPING; // clear DSBPLAY_LOOPING
}
else
{
if( lpvPtr2 && dwBytes2 > 0)
{
startPos = filePtr->file_pos();
filePtr->file_read(lpvPtr2, dwBytes2);
readStreamSize = filePtr->file_pos() - startPos; // bytes read in
if((long)dwBytes2 > readStreamSize)
{ // end of file
// memset((char *)lpvPtr2+readStreamSize, 0, dwBytes2 - readStreamSize);
playFlag &= ~DSBPLAY_LOOPING; // clear DSBPLAY_LOOPING
}
}
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
run_yield = 1;
return;
}
// load file into a channel, on last stream, don't loop back
//------- Play wav file --------//
if(lpDsb->Play(0, 0, playFlag) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
run_yield = 1;
return;
}
}
}
for(i = 0; i < MAX_LOOP_WAV_CH; ++i)
{
if( !lp_loop_ch_dsb[i] )
continue;
// if a channel is not playing, or can't restore release it
LPDIRECTSOUNDBUFFER& lpDsb = lp_loop_ch_dsb[i];
DWORD dsbStatus;
if( lpDsb->GetStatus(&dsbStatus) != DS_OK )
err_here();
if( !(dsbStatus & DSBSTATUS_PLAYING) ||
(dsbStatus & DSBSTATUS_BUFFERLOST) && lpDsb->Restore() != DS_OK )
{
lpDsb->Stop();
lpDsb->Release();
lpDsb = NULL;
// mem_del(loopwav_fileptr[i]);
delete loopwav_fileptr[i];
loopwav_fileptr[i] = NULL;
continue;
}
char writeTooFast = 1;
// buffer lost, succeeded in restoring
if( dsbStatus & DSBSTATUS_BUFFERLOST )
{
writeTooFast = 0;
}
else
{
// perform flow control
DWORD tmpPlayCursor, tmpWriteCursor;
if( lpDsb->GetCurrentPosition(&tmpPlayCursor, &tmpWriteCursor) == DS_OK)
{
writeTooFast = ((short)(tmpPlayCursor / LOOPWAV_STREAM_BUFSIZ) == loopwav_bank[i]);
}
}
if(!writeTooFast)
{
// lock a channel for loopwav_bufsiz[i]
LPVOID lpvPtr1;
DWORD dwBytes1;
LPVOID lpvPtr2;
DWORD dwBytes2;
File *filePtr = loopwav_fileptr[i];
HRESULT hr = lpDsb->Lock(loopwav_bank[i]*LOOPWAV_STREAM_BUFSIZ, LOOPWAV_STREAM_BUFSIZ,
&lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
loopwav_bank[i] = (loopwav_bank[i] + 1) % LOOPWAV_BANKS; // next bank to fill
if(DS_OK != hr)
{
// fail to lock
err_now("Cannot lock DirectSoundBuffer");
run_yield = 1;
return;
}
long startPos;
long readStreamSize;
DWORD playFlag = DSBPLAY_LOOPING;
// write to pointers
startPos = filePtr->file_pos();
filePtr->file_read(lpvPtr1, dwBytes1);
readStreamSize = filePtr->file_pos() - startPos; // bytes read in
if((long)dwBytes1 > readStreamSize)
{ // end of file, seek to beginning and read again
filePtr->file_seek(repeat_offset[i]);
filePtr->file_read((char *)lpvPtr1+readStreamSize, dwBytes1-readStreamSize);
}
// unlock data back
hr = lpDsb->Unlock(lpvPtr1, dwBytes1, lpvPtr2, dwBytes2);
if(DS_OK != hr)
{
// fail to unlock
err_now("Cannot unlock DirectSoundBuffer");
run_yield = 1;
return;
}
// set volume if fading
if( loopwav_fade_rate[i] )
{
DWORD nextFadeTime = m.get_time();
LONG volume;
if( DS_OK == (hr = lpDsb->GetVolume(&volume)) )
{
// calculate new volume
volume -= (nextFadeTime - loopwav_fade_time[i]) * loopwav_fade_rate[i];
if( volume < DSBVOLUME_MIN )
volume = DSBVOLUME_MIN;
else if( volume > DSBVOLUME_MAX )
volume = DSBVOLUME_MAX;
if( DS_OK == (hr = lpDsb->SetVolume(volume)) )
{
loopwav_fade_time[i] = nextFadeTime;
}
}
}
// load file into a channel, on last stream, don't loop back
//------- Play wav file --------//
if(lpDsb->Play(0, 0, playFlag) != DS_OK)
{
// fail to play
err_now("Cannot play DirectSoundBuffer");
run_yield = 1;
return;
}
}
}
run_yield = 1; // resume Audio::yield();
}
//------- End of function Audio::yield ---------------//
//------- Begin of function Audio::stop_wav -------//
//
void Audio::stop_wav()
{
if( !wav_init_flag || !wav_flag )
return;
// ---------- stop all short wave ------------- //
int i;
for(i = 0; i < MAX_WAV_CHANNEL; ++i)
if(lp_wav_ch_dsb[i])
{
lp_wav_ch_dsb[i]->Stop();
lp_wav_ch_dsb[i]->Release();
lp_wav_ch_dsb[i] = NULL;
}
// ----------- stop all long wave ------------- //
stop_long_wav();
// ------------ stop all loop wave ------------//
for(i = 1; i <= MAX_LOOP_WAV_CH; ++i)
{
stop_loop_wav(i);
}
}
//------- End of function Audio::stop_wav -------//
//------- Begin of function Audio::stop_long_wav -------//
//
void Audio::stop_long_wav()
{
if( !wav_init_flag || !wav_flag )
return;
for(int i = 0; i < MAX_LONG_WAV_CH; ++i)
if(lp_lwav_ch_dsb[i])
{
lp_lwav_ch_dsb[i]->Stop();
lp_lwav_ch_dsb[i]->Release();
lp_lwav_ch_dsb[i] = NULL;
// mem_del(lwav_fileptr[i]);
delete lwav_fileptr[i];
lwav_fileptr[i] = NULL;
}
}
//------- End of function Audio::stop_long_wav -------//
//------- Begin of function Audio::stop_loop_wav -------//
void Audio::stop_loop_wav(int ch)
{
int chanNum = ch-1;
if( chanNum < 0 || chanNum >= MAX_LOOP_WAV_CH)
return;
if(lp_loop_ch_dsb[chanNum])
{
lp_loop_ch_dsb[chanNum]->Stop();
lp_loop_ch_dsb[chanNum]->Release();
lp_loop_ch_dsb[chanNum] = NULL;
// mem_del(loopwav_fileptr[chanNum]); // delete lwav_fileptr[chanNum];
delete loopwav_fileptr[chanNum];
loopwav_fileptr[chanNum] = NULL;
}
}
//------- End of function Audio::stop_loop_wav ---------//
//------- Begin of function Audio::play_cd -------//
//
// trackId - the id. of the CD track to play.
//
int Audio::play_cd(int trackId, int volume)
{
if( !cd_init_flag || !cd_flag )
return 0;
// ###### begin Gilbert 3/10 ########//
MCIERROR mciError;
DWORD maxTrack = 99;
// Get the number of tracks;
// limit to number that can be displayed (20).
MCI_STATUS_PARMS mciStatusParms;
mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
mciError = mciSendCommand(mci_open.wDeviceID, MCI_STATUS,
MCI_STATUS_ITEM, (DWORD)(LPVOID) &mciStatusParms);
if( !mciError )
maxTrack = mciStatusParms.dwReturn;
//--- Send an MCI_PLAY command to the CD Audio driver ---//
mci_open.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
mci_play.dwFrom = MCI_MAKE_TMSF(trackId , 0, 0, 0);
mci_play.dwTo = MCI_MAKE_TMSF(trackId+1, 0, 0, 0);
DWORD cmdFlag = MCI_FROM;
if( (DWORD) trackId < maxTrack )
cmdFlag |= MCI_TO; // if MCI_TO is missing, play until the end
mciError = mciSendCommand( mci_open.wDeviceID, MCI_PLAY, cmdFlag,
(DWORD) (LPVOID) &mci_play);
if( mciError )
return 0;
return 1;
// ###### end Gilbert 3/10 ########//
}
//------- End of function Audio::play_cd -------//
//------- Begin of function Audio::stop_cd -------//
//
void Audio::stop_cd()
{
if( !cd_init_flag || !cd_flag )
return;
DWORD dwResult;
dwResult = mciSendCommand(mci_open.wDeviceID, MCI_STOP,
MCI_WAIT, (DWORD)(LPVOID)NULL);
}
//------- End of function Audio::stop_cd -------//
//------- Begin of function Audio::is_mid_playing -------//
//
int Audio::is_mid_playing()
{
if( !mid_init_flag || !mid_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//... insert code here ...//
return 0;
}
//------- End of function Audio::is_mid_playing -------//
//------- Begin of function Audio::is_wav_playing -------//
//
int Audio::is_wav_playing()
{
int playingChannelCount = 0;
DWORD dwStatus;
if( !wav_init_flag || !wav_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
//------ find any wav channel is playing -----//
// update lp_wav_ch_dsb[x] if necessary
for(int ch=0; ch < MAX_WAV_CHANNEL; ++ch)
if( lp_wav_ch_dsb[ch])
if( lp_wav_ch_dsb[ch]->GetStatus(&dwStatus) == DS_OK)
if (dwStatus & DSBSTATUS_PLAYING )
// a channel is playing
playingChannelCount++;
else
// is not playing, clear it
lp_wav_ch_dsb[ch] = NULL;
else
// GetStatus not ok, clear it
lp_wav_ch_dsb[ch] = NULL;
else
{
// nothing
}
return (playingChannelCount > 0);
}
//------- End of function Audio::is_wav_playing -------//
//------- Begin of function Audio::is_cd_playing -------//
//
int Audio::is_cd_playing()
{
if( !cd_init_flag || !cd_flag ) // a initialized and workable midi device can be disabled by user setting
return 0;
MCI_STATUS_PARMS status;
DWORD dwResult;
//
// get the current status
//
status.dwItem = MCI_STATUS_MODE;
dwResult = mciSendCommand(mci_open.wDeviceID, MCI_STATUS,
MCI_WAIT | MCI_STATUS_ITEM, (DWORD)(LPVOID)&status);
if (dwResult == 0)
return status.dwReturn == MCI_MODE_PLAY;
return 0;
}
//------- End of function Audio::is_cd_playing -------//
//----------------- Begin of Audio::toggle_mid -----------------//
//
void Audio::toggle_mid(int midFlag)
{
if( !midFlag )
stop_mid();
mid_flag = midFlag;
}
//------------------- End of Audio::toggle_mid ------------------//
//----------------- Begin of Audio::toggle_wav -----------------//
//
void Audio::toggle_wav(int wavFlag)
{
if( !wavFlag )
stop_wav();
wav_flag = wavFlag;
}
//------------------- End of Audio::toggle_wav ------------------//
//----------------- Begin of Audio::toggle_cd -----------------//
//
void Audio::toggle_cd(int cdFlag)
{
if( !cdFlag )
stop_cd();
cd_flag = cdFlag;
}
//------------------- End of Audio::toggle_cd ------------------//
//-------------- Begin of Audio::set_mid_volume -------------//
//
// Set mid volume
//
// midVolume = mid volume, 0-100
//
void Audio::set_mid_volume(int midVolume)
{
if( !mid_init_flag )
return;
//.. insert code here ...//
}
//--------------- End of Audio::set_mid_volume --------------//
//-------------- Begin of Audio::set_wav_volume -------------//
//
// Set wav volume
//
// wavVolume = wav volume, 0-100
//
void Audio::set_wav_volume(int wavVolume)
{
if( !wav_init_flag )
return;
LONG dsVolume;
long dsVolDiff = (wavVolume - wav_volume) * 100;
// change volume for all channels
int i;
for( i = 0; i < MAX_WAV_CHANNEL; ++i)
{
if( lp_wav_ch_dsb[i] &&
lp_wav_ch_dsb[i]->GetVolume(&dsVolume) == DS_OK)
{
dsVolume += dsVolDiff;
if( dsVolume > DSBVOLUME_MAX )
dsVolume = DSBVOLUME_MAX;
if( dsVolume < DSBVOLUME_MIN )
dsVolume = DSBVOLUME_MIN;
lp_wav_ch_dsb[i]->SetVolume(dsVolume);
}
}
for( i = 0; i < MAX_LONG_WAV_CH; ++i)
{
if( lp_lwav_ch_dsb[i] &&
lp_lwav_ch_dsb[i]->GetVolume(&dsVolume) == DS_OK)
{
dsVolume += dsVolDiff;
if( dsVolume > DSBVOLUME_MAX )
dsVolume = DSBVOLUME_MAX;
if( dsVolume < DSBVOLUME_MIN )
dsVolume = DSBVOLUME_MIN;
lp_lwav_ch_dsb[i]->SetVolume(dsVolume);
}
}
for( i = 0; i < MAX_LOOP_WAV_CH; ++i)
{
if( lp_loop_ch_dsb[i] &&
lp_loop_ch_dsb[i]->GetVolume(&dsVolume) == DS_OK)
{
dsVolume += dsVolDiff;
if( dsVolume > DSBVOLUME_MAX )
dsVolume = DSBVOLUME_MAX;
if( dsVolume < DSBVOLUME_MIN )
dsVolume = DSBVOLUME_MIN;
lp_loop_ch_dsb[i]->SetVolume(dsVolume);
}
}
wav_volume = wavVolume;
}
//--------------- End of Audio::set_wav_volume --------------//
//-------------- Begin of Audio::set_cd_volume -------------//
//
// Set cd volume
//
// cdVolume = cd volume, 0-100
//
void Audio::set_cd_volume(int cdVolume)
{
if( !cd_init_flag )
return;
//.. insert code here ...//
}
//--------------- End of Audio::set_cd_volume --------------//
//-------------- Begin of function Audio::assign_serial ----------//
int Audio::assign_serial(int &s)
{
if( s == INT_MAX)
return s = 1;
return ++s;
}
//-------------- End of function Audio::assign_serial ----------//
// ------------ Begin of function Audio::volume_long_wav -------//
void Audio::volume_long_wav(int serial, DsVolume dsVolume)
{
if( is_long_wav_playing(serial) )
{
for( int chanNum = 0; chanNum < MAX_LONG_WAV_CH; ++chanNum)
{
if(lp_lwav_ch_dsb[chanNum] != NULL && lwav_serial_no[chanNum] == serial )
{
lp_lwav_ch_dsb[chanNum]->SetVolume(dsVolume.ds_vol);
// lp_lwav_ch_dsb[chanNum]->SetPan(dsVolume.ds_pan);
break;
}
}
}
}
// ------------ End of function Audio::volume_long_wav -------//