⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 core_sound.cpp

📁 [游戏开发参考书-用DirectX编写RPG游戏]这是一个系列的丛书如果你都看并且懂的话你就可以你工作啦!
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**************************************************
WinMain.cpp
GameCore Component

Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
**************************************************/

#include "Core_Global.h"

//////////////////////////////////////////////////////////////////////
//
// cSound Functions
//
//////////////////////////////////////////////////////////////////////
cSound::cSound()
{
  short i;
  
  // Initialize COM
  CoInitialize(NULL);

  m_hWnd   = NULL;
  m_Volume = 0;

  m_hThread = NULL;
  m_ThreadID = NULL;
  m_ThreadActive = FALSE;

  m_pDMPerformance = NULL;
  m_pDMLoader      = NULL;

  m_pDS = NULL;
  m_pDSBPrimary = NULL;

  for(i=0;i<32;i++)
    m_EventChannel[i] = NULL;

  for(i=0;i<33;i++)
    m_Events[i] = NULL;
}

cSound::~cSound()
{
  Shutdown();

  // Uninitialize COM
  CoUninitialize();
}

BOOL cSound::Init(HWND hWnd, long Frequency, short Channels, short BitsPerSample, long CooperativeLevel)
{
  CHAR         strPath[MAX_PATH];
  WCHAR        wstrSearchPath[MAX_PATH];
  DSBUFFERDESC dsbd;
  WAVEFORMATEX wfex;
  long         VolumeLevel;
  short        i;
  
  // Shutdown system in case of prior install
  Shutdown();

  // Save parent window handle
  if((m_hWnd = hWnd) == NULL)
    return FALSE;

  ///////////////////////////////////////////////////////////////////
  // Initialize DirectSound
  ///////////////////////////////////////////////////////////////////

  // Save settings of sound setup
  if(CooperativeLevel == DSSCL_NORMAL)
    CooperativeLevel = DSSCL_PRIORITY;
  m_CooperativeLevel = CooperativeLevel;
  m_Frequency        = Frequency;
  m_Channels         = Channels;
  m_BitsPerSample    = BitsPerSample;

  // create an IDirectSound8 object
  if(FAILED(DirectSoundCreate8(NULL, &m_pDS, NULL)))
    return FALSE;

  // Set cooperative mode
  if(FAILED(m_pDS->SetCooperativeLevel(m_hWnd, m_CooperativeLevel)))
    return FALSE;

  // Get primary buffer control
  ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
  dsbd.dwSize        = sizeof(DSBUFFERDESC);
  dsbd.dwFlags       = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
  dsbd.dwBufferBytes = 0;
  dsbd.lpwfxFormat   = NULL;
  if(FAILED(m_pDS->CreateSoundBuffer(&dsbd, &m_pDSBPrimary, NULL)))
    return FALSE;

  // Set the primary buffer format
  ZeroMemory(&wfex, sizeof(WAVEFORMATEX)); 
  wfex.wFormatTag      = WAVE_FORMAT_PCM; 
  wfex.nChannels       = (WORD)m_Channels;
  wfex.nSamplesPerSec  = m_Frequency;
  wfex.wBitsPerSample  = (WORD)m_BitsPerSample;
  wfex.nBlockAlign     = wfex.wBitsPerSample / 8 * wfex.nChannels;
  wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
  if(FAILED(m_pDSBPrimary->SetFormat(&wfex)))
    return FALSE;

  // Create the events, plus 
  // an extra one for thread termination
  for(i=0;i<33;i++) {
    if((m_Events[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL)
      return FALSE;
  }

  // Create a thread for handling notifications
  if((m_hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)HandleNotifications, (LPVOID)this, 0, &m_ThreadID)) == NULL)
    return FALSE;

  // Start main buffer playing
  if(FAILED(m_pDSBPrimary->Play(0, 0, DSBPLAY_LOOPING)))
    return FALSE;

  ///////////////////////////////////////////////////////////////////
  // Initialize DirectMusic
  ///////////////////////////////////////////////////////////////////

  // Create the DirectMusic loader object
  CoCreateInstance(CLSID_DirectMusicLoader, NULL, CLSCTX_INPROC, 
                   IID_IDirectMusicLoader8, (void**)&m_pDMLoader);

  // Create the DirectMusic performance object
  CoCreateInstance(CLSID_DirectMusicPerformance, NULL, CLSCTX_INPROC, 
                   IID_IDirectMusicPerformance8, (void**)&m_pDMPerformance);

  // Initialize the performance with the standard audio path.
  // This initializes both DirectMusic and DirectSound and 
  // sets up the synthesizer. 
  m_pDMPerformance->InitAudio(NULL, NULL, m_hWnd,
                              DMUS_APATH_SHARED_STEREOPLUSREVERB, 128,
                              DMUS_AUDIOF_ALL, NULL);

  // set the performance global volume to +10 decibels
  VolumeLevel = 1000;
  if(FAILED(m_pDMPerformance->SetGlobalParam(GUID_PerfMasterVolume, &VolumeLevel, sizeof(long))))
    return FALSE;

  // Tell DirectMusic where the default search path is
  GetCurrentDirectory(MAX_PATH, strPath);
  MultiByteToWideChar(CP_ACP, 0, strPath, -1, wstrSearchPath, MAX_PATH);
  m_pDMLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, wstrSearchPath, FALSE);

  // Set default volume to full
  SetVolume(100);
  
  return TRUE;
}

