/* Autor: Leandro Bernsmuller (inspirado no exemplo de Omar Santiago)
Controle com DirectSound, carrega e toca sons (WAVs). */



#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
#include "..\princip\defs.h"
#include "sons.h"



/* construtor
**********************************************************/
CSons::CSons ()
{
   for ( DWORD dwcS = 0; dwcS < MAX_SONS; dwcS ++ )
      m_paSom [ dwcS ] = NULL;

   m_poDsound = NULL;
}



/* Aloca
**********************************************************/
void CSons::mCria ( HWND hWnd )
{
   mDestroi ();

   // cria objeto que gera sons (pega interface com DSound)
   if( DirectSoundCreate ( NULL, &m_poDsound, NULL ) != DS_OK ) {
      MSGSTR ( STR_ERRO_CRIAR_DSOUND );
      return;
   }

   // define o nivel de cooperacao
   if( m_poDsound->SetCooperativeLevel ( hWnd, DSSCL_NORMAL ) != DS_OK )
      MSGSTR ( STR_ERRO_CRIAR_DSOUND );
}



/* Desaloca sons
**********************************************************/
void CSons::mDestroi ()
{
   if ( m_poDsound == NULL )
      return;
   
   // desaloca sons
   for ( DWORD dwcS = 0; dwcS < MAX_SONS; dwcS ++ )
      if ( m_paSom [ dwcS ] != NULL ) {
         m_paSom [ dwcS ]->Release ();
         m_paSom [ dwcS ] = NULL;
      }

   // libera interface (objeto principal)
   m_poDsound->Release();
   m_poDsound = NULL;
}



/* Toca um certo som.
dwQual - qual som
dwComo - se for 0 - toca apenas 1 vez
                1 - toca em loop
**********************************************************/
void CSons::mToca ( DWORD dwQual, DWORD dwComo )
{
   // se nao pode tocar som
   if ( m_poDsound == NULL || m_paSom [ dwQual ] == NULL )
      return;

   m_paSom [ dwQual ]->SetCurrentPosition ( 0 );

   switch ( dwComo ) {

      case 0:   // tocar apenas 1 vez
         m_paSom [ dwQual ]->Play ( 0, 0, 0 );
         break;

      case 1:   // tocar em sequencia: termina uma, recomeca
         m_paSom [ dwQual ]->Play ( 0, 0, DSBPLAY_LOOPING );
         break;
   }
}



/* Para de tocar o som
dwQual - qual som parar
**********************************************************/
void CSons::mPara ( DWORD dwQual )
{
   // se nao pode tocar som
   if ( m_poDsound == NULL || m_paSom [ dwQual ] == NULL )
      return;

   m_paSom [ dwQual ]->Stop ();
}



/* Carrega um som de um arquivo WAV.
dwNdxSom - em qual posicao colocar o som (irah identificar o som)
szArq - arquivo com o som
**********************************************************/
void CSons::mCarrega ( DWORD dwNdxSom, char* szArq )
{
   // se nao pode tocar sons
   if ( m_poDsound == NULL )
      return;

   // verifica se jah estah alocado, se sim desaloca para substituir
   if ( m_paSom [ dwNdxSom ] != NULL )
      m_paSom [ dwNdxSom ]->Release ();

   // define qual buffer alocar
   LPDIRECTSOUNDBUFFER
      *pSom = &m_paSom [ dwNdxSom ];
      
   // abre arquivo WAV
   HMMIO
      stArqWav;
   stArqWav = mmioOpen ( szArq, 0, MMIO_READ | MMIO_ALLOCBUF );
   if ( stArqWav == NULL ) {
      char
         szMsg [ 500 ];
      sprintf ( szMsg, STR_ERRO_ARQUIVO_NAO_ENCONTRADO, szArq );
      MSGSTR ( szMsg );
      return;
   }
   
   // procura cabecalho com "wave" no arquivo
   MMCKINFO
      stInfo;
   memset ( &stInfo, 0, sizeof ( MMCKINFO ) );
   stInfo.fccType = mmioFOURCC ( 'W', 'A', 'V', 'E' );
   mmioDescend ( stArqWav, &stInfo, 0, MMIO_FINDRIFF );

   // procura "fmt "
   MMCKINFO
      stInfoDest;
   memset ( &stInfoDest, 0, sizeof ( MMCKINFO ) );
   stInfoDest.fccType = mmioFOURCC ( 'f', 'm', 't', ' ' );
   mmioDescend ( stArqWav, &stInfoDest, &stInfo, 0 );

   // le formato
   WAVEFORMATEX
      stWavForm;
   mmioRead ( stArqWav, (char*) &stWavForm, sizeof ( stWavForm ) );
   if ( stWavForm.wFormatTag != WAVE_FORMAT_PCM ) {
      MSGSTR ( STR_ERRO_FORMATO_WAV );
      return;
   }

   // procura dados
   mmioAscend ( stArqWav, &stInfoDest, 0 );
   stInfoDest.ckid = mmioFOURCC ( 'd', 'a', 't', 'a');
   mmioDescend ( stArqWav, &stInfoDest, &stInfo, MMIO_FINDCHUNK );

   // aloca buffer para som
   DSBUFFERDESC
      pMemSom;
   memset ( &pMemSom, 0, sizeof ( DSBUFFERDESC ) );
   pMemSom.dwSize =  sizeof ( DSBUFFERDESC );
   pMemSom.dwFlags = DSBCAPS_CTRLDEFAULT;
   pMemSom.dwBufferBytes = stInfoDest.cksize;
   pMemSom.lpwfxFormat = &stWavForm;
   if ( ( m_poDsound->CreateSoundBuffer ( &pMemSom, & ( *pSom ), NULL ) ) != DS_OK ) {
      MSGSTR ( STR_ERRO_ALOCAR_WAV );
      return;
   }
   
   // copia dados para buffer do SirectSound
   void
      *pvTrans1 = NULL,
      *pvTrans2 = NULL;
   DWORD
      dwCompr1,
      dwCompr2;

   (*pSom)->Lock ( 0, stInfoDest.cksize, &pvTrans1, &dwCompr1,
                                         &pvTrans2, &dwCompr2, 0 );
   if ( pvTrans1 > 0 )
      mmioRead ( stArqWav, (char*) pvTrans1, dwCompr1 );
   if ( pvTrans2 > 0 )
      mmioRead ( stArqWav, (char*) pvTrans2, dwCompr2 );

   (*pSom)->Unlock ( pvTrans1, dwCompr1, pvTrans2, dwCompr2 );

   // fecha arquivo
   mmioClose ( stArqWav, 0 );
}
