本篇是创建游戏内核(16)【OO改良版】的续篇,关于该内核的细节说明请参阅创建游戏内核(17)。
接口:
//======================================================================================
// This class encapsulate how to load sound data.
//======================================================================================
typedef class SOUND_DATA
{
private:
friend class SOUND_CHANNEL; // let SOUND_CHANNEL can use this class's member data and function
public:
SOUND_DATA();
~SOUND_DATA();
char* get_buffer();
long get_buffer_size();
BOOL copy_sound_data(const SOUND_DATA* source);
void free();
void set_sound_data_format(long frequency, short channels, short bits_per_sample);
BOOL load_wav(const char* filename);
private:
BOOL _create(long buffer_size);
BOOL _load_wav_header(const char* filename);
protected:
long m_frequency;
short m_channels;
short m_bits_per_sample;
char* m_ptr; // pointer to current sound buffer will to be played
char* m_buf; // buffer to store sound data
long m_buffer_size; // sound buffer size
long m_left_size; // left size of sound buffer which need to loaded
long m_file_start_pos; // start position of wave file will to be loaded
long m_file_curr_pos; // current position of wave file will to be loaded
} *SOUND_DATA_PTR;
实现:
#pragma pack(1)
// .WAV file header
struct WAVE_HEADER
{
char riff_sig[4]; // 'RIFF'
long waveform_chunk_size; // 8
char wave_sig[4]; // 'WAVE'
char format_sig[4]; // 'fmt ' (notice space after)
long format_chunk_size; // 16;
short format_tag; // WAVE_FORMAT_PCM
short channels; // # of channels
long sample_rate; // sampling rate
long bytes_per_sec; // bytes per second
short block_align; // sample block alignment
short bits_per_sample; // bits per second
char data_sig[4]; // 'data'
long data_size; // size of waveform data
};
#pragma pack()
//------------------------------------------------------------------------------
// Constructor, initialize member data.
//------------------------------------------------------------------------------
SOUND_DATA::SOUND_DATA()
{
memset(this, 0, sizeof(*this));
m_frequency = 22050;
m_channels = 1;
m_bits_per_sample = 16;
}
//------------------------------------------------------------------------------
// Destructor, release sound data buffer.
//------------------------------------------------------------------------------
SOUND_DATA::~SOUND_DATA()
{
free();
}
//------------------------------------------------------------------------------
// Release sound data buffer.
//------------------------------------------------------------------------------
void SOUND_DATA::free()
{
if(m_buf)
{
delete[] m_buf;
m_buf = NULL;
}
m_ptr = NULL;
m_buffer_size = 0;
}
//------------------------------------------------------------------------------
// Create sound data buffer with specified size.
//------------------------------------------------------------------------------
BOOL SOUND_DATA::_create(long size)
{
// free prior allocated data
free();
// check for valid size
if((m_buffer_size = size) == 0)
return FALSE;
// create a new buffer
m_buf = new char[m_buffer_size];
if(m_buf == NULL)
return FALSE;
// clear out new buffer
ZeroMemory(m_buf, m_buffer_size);
// point to new buffer
m_ptr = m_buf;
return TRUE;
}
//------------------------------------------------------------------------------
// Load wave header from file.
//------------------------------------------------------------------------------
BOOL SOUND_DATA::_load_wav_header(const char* filename)
{
// error checking
if(filename == NULL)
return FALSE;
FILE* _fp;
// open file
if((_fp = fopen(filename, "rb")) == NULL)
return FALSE;
// read in header and parse
WAVE_HEADER _wave_header;
fread(&_wave_header, 1, sizeof(WAVE_HEADER), _fp);
// check signature
if(!memcmp(_wave_header.riff_sig, "RIFF", 4) && !memcmp(_wave_header.wave_sig, "WAVE", 4) &&
!memcmp(_wave_header.format_sig, "fmt ", 4) && !memcmp(_wave_header.data_sig, "data", 4))
{
// all signatures satisfied
m_frequency = _wave_header.sample_rate;
m_channels = _wave_header.channels;
m_bits_per_sample = _wave_header.bits_per_sample;
m_buffer_size = m_left_size = _wave_header.data_size;
m_file_start_pos = m_file_curr_pos = ftell(_fp);
// close if we opened file, otherwise return to original position.
fclose(_fp);
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
// Get pointer to sound data buffer.
//------------------------------------------------------------------------------
char* SOUND_DATA::get_buffer()
{
return m_buf;
}
//------------------------------------------------------------------------------
// Get size of sound data buffer.
//------------------------------------------------------------------------------
long SOUND_DATA::get_buffer_size()
{
return m_buffer_size;
}
//------------------------------------------------------------------------------
// Set play property for sound data buffer.
//------------------------------------------------------------------------------
void SOUND_DATA::set_sound_data_format(long frequency, short channels, short bits_per_sample)
{
m_frequency = frequency;
m_channels = channels;
m_bits_per_sample = bits_per_sample;
}
//------------------------------------------------------------------------------
// Load in wave file.
//------------------------------------------------------------------------------
BOOL SOUND_DATA::load_wav(const char* filename)
{
if(filename == NULL)
return FALSE;
// load wave header information first
if(! _load_wav_header(filename))
return FALSE;
// create sound data buffer.
if(! _create(m_buffer_size))
return FALSE;
// open file, seek to position and read in data.
FILE* _fp;
if((_fp = fopen(filename, "rb")) == NULL)
return FALSE;
fseek(_fp, m_file_start_pos, SEEK_SET);
fread(m_buf, 1, m_buffer_size, _fp);
// reset start position and current position
m_file_start_pos = m_file_curr_pos = 0;
// close file
fclose(_fp);
return TRUE;
}
//------------------------------------------------------------------------------
// Copy sound data from another sound data.
//------------------------------------------------------------------------------
BOOL SOUND_DATA::copy_sound_data(const SOUND_DATA* source)
{
if(source == NULL)
return FALSE;
// note that m_buf is not assigned!!
m_frequency = source->m_frequency;
m_channels = source->m_channels;
m_bits_per_sample = source->m_bits_per_sample;
m_ptr = source->m_ptr;
m_buffer_size = source->m_buffer_size;
m_left_size = source->m_left_size;
m_file_curr_pos = source->m_file_curr_pos;
m_file_start_pos = source->m_file_start_pos;
return TRUE;
}