BOOL cSound::Shutdown()
{
  short i;

  // Stop the music, and close down 
  if(m_pDMPerformance != NULL) {
    m_pDMPerformance->Stop(NULL, NULL, 0, 0);
    m_pDMPerformance->CloseDown();
  }

  // Release the DirectMusic objects
  ReleaseCOM(m_pDMPerformance);
  ReleaseCOM(m_pDMLoader);

  // Go through all used sound channels and free them
  for(i=0;i<32;i++) {
    if(m_EventChannel[i] != NULL) {
      m_EventChannel[i]->Free();
      m_EventChannel[i] = NULL;
    }

    // Clear the event status
    if(m_Events[i] != NULL)
      ResetEvent(m_Events[i]);
  }

  // Stop the primary channel from playing
  if(m_pDSBPrimary != NULL)
    m_pDSBPrimary->Stop();

  // Release the DirectSound objects
  ReleaseCOM(m_pDSBPrimary);
  ReleaseCOM(m_pDS);

  // Force a closure of the thread by triggering the last event
  // and waiting for it to terminate
  if(m_hThread != NULL) {
    if(m_Events[32] != NULL) {
      while(m_ThreadActive == TRUE)
        SetEvent(m_Events[32]);
    } else {
      // getting here means no event assigned on thread
      // and need to terminate it - not desirable
      TerminateThread(m_hThread, 0);
    }
  }

  // Close all event handles
  for(i=0;i<33;i++) {
    if(m_Events[i] != NULL) {
      CloseHandle(m_Events[i]);
      m_Events[i] = NULL;
    }
  }

  // Free the thread handle
  if(m_hThread != NULL) {
    CloseHandle(m_hThread);
    m_hThread = NULL;
  }
  m_ThreadID = NULL;

  return TRUE;
}

IDirectSound8 *cSound::GetDirectSoundCOM()
{
  return m_pDS;
}

IDirectSoundBuffer *cSound::GetPrimaryBufferCOM()
{
  return m_pDSBPrimary;
}

IDirectMusicPerformance8 *cSound::GetPerformanceCOM()
{
  return m_pDMPerformance;
}

IDirectMusicLoader8 *cSound::GetLoaderCOM()
{
  return m_pDMLoader;
}

BOOL cSound::AssignEvent(cSoundChannel *Channel, short *EventNum, HANDLE *EventHandle)
{
  short i;

  for(i=0;i<32;i++) {
    if(m_Events[i] != NULL && m_EventChannel[i] == NULL) {
      ResetEvent(m_Events[i]);
      m_EventChannel[i] = Channel;
      *EventNum = i;
      *EventHandle = m_Events[i];
      return TRUE;
    }
  }

  return FALSE;
}

BOOL cSound::ReleaseEvent(cSoundChannel *Channel, short *EventNum)
{
  if((unsigned short)*EventNum < 33 && m_EventChannel[*EventNum] == Channel) {
    ResetEvent(m_Events[*EventNum]);
    m_EventChannel[*EventNum] = NULL;
    *EventNum = -1;
    return TRUE;
  } 

  return FALSE;
}

long cSound::GetVolume()
{
  return m_Volume;
}

BOOL cSound::SetVolume(long Percent)
{
  long Volume;

  // Set the sound main volume
  if(m_pDSBPrimary == NULL)
    return FALSE;

  // calculate a usable volume level
  if(!Percent)
    Volume = DSBVOLUME_MIN;
  else 
    Volume = -20 * (100 - (Percent % 101));

  if(FAILED(m_pDSBPrimary->SetVolume(Volume)))
    return FALSE;

  m_Volume = Percent % 101;

  return TRUE;
}

