snd.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  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. // snd.cpp
  21. //
  22. // History:
  23. // 04/28/95 JMI Started.
  24. //
  25. // 05/22/95 JMI Added GetPos().
  26. //
  27. // 06/08/95 JMI Added GetTime().
  28. //
  29. // 06/14/95 JMI Added ability to use any number of buffers to stream.
  30. // This is limited, of course, by the capabilities of BLUE.
  31. //
  32. // 07/15/95 JMI Added loop ability through public member m_sLoop.
  33. //
  34. // 07/31/96 JMI Now responds to BLU_SNDMSG_DATA instead of
  35. // RSP_SNDMSG_OK/PREPLAYERR/POSTPLAYERR.
  36. //
  37. // 08/26/96 JMI Changed BLU_SNDMSG_* to RSP_SNDMSG_*. Removed
  38. // lPrimeInterval parm from play. It has not been used
  39. // since 07/15/95, I think.
  40. //
  41. // 08/30/96 JMI Abort() now calls m_mix.Suspend() as it should have been.
  42. //
  43. // 09/03/96 JMI Adapted to newest revision of Blue Sound API (which
  44. // removed rspStart/StopSoundOutCallbacks,
  45. // rspIsSoundOutCallingBack, and callback messages
  46. // (RSP_SNDMSG_DONE and RSP_SNDMSG_DATA).
  47. //
  48. // 10/27/96 MJR Fixed "unused variable" warnings.
  49. //
  50. // 10/28/96 JMI Removed unused variable lPrimeInterval.
  51. //
  52. // 10/30/96 JMI Changed:
  53. // Old label: New label:
  54. // ========= =========
  55. // CMix RMix
  56. // RSnd RSnd
  57. // MIX_STATE_* *
  58. // MIX_MSG_* *
  59. // SND_STATE_* * Macros changed to enum.
  60. //
  61. // 01/29/97 JMI Added callback on done.
  62. //
  63. // 04/02/97 JMI When I added the callback, I forgot to initialize it in
  64. // Init(). Fixed.
  65. //
  66. // 05/09/97 JMI Added ability to loop sub samples.
  67. //
  68. // 05/13/97 JMI Casted instances of warning C4018 (signed/unsigned mismatch)
  69. // to make MSVC 4.1(Alpha) happy (these seem to fall under
  70. // Warning Level 3 in 4.1(Alpha) but not in 4.2(Intel)).
  71. //
  72. // 07/15/97 JRD Added members to hold sound volume information. Made
  73. // sure callbacks updated volume levels and all levels
  74. // were passed on.
  75. //
  76. // 07/30/97 JMI Added ASSERTs so stupid people (let's call one of them
  77. // JMI) don't pass loop points that exceed the overall size
  78. // of the sample buffer causing cool music.
  79. // Also, added if's to check these in non-TRACENASSERT mode.
  80. //
  81. // 08/01/97 JMI End loop time parameter to Play() was not working as
  82. // stated for 0 case b/c it had a < 0 instead of < 1.
  83. //
  84. // 08/11/97 JMI Placed Sound Done callback such that the user can still
  85. // access the sample safely, if desired.
  86. //
  87. // 09/25/97 JMI Now PlayCall() only calls the callback if Abort() was
  88. // not called (Abort() calls the callback).
  89. //
  90. //////////////////////////////////////////////////////////////////////////////
  91. //
  92. // This thing uses blue to play or stream a music file. Currently only WAV
  93. // files are supported, but I tried to make it easy for it to be modified to
  94. // autodetect and load other wave files.
  95. //
  96. //////////////////////////////////////////////////////////////////////////////
  97. #include "System.h"
  98. #ifdef PATHS_IN_INCLUDES
  99. #include "GREEN/Snd/snd.h"
  100. #include "BLUE/Blue.h"
  101. #else
  102. #include "snd.h"
  103. #include "Blue.h"
  104. #endif // PATHS_IN_INCLUDES
  105. //////////////////////////////////////////////////////////////////////////////
  106. // Initialize static member variables.
  107. //////////////////////////////////////////////////////////////////////////////
  108. //////////////////////////////////////////////////////////////////////////////
  109. // Macros.
  110. //////////////////////////////////////////////////////////////////////////////
  111. #define SND_TYPE_UNKNOWN 0x0000
  112. #define SND_TYPE_WAVE 0x0001
  113. //////////////////////////////////////////////////////////////////////////////
  114. // Functions.
  115. //////////////////////////////////////////////////////////////////////////////
  116. //////////////////////////////////////////////////////////////////////////////
  117. //
  118. // Default Constructor.
  119. // Returns nothing.
  120. // (public)
  121. //
  122. //////////////////////////////////////////////////////////////////////////////
  123. RSnd::RSnd()
  124. {
  125. Init();
  126. }
  127. //////////////////////////////////////////////////////////////////////////////
  128. //
  129. // Destructor.
  130. // Returns nothing.
  131. // (public)
  132. //
  133. //////////////////////////////////////////////////////////////////////////////
  134. RSnd::~RSnd()
  135. {
  136. // Reset and free.
  137. Reset();
  138. }
  139. //////////////////////////////////////////////////////////////////////////////
  140. //
  141. // Initialize instantiable members.
  142. // Returns nothing.
  143. // (public)
  144. //
  145. //////////////////////////////////////////////////////////////////////////////
  146. void RSnd::Init(void)
  147. {
  148. // Initialize members.
  149. m_lBufSize = 0L;
  150. m_sState = Stopped;
  151. m_psample = NULL;
  152. m_sOwnSample = FALSE;
  153. m_sLoop = FALSE;
  154. m_dcUser = NULL;
  155. m_lLoopStartPos = 0;
  156. m_lLoopEndPos = 0;
  157. m_sTypeVolume = 255; // should be overwritten by Play
  158. m_sChannelVolume = 255; // should be overwritten by Play
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////
  161. //
  162. // Reset object. Release play data and reset variables.
  163. // Returns nothing.
  164. // (public)
  165. //
  166. ///////////////////////////////////////////////////////////////////////////////
  167. void RSnd::Reset(void)
  168. {
  169. ASSERT(GetState() == Stopped);
  170. if (GetState() == Stopped)
  171. {
  172. if (m_psample != NULL)
  173. {
  174. // Unlock the sample.
  175. m_psample->Unlock();
  176. // If we are responsible for the sample . . .
  177. if (m_sOwnSample == TRUE)
  178. {
  179. delete m_psample;
  180. m_psample = NULL;
  181. }
  182. }
  183. Init();
  184. }
  185. else
  186. {
  187. TRACE("Reset(): Attempt to Reset a playing WAVE!\n");
  188. }
  189. }
  190. ///////////////////////////////////////////////////////////////////////////////
  191. //
  192. // This function instigates streaming of a sound file. The file is opened, the
  193. // header read, the sound device opened, and a task is started to begin filling
  194. // Blue's available sound output buffers with audio data. The task starts
  195. // reading data every lPrimeInterval milliseconds to fill all of Blue's buffers
  196. // and then fires them off and suspends itself. The callback reads the data
  197. // in lReadBufSize chunks and plays in lPlayBufSize chunks.
  198. //
  199. // Returns 0 on success.
  200. // (public)
  201. //
  202. ///////////////////////////////////////////////////////////////////////////////
  203. short RSnd::Stream( char* pszSampleName, long lPlayBufSize, long lReadBufSize,
  204. UCHAR ucMainVolume /* = 255 */, UCHAR ucVolume2 /* = 255 */)
  205. {
  206. short sRes = 0;
  207. // Reset variables and free data if any.
  208. Reset();
  209. // Attempt to create RSample . . .
  210. m_psample = new RSample;
  211. if (m_psample != NULL)
  212. {
  213. // Remember we're responsible for de-allocating this RSample.
  214. m_sOwnSample = TRUE;
  215. if (m_psample->Open(pszSampleName, lReadBufSize) > 0L)
  216. {
  217. // Attempt to open a sound channel . . .
  218. if (m_mix.OpenChannel( m_psample->m_lSamplesPerSec,
  219. m_psample->m_sBitsPerSample,
  220. m_psample->m_sNumChannels) == 0)
  221. {
  222. // Store the buffer size to stream with.
  223. m_lBufSize = lPlayBufSize;
  224. // Attempt to start the mixing . . .
  225. if (m_mix.Start(StreamCallStatic, (ULONG)this) == 0)
  226. {
  227. // Success. Set state to starting.
  228. m_sState = Starting;
  229. }
  230. else
  231. {
  232. TRACE("Stream(\"%s\"): Unable to start mixer.\n", pszSampleName);
  233. sRes = -7;
  234. }
  235. // If any failures . . .
  236. if (sRes != 0)
  237. {
  238. if (m_mix.CloseChannel() != 0)
  239. {
  240. TRACE("Stream(\"%s\"): Unable to close sound channel.\n", pszSampleName);
  241. }
  242. }
  243. }
  244. else
  245. {
  246. TRACE("Stream(\"%s\"): Unable to open sound channel.\n", pszSampleName);
  247. sRes = -6;
  248. }
  249. // If any failures . . .
  250. if (sRes != 0)
  251. {
  252. // Close sample.
  253. m_psample->Close();
  254. }
  255. }
  256. else
  257. {
  258. TRACE("Stream(\"%s\"): Unable to open sample file.\n", pszSampleName);
  259. sRes = -5;
  260. }
  261. // If any failures . . .
  262. if (sRes != 0)
  263. {
  264. delete m_psample;
  265. m_psample = NULL;
  266. }
  267. }
  268. else
  269. {
  270. TRACE("Stream(\"%s\"): Unable to allocate RSample.\n", pszSampleName);
  271. sRes = -3;
  272. }
  273. return sRes;
  274. }
  275. ///////////////////////////////////////////////////////////////////////////////
  276. //
  277. // Plays RSample supplied via ptr with buffer size of lPlayBufSize
  278. // (this is the size of the chunks sent to RMix).
  279. // (public)
  280. // Note on looping:
  281. // Start End
  282. // 1-----------------------------------------------------------4
  283. // 2=======================================3
  284. // lLoopStartTime lLoopEndTime
  285. //
  286. // In a looping scenario, 1..2 of the sample is played, then 2..3
  287. // is repeated until m_sLoop is FALSE, at which time, once 3 is reached,
  288. // 3..4 is played.
  289. //
  290. ///////////////////////////////////////////////////////////////////////////////
  291. short RSnd::Play( // Returns 0 on success.
  292. RSample* psample, // In: Sample to play.
  293. long lPlayBufSize, // In: Size of play buffer in bytes.
  294. UCHAR ucMainVolume/* = 255 */,// In: Primary Volume (0 - 255)
  295. UCHAR ucVolume2 /* = 255 */, // In: Secondary Volume (0 - 255)
  296. long lLoopStartTime/* = -1*/, // In: Where to loop back to in milliseconds.
  297. // -1 indicates no looping (unless m_sLoop is
  298. // explicitly set).
  299. long lLoopEndTime/* = 0*/) // In: Where to loop back from in milliseconds.
  300. // In: If less than 1, the end + lLoopEndTime is used.
  301. {
  302. short sRes = 0; // Assume success.
  303. ASSERT(psample != NULL);
  304. ASSERT(GetState() == Stopped);
  305. // Use supplied sample.
  306. m_psample = psample;
  307. // Remember we're not responsible for this buffer (i.e., freeing it).
  308. m_sOwnSample = FALSE;
  309. // Attempt to lock sample . . .
  310. if (m_psample->Lock() == 0)
  311. {
  312. // Attempt to open a sound channel . . .
  313. if (m_mix.OpenChannel( m_psample->m_lSamplesPerSec,
  314. m_psample->m_sBitsPerSample,
  315. m_psample->m_sNumChannels) == 0)
  316. {
  317. // Store the buffer size to stream with.
  318. m_lBufSize = lPlayBufSize;
  319. // Attempt to play buffer . . .
  320. if (m_mix.Start(PlayCallStatic, (ULONG)this,ucMainVolume,ucVolume2) == 0)
  321. {
  322. // Success. Set state to starting.
  323. m_sState = Starting;
  324. if (lLoopStartTime > -1)
  325. {
  326. // Set looping parameters.
  327. m_sLoop = TRUE;
  328. m_lLoopStartPos = psample->GetPos(lLoopStartTime);
  329. m_lLoopEndPos = psample->GetPos(lLoopEndTime);
  330. // If using the end . . .
  331. if (lLoopEndTime < 1)
  332. {
  333. // Use the duration plus the specified negative time.
  334. m_lLoopEndPos += psample->m_lBufSize;
  335. }
  336. // Cannot be off end of buffer or beginning of buffer.
  337. ASSERT(m_lLoopStartPos <= psample->m_lBufSize);
  338. ASSERT(m_lLoopEndPos <= psample->m_lBufSize);
  339. ASSERT(m_lLoopStartPos >= 0);
  340. ASSERT(m_lLoopStartPos < m_lLoopEndPos);
  341. // Fix these values in case we're in release mode.
  342. if (m_lLoopStartPos > psample->m_lBufSize)
  343. {
  344. m_lLoopStartPos = psample->m_lBufSize;
  345. }
  346. if (m_lLoopEndPos > psample->m_lBufSize)
  347. {
  348. m_lLoopEndPos = psample->m_lBufSize;
  349. }
  350. if (m_lLoopStartPos < 0)
  351. {
  352. m_lLoopStartPos = 0;
  353. }
  354. if (m_lLoopStartPos > m_lLoopEndPos)
  355. {
  356. m_lLoopStartPos = m_lLoopEndPos;
  357. }
  358. }
  359. else // Backwards compatability.
  360. {
  361. // If m_sLoop was set . . .
  362. if (m_sLoop != FALSE)
  363. {
  364. m_lLoopStartPos = 0;
  365. // Use end of sample as loop back point.
  366. m_lLoopEndPos = psample->m_lBufSize;
  367. }
  368. }
  369. }
  370. else
  371. {
  372. TRACE("Play(): Unable to play sound buffer.\n");
  373. sRes = -3;
  374. }
  375. // If any failures . . .
  376. if (sRes != 0)
  377. {
  378. if (m_mix.CloseChannel() != 0)
  379. {
  380. TRACE("Play(): Unable to close sound channel.\n");
  381. }
  382. }
  383. }
  384. else
  385. {
  386. // commented out due to spam from --nosound. --ryan.
  387. //TRACE("Play(): Unable to open sound output device.\n");
  388. sRes = -2;
  389. }
  390. // If any failures . . .
  391. if (sRes != 0)
  392. {
  393. // Unlock sample.
  394. m_psample->Unlock();
  395. // We have no more use for this sample.
  396. m_psample = NULL;
  397. }
  398. }
  399. else
  400. {
  401. TRACE("Play(): Unable to lock supplied sample.\n");
  402. sRes = -1;
  403. }
  404. return sRes;
  405. }
  406. ///////////////////////////////////////////////////////////////////////////////
  407. //
  408. // Aborts current play or stream.
  409. // Returns 0 on success.
  410. // (public)
  411. //
  412. ///////////////////////////////////////////////////////////////////////////////
  413. short RSnd::Abort(void)
  414. {
  415. short sRes = 0; // Assume success.
  416. ASSERT(GetState() != Stopped);
  417. // If we have a sample (i.e., we are streaming/playing) . . .
  418. if (m_psample != NULL)
  419. {
  420. // Unlock the sample.
  421. m_psample->Unlock();
  422. // Call callback, if specified.
  423. if (m_dcUser != NULL)
  424. {
  425. (*m_dcUser)(this);
  426. }
  427. if (m_sOwnSample == TRUE)
  428. {
  429. // Destroy sample.
  430. delete m_psample;
  431. // We no longer own the sample.
  432. m_sOwnSample = FALSE;
  433. }
  434. // Clear the sample ptr. This will cause streaming/playing to end.
  435. m_psample = NULL;
  436. // Let RMix know we want to abort.
  437. if (m_mix.Suspend() == 0)
  438. {
  439. }
  440. else
  441. {
  442. TRACE("Abort(): RMix::Suspend() failed.\n");
  443. }
  444. }
  445. else
  446. {
  447. // TRACE("Abort(): No current RSample.\n");
  448. sRes = -1;
  449. }
  450. return sRes;
  451. }
  452. //////////////////////////////////////////////////////////////////////////////
  453. //
  454. // Gets/returns the current position of the audio in bytes.
  455. // (public)
  456. //
  457. //////////////////////////////////////////////////////////////////////////////
  458. long RSnd::GetPos(void)
  459. {
  460. return m_mix.GetPos();
  461. }
  462. //////////////////////////////////////////////////////////////////////////////
  463. //
  464. // Gets/returns the current time of the audio in milliseconds.
  465. // (public)
  466. //
  467. //////////////////////////////////////////////////////////////////////////////
  468. long RSnd::GetTime(void)
  469. {
  470. return m_mix.GetTime();
  471. }
  472. //////////////////////////////////////////////////////////////////////////////
  473. //
  474. // Called from StreamCallStatic when Blue is done playing our buffer.
  475. // Returns current volume information back to the RMix
  476. // Returns pointer to next buffer to play or NULL to end.
  477. //
  478. //////////////////////////////////////////////////////////////////////////////
  479. void* RSnd::StreamCall(RMix::Msg msg,
  480. void* pData,
  481. ULONG* pulBufSize,
  482. ULONG ulUser,
  483. UCHAR* pucVolume,
  484. UCHAR* pucVol2)
  485. {
  486. switch (msg)
  487. {
  488. case RMix::Data:
  489. // If not done . . .
  490. if (m_psample != NULL)
  491. {
  492. // If we were starting . . .
  493. if (m_sState == Starting)
  494. {
  495. // Switch to queueing.
  496. m_sState = Queueing;
  497. }
  498. // Read a buffer . . .
  499. (*pulBufSize) = m_psample->Read(m_lBufSize);
  500. if (*pulBufSize > 0)
  501. {
  502. // Set pointer. Technically, m_psample's pointer could change
  503. // time we call Read(). Remember that!
  504. pData = m_psample->m_pData;
  505. // If the message is not queueing and our state is queueing . . .
  506. if (m_sState == Queueing)
  507. {
  508. // Switch state to playing.
  509. m_sState = Playing;
  510. }
  511. }
  512. else
  513. {
  514. // If done . . .
  515. if (*pulBufSize == 0)
  516. {
  517. }
  518. else
  519. {
  520. TRACE("StreamCall(): Error reading sample data.\n");
  521. }
  522. // End streaming.
  523. pData = NULL;
  524. }
  525. }
  526. else
  527. {
  528. // Aborted.
  529. pData = NULL;
  530. }
  531. // If abort, done, or error . . .
  532. if (pData == NULL)
  533. {
  534. // Set state to ending.
  535. m_sState = Ending;
  536. }
  537. break;
  538. case RMix::Suspended:
  539. // If sample still pointed to (this is the case when the sound ends
  540. // normally (i.e., Abort() was NOT called) ). . .
  541. if (m_psample != NULL)
  542. {
  543. // Close the sample.
  544. if (m_psample->Close() != 0)
  545. {
  546. TRACE("StreamCall(): Unable to close RSample.\n");
  547. }
  548. // Call callback, if specified.
  549. if (m_dcUser != NULL)
  550. {
  551. (*m_dcUser)(this);
  552. }
  553. // If we own the sample . . .
  554. if (m_sOwnSample == TRUE)
  555. {
  556. // Delete it.
  557. delete m_psample;
  558. // No longer own it.
  559. m_sOwnSample = FALSE;
  560. }
  561. m_psample = NULL;
  562. }
  563. // Close the sound output channel.
  564. if (m_mix.CloseChannel() != 0)
  565. {
  566. TRACE("StreamCall(): Unable to close sound channel.\n");
  567. }
  568. // Set state to stopped.
  569. m_sState = Stopped;
  570. break;
  571. }
  572. // Get current Sound from internal members
  573. if (pucVolume) *pucVolume = m_sChannelVolume;
  574. if (pucVol2) *pucVol2 = m_sTypeVolume;
  575. // Return next buffer to play.
  576. return pData;
  577. }
  578. //////////////////////////////////////////////////////////////////////////////
  579. //
  580. // Called from PlayCallStatic when Blue is done playing our buffer.
  581. // Returns pointer to next buffer to play or NULL to end.
  582. // Sends back current information back to RMix
  583. // Recursive 1 deep.
  584. //
  585. //////////////////////////////////////////////////////////////////////////////
  586. void* RSnd::PlayCall(RMix::Msg msg,
  587. void* pData,
  588. ULONG* pulBufSize,
  589. UCHAR* pucVolume,
  590. UCHAR* pucVol2)
  591. {
  592. switch (msg)
  593. {
  594. case RMix::Data:
  595. // If not done . . .
  596. if (m_psample != NULL)
  597. {
  598. // If we were starting . . .
  599. if (m_sState == Starting)
  600. {
  601. // Switch to queueing.
  602. m_sState = Queueing;
  603. // Set remaining amount of data to play.
  604. m_ulRemaining = (m_sLoop == FALSE) ? m_psample->m_lBufSize : m_lLoopEndPos;
  605. // Set size of data to play.
  606. m_ulSampleSize = m_ulRemaining;
  607. }
  608. // Move to next buffer.
  609. pData = (UCHAR*)(m_psample->m_pData) + (m_ulSampleSize - m_ulRemaining);
  610. // Get next buffer size.
  611. (*pulBufSize) = MIN((ULONG)m_lBufSize, m_ulRemaining);
  612. if (*pulBufSize > 0)
  613. {
  614. // Deduct amount to play.
  615. m_ulRemaining = m_ulRemaining - (*pulBufSize);
  616. // If the message is not queueing and our state is queueing . . .
  617. if (m_sState == Queueing)
  618. {
  619. // Switch state to playing.
  620. m_sState = Playing;
  621. }
  622. }
  623. else
  624. {
  625. // If looping is disabled . . .
  626. if (m_sLoop == FALSE)
  627. {
  628. // If we were NOT looping a sub region . . .
  629. if (m_ulSampleSize == (ULONG)m_psample->m_lBufSize)
  630. {
  631. // Clear pointer.
  632. pData = NULL;
  633. }
  634. else
  635. {
  636. // Play the rest.
  637. // Set remaining amount of data to play.
  638. m_ulRemaining = m_psample->m_lBufSize - m_lLoopEndPos;
  639. // Set size of data to play.
  640. m_ulSampleSize = m_psample->m_lBufSize;
  641. // Recurse.
  642. pData = PlayCall(msg, pData, pulBufSize, pucVolume, pucVol2);
  643. }
  644. }
  645. else
  646. {
  647. // Restart at loop pos.
  648. // Set remaining amount of data to play.
  649. m_ulRemaining = m_lLoopEndPos - m_lLoopStartPos;
  650. // Set size of data to play.
  651. m_ulSampleSize = m_lLoopEndPos;
  652. // Recurse.
  653. pData = PlayCall(msg, pData, pulBufSize, pucVolume, pucVol2);
  654. }
  655. }
  656. }
  657. else
  658. {
  659. // Clear pointer.
  660. pData = NULL;
  661. }
  662. // If done or aborted . . .
  663. if (pData == NULL)
  664. {
  665. // Set state to ending.
  666. m_sState = Ending;
  667. }
  668. break;
  669. case RMix::Suspended:
  670. if (m_psample != NULL)
  671. {
  672. // Unlock the sample.
  673. m_psample->Unlock();
  674. // Call callback, if specified.
  675. if (m_dcUser != NULL)
  676. {
  677. (*m_dcUser)(this);
  678. }
  679. }
  680. // Close the sound output channel.
  681. if (m_mix.CloseChannel() != 0)
  682. {
  683. TRACE("PlayCall(): Unable to close sound channel.\n");
  684. }
  685. #if 0
  686. TRACE("Remaining: %lu, Size: %lu, State: %s, Sample: 0x%08lx.\n",
  687. m_ulRemaining, m_ulSampleSize,
  688. (m_sState == Ending ? "Ending" :
  689. (m_sState == Playing ? "Playing" :
  690. (m_sState == Queueing ? "Queueing" :
  691. (m_sState == Starting ? "Starting" :
  692. (m_sState == Stopped ? "Stopped" : "Invalid") ) ) ) ),
  693. m_psample
  694. );
  695. #endif
  696. // Set state to stopped.
  697. m_sState = Stopped;
  698. // Clear sample. No longer needed.
  699. m_psample = NULL;
  700. break;
  701. }
  702. // Get current Sound from internal members
  703. if (pucVolume) *pucVolume = m_sChannelVolume;
  704. if (pucVol2) *pucVol2 = m_sTypeVolume;
  705. // Return next buffer to play.
  706. return pData;
  707. }
  708. ////////////////////////////// Static functions //////////////////////////////
  709. //////////////////////////////////////////////////////////////////////////////
  710. //
  711. // Called from Blue when it is done playing our buffer.
  712. // Sends back up to the second volume information back to RMix
  713. // Returns pointer to next buffer to play or NULL to end.
  714. // (static)
  715. //
  716. //////////////////////////////////////////////////////////////////////////////
  717. void* RSnd::StreamCallStatic( RMix::Msg msg,
  718. void* pData,
  719. ULONG* pulBufSize,
  720. ULONG ulUser,
  721. UCHAR* pucVolume,
  722. UCHAR* pucVol2)
  723. {
  724. return ((PSND)ulUser)->StreamCall(msg, pData, pulBufSize,ulUser,pucVolume,pucVol2);
  725. }
  726. //////////////////////////////////////////////////////////////////////////////
  727. //
  728. // Called from Blue when it is done playing our buffer.
  729. // Sends back up to the second volume information back to RMix
  730. // Returns pointer to next buffer to play or NULL to end.
  731. // (static)
  732. //
  733. //////////////////////////////////////////////////////////////////////////////
  734. void* RSnd::PlayCallStatic(RMix::Msg msg,
  735. void* pData,
  736. ULONG* pulBufSize,
  737. ULONG ulUser,
  738. UCHAR* pucVolume,
  739. UCHAR* pucVol2)
  740. {
  741. return ((PSND)ulUser)->PlayCall(msg, pData, pulBufSize, pucVolume, pucVol2);
  742. }
  743. //////////////////////////////////////////////////////////////////////////////
  744. // EOF
  745. //////////////////////////////////////////////////////////////////////////////