www.pudn.com > NeroSDK-v1.06.zip > WavSrc.cpp


/****************************************************************************** 
|* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
|* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
|* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
|* PARTICULAR PURPOSE. 
|*  
|* Copyright 1995-2005 Nero AG. All Rights Reserved. 
|*----------------------------------------------------------------------------- 
|* PROJECT: Nero Plugin Manager Example 
|* 
|* FILE: WavSrc.cpp 
|* 
|* PURPOSE: Implementation of the wave source class 
******************************************************************************/ 
 
 
#include "stdafx.h" 
#include "WavSrc.h" 
 
// helper functions for file access 
#include "FileHelper.h" 
 
// IURLHolder implementation 
 
bool CWavSrc::SetURL(const char* szURL, IStatus** ppStatus) 
{ 
  RETURN_ERROR(AE_CallNotImplemented); 
} 
 
const char* CWavSrc::GetURL() 
{ 
  return m_csURL; 
} 
 
EURLType CWavSrc::GetType() 
{ 
  return URL_LocalFile; 
} 
 
// IProcess implementation 
 
bool CWavSrc::Start(IStatus** ppStatus) 
{ 
  if(NULL != ppStatus) 
  { 
    *ppStatus = NULL; 
  } 
 
  m_dwCurPos = 0; 
 
  if(SetFilePointer(m_hFile, m_dwDataStart, 0, FILE_BEGIN) != 
                              m_dwDataStart) 
  { 
    RETURN_ERROR(GetLastError()); 
  } 
 
  m_bStarted = true; 
 
  return true; 
} 
 
bool CWavSrc::End(IStatus** ppStatus) 
{ 
  if(NULL != ppStatus) 
  { 
    *ppStatus = NULL; 
  } 
 
  m_bStarted = false; 
 
  return true; 
} 
 
bool CWavSrc::IsInProcess() 
{ 
  return m_bStarted; 
} 
 
// IAudioItem implementation 
 
bool CWavSrc::GetCreator(IAudioComponent** pCreator) 
{ 
  if(!pCreator) 
  { 
    ASSERT(FALSE); 
    return false; 
  } 
 
  *pCreator = m_pCreator; 
 
  (*pCreator)->AddRef(); 
 
  return true; 
} 
 
EAuxFlags CWavSrc::GetAuxFlags() 
{ 
  return SRC_FLAGS; 
} 
 
void CWavSrc::SetAuxFlags(EAuxFlags flags) 
{ 
  // Nothing to do here 
} 
 
// IAudioSource implementation 
 
SWavFormat CWavSrc::GetRawFormat() 
{ 
  SWavFormat format; 
 
  format.m_iSamplesPerSecond= m_format.wf.nSamplesPerSec; 
  format.m_iBitsPerSample       = m_format.wBitsPerSample; 
  format.m_iChannels            = m_format.wf.nChannels; 
 
  return format; 
} 
 
// iBufSize must contain the size in bytes of the buffer pointed by pBuf. 
 
bool CWavSrc::RawRead(BYTE* pBuf, int iBufSize, int* piRead, 
            EAudioRawState& state, 
            IStatus** ppStatus) 
{ 
  if(!(pBuf && iBufSize && piRead)) 
  { 
    RETURN_ERROR(AE_InvalidParameter); 
  } 
 
  if(NULL != ppStatus) 
  { 
    *ppStatus = NULL; 
  } 
 
  state = ERS_None; 
 
  if(m_dwCurPos >= m_dwDataLen) 
  { 
    state = ERS_EndOfFile; 
 
    RETURN_ERROR(AE_EOF); 
  } 
 
  DWORD dwRead = 0; 
 
  DWORD dwRemaining = m_dwDataLen - m_dwCurPos; 
 
  if(iBufSize > (int)dwRemaining) 
  { 
    iBufSize = dwRemaining; 
    state = ERS_EndOfFile; 
  } 
 
  if (!(ReadFile(m_hFile, pBuf, iBufSize, (DWORD*)piRead, NULL) && *piRead)) 
  { 
 
    // That means that the file is over or 
    // something is wrong, in any case 
    // stopping the process 
 
    m_dwCurPos = m_dwDataLen; 
  } 
  else 
  { 
    m_dwCurPos += *piRead; 
  } 
 
  return true; 
} 
 
