playwave.c
上传用户:nini_0081
上传日期:2022-07-21
资源大小:2628k
文件大小:12k
源码类别:

多媒体编程

开发平台:

DOS

  1. /*
  2.     PLAYWAVE:  A test application for the SDL mixer library.
  3.     Copyright (C) 1997-2009 Sam Lantinga
  4.     This library is free software; you can redistribute it and/or
  5.     modify it under the terms of the GNU Library General Public
  6.     License as published by the Free Software Foundation; either
  7.     version 2 of the License, or (at your option) any later version.
  8.     This library is distributed in the hope that it will be useful,
  9.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11.     Library General Public License for more details.
  12.     You should have received a copy of the GNU Library General Public
  13.     License along with this library; if not, write to the Free
  14.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  15.     Sam Lantinga
  16.     slouken@libsdl.org
  17. */
  18. /* $Id: playwave.c 5191 2009-11-05 00:02:50Z slouken $ */
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <signal.h>
  23. #ifdef unix
  24. #include <unistd.h>
  25. #endif
  26. #include "SDL.h"
  27. #include "SDL_mixer.h"
  28. /*
  29.  * rcg06132001 various mixer tests. Define the ones you want.
  30.  */
  31. /*#define TEST_MIX_DECODERS*/
  32. /*#define TEST_MIX_VERSIONS*/
  33. /*#define TEST_MIX_CHANNELFINISHED*/
  34. /*#define TEST_MIX_PANNING*/
  35. /*#define TEST_MIX_DISTANCE*/
  36. /*#define TEST_MIX_POSITION*/
  37. #if (defined TEST_MIX_POSITION)
  38. #if (defined TEST_MIX_PANNING)
  39. #error TEST_MIX_POSITION interferes with TEST_MIX_PANNING.
  40. #endif
  41. #if (defined TEST_MIX_DISTANCE)
  42. #error TEST_MIX_POSITION interferes with TEST_MIX_DISTANCE.
  43. #endif
  44. #endif
  45. /* rcg06192001 for debugging purposes. */
  46. static void output_test_warnings(void)
  47. {
  48. #if (defined TEST_MIX_CHANNELFINISHED)
  49. fprintf(stderr, "Warning: TEST_MIX_CHANNELFINISHED is enabled in this binary...n");
  50. #endif
  51. #if (defined TEST_MIX_PANNING)
  52. fprintf(stderr, "Warning: TEST_MIX_PANNING is enabled in this binary...n");
  53. #endif
  54. #if (defined TEST_MIX_VERSIONS)
  55. fprintf(stderr, "Warning: TEST_MIX_VERSIONS is enabled in this binary...n");
  56. #endif
  57. #if (defined TEST_MIX_DISTANCE)
  58. fprintf(stderr, "Warning: TEST_MIX_DISTANCE is enabled in this binary...n");
  59. #endif
  60. #if (defined TEST_MIX_POSITION)
  61. fprintf(stderr, "Warning: TEST_MIX_POSITION is enabled in this binary...n");
  62. #endif
  63. }
  64. static int audio_open = 0;
  65. static Mix_Chunk *wave = NULL;
  66. /* rcg06042009 Report available decoders. */
  67. #if (defined TEST_MIX_DECODERS)
  68. static void report_decoders(void)
  69. {
  70. int i, total;
  71.     printf("Supported decoders...n");
  72. total = Mix_GetNumChunkDecoders();
  73. for (i = 0; i < total; i++) {
  74. fprintf(stderr, " - chunk decoder: %sn", Mix_GetChunkDecoder(i));
  75. }
  76. total = Mix_GetNumMusicDecoders();
  77. for (i = 0; i < total; i++) {
  78. fprintf(stderr, " - music decoder: %sn", Mix_GetMusicDecoder(i));
  79. }
  80. }
  81. #endif
  82. /* rcg06192001 Check new Mixer version API. */
  83. #if (defined TEST_MIX_VERSIONS)
  84. static void output_versions(const char *libname, const SDL_version *compiled,
  85. const SDL_version *linked)
  86. {
  87. fprintf(stderr,
  88. "This program was compiled against %s %d.%d.%d,n"
  89. " and is dynamically linked to %d.%d.%d.n", libname,
  90. compiled->major, compiled->minor, compiled->patch,
  91. linked->major, linked->minor, linked->patch);
  92. }
  93. static void test_versions(void)
  94. {
  95. SDL_version compiled;
  96. const SDL_version *linked;
  97. SDL_VERSION(&compiled);
  98. linked = SDL_Linked_Version();
  99. output_versions("SDL", &compiled, linked);
  100. SDL_MIXER_VERSION(&compiled);
  101. linked = Mix_Linked_Version();
  102. output_versions("SDL_mixer", &compiled, linked);
  103. }
  104. #endif
  105. #ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
  106. static volatile int channel_is_done = 0;
  107. static void channel_complete_callback(int chan)
  108. {
  109. Mix_Chunk *done_chunk = Mix_GetChunk(chan);
  110. fprintf(stderr, "We were just alerted that Mixer channel #%d is done.n", chan);
  111. fprintf(stderr, "Channel's chunk pointer is (%p).n", done_chunk);
  112. fprintf(stderr, " Which %s correct.n", (wave == done_chunk) ? "is" : "is NOT");
  113. channel_is_done = 1;
  114. }
  115. #endif
  116. /* rcg06192001 abstract this out for testing purposes. */
  117. static int still_playing(void)
  118. {
  119. #ifdef TEST_MIX_CHANNELFINISHED
  120. return(!channel_is_done);
  121. #else
  122. return(Mix_Playing(0));
  123. #endif
  124. }
  125. #if (defined TEST_MIX_PANNING)
  126. static void do_panning_update(void)
  127. {
  128. static Uint8 leftvol = 128;
  129. static Uint8 rightvol = 128;
  130. static Uint8 leftincr = -1;
  131. static Uint8 rightincr = 1;
  132. static int panningok = 1;
  133. static Uint32 next_panning_update = 0;
  134. if ((panningok) && (SDL_GetTicks() >= next_panning_update)) {
  135. panningok = Mix_SetPanning(0, leftvol, rightvol);
  136. if (!panningok) {
  137. fprintf(stderr, "Mix_SetPanning(0, %d, %d) failed!n",
  138. (int) leftvol, (int) rightvol);
  139. fprintf(stderr, "Reason: [%s].n", Mix_GetError());
  140. }
  141. if ((leftvol == 255) || (leftvol == 0)) {
  142. if (leftvol == 255)
  143. printf("All the way in the left speaker.n");
  144. leftincr *= -1;
  145. }
  146. if ((rightvol == 255) || (rightvol == 0)) {
  147. if (rightvol == 255)
  148. printf("All the way in the right speaker.n");
  149. rightincr *= -1;
  150. }
  151. leftvol += leftincr;
  152. rightvol += rightincr;
  153. next_panning_update = SDL_GetTicks() + 10;
  154. }
  155. }
  156. #endif
  157. #if (defined TEST_MIX_DISTANCE)
  158. static void do_distance_update(void)
  159. {
  160. static Uint8 distance = 1;
  161. static Uint8 distincr = 1;
  162. static int distanceok = 1;
  163. static Uint32 next_distance_update = 0;
  164. if ((distanceok) && (SDL_GetTicks() >= next_distance_update)) {
  165. distanceok = Mix_SetDistance(0, distance);
  166. if (!distanceok) {
  167. fprintf(stderr, "Mix_SetDistance(0, %d) failed!n", (int) distance);
  168. fprintf(stderr, "Reason: [%s].n", Mix_GetError());
  169. }
  170. if (distance == 0) {
  171. printf("Distance at nearest point.n");
  172. distincr *= -1;
  173. }
  174. else if (distance == 255) {
  175. printf("Distance at furthest point.n");
  176. distincr *= -1;
  177. }
  178. distance += distincr;
  179. next_distance_update = SDL_GetTicks() + 15;
  180. }
  181. }
  182. #endif
  183. #if (defined TEST_MIX_POSITION)
  184. static void do_position_update(void)
  185. {
  186. static Sint16 distance = 1;
  187. static Sint8 distincr = 1;
  188. static Uint16 angle = 0;
  189. static Sint8 angleincr = 1;
  190. static int positionok = 1;
  191. static Uint32 next_position_update = 0;
  192. if ((positionok) && (SDL_GetTicks() >= next_position_update)) {
  193. positionok = Mix_SetPosition(0, angle, distance);
  194. if (!positionok) {
  195. fprintf(stderr, "Mix_SetPosition(0, %d, %d) failed!n",
  196. (int) angle, (int) distance);
  197. fprintf(stderr, "Reason: [%s].n", Mix_GetError());
  198. }
  199. if (angle == 0) {
  200. printf("Due north; now rotating clockwise...n");
  201. angleincr = 1;
  202. }
  203. else if (angle == 360) {
  204. printf("Due north; now rotating counter-clockwise...n");
  205. angleincr = -1;
  206. }
  207. distance += distincr;
  208. if (distance < 0) {
  209. distance = 0;
  210. distincr = 3;
  211. printf("Distance is very, very near. Stepping away by threes...n");
  212. } else if (distance > 255) {
  213. distance = 255;
  214. distincr = -3;
  215. printf("Distance is very, very far. Stepping towards by threes...n");
  216. }
  217. angle += angleincr;
  218. next_position_update = SDL_GetTicks() + 30;
  219. }
  220. }
  221. #endif
  222. static void CleanUp(int exitcode)
  223. {
  224. if ( wave ) {
  225. Mix_FreeChunk(wave);
  226. wave = NULL;
  227. }
  228. if ( audio_open ) {
  229. Mix_CloseAudio();
  230. audio_open = 0;
  231. }
  232. SDL_Quit();
  233. exit(exitcode);
  234. }
  235. static void Usage(char *argv0)
  236. {
  237. fprintf(stderr, "Usage: %s [-8] [-r rate] [-c channels] [-f] [-F] [-l] [-m] <wavefile>n", argv0);
  238. }
  239. /*
  240.  * rcg06182001 This is sick, but cool.
  241.  *
  242.  *  Actually, it's meant to be an example of how to manipulate a voice
  243.  *  without having to use the mixer effects API. This is more processing
  244.  *  up front, but no extra during the mixing process. Also, in a case like
  245.  *  this, when you need to touch the whole sample at once, it's the only
  246.  *  option you've got. And, with the effects API, you are altering a copy of
  247.  *  the original sample for each playback, and thus, your changes aren't
  248.  *  permanent; here, you've got a reversed sample, and that's that until
  249.  *  you either reverse it again, or reload it.
  250.  */
  251. static void flip_sample(Mix_Chunk *wave)
  252. {
  253. Uint16 format;
  254. int channels, i, incr;
  255. Uint8 *start = wave->abuf;
  256. Uint8 *end = wave->abuf + wave->alen;
  257. Mix_QuerySpec(NULL, &format, &channels);
  258. incr = (format & 0xFF) * channels;
  259. end -= incr;
  260. switch (incr) {
  261. case 8:
  262. for (i = wave->alen / 2; i >= 0; i -= 1) {
  263. Uint8 tmp = *start;
  264. *start = *end;
  265. *end = tmp;
  266. start++;
  267. end--;
  268. }
  269. break;
  270. case 16:
  271. for (i = wave->alen / 2; i >= 0; i -= 2) {
  272. Uint16 tmp = *start;
  273. *((Uint16 *) start) = *((Uint16 *) end);
  274. *((Uint16 *) end) = tmp;
  275. start += 2;
  276. end -= 2;
  277. }
  278. break;
  279. case 32:
  280. for (i = wave->alen / 2; i >= 0; i -= 4) {
  281. Uint32 tmp = *start;
  282. *((Uint32 *) start) = *((Uint32 *) end);
  283. *((Uint32 *) end) = tmp;
  284. start += 4;
  285. end -= 4;
  286. }
  287. break;
  288. default:
  289. fprintf(stderr, "Unhandled format in sample flipping.n");
  290. return;
  291. }
  292. }
  293. int main(int argc, char *argv[])
  294. {
  295. int audio_rate;
  296. Uint16 audio_format;
  297. int audio_channels;
  298. int loops = 0;
  299. int i;
  300. int reverse_stereo = 0;
  301. int reverse_sample = 0;
  302. setbuf(stdout, NULL);    /* rcg06132001 for debugging purposes. */
  303. setbuf(stderr, NULL);    /* rcg06192001 for debugging purposes, too. */
  304. output_test_warnings();
  305. /* Initialize variables */
  306. audio_rate = MIX_DEFAULT_FREQUENCY;
  307. audio_format = MIX_DEFAULT_FORMAT;
  308. audio_channels = 2;
  309. /* Check command line usage */
  310. for ( i=1; argv[i] && (*argv[i] == '-'); ++i ) {
  311. if ( (strcmp(argv[i], "-r") == 0) && argv[i+1] ) {
  312. ++i;
  313. audio_rate = atoi(argv[i]);
  314. } else
  315. if ( strcmp(argv[i], "-m") == 0 ) {
  316. audio_channels = 1;
  317. } else
  318. if ( (strcmp(argv[i], "-c") == 0) && argv[i+1] ) {
  319. ++i;
  320. audio_channels = atoi(argv[i]);
  321. } else
  322. if ( strcmp(argv[i], "-l") == 0 ) {
  323. loops = -1;
  324. } else
  325. if ( strcmp(argv[i], "-8") == 0 ) {
  326. audio_format = AUDIO_U8;
  327. } else
  328. if ( strcmp(argv[i], "-f") == 0 ) { /* rcg06122001 flip stereo */
  329. reverse_stereo = 1;
  330. } else
  331. if ( strcmp(argv[i], "-F") == 0 ) { /* rcg06172001 flip sample */
  332. reverse_sample = 1;
  333. } else {
  334. Usage(argv[0]);
  335. return(1);
  336. }
  337. }
  338. if ( ! argv[i] ) {
  339. Usage(argv[0]);
  340. return(1);
  341. }
  342. /* Initialize the SDL library */
  343. if ( SDL_Init(SDL_INIT_AUDIO) < 0 ) {
  344. fprintf(stderr, "Couldn't initialize SDL: %sn",SDL_GetError());
  345. return(255);
  346. }
  347. signal(SIGINT, CleanUp);
  348. signal(SIGTERM, CleanUp);
  349. /* Open the audio device */
  350. if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
  351. fprintf(stderr, "Couldn't open audio: %sn", SDL_GetError());
  352. CleanUp(2);
  353. } else {
  354. Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
  355. printf("Opened audio at %d Hz %d bit %s", audio_rate,
  356. (audio_format&0xFF),
  357. (audio_channels > 2) ? "surround" :
  358. (audio_channels > 1) ? "stereo" : "mono");
  359. if ( loops ) {
  360.   printf(" (looping)n");
  361. } else {
  362.   putchar('n');
  363. }
  364. }
  365. audio_open = 1;
  366. #if (defined TEST_MIX_VERSIONS)
  367. test_versions();
  368. #endif
  369. #if (defined TEST_MIX_DECODERS)
  370. report_decoders();
  371. #endif
  372. /* Load the requested wave file */
  373. wave = Mix_LoadWAV(argv[i]);
  374. if ( wave == NULL ) {
  375. fprintf(stderr, "Couldn't load %s: %sn",
  376. argv[i], SDL_GetError());
  377. CleanUp(2);
  378. }
  379. if (reverse_sample) {
  380. flip_sample(wave);
  381. }
  382. #ifdef TEST_MIX_CHANNELFINISHED  /* rcg06072001 */
  383. Mix_ChannelFinished(channel_complete_callback);
  384. #endif
  385. if ( (!Mix_SetReverseStereo(MIX_CHANNEL_POST, reverse_stereo)) &&
  386.  (reverse_stereo) )
  387. {
  388. printf("Failed to set up reverse stereo effect!n");
  389. printf("Reason: [%s].n", Mix_GetError());
  390. }
  391. /* Play and then exit */
  392. Mix_PlayChannel(0, wave, loops);
  393. while (still_playing()) {
  394. #if (defined TEST_MIX_PANNING)  /* rcg06132001 */
  395. do_panning_update();
  396. #endif
  397. #if (defined TEST_MIX_DISTANCE) /* rcg06192001 */
  398. do_distance_update();
  399. #endif
  400. #if (defined TEST_MIX_POSITION) /* rcg06202001 */
  401. do_position_update();
  402. #endif
  403. SDL_Delay(1);
  404. } /* while still_playing() loop... */
  405. CleanUp(0);
  406. /* Not reached, but fixes compiler warnings */
  407. return 0;
  408. }
  409. /* end of playwave.c ... */