AUD_Windows.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  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 3 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, see <http://www.gnu.org/licenses/>.
  17. */
  18. //----------------------------------------------------------------------------
  19. //
  20. // Westwood Studios Pacific.
  21. //
  22. // Confidential Information
  23. // Copyright (C) 2001 - All Rights Reserved
  24. //
  25. //----------------------------------------------------------------------------
  26. //
  27. // Project: WPAudio
  28. //
  29. // Module: AUD
  30. //
  31. // File name: AUD_Windows.cpp
  32. //
  33. // Created: 5/09/01
  34. //
  35. //----------------------------------------------------------------------------
  36. //----------------------------------------------------------------------------
  37. // Includes
  38. //----------------------------------------------------------------------------
  39. #define WIN32_LEAN_AND_MEAN
  40. #include <windows.h>
  41. #include <mmreg.h>
  42. #include <wpaudio/thread.h>
  43. #include <wpaudio/memory.h>
  44. #include <wpaudio/Source.h>
  45. #include <wsys/File.h>
  46. #include <wpaudio/device.h>
  47. #include <wpaudio/profiler.h>
  48. #include <wpaudio/win32.h>
  49. // 'assignment within condition expression'.
  50. #pragma warning(disable : 4706)
  51. //----------------------------------------------------------------------------
  52. // Externals
  53. //----------------------------------------------------------------------------
  54. //----------------------------------------------------------------------------
  55. // Defines
  56. //----------------------------------------------------------------------------
  57. //----------------------------------------------------------------------------
  58. // Private Types
  59. //----------------------------------------------------------------------------
  60. struct _aud_thread
  61. {
  62. char name[200];
  63. volatile int quit; /* thread must quit */
  64. volatile int count;
  65. volatile int leaving; /* thread is quiting */
  66. volatile TimeStamp interval; /* itask interval */
  67. volatile int running; /* thread is running */
  68. HANDLE handle; /* threads handle (windows) */
  69. void *data;
  70. AUD_ThreadCB *code;
  71. DWORD id; /* thread id (windows) */
  72. CRITICAL_SECTION access;
  73. AudioServiceInfo update;
  74. ProfileCPU cpu;
  75. DBG_TYPE()
  76. };
  77. DBG_DECLARE_TYPE ( AUD_Thread )
  78. //----------------------------------------------------------------------------
  79. // Private Data
  80. //----------------------------------------------------------------------------
  81. //----------------------------------------------------------------------------
  82. // Public Data
  83. //----------------------------------------------------------------------------
  84. static HWND audioMainWindowHandle = NULL;
  85. //----------------------------------------------------------------------------
  86. // Private Prototypes
  87. //----------------------------------------------------------------------------
  88. static DWORD WINAPI AUD_service_thread ( VOID *data );
  89. //----------------------------------------------------------------------------
  90. // Private Functions
  91. //----------------------------------------------------------------------------
  92. static DWORD WINAPI AUD_service_thread ( VOID *data )
  93. {
  94. AUD_Thread *thread = (AUD_Thread *) data;
  95. if ( !thread )
  96. {
  97. return 0;
  98. }
  99. AUD_ThreadBeginCriticalSection ( thread );
  100. thread->running = TRUE;
  101. thread->leaving = FALSE;
  102. while ( !thread->quit )
  103. {
  104. if ( thread->code ( thread, thread->data ))
  105. {
  106. AUD_ThreadEndCriticalSection ( thread );
  107. Sleep ( (unsigned long ) thread->interval );
  108. AUD_ThreadBeginCriticalSection ( thread );
  109. }
  110. else
  111. {
  112. AUD_ThreadEndCriticalSection ( thread );
  113. Sleep ( MSECONDS(5));
  114. AUD_ThreadBeginCriticalSection ( thread );
  115. }
  116. thread->count++;
  117. }
  118. AUD_ThreadEndCriticalSection ( thread );
  119. thread->leaving = TRUE;
  120. return 0;
  121. }
  122. //----------------------------------------------------------------------------
  123. // Public Functions
  124. //----------------------------------------------------------------------------
  125. AUD_Thread* AUD_ThreadCreate ( const char *name, AUD_ThreadPriority pri, AUD_ThreadCB *code )
  126. {
  127. AUD_Thread *thread;
  128. ALLOC_STRUCT ( thread, AUD_Thread );
  129. DBG_SET_TYPE ( thread, AUD_Thread );
  130. if ( !name )
  131. {
  132. name = "no name given";
  133. }
  134. strncpy ( thread->name, name, ArrayLen(thread->name));
  135. ArrayEnd(thread->name);
  136. thread->quit = FALSE;
  137. thread->leaving = FALSE;
  138. thread->running = FALSE;
  139. thread->count = 0;
  140. thread->code = code;
  141. AudioServiceInfoInit ( &thread->update );
  142. ProfileCPUInit ( thread->cpu );
  143. InitializeCriticalSection ( &thread->access );
  144. AUD_ThreadSetInterval ( thread, SECONDS(1)/30 );
  145. if ( !(thread->handle = CreateThread ( NULL, 4*1024, AUD_service_thread, thread, 0, &thread->id )))
  146. {
  147. DBGPRINTF (( "ERROR: Failed to create audio thread: '%s'\n", thread->name ));
  148. return NULL;
  149. }
  150. int set;
  151. switch (pri)
  152. {
  153. case AUD_THREAD_PRI_NORMAL:
  154. set = TRUE;
  155. break;
  156. case AUD_THREAD_PRI_HIGH:
  157. set = SetThreadPriority ( thread->handle, THREAD_PRIORITY_HIGHEST );
  158. break;
  159. case AUD_THREAD_PRI_REALTIME:
  160. set = SetThreadPriority ( thread->handle, THREAD_PRIORITY_TIME_CRITICAL );
  161. break;
  162. default:
  163. DBG_MSGASSERT ( FALSE, ("Illegal thread priority"));
  164. set = TRUE;
  165. }
  166. if ( !set )
  167. {
  168. char buffer[1024];
  169. FormatMessage ( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, buffer, sizeof(buffer), NULL);
  170. DBGPRINTF (( "Unable to change the priority of the thread - %s\n", buffer ));
  171. msg_assert ( FALSE, ( "Unable to change the priority of the thread - %s\n", buffer ));
  172. }
  173. DBGPRINTF (( "Created audio thread: '%s'\n", thread->name ));
  174. return thread;
  175. }
  176. //============================================================================
  177. // AUD_ThreadDestroy
  178. //============================================================================
  179. void AUD_ThreadDestroy ( AUD_Thread *thread )
  180. {
  181. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  182. thread->quit = TRUE;
  183. while ( !thread->leaving );
  184. WaitForSingleObject ( thread->handle, SECONDS(5));
  185. CloseHandle ( thread->handle );
  186. DeleteCriticalSection ( &thread->access );
  187. DBGPRINTF (( "Removed audio thread: '%s'\n", thread->name ));
  188. DBG_INVALIDATE_TYPE ( thread );
  189. AudioMemFree ( thread );
  190. }
  191. //============================================================================
  192. // AUD_ThreadBeginCriticalSection
  193. //============================================================================
  194. void AUD_ThreadBeginCriticalSection ( AUD_Thread *thread)
  195. {
  196. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  197. EnterCriticalSection ( &thread->access );
  198. }
  199. //============================================================================
  200. // AUD_ThreadEndCriticalSection
  201. //============================================================================
  202. void AUD_ThreadEndCriticalSection ( AUD_Thread *thread )
  203. {
  204. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  205. LeaveCriticalSection ( &thread->access );
  206. }
  207. //============================================================================
  208. // AUD_ThreadSetData
  209. //============================================================================
  210. void AUD_ThreadSetData ( AUD_Thread *thread, void *data )
  211. {
  212. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  213. AUD_ThreadBeginCriticalSection ( thread );
  214. thread->data = data;
  215. AUD_ThreadEndCriticalSection ( thread );
  216. }
  217. //============================================================================
  218. // AUD_ThreadSetInterval
  219. //============================================================================
  220. void AUD_ThreadSetInterval ( AUD_Thread *thread, TimeStamp interval )
  221. {
  222. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  223. AUD_ThreadBeginCriticalSection ( thread );
  224. thread->interval = interval;
  225. AudioServiceSetInterval ( &thread->update, thread->interval );
  226. AudioServiceSetMustServiceInterval ( &thread->update, thread->interval*4 );
  227. AudioServiceSetResetInterval ( &thread->update, thread->interval*4 );
  228. AUD_ThreadEndCriticalSection ( thread );
  229. }
  230. //============================================================================
  231. // AUD_ThreadGetInterval
  232. //============================================================================
  233. TimeStamp AUD_ThreadGetInterval ( AUD_Thread *thread )
  234. {
  235. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  236. return thread->interval;
  237. }
  238. //============================================================================
  239. // AUD_ThreadName
  240. //============================================================================
  241. char* AUD_ThreadName( AUD_Thread *thread )
  242. {
  243. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  244. return thread->name;
  245. }
  246. //============================================================================
  247. // AUD_ThreadCPUProfile
  248. //============================================================================
  249. ProfileCPU* AUD_ThreadCPUProfile( AUD_Thread *thread )
  250. {
  251. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  252. return &thread->cpu;
  253. }
  254. //============================================================================
  255. // AUD_ThreadAudioServiceInfo
  256. //============================================================================
  257. AudioServiceInfo* AUD_ThreadServiceInfo( AUD_Thread *thread )
  258. {
  259. DBG_ASSERT_TYPE ( thread, AUD_Thread );
  260. return &thread->update;
  261. }
  262. //============================================================================
  263. // AudioFormatReadWaveFile
  264. //============================================================================
  265. int AudioFormatReadWaveFile ( File *file, AudioFormat *format, int *bytes )
  266. {
  267. RIFF_HEADER rh;
  268. RIFF_CHUNK chunk;
  269. WAVEFORMATEX *wformat = NULL;
  270. int got_format = FALSE;
  271. int result = FALSE;
  272. //int mp3 = FALSE;
  273. DBG_ASSERT_TYPE ( format, AudioFormat );
  274. if ( bytes )
  275. {
  276. *bytes = 0;
  277. }
  278. if ( !file )
  279. {
  280. goto done;
  281. }
  282. file->seek ( 0, File::START );
  283. /* read wav info */
  284. if ( file->read ( &rh, sizeof (rh)) != sizeof(rh) )
  285. {
  286. DBGPRINTF (( "error: cannot read file\n" ));
  287. goto done;
  288. }
  289. if ( rh.form != vRIFF || rh.type != vWAVE )
  290. {
  291. file->seek ( 0, File::START );
  292. result = AudioFormatReadMP3File ( file, format, bytes );
  293. goto done;
  294. }
  295. while ( file->read ( &chunk, sizeof (chunk) ) == sizeof(chunk) )
  296. {
  297. switch ( chunk.type )
  298. {
  299. case vFMT :
  300. if ( chunk.length < sizeof ( WAVEFORMATEX ) )
  301. {
  302. wformat = (WAVEFORMATEX *) malloc ( sizeof(WAVEFORMATEX));
  303. memset ( wformat, 0, sizeof ( WAVEFORMATEX) );
  304. }
  305. else
  306. {
  307. wformat = (WAVEFORMATEX *) malloc ( chunk.length );
  308. memset ( wformat, 0, chunk.length );
  309. }
  310. file->read ( wformat, chunk.length );
  311. wformat->cbSize = (ushort) chunk.length;
  312. got_format = TRUE;
  313. break;
  314. case vDATA:
  315. *bytes = chunk.length;
  316. goto got_data;
  317. default:
  318. file->seek ( chunk.length, File::CURRENT );
  319. break;
  320. }
  321. }
  322. DBGPRINTF (( "no data chunk found\n" ));
  323. goto done;
  324. got_data:
  325. if ( !wformat )
  326. {
  327. DBGPRINTF (( "no format chunk found\n" ));
  328. goto done;
  329. }
  330. format->SampleWidth = wformat->wBitsPerSample / 8;
  331. if ( wformat->wFormatTag == WAVE_FORMAT_IMA_ADPCM )
  332. {
  333. format->cdata.adpcm.BlockSize = wformat->nBlockAlign;
  334. format->Compression = AUDIO_COMPRESS_IMA_ADPCM;
  335. format->SampleWidth = 2;
  336. }
  337. else if ( wformat->wFormatTag == WAVE_FORMAT_ADPCM )
  338. {
  339. ADPCMWAVEFORMAT *aformat = (ADPCMWAVEFORMAT *)wformat;
  340. if ( aformat->wNumCoef != 7 && memcmp ( aformat->aCoef, MSADPCM_StdCoef, sizeof ( MSADPCM_StdCoef )) )
  341. {
  342. //currently we only support MS ADPCM using the standard coef table
  343. goto done;
  344. }
  345. format->cdata.adpcm.BlockSize = wformat->nBlockAlign;
  346. format->Compression = AUDIO_COMPRESS_MS_ADPCM;
  347. format->SampleWidth = 2;
  348. }
  349. else if ( wformat->wFormatTag == WAVE_FORMAT_PCM )
  350. {
  351. format->Compression = AUDIO_COMPRESS_NONE;
  352. }
  353. else if ( wformat->wFormatTag == WAVE_FORMAT_MPEGLAYER3 )
  354. {
  355. result = AudioFormatReadMP3File ( file, format, NULL );
  356. goto done;
  357. }
  358. else
  359. {
  360. goto done;
  361. }
  362. format->Channels = wformat->nChannels;
  363. format->BytesPerSecond = wformat->nAvgBytesPerSec;
  364. format->Rate = wformat->nSamplesPerSec;
  365. format->Flags = mAUDIO_FORMAT_PCM;
  366. AudioFormatUpdate ( format );
  367. result = TRUE;
  368. done:
  369. if ( wformat )
  370. {
  371. free ( wformat );
  372. }
  373. return result;
  374. }
  375. //============================================================================
  376. // WindowsDebugPrint
  377. //============================================================================
  378. void WindowsDebugPrint( const char * lpOutputString )
  379. {
  380. OutputDebugStringA ( lpOutputString );
  381. }
  382. //============================================================================
  383. // AudioSetWindowsHandle
  384. //============================================================================
  385. void AudioSetWindowsHandle ( HWND hwnd )
  386. {
  387. audioMainWindowHandle = hwnd;
  388. }
  389. //============================================================================
  390. // AudioGetWindowsHandle
  391. //============================================================================
  392. HWND AudioGetWindowsHandle ( void )
  393. {
  394. return audioMainWindowHandle;
  395. }