DWORD cSound::HandleNotifications(LPVOID lpvoid)
{
  DWORD   dwResult, Channel;
  cSound *SoundPtr;
  BOOL    Complete;
  MSG     Msg;

  SoundPtr = (cSound*)lpvoid;

  SoundPtr->m_ThreadActive = TRUE;

  Complete = FALSE;

  while(Complete == FALSE) {
    // Wait for a message
    dwResult = MsgWaitForMultipleObjects(33, SoundPtr->m_Events,
                                         FALSE, INFINITE, 
                                         QS_ALLEVENTS);

    // Get channel # to update
    Channel = dwResult - WAIT_OBJECT_0;

    // Check for channel update
    if(Channel >=0 && Channel < 32) {
      if(SoundPtr->m_EventChannel[Channel] != NULL)
        SoundPtr->m_EventChannel[Channel]->Update();
    } else

    // Check for thread closure
    if(Channel == 32) {
      Complete = TRUE;
    } else

    // Check for waiting messages
    if(Channel > 32) {
      while(PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE)) {
        if(Msg.message == WM_QUIT) {
          Complete = TRUE;
          break;
        }
      }
    }
  }

  SoundPtr->m_ThreadActive = FALSE;

  return 0L;
}

BOOL cSound::Restore()
{
  short i;

  // Handle primary 
  if(m_pDSBPrimary != NULL)
    m_pDSBPrimary->Restore();

  // Handle all used sound channels
  for(i=0;i<32;i++) {
    if(m_EventChannel[i] != NULL)
      m_EventChannel[i]->m_pDSBuffer->Restore();
  }

  return TRUE;
}

//////////////////////////////////////////////////////////////////////
//
// cSoundData Functions
//
//////////////////////////////////////////////////////////////////////
cSoundData::cSoundData()
{
  m_Frequency     = 22050;
  m_Channels      = 1;
  m_BitsPerSample = 16;

  m_fp       = NULL;
  m_Ptr      = m_Buf = NULL;
  m_StartPos = m_Pos = 0;
  m_Size     = m_Left = 0;
}

cSoundData::~cSoundData()
{
  Free();
}

BOOL cSoundData::Create()
{
  return Create(m_Size);
}

BOOL cSoundData::Create(long Size)
{
  // Free prior allocated data
  Free();

  // Check for valid size
  if((m_Size = Size) == 0)
    return FALSE;

  // Create a new buffer
  m_Buf = new char[m_Size];
  if(m_Buf == NULL)
    return FALSE;

  // Point to new buffer
  m_Ptr = m_Buf;
  m_fp  = NULL;

  // Clear out new buffer
  ZeroMemory(m_Buf, m_Size);

  return TRUE;
}

BOOL cSoundData::Free()
{
  if(m_Buf != NULL) {
    delete[] m_Buf;
    m_Buf = NULL;
  }

  m_Ptr = NULL;
  m_Size = 0;

  return TRUE;
}

char *cSoundData::GetPtr()
{
  return m_Buf;
}

long cSoundData::GetSize()
{
  return m_Size;
}

BOOL cSoundData::SetFormat(long Frequency, short Channels, short BitsPerSample)
{
  m_Frequency = Frequency;
  m_Channels = Channels;
  m_BitsPerSample = BitsPerSample;

  return TRUE;
}

BOOL cSoundData::SetSource(FILE *fp, long Pos, long Size)
{
  m_fp = fp;
  m_Ptr = NULL;

  if(Pos != -1)
    m_StartPos = m_Pos = Pos;
  if(Size != -1)
    m_Size = m_Left = Size;

  return TRUE;
}

BOOL cSoundData::SetSource(void *Ptr, long Pos, long Size)
{
  m_fp = NULL;
  m_Ptr = (char*)Ptr;
  if(Pos != -1)
    m_StartPos = m_Pos = Pos;
  if(Size != -1)
    m_Size = m_Left = Size;

  return TRUE;
}

BOOL cSoundData::LoadWAV(char *Filename, FILE *fp)
{
  if(LoadWAVHeader(Filename, fp) == FALSE)
    return FALSE;

  if(Create() == FALSE)
    return FALSE;

  // open file, seek to position and read in data
  if(Filename != NULL) {
    if((fp=fopen(Filename, "rb"))==NULL)
      return FALSE;
  }
  fseek(fp, m_StartPos, SEEK_SET);
  fread(m_Buf, 1, m_Size, fp);
  m_StartPos = m_Pos = 0;

  // close up file
  if(Filename != NULL)
    fclose(fp);

  return TRUE;
}

