WavSrc.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. /******************************************************************************
  2. |* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. |* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. |* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. |* PARTICULAR PURPOSE.
  6. |*
  7. |* Copyright 1995-2005 Nero AG. All Rights Reserved.
  8. |*-----------------------------------------------------------------------------
  9. |* PROJECT: Nero Plugin Manager Example
  10. |*
  11. |* FILE: WavSrc.cpp
  12. |*
  13. |* PURPOSE: Implementation of the wave source class
  14. ******************************************************************************/
  15. #include "stdafx.h"
  16. #include "WavSrc.h"
  17. // helper functions for file access
  18. #include "FileHelper.h"
  19. // IURLHolder implementation
  20. bool CWavSrc::SetURL(const char* szURL, IStatus** ppStatus)
  21. {
  22. RETURN_ERROR(AE_CallNotImplemented);
  23. }
  24. const char* CWavSrc::GetURL()
  25. {
  26. return m_csURL;
  27. }
  28. EURLType CWavSrc::GetType()
  29. {
  30. return URL_LocalFile;
  31. }
  32. // IProcess implementation
  33. bool CWavSrc::Start(IStatus** ppStatus)
  34. {
  35. if(NULL != ppStatus)
  36. {
  37. *ppStatus = NULL;
  38. }
  39. m_dwCurPos = 0;
  40. if(SetFilePointer(m_hFile, m_dwDataStart, 0, FILE_BEGIN) !=
  41. m_dwDataStart)
  42. {
  43. RETURN_ERROR(GetLastError());
  44. }
  45. m_bStarted = true;
  46. return true;
  47. }
  48. bool CWavSrc::End(IStatus** ppStatus)
  49. {
  50. if(NULL != ppStatus)
  51. {
  52. *ppStatus = NULL;
  53. }
  54. m_bStarted = false;
  55. return true;
  56. }
  57. bool CWavSrc::IsInProcess()
  58. {
  59. return m_bStarted;
  60. }
  61. // IAudioItem implementation
  62. bool CWavSrc::GetCreator(IAudioComponent** pCreator)
  63. {
  64. if(!pCreator)
  65. {
  66. ASSERT(FALSE);
  67. return false;
  68. }
  69. *pCreator = m_pCreator;
  70. (*pCreator)->AddRef();
  71. return true;
  72. }
  73. EAuxFlags CWavSrc::GetAuxFlags()
  74. {
  75. return SRC_FLAGS;
  76. }
  77. void CWavSrc::SetAuxFlags(EAuxFlags flags)
  78. {
  79. // Nothing to do here
  80. }
  81. // IAudioSource implementation
  82. SWavFormat CWavSrc::GetRawFormat()
  83. {
  84. SWavFormat format;
  85. format.m_iSamplesPerSecond= m_format.wf.nSamplesPerSec;
  86. format.m_iBitsPerSample = m_format.wBitsPerSample;
  87. format.m_iChannels = m_format.wf.nChannels;
  88. return format;
  89. }
  90. // iBufSize must contain the size in bytes of the buffer pointed by pBuf.
  91. bool CWavSrc::RawRead(BYTE* pBuf, int iBufSize, int* piRead,
  92. EAudioRawState& state,
  93. IStatus** ppStatus)
  94. {
  95. if(!(pBuf && iBufSize && piRead))
  96. {
  97. RETURN_ERROR(AE_InvalidParameter);
  98. }
  99. if(NULL != ppStatus)
  100. {
  101. *ppStatus = NULL;
  102. }
  103. state = ERS_None;
  104. if(m_dwCurPos >= m_dwDataLen)
  105. {
  106. state = ERS_EndOfFile;
  107. RETURN_ERROR(AE_EOF);
  108. }
  109. DWORD dwRead = 0;
  110. DWORD dwRemaining = m_dwDataLen - m_dwCurPos;
  111. if(iBufSize > (int)dwRemaining)
  112. {
  113. iBufSize = dwRemaining;
  114. state = ERS_EndOfFile;
  115. }
  116. if (!(ReadFile(m_hFile, pBuf, iBufSize, (DWORD*)piRead, NULL) && *piRead))
  117. {
  118. // That means that the file is over or
  119. // something is wrong, in any case
  120. // stopping the process
  121. m_dwCurPos = m_dwDataLen;
  122. }
  123. else
  124. {
  125. m_dwCurPos += *piRead;
  126. }
  127. return true;
  128. }
  129. // Returns free-form text string about the item.
  130. const char* CWavSrc::GetInfo()
  131. {
  132. if(m_csInfo.IsEmpty())
  133. {
  134. m_csInfo.Format("PCM Wav file. Format: %d, Channels: %d,"
  135. " Sample rate: %d, Bits per sample: %d",
  136. m_format.wf.wFormatTag,
  137. m_format.wf.nChannels,
  138. m_format.wf.nSamplesPerSec,
  139. m_format.wBitsPerSample);
  140. CString* pcsStrings[] =
  141. { &m_csArtist, &m_csTitle, &m_csCopyright, &m_csDate, &m_csComments };
  142. char* szarNames[5] =
  143. { "Artist", "Title", "Copyright", "Date", "Comments" };
  144. for(int i = 0; i < 5; i++)
  145. {
  146. CString* pcs = pcsStrings[i];
  147. if (pcs->IsEmpty())
  148. continue;
  149. m_csInfo += ",\r\n";
  150. CString csTemp;
  151. csTemp.Format("%s: %s", szarNames[i], (LPCTSTR)(*pcs));
  152. m_csInfo += csTemp;
  153. }
  154. }
  155. return m_csInfo;
  156. }
  157. // Returns the file duration in milliseconds.
  158. ULONGLONG CWavSrc::GetDuration()
  159. {
  160. return m_qwDuration;
  161. }
  162. // Returns RAW data length in bytes.
  163. ULONGLONG CWavSrc::GetRawLen()
  164. {
  165. return m_dwDataLen;
  166. }
  167. // ISeekable implementation
  168. bool CWavSrc::Seek(ULONGLONG pos, IStatus** ppStatus)
  169. {
  170. if(NULL == ppStatus)
  171. {
  172. *ppStatus = NULL;
  173. }
  174. DWORD dwLastPos = SetFilePointer(m_hFile, 0, 0, FILE_CURRENT);
  175. DWORD dwNewPos = (DWORD)(m_dwDataStart + pos * m_iBlockSize);
  176. bool bRetCode = false;
  177. if(SetFilePointer(m_hFile, dwNewPos, 0, FILE_BEGIN) != dwNewPos)
  178. {
  179. SetFilePointer(m_hFile, dwLastPos, 0, FILE_BEGIN);
  180. }
  181. else
  182. {
  183. m_dwCurPos = (DWORD)(pos * m_iBlockSize);
  184. bRetCode = true;
  185. }
  186. if((false == bRetCode) && (NULL != ppStatus))
  187. {
  188. *ppStatus = new CStatus(AE_SeekFailed);
  189. }
  190. return bRetCode;
  191. }
  192. ULONGLONG CWavSrc::GetPos()
  193. {
  194. return (m_dwCurPos / m_iBlockSize);
  195. }
  196. ULONGLONG CWavSrc::GetBlockSize()
  197. {
  198. return m_iBlockSize;
  199. }
  200. ULONGLONG CWavSrc::GetDataLength()
  201. {
  202. return (m_dwDataLen / m_iBlockSize);
  203. }
  204. // ISrcInfoViewerEditor implementation
  205. bool CWavSrc::GetCallback(ISrcInfoCallback** ppCB)
  206. {
  207. if(NULL == ppCB)
  208. {
  209. ASSERT(FALSE);
  210. return false;
  211. }
  212. *ppCB = m_pCallback;
  213. if(NULL != *ppCB)
  214. {
  215. (*ppCB)->AddRef();
  216. }
  217. return true;
  218. }
  219. void CWavSrc::SetCallback(ISrcInfoCallback* pNewCallback)
  220. {
  221. m_pCallback = pNewCallback;
  222. }
  223. bool CWavSrc::DoModal(IStatus** ppStatus)
  224. {
  225. CWavSrcInfoDlg dlg(this);
  226. m_pAdvInfoDlg = &dlg;
  227. dlg.DoModal();
  228. m_pAdvInfoDlg = NULL;
  229. return true;
  230. }
  231. bool CWavSrc::CloseModal(IStatus** ppStatus)
  232. {
  233. if(!(m_pAdvInfoDlg && IsWindow(m_pAdvInfoDlg->m_hWnd)))
  234. {
  235. return false;
  236. }
  237. m_pAdvInfoDlg->EndDialog(IDCANCEL);
  238. if (0 != IsWindow(m_pAdvInfoDlg->m_hWnd))
  239. {
  240. return true;
  241. }
  242. else
  243. {
  244. return false;
  245. }
  246. }
  247. bool CWavSrc::SaveDialogToObject(IStatus** ppStatus)
  248. {
  249. return false;
  250. }
  251. bool CWavSrc::SaveObjectToFile(IStatus** ppStatus)
  252. {
  253. return false;
  254. }
  255. bool CWavSrc::CanSaveObjectToFile()
  256. {
  257. return false;
  258. }
  259. // IInfoReader implementation
  260. const char* CWavSrc::GetTitle()
  261. {
  262. return m_csTitle;
  263. }
  264. const char* CWavSrc::GetArtist()
  265. {
  266. return m_csArtist;
  267. }
  268. const char* CWavSrc::GetAlbum()
  269. {
  270. return NULL;
  271. }
  272. const char* CWavSrc::GetYear()
  273. {
  274. return NULL;
  275. }
  276. const char* CWavSrc::GetGenre()
  277. {
  278. return NULL;
  279. }
  280. CWavSrc::CWavSrc(const char* szURL, IAudioComponent* pCreator,
  281. IStatus** ppStatus)
  282. : CAggregatable (0),
  283. m_pCreator (pCreator),
  284. m_hFile (INVALID_HANDLE_VALUE),
  285. m_bRiffChunk (FALSE),
  286. m_bWavChunk (FALSE),
  287. m_dwDataStart (0),
  288. m_dwDataLen (0),
  289. m_dwCurPos (0),
  290. m_iBlockSize (0),
  291. m_bOK (false),
  292. m_bStarted (false)
  293. {
  294. try
  295. {
  296. m_csURL = szURL;
  297. // CreateFile - create or open an object: Consoles, Communications resources
  298. // Directories (open only), Files etc.
  299. //
  300. // LPCTSTR lpFileName - file name
  301. // DWORD dwDesiredAccess - access mode
  302. // DWORD dwShareMode - share mode
  303. // LPSECURITY_ATTRIBUTES lpSecurityAttributes - [in] Pointer to a SECURITY_ATTRIBUTES
  304. // structure that determines whether the returned
  305. // handle can be inherited by child processes.
  306. // If lpSecurityAttributes is NULL, the handle cannot
  307. // be inherited.
  308. // DWORD dwCreationDisposition - how to create
  309. // DWORD dwFlagsAndAttributes - file attributes
  310. // HANDLE hTemplateFile - handle to template file
  311. m_hFile = CreateFile(szURL, GENERIC_READ, FILE_SHARE_READ,
  312. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
  313. if(INVALID_HANDLE_VALUE == m_hFile )
  314. {
  315. if(NULL != ppStatus)
  316. {
  317. *ppStatus = new CStatus(GetLastError());
  318. }
  319. throw false;
  320. }
  321. // Trying to recognize the file
  322. DWORD dwRead = 0,
  323. dwFileSize = 0;
  324. try
  325. {
  326. ReadMMIO();
  327. }
  328. catch(BOOL )
  329. {
  330. // If we're here - something is wrong in this file
  331. // Sometimes files can contain some wrong information at the end,
  332. // but if the rest is OK we can accept such files.
  333. }
  334. // make sure that we are dealing with a valid file format
  335. if(false == ((INVALID_HANDLE_VALUE != m_hFile) &&
  336. (true == m_bRiffChunk) &&
  337. (true == m_bWavChunk) &&
  338. (0 != m_dwDataStart) &&
  339. (0 != m_dwDataLen)))
  340. {
  341. if(NULL != ppStatus)
  342. {
  343. *ppStatus = new CStatus(AE_BadFormat);
  344. }
  345. throw false;
  346. }
  347. // make sure that we are dealing with a valid wave format
  348. if(false == (((8 == m_format.wBitsPerSample) ||
  349. (16 == m_format.wBitsPerSample)) &&
  350. ((1 == m_format.wf.nChannels) ||
  351. (2 == m_format.wf.nChannels)) &&
  352. ((m_format.wf.nSamplesPerSec) >= 1000 &&
  353. (m_format.wf.nSamplesPerSec <= 100000))))
  354. {
  355. if(NULL != ppStatus)
  356. {
  357. *ppStatus = new CStatus(AE_BadFormat);
  358. }
  359. throw false;
  360. }
  361. // Calculating the file duration
  362. m_iBlockSize = (m_format.wBitsPerSample / BITS_PER_BYTE) *
  363. m_format.wf.nChannels;
  364. m_qwDuration = (ULONGLONG)m_dwDataLen * (ULONGLONG)1000 /
  365. m_format.wf.nAvgBytesPerSec;
  366. }
  367. catch(bool )
  368. {
  369. // Error occured
  370. return;
  371. }
  372. m_bOK = true;
  373. }
  374. CWavSrc::~CWavSrc()
  375. {
  376. if(m_hFile != INVALID_HANDLE_VALUE)
  377. {
  378. CloseHandle(m_hFile);
  379. }
  380. }
  381. HANDLE CWavSrc::GetFileHandle()
  382. {
  383. return m_hFile;
  384. }
  385. PCMWAVEFORMAT CWavSrc::GetWavSrcFormat()
  386. {
  387. return m_format;
  388. }
  389. HRESULT CWavSrc::ReadMMIO()
  390. {
  391. // Convert the CString URL to LPTSTR
  392. LPTSTR lpsz = new TCHAR[m_csURL.GetLength()+1];
  393. _tcscpy(lpsz, m_csURL);
  394. // MM I/O handle for the WAVE
  395. HMMIO hmmio;
  396. // Open the file with the appropriate multimedia function
  397. hmmio = mmioOpen(lpsz, NULL, MMIO_ALLOCBUF | MMIO_READ );
  398. // Free the temporay pointer
  399. delete lpsz;
  400. // Make sure that the file could be opened
  401. if( NULL != hmmio )
  402. {
  403. // Use in opening a WAVE file
  404. MMCKINFO ckRiff;
  405. // Use for subchunks
  406. MMCKINFO ck;
  407. // Search for the first chunk
  408. if( ( 0 != mmioDescend( hmmio, &ckRiff, NULL, 0 ) ) )
  409. {
  410. return E_FAIL;
  411. }
  412. // Make sure this is a valid wave file
  413. if( (ckRiff.ckid != FOURCC_RIFF) || (ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E')))
  414. {
  415. return E_FAIL;
  416. }
  417. // If we got here, we can be sure that there is a riff chunk, and the type is WAVE
  418. m_bRiffChunk = true;
  419. m_bWavChunk = true;
  420. // Search the input file for for the 'fmt ' chunk.
  421. ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
  422. if( 0 != mmioDescend( hmmio, &ck, &ckRiff, MMIO_FINDCHUNK))
  423. {
  424. return E_FAIL;
  425. }
  426. // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
  427. // if there are extra parameters at the end, we'll ignore them
  428. if( ck.cksize < (LONG) sizeof(PCMWAVEFORMAT))
  429. {
  430. return E_FAIL;
  431. }
  432. // Read the 'fmt ' chunk into m_format
  433. if( mmioRead( hmmio, (HPSTR) &m_format, sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
  434. {
  435. return E_FAIL;
  436. }
  437. if( m_format.wf.wFormatTag == WAVE_FORMAT_PCM )
  438. {
  439. // Seek to the data
  440. if( -1 == mmioSeek( hmmio, ckRiff.dwDataOffset + sizeof(FOURCC), SEEK_SET))
  441. {
  442. return E_FAIL;
  443. }
  444. // Search the input file for the 'data' chunk.
  445. ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  446. if( 0 != mmioDescend( hmmio, &ck, &ckRiff, MMIO_FINDCHUNK))
  447. {
  448. return E_FAIL;
  449. }
  450. // store offset and size of the data
  451. m_dwDataStart = ck.dwDataOffset;
  452. m_dwDataLen = ck.cksize;
  453. }
  454. else
  455. {
  456. // Wrong format
  457. return E_FAIL;
  458. }
  459. // Close the file
  460. mmioClose( hmmio, 0 );
  461. return S_OK;
  462. }
  463. else
  464. {
  465. // File could not be openend
  466. return E_FAIL;
  467. }
  468. }