// Returns free-form text string about the item. 
 
const char* CWavSrc::GetInfo() 
{ 
  if(m_csInfo.IsEmpty()) 
  { 
    m_csInfo.Format("PCM Wav file. Format: %d,  Channels: %d," 
              " Sample rate: %d, Bits per sample: %d", 
              m_format.wf.wFormatTag, 
              m_format.wf.nChannels, 
              m_format.wf.nSamplesPerSec, 
              m_format.wBitsPerSample); 
 
    CString* pcsStrings[] = 
    { &m_csArtist, &m_csTitle, &m_csCopyright, &m_csDate, &m_csComments }; 
 
    char* szarNames[5] = 
    { "Artist", "Title", "Copyright", "Date", "Comments" }; 
 
    for(int i = 0; i < 5; i++) 
    { 
      CString* pcs = pcsStrings[i]; 
 
      if (pcs->IsEmpty()) 
        continue; 
 
      m_csInfo += ",\r\n"; 
 
      CString csTemp; 
      csTemp.Format("%s: %s", szarNames[i], (LPCTSTR)(*pcs)); 
 
      m_csInfo += csTemp; 
    } 
  } 
 
  return m_csInfo; 
} 
 
// Returns the file duration in milliseconds. 
 
ULONGLONG CWavSrc::GetDuration() 
{ 
  return m_qwDuration; 
} 
 
// Returns RAW data length in bytes. 
 
ULONGLONG CWavSrc::GetRawLen() 
{ 
  return m_dwDataLen; 
} 
 
// ISeekable implementation 
 
bool CWavSrc::Seek(ULONGLONG pos, IStatus** ppStatus) 
{ 
  if(NULL == ppStatus) 
  { 
    *ppStatus = NULL; 
  } 
 
  DWORD dwLastPos = SetFilePointer(m_hFile, 0, 0, FILE_CURRENT); 
  DWORD dwNewPos  = (DWORD)(m_dwDataStart + pos * m_iBlockSize); 
 
  bool bRetCode = false; 
 
  if(SetFilePointer(m_hFile, dwNewPos, 0, FILE_BEGIN) != dwNewPos) 
  { 
    SetFilePointer(m_hFile, dwLastPos, 0, FILE_BEGIN); 
  } 
  else 
  { 
    m_dwCurPos = (DWORD)(pos * m_iBlockSize); 
 
    bRetCode = true; 
  } 
 
  if((false == bRetCode) && (NULL != ppStatus)) 
  { 
    *ppStatus = new CStatus(AE_SeekFailed); 
  } 
 
  return bRetCode; 
} 
 
ULONGLONG CWavSrc::GetPos() 
{ 
  return (m_dwCurPos / m_iBlockSize); 
} 
 
ULONGLONG CWavSrc::GetBlockSize() 
{ 
  return m_iBlockSize; 
} 
 
ULONGLONG CWavSrc::GetDataLength() 
{ 
  return (m_dwDataLen / m_iBlockSize); 
} 
 
// ISrcInfoViewerEditor implementation 
 
bool CWavSrc::GetCallback(ISrcInfoCallback** ppCB) 
{ 
  if(NULL == ppCB) 
  { 
    ASSERT(FALSE); 
    return false; 
  } 
 
  *ppCB = m_pCallback; 
 
  if(NULL != *ppCB) 
  { 
    (*ppCB)->AddRef(); 
  } 
 
  return true; 
} 
 
void CWavSrc::SetCallback(ISrcInfoCallback* pNewCallback) 
{ 
  m_pCallback = pNewCallback; 
} 
 
bool CWavSrc::DoModal(IStatus** ppStatus) 
{ 
  CWavSrcInfoDlg dlg(this); 
  m_pAdvInfoDlg = &dlg; 
  dlg.DoModal(); 
  m_pAdvInfoDlg = NULL; 
 
  return true; 
} 
 
