soundtest.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:11k
源码类别:

Symbian

开发平台:

C/C++

  1. /* vi:set ts=8 sw=8:
  2.  *
  3.  * soundtest.cpp: A quick program to test the sound device API.
  4.  *
  5.  * Leo L. Schwab 2003.07.08
  6.  */
  7. #include <op_types.h>
  8. #include <op_math.h>
  9. #include <OpApplication.h>
  10. #include <op_sound.h>
  11. #include "soundtest.h"
  12. static const int BLOCK_SIZE = 7040; //176400;   // ~ 1s of audio
  13. enum Cmds
  14. {
  15. kCmdPlay = 1,
  16. kCmdPause,
  17. kCmdStop,
  18. };
  19. /***************************************************************************
  20.  * Prototypes.
  21.  */
  22. static void
  23. beepdone_callback (
  24. op_sound_handle const *handle,
  25. S32 msg,
  26. op_sound_buffer const *sndbuf,
  27. void *data
  28. );
  29. /***************************************************************************
  30.  * Constructors/Destructors.
  31.  */
  32. OaSoundTest::OaSoundTest (U16CPU flags) :
  33. fSndDev (NULL),
  34. OpApplication (flags),
  35. m_bWriteDone(true),
  36. m_fp(NULL),
  37. m_totalBytesRead(0),
  38. m_totalBytesWritten(0),
  39. bigbuf(NULL)
  40. {
  41. for (int i=0; i<2; i++)
  42. {
  43. fSndBuf[i].fSampleBuffer = NULL;
  44. fSndBuf[i].fNSamples = 0;
  45. fSndBuf[i].fUserData = NULL;
  46. fSndBuf[i].fFlags = OP_SNDBUFF_CALLBACK_ON_IODONE;
  47. }
  48. }
  49. OaSoundTest::~OaSoundTest (void)
  50. {
  51. for (int i=0; i<2; i++)
  52.     if (fSndBuf[i].fSampleBuffer) 
  53. free (fSndBuf[i].fSampleBuffer);
  54. }
  55. OpApplication *
  56. OaSoundTest::Create (void)
  57. {
  58. return (new OaSoundTest);
  59. }
  60. /***************************************************************************
  61.  * Event handlers.
  62.  */
  63. bool
  64. OaSoundTest::onEvent (OpEvent &evt)
  65. {
  66. if (evt.isCmdEvent()) {
  67. int cmd = OpCmdEvent::GetCmd (&evt);
  68. if (cmd == CMD_TEST) {
  69. testbeep ();
  70. return (true);
  71. } else if (cmd == CMD_BEEPDONE) {
  72. beepdone ();
  73. return (true);
  74. } else if (cmd == kCmdPlay) {
  75. if (this->getPlayMode() == kPausedMode)
  76. {
  77. Resume();
  78. }
  79. else
  80. {
  81. Play();
  82. }
  83. this->setPlayMode(kPlayingMode);
  84. return (true);
  85. } else if (cmd == kCmdPause) {
  86. this->setPlayMode(kPausedMode);
  87. Pause();
  88. return (true);
  89. } else if (cmd == kCmdStop) {
  90. this->setPlayMode(kStoppedMode);
  91. Stop();
  92. return (true);
  93. }
  94. }
  95. return (this->INHERITED::onEvent (evt));
  96. }
  97. bool
  98. OaSoundTest::onAppEvent (OpAppEvent::Msg msg, OpEvent &evt)
  99. {
  100. switch (msg) {
  101. case OpAppEvent::kInit:
  102. init ();
  103. return (true);
  104. case OpAppEvent::kRequestQuit:
  105. uninit ();
  106. /*  Fall-through  */
  107. default:
  108. break;
  109. }
  110. return (this->INHERITED::onAppEvent (msg, evt));
  111. }
  112. /***************************************************************************
  113.  * What this whole mess is for.
  114.  */
  115. void
  116. OaSoundTest::testbeep (void)
  117. {
  118. int atomsize, nchannels, cyclelength, bufsize;
  119. OpFixed ftmp;
  120. U32 i;
  121. U8 *bufptr;
  122. op_sound_buffer* sndbuf = &(fSndBuf[0]);
  123. for (i=0; i<2; i++)
  124. {
  125.     if (fSndBuf[i].fSampleBuffer) 
  126.     {
  127. free (fSndBuf[i].fSampleBuffer);
  128. fSndBuf[i].fSampleBuffer = NULL;
  129.     }
  130. }
  131. /*
  132.  * Build sinewave buffer.
  133.  */
  134. cyclelength = 44100 / 440;
  135. U32 fNSamples = cyclelength * 100;  //10,000
  136. atomsize = 1;
  137. nchannels = 2;
  138. bufsize = fNSamples * atomsize * nchannels; //20,000
  139. if (!(sndbuf->fSampleBuffer = (void*) malloc (bufsize)))
  140. return;
  141. U8* fSampleBuf = (U8*) sndbuf->fSampleBuffer;
  142. for (bufptr = fSampleBuf, i = 0;  i < fNSamples;  i++) {
  143. ftmp = OpFixedSin (2 * kFixedPI * i / cyclelength)
  144.      + kFixed1 - 1;
  145. if (ftmp < 0)
  146. ftmp++;
  147. *bufptr++ = ftmp >> 9;
  148. ftmp = OpFixedCos (2 * kFixedPI * i / cyclelength)
  149.      + kFixed1 - 1;
  150. if (ftmp < 0)
  151. ftmp++;
  152. *bufptr++ = ftmp >> 9;
  153. }
  154. Open(2, 44100, 8); // Open and start the channel
  155. sndbuf->fNSamples = fNSamples; // Set the number of samples in the buffer
  156. op_sound_write (fSndDev, sndbuf);
  157. }
  158. void
  159. OaSoundTest::Play (void)
  160. {
  161. FILE *fp;
  162. fp = fopen("c:\Downloads\Music\Regrets.wav", "rb");
  163. if ( fp != NULL )
  164. {
  165. m_fp = fp;
  166. m_bWriteDone = false;
  167. m_totalBytesRead = 0;
  168. m_totalBytesWritten = 0;
  169. // Read in the PCM header
  170. int nbytes;
  171. unsigned char buf[sizeof(struct WAVEHeader)];
  172. if ((nbytes = fread(buf, sizeof(char), sizeof(struct WAVEHeader), fp)) > 0 ) 
  173. {
  174. struct WAVEHeader* wh = (struct WAVEHeader *)buf;
  175. m_wh = (*wh);
  176. Open(m_wh.nChannels, m_wh.nSamplesPerSec, m_wh.nBitsPerSample);
  177. }
  178. else
  179. return;
  180. // Delete old buf, and allocate a new one
  181. for (int i=0; i<2; i++)
  182. {
  183.     if (fSndBuf[i].fSampleBuffer) 
  184.     {
  185. free (fSndBuf[i].fSampleBuffer);
  186. fSndBuf[i].fSampleBuffer = NULL;
  187.     }
  188.     if (!(fSndBuf[i].fSampleBuffer = (void *) malloc (BLOCK_SIZE)))
  189. return;
  190. }
  191. if (bigbuf) 
  192. free(bigbuf);
  193. if (! (bigbuf = (unsigned char *) malloc( m_wh.data_ckSize )) )
  194. return;
  195. ReadBuf(); // Read in the whole buffer (test callback timing)
  196. m_nCurBuf = 0;
  197. fillBuffer();  // Read the from the file into the write buffer
  198. fillBuffer();  // double buffering!!!
  199. }
  200. }
  201. void 
  202. OaSoundTest::ReadBuf()
  203. {
  204. unsigned char buf[1024];
  205. int nbytes;
  206. while ((nbytes = fread(buf, sizeof(char), 1024, m_fp)) > 0 && m_totalBytesRead < (int)m_wh.data_ckSize) 
  207. {
  208. memcpy(bigbuf + m_totalBytesRead, buf, nbytes);
  209. m_totalBytesRead += nbytes;
  210. }
  211. fclose(m_fp);
  212. m_fp = NULL;
  213. }
  214. /*
  215. int 
  216. OaSoundTest::GetBuf(unsigned char* buf)
  217. {
  218. unsigned char tmp[BLOCK_SIZE];
  219. int nbytes = 0;
  220. if (m_fp != NULL && (nbytes = fread(tmp, sizeof(char), BLOCK_SIZE, m_fp)) > 0)
  221. {
  222. memcpy(buf, tmp, nbytes);
  223. m_totalBytesRead += nbytes;
  224. }
  225. else if (m_fp != NULL)
  226. {
  227. fclose(m_fp);
  228. }
  229. return nbytes;
  230. }
  231. */
  232. void
  233. OaSoundTest::fillBuffer()
  234. {
  235. op_sound_buffer* sndbuf;
  236. sndbuf = &fSndBuf[m_nCurBuf];
  237. m_nCurBuf = !m_nCurBuf;
  238. if (!m_bWriteDone && m_totalBytesRead > m_totalBytesWritten && bigbuf != NULL) 
  239. {
  240. int nbytes = BLOCK_SIZE;
  241. if ((m_totalBytesRead - m_totalBytesWritten) < BLOCK_SIZE)
  242. nbytes = m_totalBytesRead - m_totalBytesWritten;
  243. sndbuf->fNSamples = (nbytes) / (m_wh.nChannels * (m_wh.nBitsPerSample/8));
  244. memcpy(sndbuf->fSampleBuffer, bigbuf + m_totalBytesWritten, nbytes);
  245. op_sound_write (fSndDev, sndbuf);
  246. m_totalBytesWritten += nbytes;
  247. }
  248. else
  249. { if (bigbuf) 
  250. free(bigbuf);
  251. bigbuf = NULL;
  252. for (int i=0; i<2; i++)
  253. {
  254.     if (fSndBuf[i].fSampleBuffer) 
  255.     {
  256. free (fSndBuf[i].fSampleBuffer);
  257. fSndBuf[i].fSampleBuffer = NULL;
  258.     }
  259. }
  260. m_bWriteDone = true;
  261. //this->setPlayMode(kStoppedMode);
  262. }
  263. /*
  264. int nbytes;
  265. if (m_fp != NULL && (nbytes = fread(fSndBuf.fSampleBuffer, sizeof(char), BLOCK_SIZE, m_fp)) > 0 ) 
  266. {
  267. fSndBuf.fNSamples = (nbytes) / (m_wh.nChannels * (m_wh.nBitsPerSample/8));
  268. writedata();
  269. }
  270. if (nbytes < BLOCK_SIZE)
  271. {
  272. if (m_fp != NULL)
  273. {
  274. fclose(m_fp);
  275. m_fp = NULL;
  276. }
  277. m_bWriteDone = true;
  278. }
  279. */
  280. }
  281. void
  282. OaSoundTest::Stop (void)
  283. {
  284. op_sound_unregister_callback(fSndDev, beepdone_callback);
  285. op_sound_stop(fSndDev);
  286. if (m_fp != NULL)
  287. {
  288. fclose(m_fp);
  289. m_fp = NULL;
  290. }
  291. m_bWriteDone = true;
  292. }
  293. void
  294. OaSoundTest::Pause (void)
  295. {
  296. op_sound_unregister_callback(fSndDev, beepdone_callback);
  297. op_sound_pause(fSndDev);
  298. }
  299. void
  300. OaSoundTest::Resume (void)
  301. {
  302. op_sound_register_callback(fSndDev, beepdone_callback, this);
  303. fillBuffer();
  304. fillBuffer();
  305. op_sound_resume(fSndDev);
  306. }
  307. void
  308. OaSoundTest::beepdone (void)
  309. {
  310. if ( !m_bWriteDone )
  311. {
  312. fillBuffer(); // more data to write
  313. }
  314. else
  315. {
  316. // this->setPlayMode(kStoppedMode);
  317. // Close(); // freechan will hang after IODONE
  318. }
  319. }
  320. static void
  321. beepdone_callback (
  322. op_sound_handle const *handle,
  323. S32 msg,
  324. op_sound_buffer const *sndbuf,
  325. void *data
  326. )
  327. {
  328. //OaSoundTest::beepdone();
  329. OaSoundTest *app = (OaSoundTest *) data;
  330. app->fillBuffer();
  331. //app->fDoneEvent->send(); // Send the event synchronously to its sink. 
  332. // However, unlike post(), the caller is still responsible for ownership of the event object.
  333. //
  334. //app->fDoneEvent->post(); // only one callback will work with this event
  335. //app->fDoneEvent = NULL;
  336. }
  337. /***************************************************************************
  338.  * Initialization/teardown.
  339.  */
  340. void
  341. OaSoundTest::init (void)
  342. {
  343. //  Build the (ha ha) UI.  
  344. setTitle ("Sound Test");
  345. this->setPlayMode(kInitializedMode);
  346. //  Create the event that will be sent when the sound is done.  
  347. fDoneEvent = new OpCmdEvent (CMD_BEEPDONE, this->getID());
  348. // CheckFormat?
  349. }
  350. void
  351. OaSoundTest::Open(int nChannels, int nSamplesPerSec, int nBitsPerSample)
  352. {
  353. //////////////////////////////
  354. // open the channel
  355. //////////////////////////////
  356. OpError retval;
  357. if (fSndDev) {
  358. Close(); // Close last channel
  359. }
  360. //  Procure channels.  
  361. if (!(fSndDev = op_sound_allocchan (nChannels)))
  362. return;
  363. op_sound_pcm_format pcmfmt = OP_PCM_FMT_INVALID;
  364. switch (nBitsPerSample)
  365. {
  366. case 8 : pcmfmt = OP_PCM_FMT_U8; break;
  367. case 16: pcmfmt = OP_PCM_FMT_U16_LE; break;
  368. }
  369. op_sound_pcm_rate pcmrate = OP_PCM_RATE_44100;
  370. switch (nSamplesPerSec)
  371. {
  372. case 8000 : pcmrate = OP_PCM_RATE_8000; break;
  373. case 11025: pcmrate = OP_PCM_RATE_11025; break;
  374. case 16000: pcmrate = OP_PCM_RATE_16000; break;
  375. case 22050: pcmrate = OP_PCM_RATE_22050; break;
  376. case 32000: pcmrate = OP_PCM_RATE_32000; break;
  377. case 44100: pcmrate = OP_PCM_RATE_44100; break;
  378. case 48000: pcmrate = OP_PCM_RATE_48000; break;
  379. case 64000: pcmrate = OP_PCM_RATE_64000; break;
  380. }
  381. //  Configure channels for playback.  
  382. retval = op_sound_set_params_args
  383.           (fSndDev,
  384.            OP_AUDIOTAG_VOLUME, 0xFFFF,
  385.            OP_AUDIOTAG_PCMFORMAT, pcmfmt,
  386.            //OP_AUDIOTAG_PCMRATE_EXPLICIT, nSamplesPerSec, //ERROR doesn't work
  387.    OP_AUDIOTAG_PCMRATE, pcmrate,
  388.            OP_AUDIOTAG_INTERLEAVESAMPLES, true,
  389.            OP_AUDIOTAG_END);
  390. if (retval < 0)
  391. return;
  392. //  Register our callback.  
  393. retval = op_sound_register_callback
  394.           (fSndDev, beepdone_callback, this);
  395. if (retval < 0)
  396. return;
  397. retval = op_sound_start (fSndDev);
  398. }
  399. void
  400. OaSoundTest::Close()
  401. {
  402. // Only called on second open, because freechan will hang after IODONE
  403. //op_sound_stop(fSndDev);
  404. op_sound_unregister_callback(fSndDev, beepdone_callback);
  405. op_sound_freechan(fSndDev);
  406. fSndDev = NULL;
  407. }
  408. void
  409. OaSoundTest::uninit (void)
  410. {
  411. if (fSndDev) {
  412. op_sound_freechan (fSndDev);
  413. fSndDev = NULL;
  414. }
  415. for (int i=0; i<2; i++)
  416. {
  417.     if (fSndBuf[i].fSampleBuffer) 
  418.     {
  419. free (fSndBuf[i].fSampleBuffer);
  420. fSndBuf[i].fSampleBuffer = NULL;
  421.     }
  422. }
  423. }
  424. void OaSoundTest::setPlayMode(PlayMode mode)
  425. {
  426. fPlayMode = mode;
  427. this->populateSoftKeys(mode);
  428. }
  429. void OaSoundTest::populateSoftKeys(PlayMode mode)
  430. {
  431. switch (mode)
  432. {
  433. case kInitializedMode:
  434. this->setSoftKeys(new OpSoftKeys());
  435. this->getSoftKeys()->setCmdLabel(CMD_TEST, 0, "Beep");
  436. this->getSoftKeys()->setCmdLabel(kCmdPlay, 0, "Play");
  437. break;
  438. case kPlayingMode:
  439. this->getSoftKeys()->removeAllCmds();
  440. this->getSoftKeys()->setCmdLabel(kCmdPause, 0, "Pause");
  441. this->getSoftKeys()->setCmdLabel(kCmdStop, 0, "Stop");
  442. break;
  443. case kPausedMode:
  444. this->getSoftKeys()->removeAllCmds();
  445. this->getSoftKeys()->setCmdLabel(kCmdPlay, 0, "Play");
  446. this->getSoftKeys()->setCmdLabel(kCmdStop, 0, "Stop");
  447. break;
  448. case kStoppedMode:
  449. this->getSoftKeys()->removeAllCmds();
  450. this->getSoftKeys()->setCmdLabel(CMD_TEST, 0, "Beep");
  451. this->getSoftKeys()->setCmdLabel(kCmdPlay, 0, "Play");
  452. break;
  453. }
  454. }