SOUNDINT.CPP 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. ** Command & Conquer Red Alert(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. ** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
  20. ***************************************************************************
  21. * *
  22. * Project Name : Westwood 32 bit Library *
  23. * *
  24. * File Name : SOUNDINT.CPP *
  25. * *
  26. * Programmer : Phil W. Gorrow *
  27. * *
  28. * Start Date : June 23, 1995 *
  29. * *
  30. * Last Update : June 28, 1995 [PWG] *
  31. * *
  32. * This module contains all of the functions that are used within our *
  33. * sound interrupt. They are stored in a seperate module because memory *
  34. * around these functions must be locked or they will cause a read to *
  35. * be generated while in an interrupt. *
  36. * *
  37. *-------------------------------------------------------------------------*
  38. * Functions: *
  39. * Simple_Copy -- Copyies 1 or 2 source chuncks to a dest *
  40. * Sample_Copy -- Copies sound data from source format to raw format. *
  41. * DigiCallback -- Low level double buffering handler. *
  42. * save_my_regs -- Inline function which will save assembly regs *
  43. * restore_my_regs -- Inline function which will restore saved registes *
  44. * Audio_Add_Long_To_Pointer -- Adds an offset to a ptr casted void *
  45. * Init_Locked_Data -- Initializes sound driver locked data *
  46. * Audio_Mem_Set -- Quick see routine to set memory to a value *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. /*=========================================================================*/
  49. /* The following PRIVATE functions are in this file: */
  50. /*=========================================================================*/
  51. /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  52. #pragma pack(4)
  53. #define WIN32
  54. #ifndef _WIN32 // Denzil 6/2/98 Watcom 11.0 complains without this check
  55. #define _WIN32
  56. #endif // _WIN32
  57. #include <windows.h>
  58. #include <windowsx.h>
  59. #include "dsound.h"
  60. #include <wwstd.h>
  61. #include "soundint.h"
  62. #include "memflag.h"
  63. #include "audio.h"
  64. extern DebugBuffer[];
  65. /***************************************************************************
  66. ** All routines past this point must be locked for the sound driver to **
  67. ** function under a VCPI memory manager. These locks are unnecessary if **
  68. ** the driver does not have to run under windows or does not use virtual **
  69. ** memory. **
  70. ***************************************************************************/
  71. /***************************************************************************
  72. * SIMPLE_COPY -- Copyies 1 or 2 source chuncks to a dest *
  73. * *
  74. * INPUT: *
  75. * *
  76. * OUTPUT: *
  77. * *
  78. * WARNINGS: *
  79. * *
  80. * HISTORY: *
  81. * 06/23/1995 PWG : Created. *
  82. *=========================================================================*/
  83. long Simple_Copy(void ** source, long * ssize, void ** alternate, long * altsize, void **dest, long size)
  84. {
  85. long out = 0; // Number of bytes copied to the destination.
  86. /*
  87. ** It could happen that entering this routine, the source buffer
  88. ** has been exhausted, but the alternate buffer is still valid.
  89. ** Move the alternate into the primary position before proceeding.
  90. */
  91. if (!(*ssize)) {
  92. *source = *alternate;
  93. *ssize = *altsize;
  94. *alternate = NULL;
  95. *altsize = 0;
  96. }
  97. if (*source && *ssize) {
  98. long s; // Scratch length var.
  99. /*
  100. ** Copy as much as possible from the primary source, but no
  101. ** more than the primary source has to offer.
  102. */
  103. s = size;
  104. if (*ssize < s) s = *ssize;
  105. Mem_Copy(*source, *dest, s);
  106. *source = Audio_Add_Long_To_Pointer(*source, s);
  107. *ssize -= s;
  108. *dest = Audio_Add_Long_To_Pointer(*dest, s);
  109. size -= s;
  110. out += s;
  111. /*
  112. ** If the primary source was insufficient to fill the request, then
  113. ** move the alternate into the primary position and try again.
  114. */
  115. if (size) {
  116. *source = *alternate;
  117. *ssize = *altsize;
  118. *alternate = 0;
  119. *altsize = 0;
  120. out += Simple_Copy(source, ssize, alternate, altsize, dest, size);
  121. }
  122. }
  123. return(out);
  124. }
  125. /***********************************************************************************************
  126. * Sample_Copy -- Copies sound data from source format to raw format. *
  127. * *
  128. * This routine is used to copy the sound data (possibly compressed) to the destination *
  129. * buffer in raw format. *
  130. * *
  131. * INPUT: source -- Pointer to the source data (possibly compressed). *
  132. * *
  133. * dest -- Pointer to the destination buffer. *
  134. * *
  135. * size -- The size of the destination buffer. *
  136. * *
  137. * OUTPUT: Returns with the number of bytes placed into the output buffer. This is usually *
  138. * the number of bytes requested except in the case when the source is exhausted. *
  139. * *
  140. * WARNINGS: none *
  141. * *
  142. * HISTORY: *
  143. * 09/03/1994 JLB : Created. *
  144. * 09/04/1994 JLB : Revamped entirely. *
  145. *=============================================================================================*/
  146. #pragma argsused
  147. long Sample_Copy(SampleTrackerType *st, void ** source, long * ssize, void ** alternate, long * altsize, void * dest, long size, SCompressType scomp, void * , short int *)
  148. {
  149. long s;
  150. long datasize = 0; // Output bytes.
  151. switch (scomp) {
  152. default:
  153. case SCOMP_NONE:
  154. datasize = Simple_Copy(source, ssize, alternate, altsize, &dest, size);
  155. break;
  156. case SCOMP_WESTWOOD:
  157. case SCOMP_SOS:
  158. while (size > 0) {
  159. /*
  160. ** The block spans two buffers. It must be copied down to
  161. ** a staging area before it can be decompressed.
  162. */
  163. {
  164. long magic;
  165. unsigned short fsize;
  166. unsigned short dsize;
  167. void *fptr;
  168. void *dptr;
  169. void *mptr;
  170. fptr = &fsize;
  171. dptr = &dsize;
  172. mptr = &magic;
  173. s = Simple_Copy(source, ssize, alternate, altsize, &fptr, sizeof(fsize));
  174. if (s < sizeof(fsize)) {
  175. return datasize;
  176. }
  177. s = Simple_Copy(source, ssize, alternate, altsize, &dptr, sizeof(dsize));
  178. if (s < sizeof(dsize) || size < dsize) {
  179. return datasize;
  180. }
  181. s = Simple_Copy(source, ssize, alternate, altsize, &mptr, sizeof(magic));
  182. if (s < sizeof(magic) || magic != LockedData.MagicNumber) {
  183. return datasize;
  184. }
  185. /*
  186. ** If the frame and uncompressed data size are identical, then this
  187. ** indicates that the frame is not compressed. Just copy it directly
  188. ** to the destination buffer in this case.
  189. */
  190. if (fsize == dsize) {
  191. s = Simple_Copy(source, ssize, alternate, altsize, &dest, fsize);
  192. if (s < dsize) {
  193. return (datasize);
  194. }
  195. } else {
  196. /*
  197. ** The frame was compressed, so copy it to the staging buffer, and then
  198. ** uncompress it into the final destination buffer.
  199. */
  200. fptr = LockedData.UncompBuffer;
  201. s = Simple_Copy(source, ssize, alternate, altsize, &fptr, fsize);
  202. if (s < fsize) {
  203. return (datasize);
  204. }
  205. if (scomp == SCOMP_WESTWOOD) {
  206. Decompress_Frame(LockedData.UncompBuffer, dest, dsize);
  207. } else {
  208. st->sosinfo.lpSource = (char *)LockedData.UncompBuffer;
  209. st->sosinfo.lpDest = (char *)dest;
  210. if (st->sosinfo.wBitSize==16 && st->sosinfo.wChannels==1){
  211. sosCODECDecompressData(&st->sosinfo, dsize);
  212. } else {
  213. General_sosCODECDecompressData(&st->sosinfo, dsize);
  214. }
  215. }
  216. dest = Audio_Add_Long_To_Pointer(dest, dsize);
  217. }
  218. datasize += dsize;
  219. size -= dsize;
  220. }
  221. }
  222. break;
  223. }
  224. return(datasize);
  225. }
  226. extern int Convert_HMI_To_Direct_Sound_Volume(int volume);
  227. /***********************************************************************************************
  228. * maintenance_callback -- routine to service the direct play secondary buffers *
  229. * and other stuff..? *
  230. * *
  231. * *
  232. * INPUT: Nothing *
  233. * *
  234. * OUTPUT: Nothing *
  235. * *
  236. * WARNINGS: None *
  237. * *
  238. * HISTORY: *
  239. * ....Unknown *
  240. * 10/17/95 10:15PM ST : tidied up a tad for direct sound *
  241. *=============================================================================================*/
  242. VOID far __cdecl maintenance_callback(VOID)
  243. {
  244. int index; //index used in for loop
  245. SampleTrackerType *st; //ptr to SampleTracker structure
  246. DWORD play_cursor; //Position that direct sound is reading from
  247. DWORD write_cursor; //Position in buffer that we can write to
  248. int bytes_copied; //Number of bytes copied into the buffer
  249. BOOL write_more; //Flag to set if we need to write more into the buffer
  250. LPVOID play_buffer_ptr; //Beginning of locked area of buffer
  251. LPVOID dummy_buffer_ptr; //Length of locked area in buffer
  252. DWORD lock_length1; //Beginning of second locked area in buffer
  253. DWORD lock_length2; //Length of second locked area in buffer
  254. HRESULT return_code;
  255. //EnterCriticalSection(&GlobalAudioCriticalSection);
  256. st = &LockedData.SampleTracker[0];
  257. for (index = 0; index < MAX_SFX; index++) {
  258. if (st->Active) {
  259. /*
  260. ** General service routine to handle moving small blocks from the
  261. ** source into the direct sound buffers. If the source is
  262. ** compressed, then this will also uncompress it as the copy
  263. ** is performed.
  264. */
  265. if (st->Service && !st->DontTouch ) {
  266. //EnterCriticalSection (&st->AudioCriticalSection);
  267. st->DontTouch = TRUE;
  268. /*
  269. ** Get the current position of the direct sound play cursor within the buffer
  270. */
  271. return_code = st->PlayBuffer->GetCurrentPosition ( &play_cursor , &write_cursor );
  272. /*
  273. ** Check for unusual situations like a focus loss
  274. */
  275. if (return_code != DS_OK){
  276. if (return_code == DSERR_BUFFERLOST){
  277. if (Audio_Focus_Loss_Function){
  278. Audio_Focus_Loss_Function();
  279. }
  280. }
  281. //LeaveCriticalSection(&GlobalAudioCriticalSection);
  282. //LeaveCriticalSection (&st->AudioCriticalSection);
  283. return; //Our app has lost focus or something else nasty has happened
  284. } //so dont update the sound buffers
  285. if (st->MoreSource){
  286. /*
  287. ** If the direct sound read pointer is less than a quarter
  288. ** of a buffer away from the end of the data then copy some
  289. ** more.
  290. */
  291. write_more = FALSE;
  292. if ( play_cursor < (unsigned)st->DestPtr ){
  293. if ( (unsigned)st->DestPtr - (unsigned)play_cursor <= SECONDARY_BUFFER_SIZE/4 ){
  294. write_more=TRUE;
  295. }
  296. } else {
  297. /* The only time that play_cursor can be greater than DestPtr is
  298. ** if we wrote right to the end of the buffer last time and DestPtr
  299. ** looped back to the beginning of the buffer.
  300. ** That being the case, all we have to do is see if play_cursor is
  301. ** within the last 25% of the buffer
  302. */
  303. if ( ( (int)play_cursor > SECONDARY_BUFFER_SIZE*3/4) &&st->DestPtr==0 ){
  304. write_more=TRUE;
  305. }
  306. }
  307. if (write_more){
  308. /*
  309. ** Lock a 1/2 of the direct sound buffer so we can write to it
  310. */
  311. if ( DS_OK== st->PlayBuffer->Lock ( (DWORD)st->DestPtr ,
  312. (DWORD)SECONDARY_BUFFER_SIZE/2,
  313. &play_buffer_ptr,
  314. &lock_length1,
  315. &dummy_buffer_ptr,
  316. &lock_length2,
  317. 0 )){
  318. bytes_copied = Sample_Copy( st,
  319. &st->Source,
  320. &st->Remainder,
  321. &st->QueueBuffer,
  322. &st->QueueSize,
  323. play_buffer_ptr,
  324. SECONDARY_BUFFER_SIZE/4,
  325. st->Compression,
  326. &st->Trailer[0],
  327. &st->TrailerLen);
  328. if ( bytes_copied != (SECONDARY_BUFFER_SIZE/4) ){
  329. /*
  330. ** We must have reached the end of the sample
  331. */
  332. st->MoreSource=FALSE;
  333. memset (((char*)play_buffer_ptr)+bytes_copied ,
  334. 0 ,
  335. (SECONDARY_BUFFER_SIZE/4)-bytes_copied);
  336. /*
  337. ** Clear out an extra area in the buffer ahead of the play cursor
  338. ** to give us a quiet period of grace in which to stop the buffer playing
  339. */
  340. if ( (unsigned)st->DestPtr == SECONDARY_BUFFER_SIZE*3/4 ){
  341. if ( dummy_buffer_ptr && lock_length2 ){
  342. memset (dummy_buffer_ptr , 0 , lock_length2);
  343. }
  344. } else {
  345. memset ((char*)play_buffer_ptr+SECONDARY_BUFFER_SIZE/4 , 0 , SECONDARY_BUFFER_SIZE/4);
  346. }
  347. }
  348. /*
  349. ** Update our pointer into the direct sound buffer
  350. **
  351. */
  352. st->DestPtr = Audio_Add_Long_To_Pointer (st->DestPtr,bytes_copied);
  353. if ( (unsigned)st->DestPtr >= (unsigned)SECONDARY_BUFFER_SIZE ){
  354. st->DestPtr = Audio_Add_Long_To_Pointer (st->DestPtr,(long)-SECONDARY_BUFFER_SIZE);
  355. }
  356. /*
  357. ** Unlock the direct sound buffer
  358. */
  359. st->PlayBuffer->Unlock( play_buffer_ptr,
  360. lock_length1,
  361. dummy_buffer_ptr,
  362. lock_length2);
  363. }
  364. } //write_more
  365. } else { //!more_source
  366. /*
  367. ** no more source to write - check if the buffer play
  368. ** has overrun the end of the sample and stop it if it has
  369. */
  370. if ( ( (play_cursor >= (unsigned)st->DestPtr) && ( ((unsigned)play_cursor - (unsigned)st->DestPtr) <SECONDARY_BUFFER_SIZE/4) ) ||
  371. (!st->OneShot &&( (play_cursor < (unsigned)st->DestPtr) && ( ((unsigned)st->DestPtr - (unsigned)play_cursor) >(SECONDARY_BUFFER_SIZE*3/4) ) )) ){
  372. st->PlayBuffer->Stop();
  373. st->Service = FALSE;
  374. Stop_Sample( index );
  375. }
  376. } //more_source
  377. st->DontTouch = FALSE;
  378. //LeaveCriticalSection (&st->AudioCriticalSection);
  379. }
  380. /*
  381. ** For file streamed samples, fill the queue pointer if needed.
  382. ** This allows for delays in calling the Sound_Callback function.
  383. */
  384. if (!st->DontTouch && !st->QueueBuffer && st->FilePending) {
  385. st->QueueBuffer = Audio_Add_Long_To_Pointer(st->FileBuffer, (long)(st->Odd%LockedData.StreamBufferCount)*(long)LockedData.StreamBufferSize);
  386. st->FilePending--;
  387. st->Odd++;
  388. if (!st->FilePending) {
  389. st->QueueSize = st->FilePendingSize;
  390. } else {
  391. st->QueueSize = LockedData.StreamBufferSize;
  392. }
  393. }
  394. }
  395. /*
  396. ** Advance to the next sample control structure.
  397. */
  398. st++;
  399. }
  400. if (!LockedData._int) {
  401. LockedData._int++;
  402. st = &LockedData.SampleTracker[0];
  403. for (index = 0; index < MAX_SFX; index++) {
  404. /*
  405. ** If there are any samples that require fading, then do so at this
  406. ** time.
  407. */
  408. if (st->Active && st->Reducer && st->Volume) {
  409. //EnterCriticalSection (&st->AudioCriticalSection);
  410. if (st->Reducer >= st->Volume) {
  411. st->Volume = 0;
  412. } else {
  413. st->Volume -= st->Reducer;
  414. }
  415. //st->PlayBuffer->SetVolume (-( ( (32768-st->Volume)*1000) >>15 ) );
  416. if (st->IsScore){
  417. st->PlayBuffer->SetVolume ( Convert_HMI_To_Direct_Sound_Volume( ( LockedData.ScoreVolume*(st->Volume >>7))/256) );
  418. }else{
  419. st->PlayBuffer->SetVolume ( Convert_HMI_To_Direct_Sound_Volume( ( LockedData.SoundVolume*(st->Volume >>7))/256) );
  420. }
  421. //LeaveCriticalSection (&st->AudioCriticalSection);
  422. }
  423. st++;
  424. }
  425. LockedData._int--;
  426. }
  427. //LeaveCriticalSection(&GlobalAudioCriticalSection);
  428. }
  429. /***************************************************************************
  430. * ADD_LONG_TO_POINTER -- Adds an offset to a ptr casted void *
  431. * *
  432. * INPUT: void * ptr - the pointer to add to *
  433. * long size - the size to add to it *
  434. * *
  435. * OUTPUT: void * ptr - the new location it will point to *
  436. * *
  437. * HISTORY: *
  438. * 06/23/1995 PWG : Created. *
  439. *=========================================================================*/
  440. void *Audio_Add_Long_To_Pointer(void const *ptr, long size)
  441. {
  442. return ((void *) ( (char const *) ptr + size));
  443. }
  444. /***************************************************************************
  445. * AUDIO_MEM_SET -- Quick see routine to set memory to a value *
  446. * *
  447. * INPUT: void const * - the memory that needs to be set *
  448. * unsigned char - the value to set the memory to *
  449. * long size - how big an area to set *
  450. * *
  451. * OUTPUT: none *
  452. * *
  453. * HISTORY: *
  454. * 06/28/1995 PWG : Created. *
  455. *=========================================================================*/
  456. void Audio_Mem_Set(void const *ptr, unsigned char value, long size)
  457. {
  458. unsigned char *temp = (unsigned char *)ptr;
  459. for (int lp = 0; lp < size; lp ++) {
  460. *temp++ = value;
  461. }
  462. }