bool CWavSrc::CloseModal(IStatus** ppStatus) 
{ 
  if(!(m_pAdvInfoDlg && IsWindow(m_pAdvInfoDlg->m_hWnd))) 
  { 
    return false; 
  } 
 
  m_pAdvInfoDlg->EndDialog(IDCANCEL); 
 
  if (0 != IsWindow(m_pAdvInfoDlg->m_hWnd)) 
  { 
    return true; 
  } 
  else 
  { 
    return false; 
  } 
} 
 
bool CWavSrc::SaveDialogToObject(IStatus** ppStatus) 
{ 
  return false; 
} 
 
bool CWavSrc::SaveObjectToFile(IStatus** ppStatus) 
{ 
  return false; 
} 
 
bool CWavSrc::CanSaveObjectToFile() 
{ 
  return false; 
} 
 
// IInfoReader implementation 
 
const char* CWavSrc::GetTitle() 
{ 
  return m_csTitle; 
} 
 
const char* CWavSrc::GetArtist() 
{ 
  return m_csArtist; 
} 
 
const char* CWavSrc::GetAlbum() 
{ 
  return NULL; 
} 
 
const char* CWavSrc::GetYear() 
{ 
  return NULL; 
} 
 
const char* CWavSrc::GetGenre() 
{ 
  return NULL; 
} 
 
 
CWavSrc::CWavSrc(const char* szURL, IAudioComponent* pCreator, 
          IStatus** ppStatus)  
 
          : CAggregatable (0), 
            m_pCreator    (pCreator), 
            m_hFile       (INVALID_HANDLE_VALUE), 
            m_bRiffChunk  (FALSE), 
            m_bWavChunk   (FALSE), 
            m_dwDataStart (0), 
            m_dwDataLen   (0), 
            m_dwCurPos    (0), 
            m_iBlockSize  (0), 
            m_bOK         (false), 
            m_bStarted    (false) 
{ 
  try 
  { 
    m_csURL = szURL; 
 
    // CreateFile - create or open an object: Consoles, Communications resources  
    //                           Directories (open only), Files etc. 
    // 
    //  LPCTSTR lpFileName -  file name 
    // DWORD dwDesiredAccess - access mode 
    // DWORD dwShareMode - share mode 
    // LPSECURITY_ATTRIBUTES lpSecurityAttributes - [in] Pointer to a SECURITY_ATTRIBUTES 
    //                                              structure that determines whether the returned 
    //                                              handle can be inherited by child processes. 
    //                                              If lpSecurityAttributes is NULL, the handle cannot 
    //                                              be inherited.  
    // DWORD dwCreationDisposition - how to create 
    // DWORD dwFlagsAndAttributes - file attributes 
    // HANDLE hTemplateFile - handle to template file 
 
    m_hFile = CreateFile(szURL, GENERIC_READ, FILE_SHARE_READ, 
              NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); 
 
    if(INVALID_HANDLE_VALUE == m_hFile ) 
    { 
      if(NULL != ppStatus) 
      { 
        *ppStatus = new CStatus(GetLastError()); 
      } 
 
      throw false; 
    } 
 
 
    // Trying to recognize the file 
 
    DWORD dwRead    = 0, 
    dwFileSize  = 0; 
 
    try 
    { 
      ReadMMIO(); 
    } 
    catch(BOOL ) 
    { 
      // If we're here - something is wrong in this file 
      // Sometimes files can contain some wrong information at the end, 
      // but if the rest is OK we can accept such files. 
    } 
 
    // make sure that we are dealing with a valid file format 
 
    if(false == ((INVALID_HANDLE_VALUE != m_hFile)  && 
                 (true == m_bRiffChunk) && 
                 (true == m_bWavChunk) && 
                 (0 != m_dwDataStart) && 
                 (0 != m_dwDataLen))) 
    { 
      if(NULL != ppStatus) 
      { 
        *ppStatus = new CStatus(AE_BadFormat); 
      } 
 
      throw false; 
    } 
 
    // make sure that we are dealing with a valid wave format 
 
    if(false == (((8 == m_format.wBitsPerSample) || 
                  (16 == m_format.wBitsPerSample)) && 
 
                 ((1 == m_format.wf.nChannels) || 
                  (2 == m_format.wf.nChannels)) && 
   
                 ((m_format.wf.nSamplesPerSec) >= 1000 && 
                  (m_format.wf.nSamplesPerSec <= 100000)))) 
    { 
      if(NULL != ppStatus) 
      { 
        *ppStatus = new CStatus(AE_BadFormat); 
      } 
 
      throw false; 
    } 
     
    // Calculating the file duration 
 
    m_iBlockSize = (m_format.wBitsPerSample / BITS_PER_BYTE) * 
                        m_format.wf.nChannels; 
 
    m_qwDuration = (ULONGLONG)m_dwDataLen * (ULONGLONG)1000 / 
                  m_format.wf.nAvgBytesPerSec; 
  } 
  catch(bool ) 
  { 
    // Error occured 
 
    return; 
  } 
 
  m_bOK = true; 
} 
 
