mix.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  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. ///////////////////////////////////////////////////////////////////////////////
  19. //
  20. // mix.cpp
  21. //
  22. // History:
  23. // 06/17/95 JMI Started.
  24. //
  25. // 06/26/95 JMI Added critical handler to allow asynchronous closing
  26. // of Blue's sound output.
  27. //
  28. // 06/27/95 JMI Added check to make sure the task was not running before
  29. // attempting to start it. Also, moved ms_lCurPos = 0 init
  30. // to OpenChannel when Blue is opened.
  31. //
  32. // 07/15/95 JMI Removed potential for confusion on value of ms_lCurPos
  33. // when adding buffers to what was an ending mix stream.
  34. // TaskCallStatic now handles starting and adding
  35. // differently. Also, ms_lCurPos is added when it is de-
  36. // cided that the buffer is needed.
  37. //
  38. // 07/17/95 JMI Added Reset() funcion. Simply calling Blue's ResetSound-
  39. // Out is not enough, given the new way we get data from the
  40. // app (using buffers of any size). We must ResetSoundOut
  41. // and return all current user buffers.
  42. //
  43. // 09/07/95 JMI If a callback provided less than the buffer size worth
  44. // of sound data, and then returned that it was done,
  45. // BlueCall would return NULL (representing it was done
  46. // mixing this channel), causing BlueCallStatic to discard
  47. // the buffer (even though something was mixed in) IF no
  48. // other channels returned non-NULL. This has been fixed.
  49. // This fix brought to light a problem that probably would
  50. // not have otherwise surfaced but may have affected some-
  51. // one somewhere by some rarity. The problem was that
  52. // The task call assumed that it would be called in a
  53. // situation where it was definite that there were not
  54. // enough CMixBufs allocated. Now it makes sure.
  55. //
  56. // 11/28/95 JMI Added a more deferred method of suspending channels.
  57. //
  58. // 12/18/95 JMI Made changes corresponding to new Blue sound method.
  59. // This greatly simplied starting the mixing process.
  60. //
  61. // 07/08/96 JMI Converted to new CList that does not convert your
  62. // template type into a poiter.
  63. //
  64. // 07/31/96 JMI Updating so this can be included in Release 02.00.04 even
  65. // though it is not completed. It functions.
  66. //
  67. // 08/26/96 JMI Updated to use new Blue sound API. Took out a few
  68. // unused pieces of code and variables. Basic functionality
  69. // is the same.
  70. //
  71. // 08/30/96 JMI Suspend() now sets m_lLastDataPos to 0 to make sure that,
  72. // if it is not set otherwise, the Mix() will finish very
  73. // soon. Also added fail safe to BlueCallStatic() to
  74. // 'finish' all channels that are suspended on a usMsg ==
  75. // RSP_SNDMSG_DONE.
  76. //
  77. // 08/30/96 JMI RSP_SND_CALLBACK not returns 0 on success and
  78. // non-zero on failure.
  79. //
  80. // 09/03/96 JMI Adapted to newest revision of Blue Sound API (which
  81. // removed rspStart/StopSoundOutCallbacks,
  82. // rspIsSoundOutCallingBack, and callback messages
  83. // (RSP_SNDMSG_DONE and RSP_SNDMSG_DATA). Now this, CMix,
  84. // provides a complete interface to the sound instead of
  85. // the partial one it used to.
  86. //
  87. // 09/04/96 MJR Changed callback from ULONG to long for size parameter.
  88. //
  89. // 09/06/96 JMI I patched Reset() so it might work.
  90. //
  91. // 09/10/96 JMI Removed Reset() patch. Blue has been updated to fix
  92. // the problem.
  93. //
  94. // 10/30/96 JMI Changed:
  95. // Old label: New label:
  96. // ========= =========
  97. // CMixBuf RMixBuf
  98. // CMix RMix
  99. // MIXCALL RMixCall
  100. // CSndFx RSndFx
  101. // MIX_STATE_* * Macros changed to enum.
  102. // MIX_MSG_* * Macros changed to enum.
  103. // CList RList
  104. //
  105. // 11/06/96 JMI Reset ms_lCurPos to 0 in SetMode().
  106. //
  107. // 03/24/97 JMI OpenChannel() now fails, if there's no mode.
  108. //
  109. // 06/03/97 JMI Now SetMode() returns the value returned from
  110. // rspSetSoundOutMode(), if that fails.
  111. //
  112. // 06/13/97 JMI Now calls ChannelFinished() right from Supsend().
  113. //
  114. // 06/26/97 JMI Added optional constant playing of silence to keep Blue
  115. // pumping when no channels are playing.
  116. //
  117. // 07/16/97 JRD Added volume members and volume parameters to Start.
  118. // Modified BlueCall to pass parameters to MixBuf.
  119. //
  120. // 07/17/97 JRD Removed Volume parameters, as they should be set
  121. // by the callback.
  122. //
  123. // 07/17/97 JRD Added Volume parameters, as they aren't always set
  124. // by the callback.
  125. //
  126. // 08/05/97 JMI Added IsPaused(), PauseChannel(), ResumeChannel(),
  127. // and IsChannelPaused().
  128. //
  129. // 09/17/97 JMI Make sure m_sPauseLevel is initialized to 0. Didn't seem
  130. // to have affected Postal because the samples were statically
  131. // allocate -- which initializes to zero.
  132. //
  133. // 10/30/97 JMI Added alternate version of SetMode() which allows more
  134. // detail as to bit depth quality of samples and mixing.
  135. // Also, added a GetMode().
  136. //
  137. //////////////////////////////////////////////////////////////////////////////
  138. //
  139. // This module slides between a Blu_*SoundOut module and Blu_*SoundOut itself.
  140. // The advantage of using this module is that more than one person can use it
  141. // at once w/o making a mess.
  142. //
  143. // Normal limitations: This module can mix data of the same sample rate with
  144. // different buffer sizes per channel, with different sample sizes (8 or
  145. // 16 bit PCM), and different numbers of channels (mono or stereo).
  146. //
  147. // For now limitations: In order to get this module running smoothly, it only
  148. // currently accepts data of the same sample rates, sample sizes, and number
  149. // of channels.
  150. //
  151. // For ending mixes we make the suspend message come after all
  152. // of the corresponding channel's data has been played. Basically, we set the
  153. // m_lLastDataPos member to the position of the last byte played and call
  154. // Suspend() which sets the m_sSuspending flag. In every callback we check if
  155. // m_sSuspending is set, and, when set, check to see if rspGetSoundOutPos()
  156. // has exceeded m_lLastDataPos; if so, we call ChannelFinished(). When
  157. // m_sSuspending is set, we will not mix from that channel or call it back.
  158. //
  159. // NEVER CALL rspClearSoundOut() when using CMix.
  160. //
  161. //////////////////////////////////////////////////////////////////////////////
  162. #ifdef PATHS_IN_INCLUDES
  163. #include "BLUE/system.h"
  164. #include "BLUE/Blue.h"
  165. #include "GREEN/Mix/mix.h"
  166. #else
  167. #include "System.h"
  168. #include "Blue.h"
  169. #include "mix.h"
  170. #endif // PATHS_IN_INCLUDES
  171. //////////////////////////////////////////////////////////////////////////////
  172. // Macros.
  173. //////////////////////////////////////////////////////////////////////////////
  174. #define DEF_BUFSIZE 4096L
  175. #define DEF_BUFFERTIME 185
  176. #define DEF_MAXBUFFERTIME 200
  177. //////////////////////////////////////////////////////////////////////////////
  178. // Instantiate static members.
  179. //////////////////////////////////////////////////////////////////////////////
  180. RList<RMix> RMix::ms_listActive; // List of active channels.
  181. short RMix::ms_sSetMode = FALSE; // TRUE if we set Blue's
  182. // sound output mode.
  183. RMix::State RMix::ms_sState = Idle; // Current state for all
  184. // RMixes.
  185. long RMix::ms_lCurPos = 0L; // Current play position
  186. // based on absolute start.
  187. ULONG RMix::ms_ulBufSize = 0xFFFFFFFF; // The size to use when al-
  188. // locating RMixBufs.
  189. short RMix::ms_sReset = FALSE; // If TRUE, current user
  190. // buffers are returned.
  191. RSndFx* RMix::ms_psndfx = NULL; // Pointer to a global
  192. // RSndFx.
  193. short RMix::ms_sKeepPumping = FALSE; // Keep Blue pumped with
  194. // silence when no channels
  195. // are playing, if TRUE.
  196. RMixBuf RMix::ms_mixbuf; // One and only mix buffer.
  197. //////////////////////////////////////////////////////////////////////////////
  198. // <Con|De>struction.
  199. //////////////////////////////////////////////////////////////////////////////
  200. //////////////////////////////////////////////////////////////////////////////
  201. //
  202. // Default Constructor.
  203. //
  204. //////////////////////////////////////////////////////////////////////////////
  205. RMix::RMix(void)
  206. {
  207. Init();
  208. }
  209. //////////////////////////////////////////////////////////////////////////////
  210. //
  211. // Destructor.
  212. //
  213. //////////////////////////////////////////////////////////////////////////////
  214. RMix::~RMix(void)
  215. {
  216. ASSERT(m_sActive == FALSE);
  217. ASSERT(m_sOpen == FALSE);
  218. if (m_sActive == TRUE)
  219. {
  220. TRACE("~RMix(): Destroying an active RMix.\n");
  221. }
  222. if (m_sOpen == TRUE)
  223. {
  224. TRACE("~RMix(): Destroying an open RMix.\n");
  225. CloseChannel();
  226. }
  227. }
  228. //////////////////////////////////////////////////////////////////////////////
  229. // Internal Use.
  230. //////////////////////////////////////////////////////////////////////////////
  231. //////////////////////////////////////////////////////////////////////////////
  232. //
  233. // Intialize members.
  234. //
  235. //////////////////////////////////////////////////////////////////////////////
  236. void RMix::Init(void)
  237. {
  238. m_lSampleRate = 0L;
  239. m_lBitsPerSample = 0L;
  240. m_lNumChannels = 0L;
  241. m_sOpen = FALSE;
  242. m_sActive = FALSE;
  243. m_sSuspending = FALSE;
  244. m_lLastDataPos = 0L;
  245. m_mcUser = NULL;
  246. m_ulUser = 0L;
  247. m_pucData = NULL;
  248. m_ulAmount = 0L;
  249. m_lStartTime = -1L;
  250. m_lStartPos = -1L;
  251. m_psndfx = NULL;
  252. if (ms_ulBufSize == 0xFFFFFFFF)
  253. {
  254. ms_ulBufSize = 0;//rspGetSoundOutPaneSize();
  255. }
  256. m_ucVolume = 255;
  257. m_ucSecondaryVolume = 255;
  258. m_sPauseLevel = 0;
  259. }
  260. //////////////////////////////////////////////////////////////////////////////
  261. //
  262. // Implied this version of BlueCallStatic, called from BlueCallStatic.
  263. //
  264. //////////////////////////////////////////////////////////////////////////////
  265. short RMix::BlueCall( // Returns FALSE when done.
  266. long lDataPos, // Position that this buffer represents in stream.
  267. PMIXBUF pmb) // Mix buffer to mix into.
  268. {
  269. short sRes = FALSE; // Assume no sound mixed in.
  270. // If this channel is not suspending and not paused . . .
  271. if (m_sSuspending == FALSE && m_sPauseLevel == 0)
  272. {
  273. // If first time for this RMix . . .
  274. if (m_lStartTime == -1L)
  275. {
  276. // Set start time and position.
  277. m_lStartPos = ms_lCurPos;
  278. m_lStartTime = (long)(((float)ms_lCurPos * (float)1000) /
  279. ((float)m_lSampleRate * ((float)m_lBitsPerSample / (float)8)
  280. * (float)m_lNumChannels
  281. ) );
  282. }
  283. ULONG ulTotalMixedIn = 0L;
  284. ULONG ulMixBufSize = pmb->GetMixSize();
  285. ULONG ulCurMix;
  286. // If we were recently reset . . .
  287. if (ms_sReset == TRUE)
  288. {
  289. // Release current user buffer.
  290. // Setting this to zero will cause a callback whether we have more
  291. // data or not.
  292. m_ulAmount = 0L;
  293. }
  294. do
  295. {
  296. if (m_ulAmount == 0L)
  297. {
  298. // Call user callback to get more data and the current volume!.
  299. m_pucData = (UCHAR*) (*m_mcUser)(Data, m_pucData, &m_ulAmount,
  300. m_ulUser, &m_ucVolume, &m_ucSecondaryVolume);
  301. }
  302. // If not done . . .
  303. if (m_pucData != NULL)
  304. {
  305. // Amount to mix in now.
  306. ulCurMix = MIN(m_ulAmount, ulMixBufSize - ulTotalMixedIn);
  307. // If an effect is defined . . .
  308. if (m_psndfx != NULL)
  309. {
  310. // If there is an active effect . . .
  311. if (m_psndfx->GetCurrentFX() != 0)
  312. {
  313. // Attempt to allocate temp buffer . . .
  314. U8* pu8 = (U8*)malloc(ulCurMix);
  315. if (pu8 != NULL)
  316. {
  317. // Perform effect into buffer.
  318. m_psndfx->Do(m_pucData, ulCurMix, pu8);
  319. // Mix.
  320. pmb->Mix(ulTotalMixedIn, pu8, ulCurMix,
  321. m_lSampleRate, m_lBitsPerSample, m_lNumChannels,
  322. m_ucVolume,m_ucSecondaryVolume);
  323. // Free temp memory.
  324. free(pu8);
  325. }
  326. else
  327. {
  328. TRACE("BlueCall(): Not enough memory to perform effect.\n");
  329. }
  330. }
  331. }
  332. else
  333. {
  334. // Mix.
  335. pmb->Mix(ulTotalMixedIn, m_pucData, ulCurMix,
  336. m_lSampleRate, m_lBitsPerSample, m_lNumChannels,
  337. m_ucVolume,m_ucSecondaryVolume);
  338. }
  339. // Add to amount mixed in.
  340. ulTotalMixedIn += ulCurMix;
  341. // Deduct from amount available.
  342. m_ulAmount -= ulCurMix;
  343. // Move in buffer.
  344. m_pucData += ulCurMix;
  345. // Let caller know we used buffer.
  346. sRes = TRUE;
  347. }
  348. else
  349. {
  350. // Done.
  351. break;
  352. }
  353. // Until we've filled the buffer from this stream . . .
  354. } while (ulTotalMixedIn < ulMixBufSize);
  355. // If we've exhausted this stream . . .
  356. if (m_pucData == NULL)
  357. {
  358. // Suspend this channel. What we mixed in this iteration will still get
  359. // played, though.
  360. Suspend();
  361. // Remember the last byte mixed into.
  362. m_lLastDataPos = lDataPos + ulTotalMixedIn;
  363. }
  364. }
  365. else
  366. {
  367. // We did not use buffer.
  368. sRes = FALSE;
  369. }
  370. return sRes;
  371. }
  372. //////////////////////////////////////////////////////////////////////////////
  373. //
  374. // Callbacks from Blue. Call each RMix in active list.
  375. // (static)
  376. //
  377. //////////////////////////////////////////////////////////////////////////////
  378. short RMix::BlueCallStatic( // Returns TRUE to continue mixing in this
  379. // buffer or FALSE to not mix this buffer.
  380. UCHAR* pucData, // Buffer to mix into.
  381. long lBufSize, // Size of memory that pucData points to.
  382. long lDataPos, // Position this buffer will take in the overall
  383. // stream.
  384. ULONG* /*pul_ppmixbuf*/) // An unused user value.
  385. {
  386. short sBufDone = TRUE; // Assume buffer not needed.
  387. // Get head of list of active channels.
  388. RMix* pmix = ms_listActive.GetHead();
  389. // If there are any active channels or we are auto-pumping . . .
  390. if (pmix != NULL || ms_sKeepPumping != FALSE)
  391. {
  392. ms_mixbuf.SetDest(pucData, lBufSize);
  393. while (pmix != NULL)
  394. {
  395. // Call mix channel. If data mixed into buffer . . .
  396. if (pmix->BlueCall(lDataPos, &ms_mixbuf) != FALSE)
  397. {
  398. // Mark buffer as needed.
  399. sBufDone = FALSE;
  400. }
  401. // Get next.
  402. pmix = ms_listActive.GetNext();
  403. }
  404. // Prepare for playback.
  405. ms_mixbuf.PrepareForDest();
  406. // Clear buffer from mixer.
  407. ms_mixbuf.SetDest(NULL, 0);
  408. // If we were reset recently, we are done processing the reset.
  409. ms_sReset = FALSE;
  410. // If auto-pumping . . .
  411. if (ms_sKeepPumping != FALSE)
  412. {
  413. // We always need the buffer.
  414. sBufDone = FALSE;
  415. }
  416. // If buffer needed . . .
  417. if (sBufDone == FALSE)
  418. {
  419. // Buffer is going back into queue.
  420. // If there are sound fx . . .
  421. if (ms_psndfx != NULL)
  422. {
  423. // Perform them on buffer.
  424. ms_psndfx->Do(pucData, lBufSize);
  425. }
  426. // Update current position in audio.
  427. ms_lCurPos += lBufSize;
  428. }
  429. }
  430. // Non-zero return value indicates
  431. // that pucData should not be
  432. // played. Additionally, rspDoSound()
  433. // will not call the callback until
  434. // the next rspDoSound() call.
  435. return sBufDone;
  436. }
  437. //////////////////////////////////////////////////////////////////////////////
  438. // Methods.
  439. //////////////////////////////////////////////////////////////////////////////
  440. //////////////////////////////////////////////////////////////////////////////
  441. //
  442. // Set the current audio mode.
  443. // This will cause any open channels to start playing.
  444. // (static)
  445. //
  446. //////////////////////////////////////////////////////////////////////////////
  447. short RMix::SetMode( // Returns 0 on success.
  448. long lSamplesPerSec, // Sample rate in samples per second.
  449. long lDstBitsPerSample, // Number of bits per sample.
  450. long lNumChannels, // Number of channels (1 == mono,2 == stereo).
  451. long lBufferTime, // Amount of time buffer spends in queue b4
  452. // being played.
  453. long lMaxBufferTime, // Maximum that lBufferTime can be set to
  454. // dynamically with RMix::SetBufferTime().
  455. long lMixBitsPerSample, // Bit depth at which samples will be mixed.
  456. long lSrcBitsPerSample) // Bit depth at which samples must be to be
  457. // mixed or 0 for no preference.
  458. {
  459. short sRes = 0; // Assume success.
  460. if (ms_sSetMode == FALSE)
  461. {
  462. // Set up mix to values.
  463. RMixBuf::ms_lSampleRate = lSamplesPerSec;
  464. RMixBuf::ms_lNumChannels = lNumChannels;
  465. RMixBuf::ms_lSrcBitsPerSample = lSrcBitsPerSample;
  466. RMixBuf::ms_lMixBitsPerSample = lMixBitsPerSample;
  467. RMixBuf::ms_lDstBitsPerSample = lDstBitsPerSample;
  468. // Clear position.
  469. ms_lCurPos = 0L;
  470. // Set the mode to this data type.
  471. sRes = rspSetSoundOutMode(
  472. lSamplesPerSec,
  473. lDstBitsPerSample,
  474. lNumChannels,
  475. lBufferTime,
  476. lMaxBufferTime,
  477. BlueCallStatic,
  478. 0L);
  479. if (sRes == 0)
  480. {
  481. // Remember we set the mode, so we know to kill the mode.
  482. ms_sSetMode = TRUE;
  483. }
  484. else
  485. {
  486. TRACE("SetMode(): rspSetSoundOutMode failed.\n");
  487. }
  488. }
  489. else
  490. {
  491. TRACE("SetMode(): Already in a mode.\n");
  492. sRes = 1;
  493. }
  494. return sRes;
  495. }
  496. //////////////////////////////////////////////////////////////////////////////
  497. //
  498. // Kills the current audio mode.
  499. // This will cause any open channels to be closed stops Blue from
  500. // utilizing the sound audio device.
  501. // (static)
  502. //
  503. //////////////////////////////////////////////////////////////////////////////
  504. void RMix::KillMode(void)
  505. {
  506. if (ms_sSetMode != FALSE)
  507. {
  508. // Attempt to end the audio mode.
  509. rspKillSoundOutMode();
  510. ms_sSetMode = FALSE;
  511. }
  512. else
  513. {
  514. TRACE("KillMode(): Not in a mode.\n");
  515. }
  516. }
  517. //////////////////////////////////////////////////////////////////////////////
  518. //
  519. // Pause currently playing audio.
  520. // NOTE: Pause/Resume is implemented in levels by Blue.
  521. // (static)
  522. //
  523. //////////////////////////////////////////////////////////////////////////////
  524. short RMix::Pause(void) // Returns 0 on success.
  525. {
  526. short sRes = 0; // Assume success.
  527. if (ms_sSetMode != FALSE)
  528. {
  529. if (rspPauseSoundOut() == 0)
  530. {
  531. }
  532. else
  533. {
  534. TRACE("Pause(): rspPauseSoundOut() failed.\n");
  535. sRes = -1;
  536. }
  537. }
  538. else
  539. {
  540. TRACE("Pause(): Not in a mode.\n");
  541. sRes = 1;
  542. }
  543. return sRes;
  544. }
  545. //////////////////////////////////////////////////////////////////////////////
  546. //
  547. // Resume currently paused audio.
  548. // NOTE: Pause/Resume is implemented in levels by Blue.
  549. // (static)
  550. //
  551. //////////////////////////////////////////////////////////////////////////////
  552. short RMix::Resume(void) // Returns 0 on success.
  553. {
  554. short sRes = 0; // Assume success.
  555. if (ms_sSetMode != FALSE)
  556. {
  557. if (rspResumeSoundOut() == 0)
  558. {
  559. }
  560. else
  561. {
  562. TRACE("Resume(): rspResumeSoundOut() failed.\n");
  563. sRes = -1;
  564. }
  565. }
  566. else
  567. {
  568. TRACE("Resume(): Not in a mode.\n");
  569. sRes = 1;
  570. }
  571. return sRes;
  572. }
  573. //////////////////////////////////////////////////////////////////////////////
  574. //
  575. // Returns TRUE, if sound output is paused; FALSE otherwise.
  576. // (static)
  577. //
  578. //////////////////////////////////////////////////////////////////////////////
  579. short RMix::IsPaused(void) // Returns TRUE, if sound output is paused; FALSE otherwise.
  580. {
  581. return rspIsSoundOutPaused();
  582. }
  583. //////////////////////////////////////////////////////////////////////////////
  584. //
  585. // Do stuff specific to RMix and the playing of audio through Blue.
  586. // This includes calling rspDoSound().
  587. // (static)
  588. //
  589. //////////////////////////////////////////////////////////////////////////////
  590. long RMix::Do(void) // Returns value returned by rspDoSound() that
  591. // indicates how much audio, in milliseconds,
  592. // was required to be queued.
  593. {
  594. ///////////////////////////////////////////////////////////////////////////
  595. // Check for buffers that have completed playing:
  596. ///////////////////////////////////////////////////////////////////////////
  597. rspLockSound();
  598. long lPlayPos;
  599. // If in a mode . . .
  600. if (ms_sSetMode != FALSE)
  601. {
  602. // Get current play cursor position.
  603. lPlayPos = rspGetSoundOutPos();
  604. }
  605. else
  606. {
  607. // Everything might as well just be done.
  608. lPlayPos = 0x7FFFFFFF;
  609. }
  610. PMIX pmix = ms_listActive.GetHead();
  611. while (pmix != NULL)
  612. {
  613. // If pmix is suspending . . .
  614. if (pmix->m_sSuspending != FALSE)
  615. {
  616. // If the play cursor has passed the last data put in from pmix
  617. // or we were recently reset . . .
  618. if (lPlayPos > pmix->m_lLastDataPos || ms_sReset != FALSE)
  619. {
  620. // Finish this channel. Note that this function removes pmix
  621. // from the list, but since it is pmix that gets removed, when
  622. // we do a GetNext() we get the one after pmix.
  623. if (pmix->ChannelFinished() == 0)
  624. {
  625. // Successfully suspended.
  626. }
  627. else
  628. {
  629. TRACE("Do(): ChannelFinished() failed.\n");
  630. }
  631. }
  632. }
  633. pmix = ms_listActive.GetNext();
  634. }
  635. ///////////////////////////////////////////////////////////////////////////
  636. // Monitor RMix state:
  637. ///////////////////////////////////////////////////////////////////////////
  638. ///////////////////////////////////////////////////////////////////////////
  639. // Let Blue do its Sound schtuff:
  640. ///////////////////////////////////////////////////////////////////////////
  641. long rc = rspDoSound();
  642. rspUnlockSound();
  643. return(rc);
  644. }
  645. //////////////////////////////////////////////////////////////////////////////
  646. //
  647. // Open a mix channel.
  648. // Returns 0 on success, 1 if no mode, negative on error.
  649. //
  650. //////////////////////////////////////////////////////////////////////////////
  651. short RMix::OpenChannel(long lSampleRate,
  652. long lBitsPerSample,
  653. long lNumChannels)
  654. {
  655. short sRes = 0; // Assume success.
  656. // There must be a mode . . .
  657. if (ms_sSetMode != FALSE)
  658. {
  659. if (m_sOpen == FALSE)
  660. {
  661. // Set up channel.
  662. m_lSampleRate = lSampleRate;
  663. m_lBitsPerSample = lBitsPerSample;
  664. m_lNumChannels = lNumChannels;
  665. // Set open flag.
  666. m_sOpen = TRUE;
  667. }
  668. else
  669. {
  670. TRACE("OpenChannel(): Already open.\n");
  671. sRes = -1;
  672. }
  673. }
  674. else
  675. {
  676. // No current mode.
  677. sRes = 1;
  678. }
  679. return sRes;
  680. }
  681. //////////////////////////////////////////////////////////////////////////////
  682. //
  683. // Close a mix channel.
  684. // Returns 0 on success.
  685. //
  686. //////////////////////////////////////////////////////////////////////////////
  687. short RMix::CloseChannel(void)
  688. {
  689. short sRes = 0; // Assume success.
  690. if (m_sOpen == TRUE)
  691. {
  692. if (m_sActive == FALSE)
  693. {
  694. // Clear open flag.
  695. m_sOpen = FALSE;
  696. }
  697. else
  698. {
  699. TRACE("CloseChannel(): Channel is active.\n");
  700. sRes = -2;
  701. }
  702. }
  703. else
  704. {
  705. TRACE("CloseChannel(): Not open.\n");
  706. sRes = -1;
  707. }
  708. return sRes;
  709. }
  710. //////////////////////////////////////////////////////////////////////////////
  711. //
  712. // Start receiving callbacks to fill channel data.
  713. // Set the initial mix volumes
  714. // Returns 0 on success.
  715. //
  716. //////////////////////////////////////////////////////////////////////////////
  717. short RMix::Start(RMixCall mcUser, ULONG ulUser,
  718. UCHAR ucVolume /* = 255 */, UCHAR ucVol2 /* = 255 */)
  719. {
  720. short sRes = 0; // Assume success.
  721. ASSERT(m_sOpen == TRUE);
  722. ASSERT(mcUser != NULL);
  723. // Add to active list . . .
  724. if (ms_listActive.Add(this) == 0)
  725. {
  726. // Set user parms.
  727. m_mcUser = mcUser;
  728. m_ulUser = ulUser;
  729. // Init user data.
  730. m_pucData = NULL;
  731. m_ulAmount = 0L;
  732. // Flag start time/pos to be set later.
  733. m_lStartTime = -1L;
  734. m_lStartPos = -1L;
  735. // Make sure we don't suspend right away.
  736. m_sSuspending = FALSE;
  737. // If any errors occurred . . .
  738. if (sRes != 0)
  739. {
  740. if (ms_listActive.Remove(this) == 0)
  741. {
  742. }
  743. else
  744. {
  745. TRACE("Start(): Unable to remove from active list after error.\n");
  746. }
  747. }
  748. else
  749. {
  750. // Set the initial sound volumes
  751. m_ucVolume = ucVolume;
  752. m_ucSecondaryVolume = ucVol2;
  753. // Mark as active.
  754. m_sActive = TRUE;
  755. // We are now mixing or will be on the next Do().
  756. ms_sState = Processing;
  757. }
  758. }
  759. else
  760. {
  761. TRACE("Start(): Unable to add to active list.\n");
  762. sRes = -1;
  763. }
  764. return sRes;
  765. }
  766. //////////////////////////////////////////////////////////////////////////////
  767. //
  768. // Stop receiving callbacks to fill channel data.
  769. // Returns 0 on success.
  770. //
  771. //////////////////////////////////////////////////////////////////////////////
  772. short RMix::Suspend(void)
  773. {
  774. short sRes = 0; // Assume success.
  775. if (m_sActive == TRUE)
  776. {
  777. // Let callback know this channel is suspending.
  778. m_sSuspending = TRUE;
  779. // Set point at which we will be done to very, very soon.
  780. m_lLastDataPos = 0L;
  781. // Finish now, now.
  782. ChannelFinished();
  783. }
  784. return sRes;
  785. }
  786. //////////////////////////////////////////////////////////////////////////////
  787. //
  788. // Pause mix channel.
  789. //
  790. //////////////////////////////////////////////////////////////////////////////
  791. void RMix::PauseChannel(void)
  792. {
  793. ASSERT(m_sPauseLevel < 32767);
  794. m_sPauseLevel++;
  795. }
  796. //////////////////////////////////////////////////////////////////////////////
  797. //
  798. // Resume mix channel.
  799. //
  800. //////////////////////////////////////////////////////////////////////////////
  801. void RMix::ResumeChannel(void)
  802. {
  803. ASSERT(m_sPauseLevel > 0);
  804. m_sPauseLevel--;
  805. }
  806. //////////////////////////////////////////////////////////////////////////////
  807. //
  808. // Check mix channel's paused status.
  809. //
  810. //////////////////////////////////////////////////////////////////////////////
  811. short RMix::IsChannelPaused(void) // Returns TRUE, if sound output is paused; FALSE otherwise.
  812. {
  813. return (m_sPauseLevel == 0) ? FALSE : TRUE;
  814. }
  815. //////////////////////////////////////////////////////////////////////////////
  816. //
  817. // This function resets all current channels (but does not suspend) them.
  818. // Basically, it function much like Windows' Reset command in that it simply
  819. // returns any buffers currently being used. It works asynchronously.
  820. // NEVER CALL rspClearSoundOut() when using RMix.
  821. // Returns 0 on success. (static)
  822. //
  823. //////////////////////////////////////////////////////////////////////////////
  824. short RMix::Reset(void)
  825. {
  826. short sRes = 0; // Assume success.
  827. // Attempt to reset sound output . . .
  828. if (rspClearSoundOut() == 0)
  829. {
  830. // Get the current position.
  831. // Update ms_lCurPos appropriately.
  832. ms_lCurPos = rspGetSoundOutPos();
  833. // Success. Flag callbacks.
  834. ms_sReset = TRUE;
  835. }
  836. else
  837. {
  838. TRACE("Reset(): Unable to reset Blue's Sound Out.\n");
  839. sRes = -1;
  840. }
  841. return sRes;
  842. }
  843. //////////////////////////////////////////////////////////////////////////////
  844. //
  845. // Suspends all current mix channels.
  846. // (static)
  847. //
  848. //////////////////////////////////////////////////////////////////////////////
  849. short RMix::SuspendAll(void) // Returns 0 on success.
  850. {
  851. short sRes = 0; // Assume success.
  852. RMix* pmix = ms_listActive.GetHead();
  853. while (pmix != NULL)
  854. {
  855. // Finish this channel. Note that this function removes pmix
  856. // from the list, but since it is pmix that gets removed, when
  857. // we do a GetNext() we get the one after pmix.
  858. pmix->ChannelFinished();
  859. pmix = ms_listActive.GetNext();
  860. }
  861. return sRes;
  862. }
  863. //////////////////////////////////////////////////////////////////////////////
  864. //
  865. // Called when all sound on a channel has finished.
  866. // Returns 0 on success.
  867. //
  868. //////////////////////////////////////////////////////////////////////////////
  869. short RMix::ChannelFinished(void)
  870. {
  871. short sRes = 0; // Assume success.
  872. ASSERT(m_sActive == TRUE);
  873. if (ms_listActive.Remove(this) == 0)
  874. {
  875. m_sActive = FALSE;
  876. // Call user callback to let it know we're suspended.
  877. (*m_mcUser)(Suspended, NULL, NULL, m_ulUser, NULL, NULL);
  878. // If there are no more buffers . .
  879. if (ms_listActive.IsEmpty() != FALSE)
  880. {
  881. ms_sState = Idle;
  882. }
  883. }
  884. else
  885. {
  886. sRes = -1;
  887. TRACE("ChannelFinished(): Unable to remove Mixer from active list.\n");
  888. }
  889. return sRes;
  890. }
  891. //////////////////////////////////////////////////////////////////////////////
  892. // Querries.
  893. //////////////////////////////////////////////////////////////////////////////
  894. //////////////////////////////////////////////////////////////////////////////
  895. //
  896. // Returns the time for this RMix (positive if successful).
  897. //
  898. //////////////////////////////////////////////////////////////////////////////
  899. long RMix::GetTime(void)
  900. {
  901. long lRes;
  902. if (m_lStartTime >= 0L)
  903. {
  904. lRes = rspGetSoundOutTime();
  905. if (lRes != -1L)
  906. {
  907. lRes -= m_lStartTime;
  908. }
  909. else
  910. {
  911. TRACE("GetTime(): Unable to get time from Blue.\n");
  912. }
  913. }
  914. else
  915. {
  916. lRes = -1L;
  917. }
  918. return lRes;
  919. }
  920. //////////////////////////////////////////////////////////////////////////////
  921. //
  922. // Returns the position for this RMix (positive if successful).
  923. //
  924. //////////////////////////////////////////////////////////////////////////////
  925. long RMix::GetPos(void)
  926. {
  927. long lRes;
  928. if (m_lStartPos >= 0L)
  929. {
  930. lRes = rspGetSoundOutPos();
  931. if (lRes != -1L)
  932. {
  933. lRes -= m_lStartPos;
  934. }
  935. else
  936. {
  937. TRACE("GetPos(): Unable to get pos from Blue.\n");
  938. }
  939. }
  940. else
  941. {
  942. lRes = -1L;
  943. }
  944. return lRes;
  945. }
  946. //////////////////////////////////////////////////////////////////////////////
  947. //
  948. // Gets the current mode of the sound output device.
  949. // (static).
  950. //
  951. //////////////////////////////////////////////////////////////////////////////
  952. short RMix::GetMode( // Returns 0 on success;
  953. // nonzero if no mode.
  954. long* plSamplesPerSec, // Sample rate in samples per second
  955. // returned here, if not NULL.
  956. long* plDevBitsPerSample, // Bits per sample of device,
  957. // returned here, if not NULL.
  958. long* plNumChannels, // Number of channels (1 == mono,
  959. // 2 == stereo) returned here,
  960. // if not NULL.
  961. long* plBufferTime, // Amount of time in ms to lead the
  962. // current play cursor returned here,
  963. // if not NULL. This could also be
  964. // described as the maximum amount of
  965. // time in ms that can occur between
  966. // calls to rspDoSound.
  967. long* plMaxBufferTime, // Maximum buffer time. This is the amt
  968. // that *plBufferTime can be increased to.
  969. // This is indicative of how much space
  970. // was/will-be allocated for the sound
  971. // output device on rspLockSoundOut.
  972. long* plMixBitsPerSample, // Bits per sample at which samples are
  973. // mixed, if not NULL.
  974. long* plSrcBitsPerSample) // Bits per sample at which samples must
  975. // be to be mixed (0 if no requirement),
  976. // if not NULL.
  977. {
  978. short sRes = rspGetSoundOutMode(
  979. plSamplesPerSec,
  980. plDevBitsPerSample,
  981. plNumChannels,
  982. plBufferTime,
  983. plMaxBufferTime);
  984. if (plMixBitsPerSample)
  985. {
  986. *plMixBitsPerSample = RMixBuf::ms_lMixBitsPerSample;
  987. }
  988. if (plSrcBitsPerSample)
  989. {
  990. *plSrcBitsPerSample = RMixBuf::ms_lSrcBitsPerSample;
  991. }
  992. return sRes;
  993. }
  994. //////////////////////////////////////////////////////////////////////////////
  995. // EOF
  996. //////////////////////////////////////////////////////////////////////////////