2
0

SOUNDIO.CPP 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467
  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. /* $Id: soundio.cpp 1.41 1994/06/20 15:01:39 joe_bostic Exp $ */
  19. /***********************************************************************************************
  20. ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S **
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Sound Library *
  24. * *
  25. * File Name : SOUND.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : July 22, 1991 *
  30. * *
  31. *---------------------------------------------------------------------------------------------*
  32. * Functions: *
  33. * File_Callback -- called to fill queue buffer for streaming sample *
  34. * Stream_Sample_Volume -- generic streaming sample playback init *
  35. * Stream_Sample -- generic streaming sample playback init *
  36. * File_Stream_Sample -- Streams a sample directly from a file. *
  37. * File_Stream_Preload -- Handles initial proload of a streaming samples *
  38. * File_Stream_Sample_Volume -- Streams a sample directly from a file w/volume. *
  39. * Sound_Callback -- Audio driver callback function. *
  40. * Load_Sample -- Loads a digitized sample into RAM. *
  41. * Load_Sample_Into_Buffer -- Loads a digitized sample into a buffer. *
  42. * Free_Sample -- Frees a previously loaded digitized sample. *
  43. * Sound_End -- Uninitializes the sound driver. *
  44. * Stop_Sample -- Stops any currently playing sampled sound. *
  45. * Sample_Status -- Queries the current playing sample status (if any). *
  46. * Sample_Length -- returns length of a sample in ticks *
  47. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  48. #pragma pack(4)
  49. #include "soundint.h"
  50. #include <dos.h>
  51. #include <mem.h>
  52. #include <stdio.h>
  53. #include <string.h>
  54. #include <direct.h>
  55. #include <stdlib.h>
  56. #include <wwmem.h>
  57. #include <keyboard.h>
  58. #include <file.h>
  59. #include <i86.h>
  60. #include <timer.h>
  61. #pragma pack(1)
  62. #include "audio.h"
  63. #pragma pack(4)
  64. //int Mono_Printf(char const *string, ...);
  65. #include <mono.h>
  66. /*
  67. ** If this is defined, then the streaming audio buffer will be filled
  68. ** to maximum whenever filling is to occur. If undefined, it will fill
  69. ** the streaming buffer in smaller chunks.
  70. */
  71. #define SIMPLE_FILLING
  72. /*
  73. ** This define (if present) enables the simple HMI hardware initialization process.
  74. ** The process does not do auto detection, but rather takes the value directly from
  75. ** the setup program and uses that as the sound card number. The only "detection" it
  76. ** does is to recognized the presence of the card and fetch its settings.
  77. */
  78. #define SIMPLE_HMI_INIT
  79. /*
  80. ** This is the rate that the maintenance callback gets called.
  81. */
  82. #define MAINTENANCE_RATE 60
  83. /*
  84. ** Size of the temporary buffer in XMS/EMS that direct file
  85. ** streaming of sounds will allocate.
  86. */
  87. #define STREAM_BUFFER_SIZE (128L*1024L)
  88. /*
  89. ** Define the number of "StreamBufferSize" blocks that are read in
  90. ** at a minimum when the streaming sample load callback routine
  91. ** is called. We will IGNORE loads that are less that this in order
  92. ** to avoid constant seeking on the CD.
  93. */
  94. #define STREAM_CUSHION_BLOCKS 4
  95. /*
  96. ** This is the maximum size that a sonarc block can be. All sonarc blocks
  97. ** must be either a multiple of this value or a binary root of this value.
  98. */
  99. #define LARGEST_SONARC_BLOCK 2048
  100. //////////////////////////////////////////////////////////////////////////////////////
  101. ////////////////////////////////////// structs ///////////////////////////////////////
  102. static _SOS_CAPABILITIES DigiCaps;
  103. static _SOS_HARDWARE DigiHardware;
  104. static WORD MidiHandle = -1;
  105. static unsigned int far DigiTimer = 0;
  106. static unsigned int far MaintainTimer = 0;
  107. static unsigned int far SystemTimer = 0;
  108. static int Bits_Per_Sample;
  109. VOID *DigiBuffer = NULL;
  110. static BOOL StartingFileStream = FALSE;
  111. short StreamLowImpact = FALSE;
  112. MemoryFlagType StreamBufferFlag = MEM_NORMAL;
  113. int Misc;
  114. SFX_Type SoundType;
  115. Sample_Type SampleType;
  116. int ReverseChannels = FALSE;
  117. /*=========================================================================*/
  118. /* The following PRIVATE functions are in this file: */
  119. /*=========================================================================*/
  120. static BOOL File_Callback(WORD id, WORD *odd, VOID **buffer, LONG *size);
  121. static int cdecl Stream_Sample_Vol(void *buffer, long size, BOOL (*callback)(WORD id, WORD *odd, VOID **buffer, LONG *size), int volume, int handle);
  122. static int cdecl Stream_Sample(void *buffer, long size, BOOL (*callback)(WORD id, WORD *odd, VOID **buffer, LONG *size));
  123. /*= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =*/
  124. /***************************************************************************
  125. * FILE_CALLBACK -- called to fill queue buffer for streaming sample *
  126. * *
  127. * This callback is called whenever the queue buffer playback has begun *
  128. * and another buffer is needed for queuing up. Returns TRUE if there *
  129. * is more data to read from the file. *
  130. * *
  131. * INPUT: WORD id - the sample id number *
  132. * WORD *odd - which sample buffer to put info in *
  133. * VOID **buffer - the buffer pointer to load data into *
  134. * LONG *size - the amount to load *
  135. * *
  136. * OUTPUT: BOOL true if more data to load, FALSE if done loading *
  137. * *
  138. * HISTORY: *
  139. * 07/17/1995 PWG : Created. *
  140. *=========================================================================*/
  141. static BOOL File_Callback(WORD id, WORD *odd, VOID **buffer, LONG *size)
  142. {
  143. SampleTrackerType *st; // Pointer to sample playback control struct.
  144. VOID *ptr; // Pointer to working portion of file buffer.
  145. if (id != -1) {
  146. st = &LockedData.SampleTracker[id];
  147. ptr = st->FileBuffer;
  148. if (ptr) {
  149. /*
  150. ** Move the next pending block into the primary
  151. ** position. Do this only if the queue pointer is
  152. ** null.
  153. */
  154. st->DontTouch = TRUE;
  155. if (!*buffer && st->FilePending) {
  156. *buffer = Add_Long_To_Pointer(ptr, (long)(*odd % LockedData.StreamBufferCount)*(long)LockedData.StreamBufferSize);
  157. st->FilePending--;
  158. *odd = *odd + 1;
  159. if (!st->FilePending) {
  160. *size = st->FilePendingSize;
  161. } else {
  162. *size = LockedData.StreamBufferSize;
  163. }
  164. }
  165. st->DontTouch = FALSE;
  166. maintenance_callback();
  167. /*
  168. ** If the file handle is still valid, then read in the next
  169. ** block and add it to the next pending slot available.
  170. */
  171. if (st->FilePending <
  172. (StreamLowImpact ? (LockedData.StreamBufferCount>>1) : ((LockedData.StreamBufferCount-3))) && st->FileHandle != ERROR) {
  173. int num_empty_buffers;
  174. #ifdef SIMPLE_FILLING
  175. num_empty_buffers = (LockedData.StreamBufferCount-2) - st->FilePending;
  176. #else
  177. //
  178. // num_empty_buffers will be from 1 to StreamBufferCount
  179. //
  180. if (StreamLowImpact) {
  181. num_empty_buffers = MIN((LockedData.StreamBufferCount >> 1)+STREAM_CUSHION_BLOCKS, (LockedData.StreamBufferCount - 2) - st->FilePending);
  182. }
  183. else {
  184. num_empty_buffers = (LockedData.StreamBufferCount - 2) - st->FilePending;
  185. }
  186. #endif
  187. while (num_empty_buffers && st->FileHandle != ERROR) {
  188. int tofill;
  189. long psize;
  190. tofill = (*odd + st->FilePending) % LockedData.StreamBufferCount;
  191. ptr = Add_Long_To_Pointer(st->FileBuffer, (long)tofill * (long)LockedData.StreamBufferSize);
  192. psize = Read_File(st->FileHandle, ptr, LockedData.StreamBufferSize);
  193. /*
  194. ** If less than the requested amount of data was read, this
  195. ** indicates that the source file is exhausted. Flag the source
  196. ** file as closed so that no further reading is attempted.
  197. */
  198. if (psize != LockedData.StreamBufferSize) {
  199. Close_File(st->FileHandle);
  200. st->FileHandle = ERROR;
  201. }
  202. /*
  203. ** If any real data went into the pending buffer, then flag
  204. ** that this buffer is valid.
  205. */
  206. if (psize) {
  207. st->DontTouch = TRUE;
  208. st->FilePendingSize = psize;
  209. st->FilePending++;
  210. st->DontTouch = FALSE;
  211. maintenance_callback();
  212. }
  213. num_empty_buffers--;
  214. }
  215. /*
  216. ** After filling all pending buffers, check to see if the queue buffer
  217. ** is empty. If so, then assign the first available pending buffer to the
  218. ** queue.
  219. */
  220. st->DontTouch = TRUE;
  221. if (!st->QueueBuffer && st->FilePending) {
  222. st->QueueBuffer = Add_Long_To_Pointer(st->FileBuffer, (long)(st->Odd%LockedData.StreamBufferCount)*(long)LockedData.StreamBufferSize);
  223. st->FilePending--;
  224. st->Odd++;
  225. if (!st->FilePending) {
  226. st->QueueSize = st->FilePendingSize;
  227. } else {
  228. st->QueueSize = LockedData.StreamBufferSize;
  229. }
  230. }
  231. st->DontTouch = FALSE;
  232. maintenance_callback();
  233. }
  234. /*
  235. ** If there are no more buffers that the callback routine
  236. ** can slot into the primary position, then signal that
  237. ** no furthur callbacks are needed.
  238. */
  239. if (st->FilePending) {
  240. return(TRUE);
  241. }
  242. }
  243. }
  244. return(FALSE);
  245. }
  246. /***************************************************************************
  247. * STREAM_SAMPLE_VOLUME -- generic streaming sample playback init *
  248. * *
  249. * INPUT: *
  250. * *
  251. * OUTPUT: *
  252. * *
  253. * WARNINGS: *
  254. * *
  255. * HISTORY: *
  256. * 07/17/1995 PWG : Created. *
  257. *=========================================================================*/
  258. static int cdecl Stream_Sample_Vol(void *buffer, long size, BOOL (*callback)(WORD id, WORD *odd, VOID **buffer, LONG *size), int volume, int handle)
  259. {
  260. int playid=-1; // Sample play ID.
  261. SampleTrackerType *st; // Working pointer to sample control structure.
  262. long oldsize; // Copy of original sound size.
  263. AUDHeaderType header;
  264. if (buffer && size && LockedData.DigiHandle != -1) {
  265. /*
  266. ** Start the first section of the sound playing.
  267. */
  268. Mem_Copy(buffer, &header, sizeof(header));
  269. oldsize = header.Size;
  270. header.Size = size-sizeof(header);
  271. Mem_Copy(&header, buffer, sizeof(header));
  272. playid = Play_Sample_Handle(buffer, 0xFF, volume, 0x0, handle);
  273. header.Size = oldsize;
  274. Mem_Copy(&header, buffer, sizeof(header));
  275. /*
  276. ** If the sample actually started playing, then flag this
  277. ** sample as a streaming type and signal for a callback
  278. ** to occur.
  279. */
  280. if (playid != -1) {
  281. st = &LockedData.SampleTracker[playid];
  282. st->Callback = callback;
  283. st->Odd = 0;
  284. }
  285. }
  286. return (playid);
  287. }
  288. /***************************************************************************
  289. * STREAM_SAMPLE -- generic streaming sample playback init *
  290. * *
  291. * INPUT: *
  292. * *
  293. * OUTPUT: *
  294. * *
  295. * WARNINGS: *
  296. * *
  297. * HISTORY: *
  298. * 07/17/1995 PWG : Created. *
  299. *=========================================================================*/
  300. static int cdecl Stream_Sample(void *buffer, long size, BOOL (*callback)(WORD id, WORD *odd, VOID **buffer, LONG *size), int handle)
  301. {
  302. return Stream_Sample_Vol(buffer, size, callback, 0xFF, handle);
  303. }
  304. /***********************************************************************************************
  305. * File_Stream_Sample -- Streams a sample directly from a file. *
  306. * *
  307. * This will take the file specified and play it directly from disk. *
  308. * It performs this by allocating a temporary buffer in XMS/EMS and *
  309. * then keeping this buffer filled by the Sound_Callback() routine. *
  310. * *
  311. * INPUT: filename -- The name of the file to play. *
  312. * *
  313. * OUTPUT: Returns the handle to the sound -- just like Play_Sample(). *
  314. * *
  315. * WARNINGS: The temporary buffer is allocated when this routine is *
  316. * called and then freed when the sound is finished. Keep *
  317. * this in mind. *
  318. * *
  319. * HISTORY: *
  320. * 01/06/1994 JLB : Created. *
  321. *=============================================================================================*/
  322. int File_Stream_Sample(char const *filename, BOOL real_time_start)
  323. {
  324. return File_Stream_Sample_Vol(filename, 0xFF, real_time_start);
  325. }
  326. /***************************************************************************
  327. * FILE_STREAM_PRELOAD -- Handles initial proload of streaming samples *
  328. * *
  329. * This function is called before a sample which streams from disk is *
  330. * started. It can be called to either fill the buffer in small chunks *
  331. * from the call back routine or to fill the entire buffer at once. This *
  332. * is wholely dependant on whether the Loading bit is set within the *
  333. * sample tracker. *
  334. * *
  335. * INPUT: LockedData.SampleTracker * to the header which tracks this samples *
  336. * processing. *
  337. * *
  338. * OUTPUT: *
  339. * *
  340. * WARNINGS: *
  341. * *
  342. * HISTORY: *
  343. * 06/05/1995 PWG : Created. *
  344. *=========================================================================*/
  345. void File_Stream_Preload(int handle)
  346. {
  347. SampleTrackerType *st = &LockedData.SampleTracker[handle];
  348. int fh = st->FileHandle;
  349. int maxnum = (LockedData.StreamBufferCount >> 1) + STREAM_CUSHION_BLOCKS;
  350. void *buffer = st->FileBuffer;
  351. int num;
  352. /*
  353. ** Figure just how much we need to load. If we are doing the load in progress
  354. ** then we will only load two blocks.
  355. */
  356. if (st->Loading) {
  357. num = st->FilePending + 2;
  358. num = MIN(num, maxnum);
  359. } else {
  360. num = maxnum;
  361. }
  362. //printf("Before buffer load!\n");
  363. /*
  364. ** Loop through the blocks and load up the number we need.
  365. */
  366. for (int index = st->FilePending; index < num; index++) {
  367. long s = Read_File(fh, Add_Long_To_Pointer(buffer, (long)index * (long)LockedData.StreamBufferSize), LockedData.StreamBufferSize);
  368. //printf("Reading block of size %d Stream Buffer = %d\n");
  369. if (s) {
  370. st->FilePendingSize = s;
  371. st->FilePending++;
  372. }
  373. if (s < LockedData.StreamBufferSize) break;
  374. }
  375. /*
  376. ** If the last block was incomplete (ie. it didn't completely fill the buffer) or
  377. ** we have now filled up as much of the Streaming Buffer as we need to, then now is
  378. ** the time to kick off the sample.
  379. */
  380. if (st->FilePendingSize < LockedData.StreamBufferSize || index == maxnum) {
  381. //printf("Before Stream Sample Volume!\n");
  382. /*
  383. ** Actually start the sample playing, and don't worry about the file callback
  384. ** it won't be called for a while.
  385. */
  386. {
  387. int old = LockedData.SoundVolume;
  388. int size = (st->FilePending == 1) ? st->FilePendingSize : LockedData.StreamBufferSize;
  389. LockedData.SoundVolume = LockedData.ScoreVolume;
  390. StartingFileStream = TRUE;
  391. Stream_Sample_Vol(buffer, size, File_Callback, st->Volume, handle);
  392. StartingFileStream = FALSE;
  393. LockedData.SoundVolume = old;
  394. }
  395. //printf("After Stream Sample Volume!\n");
  396. /*
  397. ** The Sample is finished loading (if it was loading in small pieces) so record that
  398. ** so that it will now use the active logic in the file call back.
  399. */
  400. st->Loading = FALSE;
  401. /*
  402. ** Decrement the file pending because the first block is already playing thanks
  403. ** to the play sample call above.
  404. */
  405. st->FilePending--;
  406. /*
  407. ** If File pending is now a zero, then we only preloaded one block and there
  408. ** is nothing more to play. So clear the sample tracing structure of the
  409. ** information it no longer needs.
  410. */
  411. if (!st->FilePending) {
  412. st->Odd = 0;
  413. st->QueueBuffer = 0;
  414. st->QueueSize = 0;
  415. st->FilePendingSize = 0;
  416. st->Callback = NULL;
  417. Close_File(fh);
  418. } else {
  419. /*
  420. ** The QueueBuffer counts as an already played block so remove it from the total.
  421. ** Note: We didn't remove it before because there might not have been one.
  422. */
  423. st->FilePending--;
  424. /*
  425. ** When we start loading we need to start past the first two blocks. Why this
  426. ** is called Odd, I haven't got the slightest.
  427. */
  428. st->Odd = 2;
  429. /*
  430. ** If the file pending size is less than the stream buffer, then the last block
  431. ** we loaded was the last block period. So close the file and reset the handle.
  432. */
  433. if (st->FilePendingSize != LockedData.StreamBufferSize) {
  434. Close_File(fh);
  435. st->FileHandle = ERROR;
  436. }
  437. /*
  438. ** The Queue buffer needs to point at the next block to be processed. The size
  439. ** of the queue is dependant on how many more blocks there are.
  440. */
  441. st->QueueBuffer = Add_Long_To_Pointer(buffer, LockedData.StreamBufferSize);
  442. if (!st->FilePending) {
  443. st->QueueSize = st->FilePendingSize;
  444. } else {
  445. st->QueueSize = LockedData.StreamBufferSize;
  446. }
  447. }
  448. }
  449. }
  450. /***********************************************************************************************
  451. * File_Stream_Sample_Vol -- Streams a sample directly from a file. *
  452. * *
  453. * This will take the file specified and play it directly from disk. *
  454. * It performs this by allocating a temporary buffer in XMS/EMS and *
  455. * then keeping this buffer filled by the Sound_Callback() routine. *
  456. * *
  457. * INPUT: filename -- The name of the file to play. *
  458. * *
  459. * OUTPUT: Returns the handle to the sound -- just like Play_Sample(). *
  460. * *
  461. * WARNINGS: The temporary buffer is allocated when this routine is *
  462. * called and then freed when the sound is finished. Keep *
  463. * this in mind. *
  464. * *
  465. * HISTORY: *
  466. * 01/06/1994 JLB : Created. *
  467. *=============================================================================================*/
  468. int File_Stream_Sample_Vol(char const *filename, int volume, BOOL real_time_start)
  469. {
  470. static VOID *buffer = NULL;
  471. SampleTrackerType *st;
  472. int fh;
  473. int handle = -1;
  474. long size;
  475. int index;
  476. if (LockedData.DigiHandle != -1 && filename && Find_File(filename)) {
  477. //printf("Before initialize memory!\n");
  478. /*
  479. ** Make sure all sample tracker structures point to the same
  480. ** upper memory buffer. This allocation only occurs if at
  481. ** least one sample gets "streamed".
  482. */
  483. if (!buffer) {
  484. buffer = Alloc(LockedData.StreamBufferSize * LockedData.StreamBufferCount, (MemoryFlagType)(StreamBufferFlag | MEM_TEMP | MEM_LOCK));
  485. for (index = 0; index < LockedData.MaxSamples; index++) {
  486. LockedData.SampleTracker[index].FileBuffer = buffer;
  487. }
  488. }
  489. /*
  490. ** If after trying to allocate the buffer we still fail then
  491. ** we can stream this sample.
  492. */
  493. if (!buffer) return(-1);
  494. //printf("Before Open File!\n");
  495. /*
  496. ** Lets see if we can sucessfully open up the file. If we can't,
  497. ** then there is no point in going any farther.
  498. */
  499. if ((fh = Open_File(filename, READ)) == -1) {
  500. return (-1);
  501. }
  502. //printf("Before Get Free Handle!\n");
  503. /*
  504. ** Reserve a handle so that we can fill in the sample tracker
  505. ** with the needed information. If we dont get valid handle then
  506. ** we might as well give up.
  507. */
  508. if ((unsigned)(handle = Get_Free_Sample_Handle(0xFF)) >= LockedData.MaxSamples) {
  509. return(-1);
  510. }
  511. /*
  512. ** Now lets get a pointer to the proper sample handler and start
  513. ** our manipulations.
  514. */
  515. st = &LockedData.SampleTracker[handle];
  516. st->IsScore = TRUE;
  517. st->FilePending = 0;
  518. st->FilePendingSize = 0;
  519. st->Loading = real_time_start;
  520. st->Volume = volume;
  521. st->FileHandle = fh;
  522. /*
  523. ** Now that we have setup our initial data properly, let load up
  524. ** the beginning of the sample we intend to stream.
  525. */
  526. //printf("Before Preload!\n");
  527. File_Stream_Preload(handle);
  528. }
  529. return (handle);
  530. }
  531. /***********************************************************************************************
  532. * Sound_Callback -- Audio driver callback function. *
  533. * *
  534. * Maintains the audio buffers. This routine must be called at least *
  535. * 11 times per second or else audio glitches will occur. *
  536. * *
  537. * INPUT: none *
  538. * *
  539. * OUTPUT: none *
  540. * *
  541. * WARNINGS: If this routine is not called often enough then audio *
  542. * glitches will occur. *
  543. * *
  544. * HISTORY: *
  545. * 01/06/1994 JLB : Created. *
  546. *=============================================================================================*/
  547. VOID cdecl __saveregs __loadds Sound_Callback(VOID)
  548. {
  549. int index;
  550. SampleTrackerType *st;
  551. if (LockedData.DigiHandle != -1) {
  552. st = &LockedData.SampleTracker[0];
  553. for (index = 0; index < LockedData.MaxSamples; index++) {
  554. if (st->Loading) {
  555. File_Stream_Preload(index);
  556. } else {
  557. /*
  558. ** General service routine to handle moving small blocks from the
  559. ** source into the low RAM staging buffers.
  560. */
  561. if (st->Active) {
  562. /*
  563. ** Special check to see if the sample is a fading one AND
  564. ** it has faded to silence, then stop it here.
  565. */
  566. if (st->Reducer && !st->Volume) {
  567. Stop_Sample(index);
  568. } else {
  569. /*
  570. ** Fill the queuebuffer if it is currently empty
  571. ** and there is a callback function defined to fill it.
  572. **
  573. ** PWG/CDY & CO: We should be down by at least two blocks
  574. ** before we bother with this
  575. */
  576. if ((!st->QueueBuffer ||
  577. (st->FileHandle != ERROR && st->FilePending < LockedData.StreamBufferCount-3)) &&
  578. st->Callback) {
  579. if (!st->Callback(index, &st->Odd, &st->QueueBuffer, &st->QueueSize)) {
  580. st->Callback = NULL;
  581. }
  582. }
  583. }
  584. } else {
  585. /*
  586. ** This catches the case where a streaming sample gets
  587. ** aborted prematurely because of failure to call the
  588. ** callback function frequently enough. In this case, the
  589. ** sample will be flagged as inactive, but the file handle
  590. ** will not have been closed.
  591. */
  592. if (st->FileHandle != ERROR) {
  593. Close_File(st->FileHandle);
  594. st->FileHandle = ERROR;
  595. }
  596. }
  597. }
  598. /*
  599. ** Advance to the next sample control structure.
  600. */
  601. st++;
  602. }
  603. }
  604. }
  605. /***********************************************************************************************
  606. * Load_Sample -- Loads a digitized sample into RAM. *
  607. * *
  608. * This routine loads a digitized sample into RAM. *
  609. * *
  610. * INPUT: filename -- Name of the sound file to load. *
  611. * *
  612. * OUTPUT: Returns with a pointer to the loaded sound file. This pointer *
  613. * is passed to Play_Sample when playback is desired. *
  614. * *
  615. * WARNINGS: If there is insufficient memory to load the sample, then *
  616. * NULL will be returned. *
  617. * *
  618. * HISTORY: *
  619. * 04/17/1992 JLB : Created. *
  620. * 01/06/1994 JLB : HMI version. *
  621. *=============================================================================================*/
  622. VOID *Load_Sample(char const *filename)
  623. {
  624. void *buffer = NULL;
  625. long size;
  626. int fh;
  627. if (LockedData.DigiHandle == -1 || !filename || !Find_File(filename)) {
  628. return (NULL);
  629. }
  630. fh = Open_File(filename, READ);
  631. if (fh != ERROR) {
  632. size = File_Size(fh)+sizeof(AUDHeaderType);
  633. buffer = Alloc(size, MEM_NORMAL);
  634. if (buffer) {
  635. Sample_Read(fh, buffer, size);
  636. }
  637. Close_File(fh);
  638. Misc = size;
  639. }
  640. return(buffer);
  641. }
  642. /***********************************************************************************************
  643. * Load_Sample_Into_Buffer -- Loads a digitized sample into a buffer. *
  644. * *
  645. * This routine is used to load a digitized sample into a buffer *
  646. * provided by the programmer. This buffer can be in XMS or EMS. *
  647. * *
  648. * INPUT: filename -- The filename to load. *
  649. * *
  650. * buffer -- Pointer to the buffer to load into. *
  651. * *
  652. * size -- The size of the buffer to load into. *
  653. * *
  654. * OUTPUT: Returns the number of bytes actually used in the buffer. *
  655. * *
  656. * WARNINGS: This routine will not overflow the buffer provided. This *
  657. * means that the buffer must be big enough to hold the data *
  658. * or else the sound will be cut short. *
  659. * *
  660. * HISTORY: *
  661. * 01/06/1994 JLB : Created. *
  662. *=============================================================================================*/
  663. long Load_Sample_Into_Buffer(char const *filename, void *buffer, long size)
  664. {
  665. int fh;
  666. /*
  667. ** Verify legality of parameters.
  668. */
  669. if (!buffer || !size || LockedData.DigiHandle == -1 || !filename || !Find_File(filename)) {
  670. return (NULL);
  671. }
  672. fh = Open_File(filename, READ);
  673. if (fh != ERROR) {
  674. size = Sample_Read(fh, buffer, size);
  675. Close_File(fh);
  676. } else {
  677. return(0);
  678. }
  679. return(size);
  680. }
  681. /***********************************************************************************************
  682. * Sample_Read -- Reads sample data from an openned file. *
  683. * *
  684. * This routine reads a sample file. It is presumed that the file is *
  685. * already positioned at the start of the sample. From this, it can *
  686. * determine if it is a VOC or raw data and proceed accordingly. *
  687. * *
  688. * INPUT: fh -- File handle of already openned sample file. *
  689. * *
  690. * buffer -- Pointer to the buffer to load data into. *
  691. * *
  692. * size -- The size of the buffer. *
  693. * *
  694. * OUTPUT: Returns the number of bytes actually used in the buffer. *
  695. * *
  696. * WARNINGS: none *
  697. * *
  698. * HISTORY: *
  699. * 01/06/1994 JLB : Created. *
  700. *=============================================================================================*/
  701. long Sample_Read(int fh, void *buffer, long size)
  702. {
  703. AUDHeaderType RawHeader;
  704. VOID *outbuffer; // Pointer to start of raw data.
  705. long actual_bytes_read; // Actual bytes read in, including header
  706. /*
  707. Conversion formula for TCrate and Hz rate.
  708. TC = 256 - 1m/rate
  709. rate = 1m / (256-TC)
  710. */
  711. if (!buffer || fh == ERROR || size <= sizeof(RawHeader)) return(NULL);
  712. size -= sizeof(RawHeader);
  713. outbuffer = Add_Long_To_Pointer(buffer, sizeof(RawHeader));
  714. actual_bytes_read =
  715. Read_File(fh, &RawHeader, sizeof(RawHeader));
  716. actual_bytes_read +=
  717. Read_File(fh, outbuffer, MIN(size, RawHeader.Size));
  718. Mem_Copy(&RawHeader, buffer, sizeof(RawHeader));
  719. return(actual_bytes_read);
  720. }
  721. /***********************************************************************************************
  722. * Free_Sample -- Frees a previously loaded digitized sample. *
  723. * *
  724. * Use this routine to free the memory allocated by a previous call to *
  725. * Load_Sample. *
  726. * *
  727. * INPUT: sample -- Pointer to the sample to be freed. *
  728. * *
  729. * OUTPUT: none *
  730. * *
  731. * WARNINGS: none *
  732. * *
  733. * HISTORY: *
  734. * 04/17/1992 JLB : Created. *
  735. *=============================================================================================*/
  736. VOID Free_Sample(VOID const *sample)
  737. {
  738. if (sample) Free((void *)sample);
  739. }
  740. BOOL Sound_Init(int sfx, int score, int sample, RateType rate, int bits_per_sample, int max_samples, int reverse_channels)
  741. {
  742. return Audio_Init(sample, -1, -1, -1, rate, bits_per_sample, max_samples, reverse_channels);
  743. }
  744. BOOL Audio_Init(int sample, int address, int inter, int dma, RateType rate, int bits_per_sample, int max_samples, int reverse_channels)
  745. {
  746. int error; // Function error return code.
  747. unsigned int port;
  748. int index;
  749. _SOS_INIT_DRIVER init; // Driver init structure.
  750. Init_Locked_Data();
  751. memset(&LockedData.SampleTracker[0], 0, sizeof(LockedData.SampleTracker));
  752. LockedData.Rate = rate;
  753. Bits_Per_Sample = bits_per_sample;
  754. sosTIMERInitSystem(_TIMER_DOS_RATE, _SOS_DEBUG_NORMAL);
  755. if (TimerSystemOn) {
  756. sosTIMERRegisterEvent(60, &Timer_Interrupt_Func, &SystemTimer);
  757. // TickCount.Start();
  758. } else
  759. sosTIMERRegisterEvent(60, &HMI_TimerCallback, &SystemTimer);
  760. /*
  761. ** Special code to handle the HMI problem with running under Windows.
  762. */
  763. if (/*Operating_System() != OS_DOS ||*/ sample == SAMPLE_NONE) {
  764. return(FALSE);
  765. }
  766. while (sample) {
  767. #ifdef SIMPLE_HMI_INIT
  768. if (address == -1 || inter == -1 || dma == -1) {
  769. error = sosDIGIDetectInit((LPSTR)NULL);
  770. if (error) {
  771. printf("Cannot initialize detection system (%d).\n", error);
  772. Get_Key();
  773. break;
  774. }
  775. error = sosDIGIDetectFindHardware(sample, &DigiCaps, &port);
  776. if (error) {
  777. printf("Cannot find sound card specified.\n");
  778. Get_Key();
  779. break;
  780. }
  781. /*
  782. ** Handle the override for Address, Interrupt, and DMA settings.
  783. */
  784. error = sosDIGIDetectGetSettings(&DigiHardware);
  785. sosDIGIDetectUnInit();
  786. if (error) {
  787. printf("Cannot get sound card settings.\n");
  788. Get_Key();
  789. break;
  790. }
  791. } else {
  792. DigiHardware.wPort = address;
  793. DigiHardware.wIRQ = inter;
  794. DigiHardware.wDMA = dma;
  795. }
  796. #endif
  797. /*
  798. ** Initialize the digi-system and driver.
  799. */
  800. sosDIGIInitSystem((LPSTR)NULL, _SOS_DEBUG_NORMAL);
  801. init.wBufferSize = 1024*8; // Specify the DMA buf size
  802. init.lpBuffer = (LPSTR)NULL;
  803. init.wAllocateBuffer = TRUE;
  804. init.wSampleRate = rate; // Sample playback rate.
  805. init.wParam = 19;
  806. init.dwParam = 0;
  807. init.lpFillHandler = NULL;
  808. init.lpDriverMemory = (LPSTR)NULL;
  809. init.lpTimerMemory = (LPSTR)NULL;
  810. init.wTimerID = _SOS_NORMAL_TIMER;
  811. error = 0;
  812. error = sosDIGIInitDriver( (int)sample, &DigiHardware, &init, &LockedData.DigiHandle);
  813. if (error) {
  814. printf("Unable to initialize the sound driver.\n");
  815. Get_Key();
  816. break;
  817. }
  818. error = 0;
  819. if (sample >= _GUS_8_MONO && sample <= _GUS_16_ST) {
  820. error = sosTIMERRegisterEvent(120, init.lpFillHandler, &DigiTimer);
  821. } else {
  822. error = sosTIMERRegisterEvent(60, init.lpFillHandler, &DigiTimer);
  823. }
  824. if (error) {
  825. printf("Unable to regiser the fill handler.\n");
  826. Get_Key();
  827. sosDIGIUnInitDriver(LockedData.DigiHandle, TRUE, TRUE);
  828. LockedData.DigiHandle = -1;
  829. break;
  830. }
  831. /*
  832. ** Allocate a decompression buffer equal to the size of a SONARC frame
  833. ** block.
  834. */
  835. LockedData.UncompBuffer = Alloc(LARGEST_SONARC_BLOCK + 50, (MemoryFlagType)(MEM_NORMAL|MEM_CLEAR|MEM_LOCK));
  836. LockedData.MaxSamples = max_samples;
  837. /*
  838. ** Allocate private staging buffers for double buffering sound into HMI
  839. ** driver.
  840. */
  841. DigiBuffer = Alloc(2048+(((LONG)LockedData.MaxSamples*2) * (LONG)(SFX_MINI_STAGE_BUFFER_SIZE+SONARC_MARGIN)), (MemoryFlagType)(MEM_NORMAL|MEM_CLEAR|MEM_LOCK));
  842. for (index = 0; index < LockedData.MaxSamples; index++) {
  843. LockedData.SampleTracker[index].Buffer[0] = Add_Long_To_Pointer(DigiBuffer, ((LONG)index*2) * (LONG)(SFX_MINI_STAGE_BUFFER_SIZE+SONARC_MARGIN));
  844. LockedData.SampleTracker[index].Buffer[1] = Add_Long_To_Pointer(DigiBuffer, ((LONG)index*2+1) * (LONG)(SFX_MINI_STAGE_BUFFER_SIZE+SONARC_MARGIN));
  845. LockedData.SampleTracker[index].FileHandle = ERROR;
  846. LockedData.SampleTracker[index].QueueBuffer = NULL;
  847. }
  848. error = sosTIMERRegisterEvent(MAINTENANCE_RATE, (void (__far *)(void))maintenance_callback, &MaintainTimer);
  849. if (error) {
  850. printf("Unable to initialize the maintenance callback.\n");
  851. Get_Key();
  852. sosTIMERRemoveEvent(DigiTimer);
  853. sosDIGIUnInitDriver(LockedData.DigiHandle, TRUE, TRUE);
  854. LockedData.DigiHandle = -1;
  855. break;
  856. }
  857. SoundType = (SFX_Type)sample;
  858. SampleType = (Sample_Type)sample;
  859. ReverseChannels = reverse_channels;
  860. break;
  861. }
  862. return(TRUE);
  863. }
  864. /***********************************************************************************************
  865. * Sound_End -- Uninitializes the sound driver. *
  866. * *
  867. * This routine will uninitialize the sound driver (if any was *
  868. * installed). This routine must be called at program termination *
  869. * time. *
  870. * *
  871. * INPUT: none *
  872. * *
  873. * OUTPUT: none *
  874. * *
  875. * WARNINGS: none *
  876. * *
  877. * HISTORY: *
  878. * 07/23/1991 JLB : Created. *
  879. *=============================================================================================*/
  880. VOID Sound_End(VOID)
  881. {
  882. if (LockedData.DigiHandle != -1) {
  883. sosTIMERRemoveEvent(DigiTimer);
  884. sosTIMERRemoveEvent(MaintainTimer);
  885. sosDIGIUnInitDriver(LockedData.DigiHandle, TRUE, TRUE);
  886. sosDIGIUnInitSystem();
  887. LockedData.DigiHandle = -1;
  888. }
  889. if (DigiBuffer) {
  890. Free(DigiBuffer);
  891. DigiBuffer = 0;
  892. }
  893. if (LockedData.UncompBuffer) {
  894. Free(LockedData.UncompBuffer);
  895. LockedData.UncompBuffer = 0;
  896. }
  897. sosTIMERRemoveEvent(SystemTimer);
  898. sosTIMERUnInitSystem(0);
  899. Unlock_Locked_Data();
  900. }
  901. /***********************************************************************************************
  902. * Stop_Sample -- Stops any currently playing sampled sound. *
  903. * *
  904. * *
  905. * *
  906. * INPUT: *
  907. * *
  908. * OUTPUT: *
  909. * *
  910. * WARNINGS: *
  911. * *
  912. * HISTORY: *
  913. * 06/02/1992 JLB : Created. *
  914. *=============================================================================================*/
  915. VOID Stop_Sample(int handle)
  916. {
  917. if (LockedData.DigiHandle != -1 && (unsigned)handle < LockedData.MaxSamples) {
  918. if (LockedData.SampleTracker[handle].Active || LockedData.SampleTracker[handle].Loading) {
  919. LockedData.SampleTracker[handle].Active = FALSE;
  920. if (!LockedData.SampleTracker[handle].IsScore) {
  921. DPMI_Unlock(LockedData.SampleTracker[handle].Original, LockedData.SampleTracker[handle].OriginalSize);
  922. LockedData.SampleTracker[handle].Original = NULL;
  923. }
  924. LockedData.SampleTracker[handle].Priority = 0;
  925. /*
  926. ** Stop the sample if it is playing.
  927. */
  928. if (!LockedData.SampleTracker[handle].Loading) {
  929. sosDIGIStopSample(LockedData.DigiHandle, LockedData.SampleTracker[handle].Handle);
  930. }
  931. LockedData.SampleTracker[handle].Loading = FALSE;
  932. /*
  933. ** If this is a streaming sample, then close the source file.
  934. */
  935. if (LockedData.SampleTracker[handle].FileHandle != ERROR) {
  936. Close_File(LockedData.SampleTracker[handle].FileHandle);
  937. LockedData.SampleTracker[handle].FileHandle = ERROR;
  938. }
  939. LockedData.SampleTracker[handle].QueueBuffer = NULL;
  940. }
  941. }
  942. }
  943. /***********************************************************************************************
  944. * Sample_Status -- Queries the current playing sample status (if any). *
  945. * *
  946. * *
  947. * *
  948. * INPUT: *
  949. * *
  950. * OUTPUT: *
  951. * *
  952. * WARNINGS: *
  953. * *
  954. * HISTORY: *
  955. * 06/02/1992 JLB : Created. *
  956. *=============================================================================================*/
  957. BOOL Sample_Status(int handle)
  958. {
  959. /*
  960. ** If its an invalid handle or we do not have a sound driver then
  961. ** the sample in question is not playing.
  962. */
  963. if (LockedData.DigiHandle == -1 || (unsigned)handle >= LockedData.MaxSamples) return(FALSE);
  964. /*
  965. ** If the sample is loading, then for all intents and purposes the
  966. ** sample is playing.
  967. */
  968. if (LockedData.SampleTracker[handle].Loading) return(TRUE);
  969. /*
  970. ** If the sample is not active, then it is not playing
  971. */
  972. if (!LockedData.SampleTracker[handle].Active) return(FALSE);
  973. /*
  974. ** If we made it this far, then the Sample is still playing if sos says
  975. ** that it is.
  976. */
  977. return (!sosDIGISampleDone(LockedData.DigiHandle, LockedData.SampleTracker[handle].Handle));
  978. }
  979. BOOL Is_Sample_Playing(void const * sample)
  980. {
  981. int index;
  982. if (!sample) return FALSE;
  983. for (index = 0; index < LockedData.MaxSamples; index++) {
  984. if (LockedData.SampleTracker[index].Original == sample && Sample_Status(index)) {
  985. return (TRUE);
  986. }
  987. }
  988. return (FALSE);
  989. }
  990. VOID Stop_Sample_Playing(void const * sample)
  991. {
  992. int index;
  993. if (sample) {
  994. for (index = 0; index < LockedData.MaxSamples; index++) {
  995. if (LockedData.SampleTracker[index].Original == sample) {
  996. Stop_Sample(index);
  997. break;
  998. }
  999. }
  1000. }
  1001. }
  1002. int Get_Free_Sample_Handle(int priority)
  1003. {
  1004. int id;
  1005. /*
  1006. ** Find a free SFX holding buffer slot.
  1007. */
  1008. for (id = LockedData.MaxSamples - 1; id >= 0; id--) {
  1009. if (!LockedData.SampleTracker[id].Active && !LockedData.SampleTracker[id].Loading) {
  1010. if (!StartingFileStream && LockedData.SampleTracker[id].IsScore) {
  1011. StartingFileStream = TRUE; // Ensures only one channel is kept free for scores.
  1012. continue;
  1013. }
  1014. break;
  1015. }
  1016. }
  1017. if (id < 0) {
  1018. for (id = 0; id < LockedData.MaxSamples; id++) {
  1019. if (LockedData.SampleTracker[id].Priority <= priority) break;
  1020. }
  1021. if (id == LockedData.MaxSamples) {
  1022. return(-1); // Cannot play!
  1023. }
  1024. Stop_Sample(id); // This sample gets clobbered.
  1025. }
  1026. if (id == -1) {
  1027. return -1;
  1028. }
  1029. if (LockedData.SampleTracker[id].FileHandle != ERROR) {
  1030. Close_File(LockedData.SampleTracker[id].FileHandle);
  1031. LockedData.SampleTracker[id].FileHandle = ERROR;
  1032. }
  1033. if (LockedData.SampleTracker[id].Original && !LockedData.SampleTracker[id].IsScore) {
  1034. DPMI_Unlock(LockedData.SampleTracker[id].Original, LockedData.SampleTracker[id].OriginalSize);
  1035. LockedData.SampleTracker[id].Original = NULL;
  1036. }
  1037. LockedData.SampleTracker[id].IsScore = FALSE;
  1038. return(id);
  1039. }
  1040. int Play_Sample(void const *sample, int priority, int volume, signed short panloc)
  1041. {
  1042. return(Play_Sample_Handle(sample, priority, volume, panloc, Get_Free_Sample_Handle(priority)));
  1043. }
  1044. /***********************************************************************************************
  1045. * Play_Sample_Vol -- Plays a digitized sample. *
  1046. * *
  1047. * Use this routine to play a previously loaded digitized sample. *
  1048. * *
  1049. * INPUT: sample -- Sample pointer as returned from Load_Sample. *
  1050. * *
  1051. * volume -- The volume to play (0..255 with 255=loudest). *
  1052. * *
  1053. * OUTPUT: none *
  1054. * *
  1055. * WARNINGS: none *
  1056. * *
  1057. * HISTORY: *
  1058. * 04/17/1992 JLB : Created. *
  1059. * 05/24/1992 JLB : Volume support -- Soundblaster Pro *
  1060. * 04/22/1994 JLB : Multiple sample playback rates. *
  1061. *=============================================================================================*/
  1062. int Play_Sample_Handle(void const *sample, int priority, int volume, signed short panloc, int id)
  1063. {
  1064. AUDHeaderType RawHeader;
  1065. _SOS_START_SAMPLE start;
  1066. SampleTrackerType *st=NULL; // Working pointer to sample tracker structure.
  1067. if (!sample || LockedData.DigiHandle == -1) {
  1068. return(-1);
  1069. }
  1070. if (id == -1) {
  1071. return -1;
  1072. }
  1073. /*
  1074. ** Fetch the control bytes from the start of the sample data.
  1075. */
  1076. Mem_Copy((void *)sample, (void *)&RawHeader, sizeof(RawHeader));
  1077. /*
  1078. ** Prepare the sample tracker structure for processing of this
  1079. ** sample. Fill the structure with data that can be determined
  1080. ** before the sample is started.
  1081. */
  1082. st = &LockedData.SampleTracker[id];
  1083. st->Compression = (SCompressType) ((unsigned char)RawHeader.Compression);
  1084. st->Original = sample;
  1085. st->OriginalSize = RawHeader.Size + sizeof(RawHeader);
  1086. if (!st->IsScore) {
  1087. DPMI_Lock(st->Original, st->OriginalSize);
  1088. }
  1089. st->Priority = priority;
  1090. st->DontTouch = FALSE;
  1091. st->Odd = 0;
  1092. st->Reducer = 0;
  1093. st->Restart = FALSE;
  1094. st->QueueBuffer = NULL;
  1095. st->QueueSize = NULL;
  1096. st->TrailerLen = 0;
  1097. st->Remainder = RawHeader.Size;
  1098. st->Source = Add_Long_To_Pointer((void *)sample, sizeof(RawHeader));
  1099. st->Service = FALSE;
  1100. /*
  1101. ** If the code in question using HMI based compression then we need
  1102. ** to set up for uncompressing it.
  1103. */
  1104. if (st->Compression == SCOMP_SOS) {
  1105. st->sosinfo.wChannels = (RawHeader.Flags & AUD_FLAG_STEREO) ? 2 : 1;
  1106. st->sosinfo.wBitSize = (RawHeader.Flags & AUD_FLAG_16BIT) ? 16 : 8;
  1107. st->sosinfo.dwCompSize = RawHeader.Size;
  1108. st->sosinfo.dwUnCompSize = RawHeader.Size * ( st->sosinfo.wBitSize / 4 );
  1109. sosCODECInitStream(&st->sosinfo);
  1110. }
  1111. /*
  1112. ** Fill in one or both staging buffers if possible.
  1113. */
  1114. _disable();
  1115. // Disable_Timer_Interrupt();
  1116. if (SFX_MINI_STAGE_BUFFER_SIZE ==
  1117. Sample_Copy(st,
  1118. &st->Source,
  1119. &st->Remainder,
  1120. &st->QueueBuffer,
  1121. &st->QueueSize,
  1122. st->Buffer[0],
  1123. SFX_MINI_STAGE_BUFFER_SIZE,
  1124. st->Compression,
  1125. &st->Trailer[0],
  1126. &st->TrailerLen)) {
  1127. st->DataLength = Sample_Copy(st,
  1128. &st->Source,
  1129. &st->Remainder,
  1130. &st->QueueBuffer,
  1131. &st->QueueSize,
  1132. st->Buffer[1],
  1133. SFX_MINI_STAGE_BUFFER_SIZE,
  1134. st->Compression,
  1135. &st->Trailer[0],
  1136. &st->TrailerLen);
  1137. st->Index = 1;
  1138. } else {
  1139. st->Index = 0;
  1140. st->DataLength = 0;
  1141. }
  1142. _enable();
  1143. // Enable_Timer_Interrupt();
  1144. /*
  1145. ** Fill in the HMI start sample structure.
  1146. */
  1147. memset(&start, 0, sizeof(start));
  1148. start.lpSamplePtr = (LPSTR)st->Buffer[0];
  1149. if (st->Index == 1) {
  1150. start.dwSampleSize = SFX_MINI_STAGE_BUFFER_SIZE-1;
  1151. } else {
  1152. start.dwSampleSize = st->DataLength-1;
  1153. }
  1154. start.lpCallback = (void cdecl (far *)(unsigned int, unsigned int, unsigned int))&DigiCallback;
  1155. start.wLoopCount = 0;
  1156. start.wSampleID = id;
  1157. /*
  1158. ** Adjust pitch shifting as necessary so that lower playback
  1159. ** samples can be supported.
  1160. */
  1161. if (RawHeader.Rate != LockedData.Rate) {
  1162. ldiv_t result;
  1163. result = ldiv((long)RawHeader.Rate, LockedData.Rate);
  1164. start.dwSamplePitchAdd = (long)MAKE_LONG((short)result.quot, (short)(((long)result.rem * 0x10000L) / LockedData.Rate));
  1165. start.wSampleFlags |= _PITCH_SHIFT;
  1166. }
  1167. /*
  1168. ** Sample translation flag.
  1169. */
  1170. if (RawHeader.Flags & AUD_FLAG_16BIT) {
  1171. if (Bits_Per_Sample == 8) {
  1172. start.wSampleFlags |= _TRANSLATE16TO8;
  1173. }
  1174. } else {
  1175. if (Bits_Per_Sample == 16) {
  1176. start.wSampleFlags |= _TRANSLATE8TO16;
  1177. }
  1178. }
  1179. /*
  1180. ** Sample stereo flag.
  1181. */
  1182. if (RawHeader.Flags & AUD_FLAG_STEREO) {
  1183. start.wChannel = _INTERLEAVED;
  1184. start.wSampleFlags |= _STEREOTOMONO;
  1185. } else {
  1186. start.wChannel = _CENTER_CHANNEL;
  1187. }
  1188. /*
  1189. ** Sample volume control flags. Always give it volume control because
  1190. ** if not, then future volume control is either ignored or stops the
  1191. ** sample.
  1192. */
  1193. st->Volume = volume << 7;
  1194. start.wVolume = (st->Volume >> 8) * LockedData.SoundVolume;
  1195. start.wSampleFlags |= _VOLUME;
  1196. /*
  1197. ** If we have defined a panning location for the sound driver than
  1198. ** take care of it here. Panning will only work with a stereo driver
  1199. ** and only if the sample is played _CENTER_CHANNEL.
  1200. */
  1201. if ((panloc != 0x0) && (!(RawHeader.Flags & AUD_FLAG_STEREO))) {
  1202. start.wChannel = _CENTER_CHANNEL;
  1203. panloc = ((ReverseChannels) ? ((-panloc) + 0x8000) : ((panloc) + 0x8000));
  1204. start.wSampleFlags |= _PANNING;
  1205. start.wSamplePanLocation= panloc;
  1206. }
  1207. st->Stereo = start.wChannel;
  1208. st->Pitch = start.dwSamplePitchAdd;
  1209. st->Flags = start.wSampleFlags;
  1210. /*
  1211. ** Start the sample playing now.
  1212. */
  1213. _disable(); // NEW
  1214. // Disable_Timer_Interrupt();
  1215. st->Handle = sosDIGIStartSample(LockedData.DigiHandle, &start);
  1216. if (st->Handle == -1) {
  1217. id = -1;
  1218. } else {
  1219. /*
  1220. ** Fill in the sample tracker structure with those values that are
  1221. ** determined AFTER the sample starts.
  1222. */
  1223. st->Active = TRUE;
  1224. }
  1225. _enable(); // NEW
  1226. // Enable_Timer_Interrupt();
  1227. return(id);
  1228. }
  1229. int Set_Sound_Vol(int volume)
  1230. {
  1231. int old;
  1232. old = LockedData.SoundVolume;
  1233. LockedData.SoundVolume = volume & 0xFF;
  1234. return(old);
  1235. }
  1236. int Set_Score_Vol(int volume)
  1237. {
  1238. int old;
  1239. old = LockedData.ScoreVolume;
  1240. LockedData.ScoreVolume = volume & 0xFF;
  1241. return(old);
  1242. }
  1243. VOID Fade_Sample(int handle, int ticks)
  1244. {
  1245. if (Sample_Status(handle)) {
  1246. if (!ticks || LockedData.SampleTracker[handle].Loading) {
  1247. Stop_Sample(handle);
  1248. } else {
  1249. SampleTrackerType * st;
  1250. st = &LockedData.SampleTracker[handle];
  1251. st->Reducer = (st->Volume / ticks)+1;
  1252. }
  1253. }
  1254. }
  1255. int Get_Digi_Handle(void)
  1256. {
  1257. return(LockedData.DigiHandle);
  1258. }
  1259. /***************************************************************************
  1260. * SAMPLE_LENGTH -- returns length of a sample in ticks *
  1261. * *
  1262. * INPUT: void const *sample - pointer to the sample to get length *
  1263. * of. *
  1264. * *
  1265. * OUTPUT: long - length of the sample in ticks (60/sec) *
  1266. * *
  1267. * HISTORY: *
  1268. * 07/05/1995 PWG : Created. *
  1269. *=========================================================================*/
  1270. long Sample_Length(void const *sample)
  1271. {
  1272. AUDHeaderType RawHeader;
  1273. if (!sample) return(0);
  1274. Mem_Copy((void *)sample, (void *)&RawHeader, sizeof(RawHeader));
  1275. long time = RawHeader.UncompSize;
  1276. /*
  1277. ** If the sample is a 16 bit sample, then it will take only half
  1278. ** as long to play.
  1279. */
  1280. if (RawHeader.Flags & AUD_FLAG_16BIT) {
  1281. time >>= 1;
  1282. }
  1283. /*
  1284. ** If the sample is a stereo sample, then it will take only half
  1285. ** as long to play.
  1286. */
  1287. if (RawHeader.Flags & AUD_FLAG_STEREO) {
  1288. time >>= 1;
  1289. }
  1290. if (RawHeader.Rate/60) {
  1291. time /= (RawHeader.Rate/60);
  1292. }
  1293. return(time);
  1294. }