SampleMaster.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // SampleMaster.cpp
  19. //
  20. // History:
  21. // 01/29/97 JMI Started.
  22. //
  23. // 02/02/97 JMI Added functions to determine if samples are playing.
  24. //
  25. // 02/04/97 JMI Updated to new rspGetResource().
  26. //
  27. // 02/10/97 JMI rspReleaseResource() now takes a ptr to a ptr.
  28. //
  29. // 02/10/97 JMI Increased NUM_CHANNELS from 32 to 64.
  30. //
  31. // 02/18/97 JMI Made ms_resmgr g_resmgrSamples and made it globally
  32. // accessible.
  33. //
  34. // 03/07/97 JMI Now PlaySample() returns the RSnd* it played the sample
  35. // on which can be querried and/or passed to AbortSample().
  36. //
  37. // 03/07/97 JMI Decreased play buffer size to 4096.
  38. //
  39. // 03/24/97 JMI Now, PlaySample(), if RSnd::Play() fails, does not
  40. // complain. RSnd::Play() will complain anyways.
  41. //
  42. // 04/22/97 JMI AbortSample() was causing the RSnd ptr passed to the done
  43. // callback to no longer contain a sample. This means the
  44. // resource had to released immediately after the call to
  45. // the abort.
  46. //
  47. // 04/29/97 JMI Added g_smidNil, a way of specifying to SampleMaster that
  48. // it should not bother with this sample. This is useful
  49. // for things that require a sample ID.
  50. //
  51. // 05/09/97 JMI PlaySample() now takes optional looping parameters which
  52. // are passed directly on to RSnd::Play().
  53. //
  54. // 06/04/97 JMI Added AbortAllSamples() which aborts all currently
  55. // playing samples.
  56. //
  57. // 06/11/97 BRH Added PlaySampleThenPurge function which is a convenient
  58. // way to pass a new purge parameter to PlaySample. It then
  59. // uses the new resource manager's ReleaseAndPurge function
  60. // rather than the regular release. This will allow you to
  61. // purge single samples that you don't want to stay in the
  62. // cache.
  63. //
  64. // 06/12/97 JMI PlaySample() function was only using
  65. // rspReleaseAndPurgeResource() if an error occurred
  66. // during startup.
  67. // Added an rspReleaseAndPurgeResource() in the SndDoneCall
  68. // so that when the sample was actually done playing, it
  69. // would release and purge.
  70. //
  71. // 06/16/97 JMI Added a version of IsSamplePlaying() that allows one to
  72. // specify the sound channel to check.
  73. // Also, removed ASSERTs on psnd in AbortSample().
  74. //
  75. // 06/17/97 JMI PlaySample() (and PlaySampleThenPurge() ) now always
  76. // return an RSnd* (even if they fail) and also, optionally,
  77. // can return the length of the sample to play.
  78. //
  79. // 07/01/97 JMI Added g_smidMenuItemChange.
  80. //
  81. // 07/09/97 JMI Added g_smidTitle.
  82. //
  83. // 07/13/97 JMI Removed 'sound/' from all sample names. Now that these
  84. // sounds are stored in folders named for their sample type
  85. // it seemed rhetorical and annoying.
  86. //
  87. // 07/15/97 JRD Added support for local sound volume by channel and
  88. // category
  89. //
  90. // 07/17/97 JRD Moved sound category information out of RSND and into
  91. // sample master for a more appropriate app vs rspix division.
  92. //
  93. // 07/17/97 JRD Provided a backwards compatible PlaySample stub so old code
  94. // will simply compile.
  95. //
  96. // 07/17/97 JMI Changed VolumeCode to SampleMaster::SoundInstance. Trying
  97. // to make it a generic playing sample identifier.
  98. // Also, PlaySample() no longer returns a ptr to the RSnd
  99. // reducing the chances we rely on sound for synch.
  100. //
  101. // 07/17/97 JRD Added functionality to calculate volume based on 3d
  102. // distance.
  103. //
  104. // 07/18/97 JMI Added StopLoopingSample() to reduce the need for
  105. // GetInstanceChannel().
  106. //
  107. // 07/18/97 JMI Got rid of bogus immitation PlaySample functions.
  108. // Now there is one PlaySample() function. Also, you now
  109. // MUST specify a category and you don't have to specify a
  110. // SoundInstance ptr to specify a volume.
  111. //
  112. // 07/20/97 JMI DistanceToVolume() now always returns 255, if that
  113. // feature is off.
  114. //
  115. // 08/05/97 JMI Added PauseAllSamples() and ResumeAllSamples().
  116. //
  117. // 08/05/97 JRD Added CSoundCatalogue and automated the listing
  118. // of sounds for use with organ.
  119. //
  120. // 08/20/97 BRH Added new pain and suffering volume categories. Also
  121. // changed Music to Soundtrack, and Voice to Comments.
  122. //
  123. // 08/25/97 JMI Added default volumes for each category in each quality
  124. // via the ms_asQualityCategoryAdjustors.
  125. // Also, added macro enums for UserDefaultVolume,
  126. // UserMaxVolume, and MaxVolume.
  127. //
  128. // 09/05/97 JMI Lowered adjustor volumes on 22KHz 16bit b/c the source
  129. // volumes are so loud that they hose when they mix.
  130. // Unfortunately, 8 bit could use this as well but it sounds
  131. // bad when we use the volume scaling so either way it sucks.
  132. //
  133. // 09/17/97 JMI Now gets sound category names from Localize.
  134. //
  135. // 09/17/97 JMI Even though I'd swear I compiled and tested this before
  136. // it was not compiling with the new array assignment I
  137. // added. Perhaps I did the conditional compilation
  138. // wrong...fixed.
  139. //
  140. // 09/24/97 JMI Added bFemalePain member to SampleMasterID. This field
  141. // is true if the sample is of a female in pain. If this
  142. // field is true, SampleMaster.cpp won't play the sample
  143. // if the LOCALE is that of a country that does not allow
  144. // such things in games (currently all but the US).
  145. //
  146. // 10/07/97 JMI Changed bFemalePain to usDescFlags, a bits field of flags
  147. // describing the sound so we can know which ones to filter
  148. // out for various languages.
  149. //
  150. // 01/05/98 JMI Changed default volumes for SQ_22050_8, SQ_11025_8, and
  151. // SQ_11025_16.
  152. //
  153. // 09/27/99 JMI Changed to allow "violent" sounds in any locale
  154. // satisfying the CompilerOptions macro VIOLENT_LOCALE.
  155. //
  156. //////////////////////////////////////////////////////////////////////////////
  157. //
  158. // See .H for explanation of this module.
  159. //
  160. //////////////////////////////////////////////////////////////////////////////
  161. //////////////////////////////////////////////////////////////////////////////
  162. // C Headers -- Must be included before RSPiX.h b/c RSPiX utilizes SHMalloc.
  163. //////////////////////////////////////////////////////////////////////////////
  164. ///////////////////////////////////////////////////////////////////////////////
  165. // RSPiX Headers.
  166. ///////////////////////////////////////////////////////////////////////////////
  167. #include "RSPiX.h"
  168. ///////////////////////////////////////////////////////////////////////////////
  169. // WishPiX Headers.
  170. // If PATHS_IN_INCLUDES macro is defined, we can utilize relative
  171. // paths to a header file. In this case we generally go off of our
  172. // RSPiX root directory. System.h MUST be included before this macro
  173. // is evaluated. System.h is the header that, based on the current
  174. // platform (or more so in this case on the compiler), defines
  175. // PATHS_IN_INCLUDES. Blue.h includes system.h so you can include that
  176. // instead.
  177. ///////////////////////////////////////////////////////////////////////////////
  178. #ifdef PATHS_IN_INCLUDES
  179. #include "WishPiX/ResourceManager/resmgr.h"
  180. #else
  181. #include "resmgr.h"
  182. #endif
  183. ///////////////////////////////////////////////////////////////////////////////
  184. // Postal Headers.
  185. ///////////////////////////////////////////////////////////////////////////////
  186. // Let .H know what CPP is being compiled.
  187. #define SAMPLEMASTER_CPP
  188. #include "SampleMaster.h"
  189. #include "game.h"
  190. #include "CompileOptions.h"
  191. //////////////////////////////////////////////////////////////////////////////
  192. // Module specific macros.
  193. //////////////////////////////////////////////////////////////////////////////
  194. #define NUM_CHANNELS 64 // Max number of sample channels usable at once.
  195. #define CHANNEL_MASK 63 // Used to store channel number as part of sample UID
  196. #define PLAY_BUF_SIZE 4096 // In bytes.
  197. #define SET(ptr, val) ((ptr) ? *(ptr) = val : 0)
  198. // If not a violent locale . . .
  199. #if !VIOLENT_LOCALE
  200. // No sounds indicating females are in pain or including police references can be played.
  201. #define CAN_PLAY_SAMPLE(id) ( (id.usDescFlags & (SMDF_FEMALE_PAIN | SMDF_POLICE_REF) ) == 0)
  202. #else
  203. // All sounds can be played.
  204. #define CAN_PLAY_SAMPLE(id) (1)
  205. #endif
  206. //////////////////////////////////////////////////////////////////////////////
  207. // Module specific typedefs.
  208. //////////////////////////////////////////////////////////////////////////////
  209. //////////////////////////////////////////////////////////////////////////////
  210. // Exported (extern) variables.
  211. //////////////////////////////////////////////////////////////////////////////
  212. RResMgr g_resmgrSamples;
  213. //////////////////////////////////////////////////////////////////////////////
  214. // Module specific (static) variables / Instantiate class statics.
  215. //////////////////////////////////////////////////////////////////////////////
  216. //------------ put in C file:
  217. short CSoundCatalogue::ms_sCurPos = 0;
  218. short CSoundCatalogue::ms_sRefCount = 0;
  219. SampleMasterID** CSoundCatalogue::ms_ppsmNameList = NULL;
  220. // Sound channels for playing samples.
  221. static RSnd ms_asndChannels[NUM_CHANNELS];
  222. // Unique Sample IDs used in identifying playing sample/channel combos (without channel bits set)
  223. static SampleMaster::SoundInstance ms_aSoundInstances[NUM_CHANNELS] = {0,};
  224. // Stores the Sound Levels (0-255) for each sound category
  225. static short ms_asCategoryVolumes[SampleMaster::MAX_NUM_SOUND_CATEGORIES] = {255,};
  226. // Stores the Sound Category for each sound channel:
  227. static SampleMaster::SoundCategory ms_aeSoundTypes[NUM_CHANNELS] = {SampleMaster::Unspecified,};
  228. // Sound channel for failures.
  229. static RSnd ms_sndFailure;
  230. // Module local storage for current 3d location for the sound
  231. static float fSoundX = 0.,fSoundY = 0., fSoundZ = 0.;
  232. //////////////////////////////////////////////////////////////
  233. // These are the names for the corresponding SoundCategory
  234. // used as an index.
  235. char* SampleMaster::ms_apszSoundCategories[SampleMaster::MAX_NUM_SOUND_CATEGORIES] =
  236. {
  237. g_apszSoundCategories[Unspecified],
  238. g_apszSoundCategories[BackgroundMusic],
  239. g_apszSoundCategories[Weapon],
  240. g_apszSoundCategories[UserFeedBack],
  241. g_apszSoundCategories[Destruction],
  242. g_apszSoundCategories[Ambient],
  243. g_apszSoundCategories[Demon],
  244. g_apszSoundCategories[Voices],
  245. g_apszSoundCategories[Pain],
  246. g_apszSoundCategories[Suffering],
  247. };
  248. //////////////////////////////////////////////////////////////
  249. // These are the default volumes for each category in each
  250. // quality.
  251. short SampleMaster::ms_asQualityCategoryAdjustors[NumSoundQualities][MAX_NUM_SOUND_CATEGORIES] =
  252. {
  253. // SQ_11025_8:
  254. {
  255. 5, // General.
  256. 5, // Music - Soundtrack.
  257. 5, // Weapon.
  258. 5, // FeedBack.
  259. 5, // Destruction.
  260. 5, // Ambient.
  261. 5, // Demon.
  262. 5, // Voices - Comments.
  263. 5, // Pain - Shot, Burning, blownup
  264. 5, // Suffering - writhing sounds
  265. },
  266. // SQ_11025_16:
  267. {
  268. 9, // General.
  269. 9, // Music - Soundtrack.
  270. 9, // Weapon.
  271. 9, // FeedBack.
  272. 9, // Destruction.
  273. 9, // Ambient.
  274. 9, // Demon.
  275. 9, // Voices - Comments.
  276. 9, // Pain - Shot, Burning, blownup
  277. 9, // Suffering - writhing sounds
  278. },
  279. // SQ_22050_8:
  280. {
  281. 3, // General.
  282. 3, // Music - Soundtrack.
  283. 3, // Weapon.
  284. 3, // FeedBack.
  285. 3, // Destruction.
  286. 3, // Ambient.
  287. 3, // Demon.
  288. 3, // Voices - Comments.
  289. 3, // Pain - Shot, Burning, blownup
  290. 3, // Suffering - writhing sounds
  291. },
  292. // SQ_22050_16:
  293. {
  294. 7, // General.
  295. 7, // Music - Soundtrack.
  296. 7, // Weapon.
  297. 7, // FeedBack.
  298. 7, // Destruction.
  299. 7, // Ambient.
  300. 7, // Demon.
  301. 7, // Voices - Comments.
  302. 7, // Pain - Shot, Burning, blownup
  303. 7, // Suffering - writhing sounds
  304. },
  305. // SQ_44100_8:
  306. {
  307. 10, // General.
  308. 10, // Music - Soundtrack.
  309. 10, // Weapon.
  310. 10, // FeedBack.
  311. 10, // Destruction.
  312. 10, // Ambient.
  313. 10, // Demon.
  314. 10, // Voices - Comments.
  315. 10, // Pain - Shot, Burning, blownup
  316. 10, // Suffering - writhing sounds
  317. },
  318. // SQ_44100_16:
  319. {
  320. 10, // General.
  321. 10, // Music - Soundtrack.
  322. 10, // Weapon.
  323. 10, // FeedBack.
  324. 10, // Destruction.
  325. 10, // Ambient.
  326. 10, // Demon.
  327. 10, // Voices - Comments.
  328. 10, // Pain - Shot, Burning, blownup
  329. 10, // Suffering - writhing sounds
  330. },
  331. };
  332. //////////////////////////////////////////////////////////////////////////////
  333. // Global variables used to pass sound IDs in an object oriented environment.
  334. //////////////////////////////////////////////////////////////////////////////
  335. SampleMaster::SoundInstance g_siEndingMusak = 0;
  336. //////////////////////////////////////////////////////////////////////////////
  337. // Module specific (static) protos.
  338. //////////////////////////////////////////////////////////////////////////////
  339. //////////////////////////////////////////////////////////////////////////////
  340. // Intern Functions.
  341. //////////////////////////////////////////////////////////////////////////////
  342. //////////////////////////////////////////////////////////////////////////////
  343. //
  344. // Callback when done playing/streaming.
  345. //
  346. //////////////////////////////////////////////////////////////////////////////
  347. void SndDoneCall( // Returns nothing.
  348. RSnd* psnd); // This RSnd.
  349. void SndDoneCall( // Returns nothing.
  350. RSnd* psnd) // This RSnd.
  351. {
  352. ASSERT(psnd != NULL);
  353. RSample* psample = psnd->GetSample();
  354. if (psample != NULL)
  355. {
  356. // Reduce ResMgr ref count.
  357. // Either release the sample, or purge and release//////////////////////////////////////////////////////////////////////
  358. if (psnd->m_ulUser)
  359. rspReleaseAndPurgeResource(&g_resmgrSamples, &psample);
  360. else
  361. rspReleaseResource(&g_resmgrSamples, &psample);
  362. }
  363. }
  364. //////////////////////////////////////////////////////////////////////////////
  365. // Extern Functions.
  366. //////////////////////////////////////////////////////////////////////////////
  367. //////////////////////////////////////////////////////////////////////////////
  368. // Set the volume for a category of sounds (0-UserMaxVolume)
  369. // This goes through the RSnd array and recalibrates the samples as well
  370. // returns SUCCESS if input is valid
  371. //////////////////////////////////////////////////////////////////////////////
  372. short SetCategoryVolume(
  373. SampleMaster::SoundCategory eType,
  374. short sVolume /* = SampleMaster::UserMaxVolume*/)
  375. {
  376. if ((eType < SampleMaster::Unspecified) || (eType >= SampleMaster::MAX_NUM_SOUND_CATEGORIES))
  377. {
  378. return FAILURE;
  379. }
  380. if ((sVolume < 0) || (sVolume > SampleMaster::UserMaxVolume))
  381. {
  382. return FAILURE;
  383. }
  384. // Set the new volume for that sound type adjusted through
  385. // the quality's category volume adjustor.
  386. // This means we're scaling it TWICE and that is why there are two ratios.
  387. // Ratio1: AdjustorVolume to MaxUserVolume Ratio2: UserVolume to SampleMasterVolume.
  388. //
  389. // ms_asQualityCategoryAdjustors[qual][cat] SampleMaster::VolumeMax
  390. // sVolume * ============================================= * =============================================
  391. // (UserMaxVolume) (UserMaxVolume)
  392. //
  393. // For the sake of using integer math, we don't do these operations in the above order.
  394. //
  395. ms_asCategoryVolumes[eType] = sVolume * SampleMaster::ms_asQualityCategoryAdjustors[g_GameSettings.m_eCurSoundQuality][eType] * SampleMaster::MaxVolume / (SampleMaster::UserMaxVolume * SampleMaster::UserMaxVolume);
  396. // Notify all playing sounds of that type that their volume has changed
  397. for (short i = 0; i < NUM_CHANNELS; i++)
  398. {
  399. if (ms_aeSoundTypes[i] == eType)
  400. {
  401. ms_asndChannels[i].m_sTypeVolume = ms_asCategoryVolumes[eType]; // adjust volume
  402. }
  403. }
  404. return SUCCESS;
  405. }
  406. //////////////////////////////////////////////////////////////////////////////
  407. // Get the volume for a category of sounds (0-UserMaxVolume)
  408. // returns category volume, ( 0 - MaxUserVolume ) or -1 if category is invalid.
  409. //////////////////////////////////////////////////////////////////////////////
  410. short GetCategoryVolume(
  411. SampleMaster::SoundCategory eType /* = SampleMaster::SoundCategory::Unspecified */)
  412. {
  413. if ((eType < SampleMaster::Unspecified) || (eType >= SampleMaster::MAX_NUM_SOUND_CATEGORIES))
  414. {
  415. return -1;
  416. }
  417. // Get the new volume for that sound type dejusted through
  418. // the quality's category volume adjustor.
  419. // This means we're scaling it TWICE and that is why there are two ratios.
  420. // Ratio1: AdjustorVolume to MaxUserVolume Ratio2: UserVolume to SampleMasterVolume.
  421. //
  422. // (UserVolumeRange) (UserVolumeRange)
  423. // sVolume * ============================================= * =============================================
  424. // ms_asQualityCategoryAdjustors[qual][cat] SampleMaster::VolumeRange
  425. //
  426. // For the sake of using integer math, we don't do these operations in the above order.
  427. //
  428. return ms_asCategoryVolumes[eType] * SampleMaster::UserMaxVolume * SampleMaster::UserMaxVolume / (SampleMaster::ms_asQualityCategoryAdjustors[g_GameSettings.m_eCurSoundQuality][eType] * SampleMaster::MaxVolume);
  429. }
  430. //////////////////////////////////////////////////////////////////////////////
  431. // Set the current volume for a sound currently playing. (0-255)
  432. // You need the volume ID returned from PlaySample.
  433. // You will NOT get an error if number doesn't match, but the colume won't
  434. // change.
  435. // (It is assumed your sound has merely finished playing.)
  436. //
  437. // Returns SUCCESS or FAILURE
  438. //////////////////////////////////////////////////////////////////////////////
  439. short SetInstanceVolume(
  440. SampleMaster::SoundInstance si, // make sure it is YOUR sound
  441. short sVolume /* = 255 */) // 0 - 255
  442. {
  443. if ( (si < 0) || (sVolume < 0) || (sVolume > 255) )
  444. {
  445. return FAILURE;
  446. }
  447. // Get the channel number from the lowest bits:
  448. short sChannel = si & CHANNEL_MASK;
  449. if (sChannel >= NUM_CHANNELS)
  450. {
  451. return FAILURE; // MASK error!
  452. }
  453. // Make sure the sound is still playing (this is NOT an error)
  454. // Compare current channel ID with high bits of vid:
  455. if (ms_aSoundInstances[sChannel] == (si & (~CHANNEL_MASK) ) )
  456. {
  457. // Security approved! You may set the sound volume!
  458. ms_asndChannels[sChannel].m_sChannelVolume = sVolume;
  459. }
  460. return SUCCESS;
  461. }
  462. //////////////////////////////////////////////////////////////////////////////
  463. //
  464. // Calculate volume based on 3d distance... [ 1 / (R*R) ]
  465. // Distance is relative to the current sound position, which
  466. // is set independently by the App.
  467. //
  468. // The attenuation radius is the distance at which volume is
  469. // half the original level. (Very soft, but still audible)
  470. //
  471. // Returns 0-255 for volume (255 = epicenter), or -1 on error
  472. // Returns 255 if this feature is off.
  473. //
  474. //////////////////////////////////////////////////////////////////////////////
  475. short DistanceToVolume(float fX, // in Postal 3d coordinates
  476. float fY,
  477. float fZ,
  478. float fR // Sound half life
  479. )
  480. {
  481. ASSERT(fR >= 1.0);
  482. if (g_GameSettings.m_sVolumeDistance != FALSE)
  483. {
  484. // -ln 2 = ln (1/2) = 1/2 level (ln 10 = 1/10 volume, etc.)
  485. const float fln2 = float(0.6931471805599);
  486. float fDist2 = ABS2(fX - fSoundX,
  487. fY - fSoundY,
  488. fZ - fSoundZ );
  489. if (fDist2 < 1.0) return 255; // Dead epicenter
  490. return short(255.0 * exp( -fln2 * fDist2 / (fR * fR) ) );
  491. }
  492. else
  493. {
  494. return 255;
  495. }
  496. }
  497. //////////////////////////////////////////////////////////////////////////////
  498. // Set the current 3d center of the sound being played
  499. //////////////////////////////////////////////////////////////////////////////
  500. void SetSoundLocation(float fX, float fY, float fZ)
  501. {
  502. fSoundX = fX; // global static
  503. fSoundY = fY;
  504. fSoundZ = fZ;
  505. }
  506. //////////////////////////////////////////////////////////////////////////////
  507. //
  508. // Cache a sample. Causes sample to be loaded, if it is not. This keeps it
  509. // available in an instant until the next PurgeSamples() call.
  510. //
  511. //////////////////////////////////////////////////////////////////////////////
  512. void CacheSample( // Returns nothing.
  513. SampleMasterID id) // Identifier of sample you want played.
  514. {
  515. if (id.pszId != NULL && CAN_PLAY_SAMPLE(id) )
  516. {
  517. RSample* psample;
  518. // Get it into memory.
  519. // If successful . . .
  520. if (rspGetResource(
  521. &g_resmgrSamples,
  522. id.pszId,
  523. &psample) == 0)
  524. {
  525. // Release it, so the next purge will remove this sample from RAM.
  526. // Sort of a flush.
  527. rspReleaseResource(&g_resmgrSamples, &psample);
  528. }
  529. else
  530. {
  531. TRACE("CacheSample(): Could not cache sample \"%s\".\n", id.pszId);
  532. }
  533. }
  534. }
  535. //////////////////////////////////////////////////////////////////////////////
  536. //
  537. // Plays a sample. This may require load from disk.
  538. // Returns a volume handle if you wish to dynamically adjust the volume
  539. //
  540. //////////////////////////////////////////////////////////////////////////////
  541. void PlaySample( // Returns nothing.
  542. // Does not fail.
  543. SampleMasterID id, // In: Identifier of sample you want played.
  544. SampleMaster::SoundCategory eType, // In: Sound Volume Category for user adjustment
  545. short sInitialVolume /* = 255 */, // In: Initial Sound Volume (0 - 255)
  546. SampleMaster::SoundInstance* psi/* = NULL */, // Out: Handle for adjusting sound volume
  547. long* plSampleDuration /* = NULL */, // Out: Sample duration in ms, if not NULL.
  548. long lLoopStartTime /* = -1 */, // In: Where to loop back to in milliseconds.
  549. // -1 indicates no looping (unless m_sLoop is
  550. // explicitly set).
  551. long lLoopEndTime /* = 0 */, // In: Where to loop back from in milliseconds.
  552. // In: If less than 1, the end + lLoopEndTime is used.
  553. bool bPurgeSample /* = false */) // In: Call ReleaseAndPurge rather than Release after playing
  554. {
  555. short sError = 0; // Assume no error.
  556. RSnd* psnd = &ms_sndFailure; // Default to failure case.
  557. if (psi) *psi = 0; // Default to failure case.
  558. if (id.pszId != NULL && CAN_PLAY_SAMPLE(id) )
  559. {
  560. RSample* psample;
  561. // Get the sample . . .
  562. if (rspGetResource(
  563. &g_resmgrSamples,
  564. id.pszId,
  565. &psample) == 0)
  566. {
  567. // Get the duration right away. We want to return this even if we fail
  568. // to play the sample.
  569. SET(plSampleDuration, psample->GetDuration() );
  570. // Brute force search to find open channel.
  571. short i;
  572. for (i = 0; i < NUM_CHANNELS; i++)
  573. {
  574. if (ms_asndChannels[i].GetState() == RSnd::Stopped)
  575. {
  576. break;
  577. }
  578. }
  579. // If we got one . . .
  580. if (i < NUM_CHANNELS)
  581. {
  582. // Release sample when done via this callback.
  583. ms_asndChannels[i].m_dcUser = SndDoneCall;
  584. ms_asndChannels[i].m_sLoop = FALSE; // Safety.
  585. ms_asndChannels[i].m_ulUser = bPurgeSample;
  586. // Set volume in RSound assuming success:
  587. ms_aeSoundTypes[i] = eType;
  588. ms_asndChannels[i].m_sTypeVolume = ms_asCategoryVolumes[eType];
  589. ms_asndChannels[i].m_sChannelVolume = sInitialVolume;
  590. // Atttempt to play sample . . .
  591. if (ms_asndChannels[i].Play(psample, PLAY_BUF_SIZE, ms_asndChannels[i].m_sChannelVolume,
  592. ms_asndChannels[i].m_sTypeVolume, lLoopStartTime, lLoopEndTime) == 0)
  593. {
  594. // Success. Give user access to this channel.
  595. psnd = &(ms_asndChannels[i]);
  596. // Set return ID so user can tweak the volume:
  597. ms_aSoundInstances[i] += NUM_CHANNELS; // It is a new sound now!
  598. // Reserve the lower mask bits for the channel number
  599. if (psi) *psi = ms_aSoundInstances[i] + i;
  600. }
  601. else
  602. {
  603. // TRACE("PlaySample(): RSnd::Play() failed for sample.\n");
  604. sError = 3;
  605. }
  606. }
  607. else
  608. {
  609. TRACE("PlaySample(): No available sound channels. Increase NUM_CHANNELS"
  610. " or like it.\n");
  611. sError = 2;
  612. }
  613. // If an error occurred . . .
  614. if (sError != 0)
  615. {
  616. // Either release the sample, or purge and release//////////////////////////////////////////////////////////////////////
  617. if (bPurgeSample)
  618. rspReleaseAndPurgeResource(&g_resmgrSamples, &psample);
  619. else
  620. rspReleaseResource(&g_resmgrSamples, &psample);
  621. }
  622. }
  623. else
  624. {
  625. TRACE("PlaySample(): Could not get sample \"%s\".\n", id.pszId);
  626. sError = 1;
  627. }
  628. }
  629. }
  630. #if 0
  631. ///////////////////////////////////////////////////////////////////////////////////////////////////
  632. // BACKWARDS COMPATIBLE STUB PROVIDED FOR YOUR COMPILING CONVENIENCE
  633. // Plays a sample. This may require load from disk.
  634. ///////////////////////////////////////////////////////////////////////////////////////////////////
  635. void PlaySample( // Returns nothing.
  636. // Does not fail.
  637. SampleMasterID id, // In: Identifier of sample you want played.
  638. long* plSampleDuration /* = NULL*/, // Out: Sample duration in ms, if not NULL.
  639. long lLoopStartTime /* = -1 */, // In: Where to loop back to in milliseconds.
  640. // -1 indicates no looping (unless m_sLoop is
  641. // explicitly set).
  642. long lLoopEndTime /* = 0 */, // In: Where to loop back from in milliseconds.
  643. // In: If less than 1, the end + lLoopEndTime is used.
  644. bool bPurgeSample /* = false */) // In: Call ReleaseAndPurge rather than Release after playing
  645. {
  646. PlaySampleEx(id,NULL,SampleMaster::Unspecified,255,plSampleDuration,lLoopStartTime,lLoopEndTime,bPurgeSample);
  647. }
  648. //////////////////////////////////////////////////////////////////////////////
  649. // Handier interface for purging a sample on release.
  650. //////////////////////////////////////////////////////////////////////////////
  651. void PlaySampleThenPurge( // Returns nothing.
  652. // Does not fail.
  653. SampleMasterID id, // In: Identifier of sample you want played.
  654. SampleMaster::SoundInstance* psi /* = NULL */, // Out: Handle for adjusting sound volume
  655. SampleMaster::SoundCategory eType /* =
  656. SampleMaster::SoundCategory::Unspecified */, // In: Sound Volume Category for user adjustment
  657. short sInitialVolume /* = 255 */, // In: Initial Sound Volume (0 - 255)
  658. long* plSampleDuration /* = NULL */,// Out: Sample duration in ms, if not NULL.
  659. long lLoopStartTime /* = -1 */, // In: Where to loop back to in milliseconds.
  660. // -1 indicates no looping (unless m_sLoop is
  661. // explicitly set).
  662. long lLoopEndTime /* = 0 */) // In: Where to loop back from in milliseconds.
  663. // In: If less than 1, the end + lLoopEndTime is used.
  664. {
  665. PlaySampleEx(id, psi, eType, sInitialVolume,
  666. plSampleDuration, lLoopStartTime, lLoopEndTime, true);
  667. }
  668. #endif
  669. //////////////////////////////////////////////////////////////////////////////
  670. //
  671. // Checks if a particular sample is playing.
  672. // Note: An ugly side effect is that this will cause the sample to
  673. // load, if it is not already loaded.
  674. //
  675. //////////////////////////////////////////////////////////////////////////////
  676. bool IsSamplePlaying( // Returns true, if the sample is playing,
  677. // false otherwise.
  678. SampleMasterID id) // Identifier of sample to be checked.
  679. {
  680. bool bRes = false; // Assume not playing.
  681. if (id.pszId != NULL && CAN_PLAY_SAMPLE(id) )
  682. {
  683. RSample* psample;
  684. // Get it into memory.
  685. // If successful . . .
  686. if (rspGetResource(
  687. &g_resmgrSamples,
  688. id.pszId,
  689. &psample) == 0)
  690. {
  691. // Check if it is locked.
  692. if (psample->IsLocked() != FALSE)
  693. {
  694. bRes = true;
  695. }
  696. // Release it, so the next purge will remove this sample from RAM.
  697. // Sort of a flush.
  698. rspReleaseResource(&g_resmgrSamples, &psample);
  699. }
  700. else
  701. {
  702. TRACE("IsSamplePlaying(): Could not cache sample \"%s\".\n", id.pszId);
  703. }
  704. }
  705. return bRes;
  706. }
  707. //////////////////////////////////////////////////////////////////////////////
  708. //
  709. // Checks if the specified play instance is still going.
  710. //
  711. //////////////////////////////////////////////////////////////////////////////
  712. bool IsSamplePlaying( // Returns true, if the sample is playing,
  713. // false otherwise.
  714. SampleMaster::SoundInstance si) // In: Identifies play instance.
  715. {
  716. bool bPlaying = false; // Assume not playing.
  717. // Get the channel number from the lowest bits:
  718. short sChannel = si & CHANNEL_MASK;
  719. if (sChannel < NUM_CHANNELS)
  720. {
  721. // Make sure the sound is still playing (this is NOT an error)
  722. // Compare current channel ID with high bits of sc:
  723. if (ms_aSoundInstances[sChannel] == (si & (~CHANNEL_MASK) ) )
  724. {
  725. // Security approved! You may check the RSnd!
  726. if (ms_asndChannels[sChannel].GetState() != RSnd::Stopped)
  727. {
  728. // Yes, it is.
  729. bPlaying = true;
  730. }
  731. }
  732. }
  733. else
  734. {
  735. // MASK error!
  736. }
  737. return bPlaying;
  738. }
  739. //////////////////////////////////////////////////////////////////////////////
  740. //
  741. // Checks if any sample is playing.
  742. //
  743. //////////////////////////////////////////////////////////////////////////////
  744. bool IsSamplePlaying(void) // Returns true, if a sample is playing,
  745. // false otherwise.
  746. {
  747. bool bRes = false; // Assume none playing.
  748. // Check all channels.
  749. // Brute force search to find open channel.
  750. short i;
  751. for (i = 0; i < NUM_CHANNELS; i++)
  752. {
  753. if (ms_asndChannels[i].GetState() != RSnd::Stopped)
  754. {
  755. bRes = true;
  756. break;
  757. }
  758. }
  759. return bRes;
  760. }
  761. //////////////////////////////////////////////////////////////////////////////
  762. //
  763. // Aborts the specified play instance if it is still going.
  764. //
  765. //////////////////////////////////////////////////////////////////////////////
  766. short AbortSample( // Returns 0 if sample aborted, 1 if not.
  767. SampleMaster::SoundInstance si) // In: Identifies play instance.
  768. {
  769. short sRes = 1; // Assume failure.
  770. // Get the channel number from the lowest bits:
  771. short sChannel = si & CHANNEL_MASK;
  772. if (sChannel < NUM_CHANNELS)
  773. {
  774. // Make sure the sound is still playing (this is NOT an error)
  775. // Compare current channel ID with high bits of sc:
  776. if (ms_aSoundInstances[sChannel] == (si & (~CHANNEL_MASK) ) )
  777. {
  778. // Okay. Abort.
  779. if (ms_asndChannels[sChannel].GetState() != RSnd::Stopped)
  780. {
  781. if (ms_asndChannels[sChannel].Abort() == 0)
  782. {
  783. // Success.
  784. sRes = 0;
  785. // Do we have to release it? Should get a callback.
  786. }
  787. else
  788. {
  789. TRACE("AbortSample(): ms_asndChannels[sChannel].Abort() failed.\n");
  790. }
  791. }
  792. }
  793. }
  794. else
  795. {
  796. // MASK error!
  797. }
  798. return sRes;
  799. }
  800. //////////////////////////////////////////////////////////////////////////////
  801. //
  802. // Purges all samples that are not in use.
  803. //
  804. //////////////////////////////////////////////////////////////////////////////
  805. void PurgeSamples(void) // Returns nothing.
  806. {
  807. g_resmgrSamples.Purge();
  808. }
  809. //////////////////////////////////////////////////////////////////////////////
  810. //
  811. // Purge sample. Releases a particular sample if not in use.
  812. // If implemented with the current state of the RResMgr I would have to do
  813. // an rspGetResource() to get the resource pointer to pass to
  814. // rspReleaseAndPurgeResource() which might defeat the purpose in some cases
  815. // but would be fine for samples you know are loaded.
  816. //
  817. //////////////////////////////////////////////////////////////////////////////
  818. void PurgeSample( // Returns nothing.
  819. SampleMasterID id) // Identifier of sample you want played.
  820. {
  821. TRACE("PurgeSample(): NYI.\n");
  822. }
  823. ///////////////////////////////////////////////////////////////////////////////
  824. // Aborts all currently playing samples.
  825. ///////////////////////////////////////////////////////////////////////////////
  826. void AbortAllSamples(void) // Returns nothing.
  827. {
  828. // Check all channels.
  829. short i;
  830. for (i = 0; i < NUM_CHANNELS; i++)
  831. {
  832. if (ms_asndChannels[i].GetState() != RSnd::Stopped)
  833. {
  834. ms_asndChannels[i].Abort();
  835. }
  836. }
  837. }
  838. ///////////////////////////////////////////////////////////////////////////////
  839. // Pauses all active samples.
  840. ///////////////////////////////////////////////////////////////////////////////
  841. extern void PauseAllSamples(void)
  842. {
  843. // Pause all active channels.
  844. short i;
  845. for (i = 0; i < NUM_CHANNELS; i++)
  846. {
  847. if (ms_asndChannels[i].GetState() != RSnd::Stopped)
  848. {
  849. ms_asndChannels[i].Pause();
  850. }
  851. }
  852. }
  853. ///////////////////////////////////////////////////////////////////////////////
  854. // Resumes all paused samples.
  855. ///////////////////////////////////////////////////////////////////////////////
  856. extern void ResumeAllSamples(void)
  857. {
  858. // Resume all active channels.
  859. short i;
  860. for (i = 0; i < NUM_CHANNELS; i++)
  861. {
  862. if (ms_asndChannels[i].IsPaused() )
  863. {
  864. ms_asndChannels[i].Resume();
  865. }
  866. }
  867. }
  868. ///////////////////////////////////////////////////////////////////////////////
  869. // Stops looping the specified play instance. That is, it will continue from
  870. // its current play point to the end.
  871. ///////////////////////////////////////////////////////////////////////////////
  872. void StopLoopingSample( // Returns nothing.
  873. SampleMaster::SoundInstance si) // In: Identifies play instance.
  874. {
  875. RSnd* psndInstance = GetInstanceChannel(si); // Does not fail.
  876. psndInstance->m_sLoop = FALSE;
  877. }
  878. ///////////////////////////////////////////////////////////////////////////////
  879. // If you must, you can access the RSnd. IF YOU DO, READ THIS:
  880. // This function will always return an RSnd, even if your play instance is
  881. // long gone.
  882. // THERE ARE LIMITATIONS TO WHAT YOU CAN DO WITH THIS RSND:
  883. // 1) NEVER READ any value from the RSnd. You may only WRITE to the RSnd.
  884. ///////////////////////////////////////////////////////////////////////////////
  885. RSnd* GetInstanceChannel( // Returns ptr to an RSnd. Yours, if
  886. // it has not finished with your sample.
  887. // A generic one, otherwise.
  888. SampleMaster::SoundInstance si) // In: Identifies play instance.
  889. {
  890. RSnd* psndInstance = &ms_sndFailure; // Assume long gone.
  891. // Get the channel number from the lowest bits:
  892. short sChannel = si & CHANNEL_MASK;
  893. if (sChannel < NUM_CHANNELS)
  894. {
  895. // Make sure the sound is still playing (this is NOT an error)
  896. // Compare current channel ID with high bits of sc:
  897. if (ms_aSoundInstances[sChannel] == (si & (~CHANNEL_MASK) ) )
  898. {
  899. if (ms_asndChannels[sChannel].GetState() != RSnd::Stopped)
  900. {
  901. psndInstance = &(ms_asndChannels[sChannel]);
  902. }
  903. }
  904. }
  905. return psndInstance;
  906. }
  907. ///////////////////////////////////////////////////////////////////////////////
  908. // EOF
  909. ///////////////////////////////////////////////////////////////////////////////