BOOL cSoundData::LoadWAVHeader(char *Filename, FILE *fp)
{
  sWaveHeader Hdr;
  BOOL ReturnVal;
  long Pos;

  if(Filename == NULL && fp == NULL)
    return FALSE;

  if(Filename != NULL) {
    if((fp=fopen(Filename, "rb"))==NULL)
      return FALSE;
  }

  // Save position in file
  Pos = ftell(fp);

  // Read in header and parse
  ReturnVal = FALSE;
  fread(&Hdr, 1, sizeof(sWaveHeader), fp);
  if(!memcmp(Hdr.RiffSig, "RIFF", 4) && !memcmp(Hdr.WaveSig, "WAVE", 4) && !memcmp(Hdr.FormatSig, "fmt ", 4) && !memcmp(Hdr.DataSig, "data", 4)) {
    m_Frequency     = Hdr.SampleRate;
    m_Channels      = Hdr.Channels;
    m_BitsPerSample = Hdr.BitsPerSample;

    m_Size = m_Left = Hdr.DataSize;
    m_StartPos = m_Pos = ftell(fp);

    ReturnVal = TRUE;
  }

  // Close if we opened file
  // otherwise return to original position
  if(Filename != NULL)
    fclose(fp);
  else 
    fseek(fp, Pos, SEEK_SET);

  return ReturnVal;
}

BOOL cSoundData::Copy(cSoundData *Source)
{
  if(Source == NULL)
    return FALSE;
  
  m_Frequency     = Source->m_Frequency;
  m_Channels      = Source->m_Channels;
  m_BitsPerSample = Source->m_BitsPerSample;

  m_fp       = Source->m_fp;
  m_Ptr      = Source->m_Ptr;
  m_Size     = Source->m_Size;
  m_Left     = Source->m_Left;
  m_Pos      = Source->m_Pos;
  m_StartPos = Source->m_StartPos;

  return TRUE;
}

//////////////////////////////////////////////////////////////////////
//
// cSoundChannel Functions
//
//////////////////////////////////////////////////////////////////////
cSoundChannel::cSoundChannel()
{
  m_Sound     = NULL;
  m_pDSBuffer = NULL;
  m_pDSNotify = NULL;

  m_Event     = -1;

  m_Volume    = 0;
  m_Pan       = 0;
  m_Frequency = 0;
  m_Playing   = FALSE;
}

cSoundChannel::~cSoundChannel()
{
  Free();
}

IDirectSoundBuffer8 *cSoundChannel::GetSoundBufferCOM()
{
  return m_pDSBuffer;
}

IDirectSoundNotify8 *cSoundChannel::GetNotifyCOM()
{
  return m_pDSNotify;
}    

BOOL cSoundChannel::Create(cSound *Sound, long Frequency, short Channels, short BitsPerSample)
{
  DSBUFFERDESC dsbd;
  WAVEFORMATEX wfex;
  HANDLE       hEvent;
  DSBPOSITIONNOTIFY   dspn[3];
  IDirectSoundBuffer *pDSBuffer;

  // Free a prior channel
  Free();

  if((m_Sound = Sound) == NULL)
    return FALSE;
  if(m_Sound->GetDirectSoundCOM() == NULL)
    return FALSE;

  // Save playback format
  m_Frequency     = Frequency;
  m_BitsPerSample = BitsPerSample;
  m_Channels      = Channels;

  // Create a new sound buffer for this channel
  // Using specified format
  ZeroMemory(&wfex, sizeof(WAVEFORMATEX)); 
  wfex.wFormatTag      = WAVE_FORMAT_PCM; 
  wfex.nChannels       = (WORD)m_Channels;
  wfex.nSamplesPerSec  = m_Frequency;
  wfex.wBitsPerSample  = (WORD)m_BitsPerSample;
  wfex.nBlockAlign     = wfex.wBitsPerSample / 8 * wfex.nChannels;
  wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;

  ZeroMemory(&dsbd, sizeof(DSBUFFERDESC));
  dsbd.dwSize        = sizeof(DSBUFFERDESC);
  dsbd.dwFlags       = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN | DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_LOCSOFTWARE;
  dsbd.dwBufferBytes = g_SoundBufferSize;
  dsbd.lpwfxFormat   = &wfex;
  if(FAILED(m_Sound->GetDirectSoundCOM()->CreateSoundBuffer(&dsbd, &pDSBuffer, NULL)))
    return FALSE;

  // query for newer interface
  if(FAILED(pDSBuffer->QueryInterface(IID_IDirectSoundBuffer8, (void**)&m_pDSBuffer))) {
    pDSBuffer->Release();
    return FALSE;
  }

  // Release old object - we have the newer one now
  pDSBuffer->Release();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -