CPI_Player_Output_File.c
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:10k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /*
  2. * CoolPlayer - Blazing fast audio player.
  3. * Copyright (C) 2000-2001 Niek Albers
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19. ////////////////////////////////////////////////////////////////////////////////
  20. #include "stdafx.h"
  21. #include "globals.h"
  22. #include "CPI_Player.h"
  23. #include "CPI_Player_CoDec.h"
  24. #include "CPI_Player_Output.h"
  25. #include "CPI_Equaliser.h"
  26. #include "CPI_Playlist.h"
  27. #include "CPI_PlaylistItem.h"
  28. ////////////////////////////////////////////////////////////////////////////////
  29. //
  30. // This is an output stage that uses the File output. 
  31. //
  32. ////////////////////////////////////////////////////////////////////////////////
  33. // Total buffer size must quantise at 64Kb (because that what Windows gives us anyway!)
  34. #define CPC_OUTPUTBLOCKSIZE 0x8000 // 32k blocks
  35. ////////////////////////////////////////////////////////////////////////////////
  36. //
  37. typedef struct __CPs_OutputContext_File
  38. {
  39. FILE *m_hFile;
  40. CPs_EqualiserModule* m_pEqualiser;
  41. BOOL m_bPaused;
  42. } CPs_OutputContext_File;
  43. //
  44. ////////////////////////////////////////////////////////////////////////////////
  45. void CPP_OMFL_Initialise(CPs_OutputModule* pModule, const CPs_FileInfo* pFileInfo, CP_HEQUALISER hEqualiser);
  46. void CPP_OMFL_Uninitialise(CPs_OutputModule* pModule);
  47. void CPP_OMFL_RefillBuffers(CPs_OutputModule* pModule);
  48. void CPP_OMFL_SetPause(CPs_OutputModule* pModule, const BOOL bPause);
  49. BOOL CPP_OMFL_IsOutputComplete(CPs_OutputModule* pModule);
  50. void CPP_OMFL_Flush(CPs_OutputModule* pModule);
  51. void CPP_OMFL_OnEQChanged(CPs_OutputModule* pModule);
  52. void CPP_OMFL_SetInternalVolume(CPs_OutputModule* pModule, const int iNewVolume);
  53. ////////////////////////////////////////////////////////////////////////////////
  54. //
  55. //
  56. //
  57. void CPI_Player_Output_Initialise_File(CPs_OutputModule* pModule)
  58. {
  59. // This is a one off call to set up the function pointers
  60. pModule->Initialise = CPP_OMFL_Initialise;
  61. pModule->Uninitialise = CPP_OMFL_Uninitialise;
  62. pModule->RefillBuffers = CPP_OMFL_RefillBuffers;
  63. pModule->SetPause = CPP_OMFL_SetPause;
  64. pModule->IsOutputComplete = CPP_OMFL_IsOutputComplete;
  65. pModule->Flush = CPP_OMFL_Flush;
  66. pModule->OnEQChanged = CPP_OMFL_OnEQChanged;
  67. pModule->SetInternalVolume = CPP_OMFL_SetInternalVolume;
  68. pModule->m_pModuleCookie = NULL;
  69. pModule->m_pcModuleName = "WAV File Writer";
  70. pModule->m_pCoDec = NULL;
  71. pModule->m_pEqualiser = NULL;
  72. }
  73. //
  74. //
  75. //
  76. void CPP_OMFL_Initialise(CPs_OutputModule* pModule, const CPs_FileInfo* pFileInfo, CP_HEQUALISER hEqualiser)
  77. {
  78. // This is called when some playing is required.
  79. // Do all allocation here so that we do not hold
  80. // resources while we are just sitting waiting for
  81. // something to happen.
  82. // Create a context
  83. CPs_OutputContext_File* pContext;
  84. CP_ASSERT(pModule->m_pModuleCookie == NULL);
  85. pContext = (CPs_OutputContext_File*)malloc(sizeof(CPs_OutputContext_File));
  86. pModule->m_pModuleCookie = pContext;
  87. CP_TRACE0("File out initialising");
  88. // Create sync object
  89. pModule->m_evtBlockFree = CreateEvent(NULL, FALSE, FALSE, NULL);
  90. // Setup thread prioity to lowest 
  91. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL  );
  92. pModule->m_pEqualiser = hEqualiser;
  93. pContext->m_bPaused=FALSE;
  94. pContext->m_hFile=NULL;
  95. }
  96. //
  97. //
  98. //
  99. void CPP_OMFL_Uninitialise(CPs_OutputModule* pModule)
  100. {
  101. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  102. CP_CHECKOBJECT(pContext);
  103. CP_TRACE0("Wave out shutting down");
  104. SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  105. // If there is a File handle
  106. if(pContext->m_hFile)
  107. {
  108. // Stop any pending playing
  109. fclose(pContext->m_hFile);
  110. pContext->m_hFile=NULL;
  111. // Clean up
  112. DeleteObject(pModule->m_evtBlockFree);
  113. }
  114. free(pContext);
  115. pModule->m_pModuleCookie = NULL;
  116. }
  117. //
  118. //
  119. //
  120. void CPP_OMFL_RefillBuffers(CPs_OutputModule* pModule)
  121. {
  122. BOOL bMoreData;
  123. DWORD dwBufferLength = CPC_OUTPUTBLOCKSIZE;
  124. BYTE lpData[CPC_OUTPUTBLOCKSIZE];
  125. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  126. CP_CHECKOBJECT(pContext);
  127. // Open a file out
  128. if(!pContext->m_hFile)
  129. {
  130. CPs_FileInfo pFileInfo;
  131. CP_HPLAYLISTITEM hCurrent = CPL_GetActiveItem(globals.m_hPlaylist);
  132. const char *pathname = CPLI_GetPath(hCurrent);
  133. char newpath[MAX_PATH];
  134. int rec_rate;
  135. int rec_bits;
  136. UINT temp;
  137. WAVEFORMATEX wfs;
  138. char *dot;
  139. pModule->m_pCoDec->GetFileInfo(pModule->m_pCoDec,&pFileInfo);
  140. rec_rate = pFileInfo.m_iFreq_Hz;
  141. rec_bits = pFileInfo.m_b16bit == TRUE ? 16 : 8;
  142. // saving internet stream
  143. if(strnicmp(pathname,CIC_HTTPHEADER,strlen(CIC_HTTPHEADER)) == 0)
  144. {
  145. strcpy(newpath,"Stream.wav");
  146. pFileInfo.m_iFileLength_Secs = 0xffffffff;
  147. }else
  148. {
  149. // replace the extension with .wav
  150. strcpy(newpath,pathname);
  151. dot = strrchr(newpath,'.');
  152. if(dot)*dot='';
  153. strcat(newpath,".wav");
  154. }
  155. // Trap error
  156. while(!pContext->m_hFile)
  157. {
  158. OPENFILENAME fn;
  159. char    filefilter[] =
  160. "WAV files (*.wav)*.wav"
  161. "All Files (*.*)*.*";
  162. BOOL    returnval;
  163. fn.lStructSize = sizeof(OPENFILENAME);
  164. fn.hwndOwner = (HWND) GetWindowLong(windows.wnd_main, DWL_USER);
  165. fn.hInstance = NULL;
  166. fn.lpstrFilter = filefilter;
  167. fn.lpstrCustomFilter = NULL;
  168. fn.nMaxCustFilter = 0;
  169. fn.nFilterIndex = 0;
  170. fn.lpstrFile = newpath;
  171. fn.nMaxFile = MAX_PATH * 200;
  172. fn.lpstrFileTitle = NULL;
  173. fn.nMaxFileTitle = 0;
  174. fn.lpstrInitialDir = options.last_used_directory;
  175. fn.lpstrTitle = NULL;
  176. fn.Flags = OFN_ENABLESIZING |
  177. OFN_HIDEREADONLY | OFN_EXPLORER;
  178. fn.nFileOffset = 0;
  179. fn.nFileExtension = 0;
  180. fn.lpstrDefExt = NULL;
  181. fn.lCustData = 0;
  182. fn.lpfnHook = NULL;
  183. fn.lpTemplateName = NULL;
  184. returnval = GetSaveFileName(&fn);
  185. if(!returnval) return;
  186. pContext->m_hFile = fopen(fn.lpstrFile,"wb");
  187. if(pContext->m_hFile)break;
  188. }
  189. // Wave header stuff
  190. // prep wave format header
  191. wfs.wFormatTag = WAVE_FORMAT_PCM;
  192. wfs.nChannels = pFileInfo.m_bStereo == TRUE ? 2 : 1;
  193. wfs.nSamplesPerSec = rec_rate;
  194. wfs.nBlockAlign = (short)(rec_bits/8 * wfs.nChannels);
  195. wfs.nAvgBytesPerSec = rec_rate * wfs.nBlockAlign;
  196. wfs.wBitsPerSample = rec_bits;
  197. wfs.cbSize = 0;
  198. // RIFF header block
  199. fwrite("RIFF",4,1,pContext->m_hFile);
  200. temp =  sizeof(wfs) + 20 + (pFileInfo.m_iFileLength_Secs*wfs.nAvgBytesPerSec);
  201. fwrite(&temp,4,1,pContext->m_hFile);
  202. fwrite("WAVE",4,1,pContext->m_hFile);
  203. // 'fmt ' block
  204. fwrite("fmt ",4,1,pContext->m_hFile);
  205. temp = sizeof(wfs);
  206. fwrite(&temp,4,1,pContext->m_hFile);
  207. fwrite(&wfs,sizeof(wfs),1,pContext->m_hFile);
  208. // 'data' block
  209. fwrite("data",4,1,pContext->m_hFile);
  210. temp = pFileInfo.m_iFileLength_Secs*wfs.nAvgBytesPerSec;
  211. fwrite(&temp,4,1,pContext->m_hFile);
  212. }
  213. // Scan ring buffer and fill any empty blocks - any blocks that become free
  214. // while this loop is running will retrigger the event - the worse that can
  215. // happen is that we enter this loop with no blocks free
  216. // Get block from CoDec and then just send it to the device (how easy is this!)
  217. bMoreData = pModule->m_pCoDec->GetPCMBlock(pModule->m_pCoDec, lpData, &dwBufferLength);
  218. // If there is EQ then apply it
  219. {
  220. // Note that the EQ module is initailised and uninitialsed by the engine
  221. CPs_EqualiserModule* pEQModule = (CPs_EqualiserModule*)pModule->m_pEqualiser;
  222. pEQModule->ApplyEQToBlock_Inplace(pEQModule, lpData, dwBufferLength);
  223. }
  224. if(dwBufferLength > 0)
  225. fwrite(lpData,dwBufferLength,1,pContext->m_hFile);
  226. // Nothing to send
  227. if(bMoreData == FALSE)
  228. {
  229. pModule->m_pCoDec->CloseFile(pModule->m_pCoDec);
  230. pModule->m_pCoDec = NULL;
  231. if(pContext->m_hFile) fclose(pContext->m_hFile);
  232. pContext->m_hFile=NULL;
  233. }
  234. if(!pContext->m_bPaused)
  235. SetEvent(pModule->m_evtBlockFree);
  236. }
  237. //
  238. //
  239. //
  240. void CPP_OMFL_SetPause(CPs_OutputModule* pModule, const BOOL bPause)
  241. {
  242. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  243. CP_CHECKOBJECT(pContext);
  244. if(!pContext->m_hFile)
  245. return;
  246. // Toggle pause state
  247. if(bPause == TRUE)
  248. pContext->m_bPaused=TRUE;
  249. else
  250. {
  251. pContext->m_bPaused=FALSE;   
  252. SetEvent(pModule->m_evtBlockFree);
  253. }
  254. }
  255. //
  256. //
  257. //
  258. BOOL CPP_OMFL_IsOutputComplete(CPs_OutputModule* pModule)
  259. {
  260. //    int iBlockIDX;
  261. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  262. CP_CHECKOBJECT(pContext);
  263. if(!pContext->m_hFile)
  264. return TRUE;
  265. return TRUE;
  266. }
  267. //
  268. //
  269. //
  270. void CPP_OMFL_OnEQChanged(CPs_OutputModule* pModule)
  271. {
  272. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  273. CP_CHECKOBJECT(pContext);
  274. return;
  275. }
  276. //
  277. //
  278. //
  279. void CPP_OMFL_Flush(CPs_OutputModule* pModule)
  280. {
  281. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  282. CP_CHECKOBJECT(pContext);
  283. // Stop any pending playing
  284. CP_ASSERT(CPP_OMFL_IsOutputComplete(pModule));
  285. }
  286. //
  287. //
  288. //
  289. void CPP_OMFL_SetInternalVolume(CPs_OutputModule* pModule, const int iNewVolume)
  290. {
  291. CPs_OutputContext_File* pContext = (CPs_OutputContext_File*)pModule->m_pModuleCookie;
  292. int iNewVolume_DWORD;
  293. CP_CHECKOBJECT(pContext);
  294. if(!pContext->m_hFile)
  295. return;
  296. // Clip volume to word
  297. iNewVolume_DWORD = iNewVolume * 656;
  298. if(iNewVolume_DWORD > 0xFFFF)
  299. iNewVolume_DWORD = 0xFFFF;
  300. iNewVolume_DWORD |= (iNewVolume_DWORD<<16);
  301. }
  302. //
  303. //
  304. //