CWavSrc::~CWavSrc() 
{ 
  if(m_hFile != INVALID_HANDLE_VALUE) 
  { 
    CloseHandle(m_hFile); 
  } 
} 
 
HANDLE CWavSrc::GetFileHandle() 
{ 
  return m_hFile; 
} 
 
PCMWAVEFORMAT CWavSrc::GetWavSrcFormat() 
{ 
  return m_format; 
} 
 
HRESULT CWavSrc::ReadMMIO() 
{ 
  // Convert the CString URL to LPTSTR 
 
  LPTSTR lpsz = new TCHAR[m_csURL.GetLength()+1]; 
  _tcscpy(lpsz, m_csURL); 
 
 
  // MM I/O handle for the WAVE 
  HMMIO         hmmio;  
 
  // Open the file with the appropriate multimedia function 
 
  hmmio = mmioOpen(lpsz, NULL, MMIO_ALLOCBUF | MMIO_READ ); 
 
  // Free the temporay pointer 
 
  delete lpsz; 
 
  // Make sure that the file could be opened 
   
  if( NULL != hmmio ) 
  { 
    // Use in opening a WAVE file 
    MMCKINFO      ckRiff;    
 
    // Use for subchunks 
    MMCKINFO      ck;       
 
    // Search for the first chunk 
    if( ( 0 != mmioDescend( hmmio, &ckRiff, NULL, 0 ) ) ) 
    { 
      return E_FAIL; 
    } 
 
    // Make sure this is a valid wave file 
     
    if( (ckRiff.ckid != FOURCC_RIFF) || (ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E'))) 
    { 
      return E_FAIL;  
    } 
 
    // If we got here, we can be sure that there is a riff chunk, and the type is WAVE 
     
    m_bRiffChunk = true; 
    m_bWavChunk = true; 
 
    // Search the input file for for the 'fmt ' chunk. 
 
    ck.ckid = mmioFOURCC('f', 'm', 't', ' '); 
    if( 0 != mmioDescend( hmmio, &ck, &ckRiff, MMIO_FINDCHUNK)) 
    { 
      return E_FAIL; 
    } 
 
    // Expect the 'fmt' chunk to be at least as large as ; 
    // if there are extra parameters at the end, we'll ignore them 
 
    if( ck.cksize < (LONG) sizeof(PCMWAVEFORMAT)) 
    { 
     return E_FAIL; 
    } 
 
    // Read the 'fmt ' chunk into m_format 
 
    if( mmioRead( hmmio, (HPSTR) &m_format, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT)) 
    { 
      return E_FAIL; 
    } 
 
    if( m_format.wf.wFormatTag == WAVE_FORMAT_PCM ) 
    { 
      // Seek to the data 
 
      if( -1 == mmioSeek( hmmio, ckRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET)) 
      { 
          return E_FAIL; 
      } 
 
      // Search the input file for the 'data' chunk. 
 
      ck.ckid = mmioFOURCC('d', 'a', 't', 'a'); 
      if( 0 != mmioDescend( hmmio, &ck, &ckRiff, MMIO_FINDCHUNK)) 
      { 
        return E_FAIL; 
      } 
 
      // store offset and size of the data 
 
      m_dwDataStart = ck.dwDataOffset; 
      m_dwDataLen = ck.cksize; 
    } 
    else 
    { 
      // Wrong format  
 
      return E_FAIL; 
    } 
 
    // Close the file 
 
    mmioClose( hmmio, 0 ); 
 
    return S_OK; 
  } 
  else 
  { 
    // File could not be openend 
    return E_FAIL; 
  } 
}