SOUNDINT.BAK 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  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. #include "soundint.h"
  54. //#include "mem.h"
  55. /***************************************************************************
  56. ** All routines past this point must be locked for the sound driver to **
  57. ** function under a VCPI memory manager. These locks are unnecessary if **
  58. ** the driver does not have to run under windows or does not use virtual **
  59. ** memory. **
  60. ***************************************************************************/
  61. /***************************************************************************
  62. * SAVE_MY_REGS -- Inline function which will save assembly regs *
  63. * *
  64. * *
  65. * *
  66. * INPUT: none *
  67. * *
  68. * OUTPUT: none *
  69. * *
  70. * HISTORY: *
  71. * 06/23/1995 PWG : Created. *
  72. *=========================================================================*/
  73. #pragma aux save_my_regs = \
  74. "pushfd" \
  75. "pushad" \
  76. "push ds" \
  77. "push es" \
  78. "push fs" \
  79. "push gs" \
  80. "push ds" \
  81. "pop es";
  82. #pragma aux enable = \
  83. "sti";
  84. #pragma aux disable = \
  85. "cli";
  86. /***************************************************************************
  87. * RESTORE_MY_REGS -- Inline function which will restore saved registers *
  88. * *
  89. * INPUT: none *
  90. * *
  91. * OUTPUT: none *
  92. * *
  93. * WARNINGS: *
  94. * *
  95. * HISTORY: *
  96. * 06/23/1995 PWG : Created. *
  97. *=========================================================================*/
  98. #pragma aux restore_my_regs = \
  99. "pop gs" \
  100. "pop fs" \
  101. "pop es" \
  102. "pop ds" \
  103. "popad" \
  104. "popfd";
  105. /***************************************************************************
  106. * SIMPLE_COPY -- Copyies 1 or 2 source chuncks to a dest *
  107. * *
  108. * INPUT: *
  109. * *
  110. * OUTPUT: *
  111. * *
  112. * WARNINGS: *
  113. * *
  114. * HISTORY: *
  115. * 06/23/1995 PWG : Created. *
  116. *=========================================================================*/
  117. long Simple_Copy(void ** source, long * ssize, void ** alternate, long * altsize, void **dest, long size)
  118. {
  119. long out = 0; // Number of bytes copied to the destination.
  120. /*
  121. ** It could happen that entering this routine, the source buffer
  122. ** has been exhausted, but the alternate buffer is still valid.
  123. ** Move the alternate into the primary position before proceeding.
  124. */
  125. if (!(*ssize)) {
  126. *source = *alternate;
  127. *ssize = *altsize;
  128. *alternate = NULL;
  129. *altsize = 0;
  130. }
  131. if (*source && *ssize) {
  132. long s; // Scratch length var.
  133. /*
  134. ** Copy as much as possible from the primary source, but no
  135. ** more than the primary source has to offer.
  136. */
  137. s = size;
  138. if (*ssize < s) s = *ssize;
  139. Mem_Copy(*source, *dest, s);
  140. *source = Audio_Add_Long_To_Pointer(*source, s);
  141. *ssize -= s;
  142. *dest = Audio_Add_Long_To_Pointer(*dest, s);
  143. size -= s;
  144. out += s;
  145. /*
  146. ** If the primary source was insufficient to fill the request, then
  147. ** move the alternate into the primary position and try again.
  148. */
  149. if (size) {
  150. *source = *alternate;
  151. *ssize = *altsize;
  152. *alternate = 0;
  153. *altsize = 0;
  154. out += Simple_Copy(source, ssize, alternate, altsize, dest, size);
  155. }
  156. }
  157. return(out);
  158. }
  159. /***********************************************************************************************
  160. * Sample_Copy -- Copies sound data from source format to raw format. *
  161. * *
  162. * This routine is used to copy the sound data (possibly compressed) to the destination *
  163. * buffer in raw format. *
  164. * *
  165. * INPUT: source -- Pointer to the source data (possibly compressed). *
  166. * *
  167. * dest -- Pointer to the destination buffer. *
  168. * *
  169. * size -- The size of the destination buffer. *
  170. * *
  171. * OUTPUT: Returns with the number of bytes placed into the output buffer. This is usually *
  172. * the number of bytes requested except in the case when the source is exhausted. *
  173. * *
  174. * WARNINGS: none *
  175. * *
  176. * HISTORY: *
  177. * 09/03/1994 JLB : Created. *
  178. * 09/04/1994 JLB : Revamped entirely. *
  179. *=============================================================================================*/
  180. #pragma argsused
  181. long Sample_Copy(SampleTrackerType *st, void ** source, long * ssize, void ** alternate, long * altsize, void * dest, long size, SCompressType scomp, void * trailer, WORD *trailersize)
  182. {
  183. long s;
  184. long datasize = 0; // Output bytes.
  185. switch (scomp) {
  186. default:
  187. case SCOMP_NONE:
  188. datasize = Simple_Copy(source, ssize, alternate, altsize, &dest, size);
  189. break;
  190. case SCOMP_WESTWOOD:
  191. case SCOMP_SOS:
  192. while (size > 0) {
  193. /*
  194. ** The block spans two buffers. It must be copied down to
  195. ** a staging area before it can be decompressed.
  196. */
  197. {
  198. long magic;
  199. unsigned short fsize;
  200. unsigned short dsize;
  201. void *fptr;
  202. void *dptr;
  203. void *mptr;
  204. fptr = &fsize;
  205. dptr = &dsize;
  206. mptr = &magic;
  207. s = Simple_Copy(source, ssize, alternate, altsize, &fptr, sizeof(fsize));
  208. if (s < sizeof(fsize)) {
  209. return datasize;
  210. }
  211. s = Simple_Copy(source, ssize, alternate, altsize, &dptr, sizeof(dsize));
  212. if (s < sizeof(dsize) || size < dsize) {
  213. return datasize;
  214. }
  215. s = Simple_Copy(source, ssize, alternate, altsize, &mptr, sizeof(magic));
  216. if (s < sizeof(magic) || magic != LockedData.MagicNumber) {
  217. return datasize;
  218. }
  219. /*
  220. ** If the frame and uncompressed data size are identical, then this
  221. ** indicates that the frame is not compressed. Just copy it directly
  222. ** to the destination buffer in this case.
  223. */
  224. if (fsize == dsize) {
  225. s = Simple_Copy(source, ssize, alternate, altsize, &dest, fsize);
  226. if (s < dsize) {
  227. return (datasize);
  228. }
  229. } else {
  230. /*
  231. ** The frame was compressed, so copy it to the staging buffer, and then
  232. ** uncompress it into the final destination buffer.
  233. */
  234. fptr = LockedData.UncompBuffer;
  235. s = Simple_Copy(source, ssize, alternate, altsize, &fptr, fsize);
  236. if (s < fsize) {
  237. return (datasize);
  238. }
  239. if (scomp == SCOMP_WESTWOOD) {
  240. Decompress_Frame(LockedData.UncompBuffer, dest, dsize);
  241. } else {
  242. st->sosinfo.lpSource = (char *)LockedData.UncompBuffer;
  243. st->sosinfo.lpDest = (char *)dest;
  244. sosCODECDecompressData(&st->sosinfo, dsize);
  245. }
  246. dest = Audio_Add_Long_To_Pointer(dest, dsize);
  247. }
  248. datasize += dsize;
  249. size -= dsize;
  250. }
  251. }
  252. break;
  253. }
  254. return(datasize);
  255. }
  256. VOID far cdecl maintenance_callback(VOID)
  257. {
  258. save_my_regs();
  259. int index;
  260. SampleTrackerType *st;
  261. if (!LockedData._int && LockedData.DigiHandle != -1 && LockedData.ServiceSomething) {
  262. LockedData._int++;
  263. enable();
  264. LockedData.ServiceSomething = FALSE;
  265. st = &LockedData.SampleTracker[0];
  266. for (index = 0; index < LockedData.MaxSamples; index++) {
  267. if (st->Active) {
  268. /*
  269. ** General service routine to handle moving small blocks from the
  270. ** source into the low RAM staging buffers. If the source is
  271. ** compressed, then this will also uncompress it as the copy
  272. ** is performed.
  273. */
  274. if (st->Service) {
  275. if (st->DontTouch) {
  276. LockedData.ServiceSomething = TRUE;
  277. } else {
  278. st->Service = FALSE;
  279. #if(FALSE)
  280. st->DataLength = SFX_MINI_STAGE_BUFFER_SIZE;
  281. #else
  282. st->DataLength = Sample_Copy( st,
  283. &st->Source,
  284. &st->Remainder,
  285. &st->QueueBuffer,
  286. &st->QueueSize,
  287. st->Buffer[st->Index],
  288. SFX_MINI_STAGE_BUFFER_SIZE,
  289. st->Compression,
  290. &st->Trailer[0],
  291. &st->TrailerLen);
  292. #endif
  293. }
  294. }
  295. /*
  296. ** For file streamed samples, fill the queue pointer if needed.
  297. ** This allows for delays in calling the Sound_Callback function.
  298. */
  299. if (!st->DontTouch && !st->QueueBuffer && st->FilePending) {
  300. st->QueueBuffer = Audio_Add_Long_To_Pointer(st->FileBuffer, (long)(st->Odd%LockedData.StreamBufferCount)*(long)LockedData.StreamBufferSize);
  301. st->FilePending--;
  302. st->Odd++;
  303. if (!st->FilePending) {
  304. st->QueueSize = st->FilePendingSize;
  305. } else {
  306. st->QueueSize = LockedData.StreamBufferSize;
  307. }
  308. }
  309. }
  310. /*
  311. ** Advance to the next sample control structure.
  312. */
  313. st++;
  314. }
  315. LockedData._int--;
  316. }
  317. if (!LockedData._int) {
  318. LockedData._int++;
  319. st = &LockedData.SampleTracker[0];
  320. for (index = 0; index < LockedData.MaxSamples; index++) {
  321. /*
  322. ** If there are any samples that require fading, then do so at this
  323. ** time.
  324. */
  325. if (st->Active && st->Reducer && st->Volume) {
  326. if (st->Reducer >= st->Volume) {
  327. st->Volume = 0;
  328. } else {
  329. st->Volume -= st->Reducer;
  330. }
  331. if (st->IsScore) {
  332. sosDIGISetSampleVolume(LockedData.DigiHandle, st->Handle, (st->Volume>>8) * LockedData.ScoreVolume);
  333. } else {
  334. sosDIGISetSampleVolume(LockedData.DigiHandle, st->Handle, (st->Volume>>8) * LockedData.SoundVolume);
  335. }
  336. }
  337. st++;
  338. }
  339. LockedData._int--;
  340. }
  341. restore_my_regs();
  342. }
  343. /***********************************************************************************************
  344. * DigiCallback -- Low level double buffering handler. *
  345. * *
  346. * This routine is called in an interrupt to handle the double *
  347. * buffering of digital audio. This routine is the interface between *
  348. * the buffers maintained by Sound_Callback() and the HMI driver *
  349. * itself. *
  350. * *
  351. * INPUT: driverhandle -- The handle to the HMI driver. *
  352. * *
  353. * callsource -- Code indicating the reason for the callback. *
  354. * *
  355. * sampleid -- The ID number of the sample itself. *
  356. * *
  357. * OUTPUT: none *
  358. * *
  359. * WARNINGS: This is called in an interrupt so it return as quickly as *
  360. * possible. *
  361. * *
  362. * HISTORY: *
  363. * 01/06/1994 JLB : Created. *
  364. *=============================================================================================*/
  365. VOID cdecl far DigiCallback(unsigned int driverhandle, unsigned int callsource, unsigned int sampleid)
  366. {
  367. SampleTrackerType *st;
  368. int index;
  369. /*
  370. ** Find the correct control structure for the handle specified.
  371. */
  372. for (index = 0; index < LockedData.MaxSamples; index++) {
  373. st = &LockedData.SampleTracker[index];
  374. if (st->Active && st->Handle == sampleid) {
  375. break;
  376. }
  377. }
  378. if (index == LockedData.MaxSamples) {
  379. return;
  380. }
  381. if (driverhandle == LockedData.DigiHandle) {
  382. switch (callsource) {
  383. /*
  384. ** The sample is now no longer audible. Don't stop the sample
  385. ** tracking if a servicing is needed. If it is needed then
  386. ** obviously the sample isn't quite done.
  387. */
  388. case _SAMPLE_DONE:
  389. st->Active = FALSE;
  390. if (!st->IsScore) {
  391. // DPMI_Unlock(st->Original, st->OriginalSize);
  392. }
  393. break;
  394. /*
  395. ** The sample is finished processing, but not necessarily finished playing.
  396. */
  397. case _SAMPLE_PROCESSED:
  398. if (st->DataLength && st->Active) {
  399. _SOS_START_SAMPLE start;
  400. long dlength;
  401. dlength = st->DataLength;
  402. st->DataLength = 0;
  403. Audio_Mem_Set(&start, 0, sizeof(start));
  404. start.lpSamplePtr = (LPSTR)st->Buffer[st->Index];
  405. start.dwSampleSize = dlength-1;
  406. start.wSampleFlags = st->Flags;
  407. start.lpCallback = (void cdecl (far *)(unsigned int, unsigned int, unsigned int))&DigiCallback;
  408. start.wLoopCount = 0;
  409. if (st->IsScore) {
  410. start.wVolume = (st->Volume>>8) * LockedData.ScoreVolume;
  411. sosDIGISetSampleVolume(LockedData.DigiHandle, st->Handle, start.wVolume);
  412. } else {
  413. start.wVolume = (st->Volume>>8) * LockedData.SoundVolume;
  414. sosDIGISetSampleVolume(LockedData.DigiHandle, st->Handle, start.wVolume);
  415. }
  416. start.wChannel = st->Stereo;
  417. start.wSampleID = index+1;
  418. start.dwSamplePitchAdd = st->Pitch;
  419. st->Index ^= 1;
  420. if (st->Remainder || st->QueueBuffer || st->Callback || st->FilePending) {
  421. st->Service = TRUE;
  422. LockedData.ServiceSomething = TRUE;
  423. }
  424. sosDIGIContinueSample(LockedData.DigiHandle, st->Handle, &start);
  425. } else {
  426. /*
  427. ** This is necessary because Stop_Sample may screw things
  428. ** up, otherwise. Can't rely on the _SAMPLE_DONE call.
  429. */
  430. st->Active = FALSE;
  431. if (!st->IsScore) {
  432. // DPMI_Unlock(st->Original, st->OriginalSize);
  433. }
  434. }
  435. break;
  436. /*
  437. ** Sample is now looping (not used).
  438. */
  439. case _SAMPLE_LOOPING:
  440. break;
  441. }
  442. }
  443. }
  444. void far HMI_TimerCallback(void)
  445. {
  446. }
  447. /***************************************************************************
  448. * ADD_LONG_TO_POINTER -- Adds an offset to a ptr casted void *
  449. * *
  450. * INPUT: void * ptr - the pointer to add to *
  451. * long size - the size to add to it *
  452. * *
  453. * OUTPUT: void * ptr - the new location it will point to *
  454. * *
  455. * HISTORY: *
  456. * 06/23/1995 PWG : Created. *
  457. *=========================================================================*/
  458. void *Audio_Add_Long_To_Pointer(void const *ptr, long size)
  459. {
  460. return ((void *) ( (char const *) ptr + size));
  461. }
  462. /***************************************************************************
  463. * AUDIO_MEM_SET -- Quick see routine to set memory to a value *
  464. * *
  465. * INPUT: void const * - the memory that needs to be set *
  466. * unsigned char - the value to set the memory to *
  467. * long size - how big an area to set *
  468. * *
  469. * OUTPUT: none *
  470. * *
  471. * HISTORY: *
  472. * 06/28/1995 PWG : Created. *
  473. *=========================================================================*/
  474. void Audio_Mem_Set(void const *ptr, unsigned char value, long size)
  475. {
  476. unsigned char *temp = (unsigned char *)ptr;
  477. for (int lp = 0; lp < size; lp ++) {
  478. *temp++ = value;
  479. }
  480. }