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

多媒体编程

开发平台:

DOS

  1. /*
  2.     SDL_mixer:  An audio mixer library based on the SDL 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: wavestream.c 5214 2009-11-08 17:11:09Z slouken $ */
  19. /* This file supports streaming WAV files, without volume adjustment */
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "SDL_audio.h"
  23. #include "SDL_mutex.h"
  24. #include "SDL_rwops.h"
  25. #include "SDL_endian.h"
  26. #include "SDL_mixer.h"
  27. #include "wavestream.h"
  28. /*
  29.     Taken with permission from SDL_wave.h, part of the SDL library,
  30.     available at: http://www.libsdl.org/
  31.     and placed under the same license as this mixer library.
  32. */
  33. /* WAVE files are little-endian */
  34. /*******************************************/
  35. /* Define values for Microsoft WAVE format */
  36. /*******************************************/
  37. #define RIFF 0x46464952 /* "RIFF" */
  38. #define WAVE 0x45564157 /* "WAVE" */
  39. #define FACT 0x74636166 /* "fact" */
  40. #define LIST 0x5453494c /* "LIST" */
  41. #define FMT 0x20746D66 /* "fmt " */
  42. #define DATA 0x61746164 /* "data" */
  43. #define PCM_CODE 1
  44. #define ADPCM_CODE 2
  45. #define WAVE_MONO 1
  46. #define WAVE_STEREO 2
  47. /* Normally, these three chunks come consecutively in a WAVE file */
  48. typedef struct WaveFMT {
  49. /* Not saved in the chunk we read:
  50. Uint32 FMTchunk;
  51. Uint32 fmtlen;
  52. */
  53. Uint16 encoding;
  54. Uint16 channels; /* 1 = mono, 2 = stereo */
  55. Uint32 frequency; /* One of 11025, 22050, or 44100 Hz */
  56. Uint32 byterate; /* Average bytes per second */
  57. Uint16 blockalign; /* Bytes per sample block */
  58. Uint16 bitspersample; /* One of 8, 12, 16, or 4 for ADPCM */
  59. } WaveFMT;
  60. /* The general chunk found in the WAVE file */
  61. typedef struct Chunk {
  62. Uint32 magic;
  63. Uint32 length;
  64. Uint8 *data; /* Data includes magic and length */
  65. } Chunk;
  66. /*********************************************/
  67. /* Define values for AIFF (IFF audio) format */
  68. /*********************************************/
  69. #define FORM 0x4d524f46 /* "FORM" */
  70. #define AIFF 0x46464941 /* "AIFF" */
  71. #define SSND 0x444e5353 /* "SSND" */
  72. #define COMM 0x4d4d4f43 /* "COMM" */
  73. /* Currently we only support a single stream at a time */
  74. static WAVStream *music = NULL;
  75. /* This is the format of the audio mixer data */
  76. static SDL_AudioSpec mixer;
  77. static int wavestream_volume = MIX_MAX_VOLUME;
  78. /* Function to load the WAV/AIFF stream */
  79. static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
  80. long *start, long *stop);
  81. static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
  82. long *start, long *stop);
  83. /* Initialize the WAVStream player, with the given mixer settings
  84.    This function returns 0, or -1 if there was an error.
  85.  */
  86. int WAVStream_Init(SDL_AudioSpec *mixerfmt)
  87. {
  88. mixer = *mixerfmt;
  89. return(0);
  90. }
  91. void WAVStream_SetVolume(int volume)
  92. {
  93. wavestream_volume = volume;
  94. }
  95. WAVStream *WAVStream_LoadSong(const char *file, const char *magic)
  96. {
  97. SDL_RWops *rw;
  98. WAVStream *wave;
  99. rw = SDL_RWFromFile(file, "rb");
  100. if ( rw == NULL ) {
  101. SDL_SetError("Couldn't open %s", file);
  102. return NULL;
  103. }
  104. wave = WAVStream_LoadSong_RW(rw, magic);
  105. if ( wave == NULL ) {
  106. SDL_FreeRW(rw);
  107. return NULL;
  108. }
  109. return wave;
  110. }
  111. /* Load a WAV stream from the given file */
  112. WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic)
  113. {
  114. WAVStream *wave;
  115. SDL_AudioSpec wavespec;
  116. if ( ! mixer.format ) {
  117. Mix_SetError("WAV music output not started");
  118. return(NULL);
  119. }
  120. wave = (WAVStream *)malloc(sizeof *wave);
  121. if ( wave ) {
  122. memset(wave, 0, (sizeof *wave));
  123. if ( strcmp(magic, "RIFF") == 0 ) {
  124. wave->rw = LoadWAVStream(rw, &wavespec,
  125. &wave->start, &wave->stop);
  126. } else
  127. if ( strcmp(magic, "FORM") == 0 ) {
  128. wave->rw = LoadAIFFStream(rw, &wavespec,
  129. &wave->start, &wave->stop);
  130. } else {
  131. Mix_SetError("Unknown WAVE format");
  132. }
  133. if ( wave->rw == NULL ) {
  134. free(wave);
  135. return(NULL);
  136. }
  137. SDL_BuildAudioCVT(&wave->cvt,
  138. wavespec.format, wavespec.channels, wavespec.freq,
  139. mixer.format, mixer.channels, mixer.freq);
  140. }
  141. return(wave);
  142. }
  143. /* Start playback of a given WAV stream */
  144. void WAVStream_Start(WAVStream *wave)
  145. {
  146. SDL_RWseek (wave->rw, wave->start, RW_SEEK_SET);
  147. music = wave;
  148. }
  149. /* Play some of a stream previously started with WAVStream_Start() */
  150. int WAVStream_PlaySome(Uint8 *stream, int len)
  151. {
  152. long pos;
  153. int left = 0;
  154. if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
  155. if ( music->cvt.needed ) {
  156. int original_len;
  157. original_len=(int)((double)len/music->cvt.len_ratio);
  158. if ( music->cvt.len != original_len ) {
  159. int worksize;
  160. if ( music->cvt.buf != NULL ) {
  161. free(music->cvt.buf);
  162. }
  163. worksize = original_len*music->cvt.len_mult;
  164. music->cvt.buf=(Uint8 *)malloc(worksize);
  165. if ( music->cvt.buf == NULL ) {
  166. return 0;
  167. }
  168. music->cvt.len = original_len;
  169. }
  170. if ( (music->stop - pos) < original_len ) {
  171. left = (original_len - (music->stop - pos));
  172. original_len -= left;
  173. left = (int)((double)left*music->cvt.len_ratio);
  174. }
  175. original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
  176. /* At least at the time of writing, SDL_ConvertAudio()
  177.    does byte-order swapping starting at the end of the
  178.    buffer. Thus, if we are reading 16-bit samples, we
  179.    had better make damn sure that we get an even
  180.    number of bytes, or we'll get garbage.
  181.  */
  182. if ( (music->cvt.src_format & 0x0010) && (original_len & 1) ) {
  183. original_len--;
  184. }
  185. music->cvt.len = original_len;
  186. SDL_ConvertAudio(&music->cvt);
  187. SDL_MixAudio(stream, music->cvt.buf, music->cvt.len_cvt, wavestream_volume);
  188. } else {
  189. Uint8 *data;
  190. if ( (music->stop - pos) < len ) {
  191. left = (len - (music->stop - pos));
  192. len -= left;
  193. }
  194. data = SDL_stack_alloc(Uint8, len);
  195. if (data)
  196. {
  197. SDL_RWread(music->rw, data, len, 1);
  198. SDL_MixAudio(stream, data, len, wavestream_volume);
  199. SDL_stack_free(data);
  200. }
  201. }
  202. }
  203. return left;
  204. }
  205. /* Stop playback of a stream previously started with WAVStream_Start() */
  206. void WAVStream_Stop(void)
  207. {
  208. music = NULL;
  209. }
  210. /* Close the given WAV stream */
  211. void WAVStream_FreeSong(WAVStream *wave)
  212. {
  213. if ( wave ) {
  214. /* Clean up associated data */
  215. if ( wave->freerw ) {
  216. SDL_FreeRW(wave->rw);
  217. }
  218. if ( wave->cvt.buf ) {
  219. free(wave->cvt.buf);
  220. }
  221. free(wave);
  222. }
  223. }
  224. /* Return non-zero if a stream is currently playing */
  225. int WAVStream_Active(void)
  226. {
  227. int active;
  228. active = 0;
  229. if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
  230. active = 1;
  231. }
  232. return(active);
  233. }
  234. static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data)
  235. {
  236. chunk->magic = SDL_ReadLE32(src);
  237. chunk->length = SDL_ReadLE32(src);
  238. if ( read_data ) {
  239. chunk->data = (Uint8 *)malloc(chunk->length);
  240. if ( chunk->data == NULL ) {
  241. Mix_SetError("Out of memory");
  242. return(-1);
  243. }
  244. if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) {
  245. Mix_SetError("Couldn't read chunk");
  246. free(chunk->data);
  247. return(-1);
  248. }
  249. } else {
  250. SDL_RWseek(src, chunk->length, RW_SEEK_CUR);
  251. }
  252. return(chunk->length);
  253. }
  254. static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
  255. long *start, long *stop)
  256. {
  257. int was_error;
  258. Chunk chunk;
  259. int lenread;
  260. /* WAV magic header */
  261. Uint32 RIFFchunk;
  262. Uint32 wavelen;
  263. Uint32 WAVEmagic;
  264. /* FMT chunk */
  265. WaveFMT *format = NULL;
  266. was_error = 0;
  267. /* Check the magic header */
  268. RIFFchunk = SDL_ReadLE32(src);
  269. wavelen = SDL_ReadLE32(src);
  270. WAVEmagic = SDL_ReadLE32(src);
  271. if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) {
  272. Mix_SetError("Unrecognized file type (not WAVE)");
  273. was_error = 1;
  274. goto done;
  275. }
  276. /* Read the audio data format chunk */
  277. chunk.data = NULL;
  278. do {
  279. /* FIXME! Add this logic to SDL_LoadWAV_RW() */
  280. if ( chunk.data ) {
  281. free(chunk.data);
  282. }
  283. lenread = ReadChunk(src, &chunk, 1);
  284. if ( lenread < 0 ) {
  285. was_error = 1;
  286. goto done;
  287. }
  288. } while ( (chunk.magic == FACT) || (chunk.magic == LIST) );
  289. /* Decode the audio data format */
  290. format = (WaveFMT *)chunk.data;
  291. if ( chunk.magic != FMT ) {
  292. free(chunk.data);
  293. Mix_SetError("Complex WAVE files not supported");
  294. was_error = 1;
  295. goto done;
  296. }
  297. switch (SDL_SwapLE16(format->encoding)) {
  298. case PCM_CODE:
  299. /* We can understand this */
  300. break;
  301. default:
  302. Mix_SetError("Unknown WAVE data format");
  303. was_error = 1;
  304. goto done;
  305. }
  306. memset(spec, 0, (sizeof *spec));
  307. spec->freq = SDL_SwapLE32(format->frequency);
  308. switch (SDL_SwapLE16(format->bitspersample)) {
  309. case 8:
  310. spec->format = AUDIO_U8;
  311. break;
  312. case 16:
  313. spec->format = AUDIO_S16;
  314. break;
  315. default:
  316. Mix_SetError("Unknown PCM data format");
  317. was_error = 1;
  318. goto done;
  319. }
  320. spec->channels = (Uint8) SDL_SwapLE16(format->channels);
  321. spec->samples = 4096; /* Good default buffer size */
  322. /* Set the file offset to the DATA chunk data */
  323. chunk.data = NULL;
  324. do {
  325. *start = SDL_RWtell(src) + 2*sizeof(Uint32);
  326. lenread = ReadChunk(src, &chunk, 0);
  327. if ( lenread < 0 ) {
  328. was_error = 1;
  329. goto done;
  330. }
  331. } while ( chunk.magic != DATA );
  332. *stop = SDL_RWtell(src);
  333. done:
  334. if ( format != NULL ) {
  335. free(format);
  336. }
  337. if ( was_error ) {
  338. return NULL;
  339. }
  340. return(src);
  341. }
  342. /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
  343.  * I don't pretend to fully understand it.
  344.  */
  345. static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
  346. {
  347. /* Negative number? */
  348. if (sanebuf[0] & 0x80)
  349. return 0;
  350. /* Less than 1? */
  351. if (sanebuf[0] <= 0x3F)
  352. return 1;
  353. /* Way too big? */
  354. if (sanebuf[0] > 0x40)
  355. return 0x4000000;
  356. /* Still too big? */
  357. if (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C)
  358. return 800000000;
  359. return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
  360. | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
  361. }
  362. static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
  363. long *start, long *stop)
  364. {
  365. int was_error;
  366. int found_SSND;
  367. int found_COMM;
  368. Uint32 chunk_type;
  369. Uint32 chunk_length;
  370. long next_chunk;
  371. /* AIFF magic header */
  372. Uint32 FORMchunk;
  373. Uint32 AIFFmagic;
  374. /* SSND chunk        */
  375. Uint32 offset;
  376. Uint32 blocksize;
  377. /* COMM format chunk */
  378. Uint16 channels = 0;
  379. Uint32 numsamples = 0;
  380. Uint16 samplesize = 0;
  381. Uint8 sane_freq[10];
  382. Uint32 frequency = 0;
  383. was_error = 0;
  384. /* Check the magic header */
  385. FORMchunk = SDL_ReadLE32(src);
  386. chunk_length = SDL_ReadBE32(src);
  387. AIFFmagic = SDL_ReadLE32(src);
  388. if ( (FORMchunk != FORM) || (AIFFmagic != AIFF) ) {
  389. Mix_SetError("Unrecognized file type (not AIFF)");
  390. was_error = 1;
  391. goto done;
  392. }
  393. /* From what I understand of the specification, chunks may appear in
  394.          * any order, and we should just ignore unknown ones.
  395.  *
  396.  * TODO: Better sanity-checking. E.g. what happens if the AIFF file
  397.  *       contains compressed sound data?
  398.          */
  399. found_SSND = 0;
  400. found_COMM = 0;
  401. do {
  402.     chunk_type = SDL_ReadLE32(src);
  403.     chunk_length = SDL_ReadBE32(src);
  404.     next_chunk = SDL_RWtell(src) + chunk_length;
  405.     /* Paranoia to avoid infinite loops */
  406.     if (chunk_length == 0)
  407. break;
  408.             switch (chunk_type) {
  409. case SSND:
  410.     found_SSND = 1;
  411.     offset = SDL_ReadBE32(src);
  412.     blocksize = SDL_ReadBE32(src);
  413.     *start = SDL_RWtell(src) + offset;
  414.     break;
  415. case COMM:
  416.     found_COMM = 1;
  417.     /* Read the audio data format chunk */
  418.     channels = SDL_ReadBE16(src);
  419.     numsamples = SDL_ReadBE32(src);
  420.     samplesize = SDL_ReadBE16(src);
  421.     SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
  422.     frequency = SANE_to_Uint32(sane_freq);
  423.     break;
  424. default:
  425.     break;
  426.     }
  427. } while ((!found_SSND || !found_COMM)
  428.  && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != -1);
  429. if (!found_SSND) {
  430.     Mix_SetError("Bad AIFF file (no SSND chunk)");
  431.     was_error = 1;
  432.     goto done;
  433. }
  434.     
  435. if (!found_COMM) {
  436.     Mix_SetError("Bad AIFF file (no COMM chunk)");
  437.     was_error = 1;
  438.     goto done;
  439. }
  440. *stop = *start + channels * numsamples * (samplesize / 8);
  441. /* Decode the audio data format */
  442. memset(spec, 0, (sizeof *spec));
  443. spec->freq = frequency;
  444. switch (samplesize) {
  445. case 8:
  446. spec->format = AUDIO_S8;
  447. break;
  448. case 16:
  449. spec->format = AUDIO_S16MSB;
  450. break;
  451. default:
  452. Mix_SetError("Unknown samplesize in data format");
  453. was_error = 1;
  454. goto done;
  455. }
  456. spec->channels = (Uint8) channels;
  457. spec->samples = 4096; /* Good default buffer size */
  458. done:
  459. if ( was_error ) {
  460. return NULL;
  461. }
  462. return(src);
  463. }