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

多媒体编程

开发平台:

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: music_ogg.c 5211 2009-11-08 16:35:36Z slouken $ */
  19. #ifdef OGG_MUSIC
  20. /* This file supports Ogg Vorbis music streams */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include "SDL_mixer.h"
  25. #include "dynamic_ogg.h"
  26. #include "music_ogg.h"
  27. /* This is the format of the audio mixer data */
  28. static SDL_AudioSpec mixer;
  29. /* Initialize the Ogg Vorbis player, with the given mixer settings
  30.    This function returns 0, or -1 if there was an error.
  31.  */
  32. int OGG_init(SDL_AudioSpec *mixerfmt)
  33. {
  34. mixer = *mixerfmt;
  35. return(0);
  36. }
  37. /* Set the volume for an OGG stream */
  38. void OGG_setvolume(OGG_music *music, int volume)
  39. {
  40. music->volume = volume;
  41. }
  42. /* Load an OGG stream from the given file */
  43. OGG_music *OGG_new(const char *file)
  44. {
  45. SDL_RWops *rw;
  46. rw = SDL_RWFromFile(file, "rb");
  47. if ( rw == NULL ) {
  48. SDL_SetError("Couldn't open %s", file);
  49. return NULL;
  50. }
  51. return OGG_new_RW(rw);
  52. }
  53. static size_t sdl_read_func(void *ptr, size_t size, size_t nmemb, void *datasource)
  54. {
  55.     return SDL_RWread((SDL_RWops*)datasource, ptr, size, nmemb);
  56. }
  57. static int sdl_seek_func(void *datasource, ogg_int64_t offset, int whence)
  58. {
  59.     return SDL_RWseek((SDL_RWops*)datasource, (int)offset, whence);
  60. }
  61. static int sdl_close_func(void *datasource)
  62. {
  63.     return SDL_RWclose((SDL_RWops*)datasource);
  64. }
  65. static long sdl_tell_func(void *datasource)
  66. {
  67.     return SDL_RWtell((SDL_RWops*)datasource);
  68. }
  69. /* Load an OGG stream from an SDL_RWops object */
  70. OGG_music *OGG_new_RW(SDL_RWops *rw)
  71. {
  72. OGG_music *music;
  73. ov_callbacks callbacks;
  74. callbacks.read_func = sdl_read_func;
  75. callbacks.seek_func = sdl_seek_func;
  76. callbacks.close_func = sdl_close_func;
  77. callbacks.tell_func = sdl_tell_func;
  78. music = (OGG_music *)malloc(sizeof *music);
  79. if ( music ) {
  80. /* Initialize the music structure */
  81. memset(music, 0, (sizeof *music));
  82. OGG_stop(music);
  83. OGG_setvolume(music, MIX_MAX_VOLUME);
  84. music->section = -1;
  85. if ( !Mix_Init(MIX_INIT_OGG) ) {
  86. return(NULL);
  87. }
  88. if ( vorbis.ov_open_callbacks(rw, &music->vf, NULL, 0, callbacks) < 0 ) {
  89. free(music);
  90. SDL_RWclose(rw);
  91. SDL_SetError("Not an Ogg Vorbis audio stream");
  92. return(NULL);
  93. }
  94. } else {
  95. SDL_OutOfMemory();
  96. }
  97. return(music);
  98. }
  99. /* Start playback of a given OGG stream */
  100. void OGG_play(OGG_music *music)
  101. {
  102. music->playing = 1;
  103. }
  104. /* Return non-zero if a stream is currently playing */
  105. int OGG_playing(OGG_music *music)
  106. {
  107. return(music->playing);
  108. }
  109. /* Read some Ogg stream data and convert it for output */
  110. static void OGG_getsome(OGG_music *music)
  111. {
  112. int section;
  113. int len;
  114. char data[4096];
  115. SDL_AudioCVT *cvt;
  116. #ifdef OGG_USE_TREMOR
  117. len = vorbis.ov_read(&music->vf, data, sizeof(data), &section);
  118. #else
  119. len = vorbis.ov_read(&music->vf, data, sizeof(data), 0, 2, 1, &section);
  120. #endif
  121. if ( len <= 0 ) {
  122. if ( len == 0 ) {
  123. music->playing = 0;
  124. }
  125. return;
  126. }
  127. cvt = &music->cvt;
  128. if ( section != music->section ) {
  129. vorbis_info *vi;
  130. vi = vorbis.ov_info(&music->vf, -1);
  131. SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate,
  132.                        mixer.format,mixer.channels,mixer.freq);
  133. if ( cvt->buf ) {
  134. free(cvt->buf);
  135. }
  136. cvt->buf = (Uint8 *)malloc(sizeof(data)*cvt->len_mult);
  137. music->section = section;
  138. }
  139. if ( cvt->buf ) {
  140. memcpy(cvt->buf, data, len);
  141. if ( cvt->needed ) {
  142. cvt->len = len;
  143. SDL_ConvertAudio(cvt);
  144. } else {
  145. cvt->len_cvt = len;
  146. }
  147. music->len_available = music->cvt.len_cvt;
  148. music->snd_available = music->cvt.buf;
  149. } else {
  150. SDL_SetError("Out of memory");
  151. music->playing = 0;
  152. }
  153. }
  154. /* Play some of a stream previously started with OGG_play() */
  155. int OGG_playAudio(OGG_music *music, Uint8 *snd, int len)
  156. {
  157. int mixable;
  158. while ( (len > 0) && music->playing ) {
  159. if ( ! music->len_available ) {
  160. OGG_getsome(music);
  161. }
  162. mixable = len;
  163. if ( mixable > music->len_available ) {
  164. mixable = music->len_available;
  165. }
  166. if ( music->volume == MIX_MAX_VOLUME ) {
  167. memcpy(snd, music->snd_available, mixable);
  168. } else {
  169. SDL_MixAudio(snd, music->snd_available, mixable,
  170.                               music->volume);
  171. }
  172. music->len_available -= mixable;
  173. music->snd_available += mixable;
  174. len -= mixable;
  175. snd += mixable;
  176. }
  177. return len;
  178. }
  179. /* Stop playback of a stream previously started with OGG_play() */
  180. void OGG_stop(OGG_music *music)
  181. {
  182. music->playing = 0;
  183. }
  184. /* Close the given OGG stream */
  185. void OGG_delete(OGG_music *music)
  186. {
  187. if ( music ) {
  188. if ( music->cvt.buf ) {
  189. free(music->cvt.buf);
  190. }
  191. vorbis.ov_clear(&music->vf);
  192. free(music);
  193. }
  194. }
  195. /* Jump (seek) to a given position (time is in seconds) */
  196. void OGG_jump_to_time(OGG_music *music, double time)
  197. {
  198.        vorbis.ov_time_seek( &music->vf, time );
  199. }
  200. #endif /* OGG_MUSIC */