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

多媒体编程

开发平台:

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_mod.c 4211 2008-12-08 00:27:32Z slouken $ */
  19. #ifdef MOD_MUSIC
  20. /* This file supports MOD tracker music streams */
  21. #include "SDL_mixer.h"
  22. #include "dynamic_mod.h"
  23. #include "music_mod.h"
  24. #include "mikmod.h"
  25. #define SDL_SURROUND
  26. #ifdef SDL_SURROUND
  27. #define MAX_OUTPUT_CHANNELS 6
  28. #else
  29. #define MAX_OUTPUT_CHANNELS 2
  30. #endif
  31. /* Reference for converting mikmod output to 4/6 channels */
  32. static int current_output_channels;
  33. static Uint16 current_output_format;
  34. static int music_swap8;
  35. static int music_swap16;
  36. /* Initialize the MOD player, with the given mixer settings
  37.    This function returns 0, or -1 if there was an error.
  38.  */
  39. int MOD_init(SDL_AudioSpec *mixerfmt)
  40. {
  41. CHAR *list;
  42. if ( !Mix_Init(MIX_INIT_MOD) ) {
  43. return -1;
  44. }
  45. /* Set the MikMod music format */
  46. music_swap8 = 0;
  47. music_swap16 = 0;
  48. switch (mixerfmt->format) {
  49. case AUDIO_U8:
  50. case AUDIO_S8: {
  51. if ( mixerfmt->format == AUDIO_S8 ) {
  52. music_swap8 = 1;
  53. }
  54. *mikmod.md_mode = 0;
  55. }
  56. break;
  57. case AUDIO_S16LSB:
  58. case AUDIO_S16MSB: {
  59. /* See if we need to correct MikMod mixing */
  60. #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  61. if ( mixerfmt->format == AUDIO_S16MSB ) {
  62. #else
  63. if ( mixerfmt->format == AUDIO_S16LSB ) {
  64. #endif
  65. music_swap16 = 1;
  66. }
  67. *mikmod.md_mode = DMODE_16BITS;
  68. }
  69. break;
  70. default: {
  71. Mix_SetError("Unknown hardware audio format");
  72. return -1;
  73. }
  74. }
  75. current_output_channels = mixerfmt->channels;
  76. current_output_format = mixerfmt->format;
  77. if ( mixerfmt->channels > 1 ) {
  78. if ( mixerfmt->channels > MAX_OUTPUT_CHANNELS ) {
  79. Mix_SetError("Hardware uses more channels than mixerfmt");
  80. return -1;
  81. }
  82. *mikmod.md_mode |= DMODE_STEREO;
  83. }
  84. *mikmod.md_mixfreq = mixerfmt->freq;
  85. *mikmod.md_device  = 0;
  86. *mikmod.md_volume  = 96;
  87. *mikmod.md_musicvolume = 128;
  88. *mikmod.md_sndfxvolume = 128;
  89. *mikmod.md_pansep  = 128;
  90. *mikmod.md_reverb  = 0;
  91. *mikmod.md_mode    |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;
  92. list = mikmod.MikMod_InfoDriver();
  93. if ( list )
  94.   free(list);
  95. else
  96.   mikmod.MikMod_RegisterDriver(mikmod.drv_nos);
  97. list = mikmod.MikMod_InfoLoader();
  98. if ( list )
  99.   free(list);
  100. else
  101.   mikmod.MikMod_RegisterAllLoaders();
  102. if ( mikmod.MikMod_Init(NULL) ) {
  103. Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
  104. return -1;
  105. }
  106. return 0;
  107. }
  108. /* Uninitialize the music players */
  109. void MOD_exit(void)
  110. {
  111. if (mikmod.MikMod_Exit) {
  112. mikmod.MikMod_Exit();
  113. }
  114. }
  115. /* Set the volume for a MOD stream */
  116. void MOD_setvolume(MODULE *music, int volume)
  117. {
  118. mikmod.Player_SetVolume((SWORD)volume);
  119. }
  120. /* Load a MOD stream from the given file */
  121. MODULE *MOD_new(const char *file)
  122. {
  123. SDL_RWops *rw;
  124. rw = SDL_RWFromFile(file, "rb");
  125. if ( rw == NULL ) {
  126. /* FIXME: Free rw, need to free on delete */
  127. SDL_SetError("Couldn't open %s", file);
  128. return NULL;
  129. }
  130. return MOD_new_RW(rw);
  131. }
  132. typedef struct
  133. {
  134. MREADER mr;
  135. long offset;
  136. long eof;
  137. SDL_RWops *rw;
  138. } LMM_MREADER;
  139. BOOL LMM_Seek(struct MREADER *mr,long to,int dir)
  140. {
  141. LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
  142. if ( dir == SEEK_SET ) {
  143. to += lmmmr->offset;
  144. }
  145. return (SDL_RWseek(lmmmr->rw, to, dir) < lmmmr->offset);
  146. }
  147. long LMM_Tell(struct MREADER *mr)
  148. {
  149. LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
  150. return SDL_RWtell(lmmmr->rw) - lmmmr->offset;
  151. }
  152. BOOL LMM_Read(struct MREADER *mr,void *buf,size_t sz)
  153. {
  154. LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
  155. return SDL_RWread(lmmmr->rw, buf, sz, 1);
  156. }
  157. int LMM_Get(struct MREADER *mr)
  158. {
  159. unsigned char c;
  160. LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
  161. if ( SDL_RWread(lmmmr->rw, &c, 1, 1) ) {
  162. return c;
  163. }
  164. return EOF;
  165. }
  166. BOOL LMM_Eof(struct MREADER *mr)
  167. {
  168. long offset;
  169. LMM_MREADER* lmmmr = (LMM_MREADER*)mr;
  170. offset = LMM_Tell(mr);
  171. return offset >= lmmmr->eof;
  172. }
  173. MODULE *MikMod_LoadSongRW(SDL_RWops *rw, int maxchan)
  174. {
  175. LMM_MREADER lmmmr = {
  176. { LMM_Seek, LMM_Tell, LMM_Read, LMM_Get, LMM_Eof },
  177. 0,
  178. 0,
  179. 0
  180. };
  181. lmmmr.offset = SDL_RWtell(rw);
  182. SDL_RWseek(rw, 0, RW_SEEK_END);
  183. lmmmr.eof = SDL_RWtell(rw);
  184. SDL_RWseek(rw, lmmmr.offset, RW_SEEK_SET);
  185.         lmmmr.rw = rw;
  186. return mikmod.Player_LoadGeneric((MREADER*)&lmmmr, maxchan, 0);
  187. }
  188. /* Load a MOD stream from an SDL_RWops object */
  189. MODULE *MOD_new_RW(SDL_RWops *rw)
  190. {
  191. MODULE *module;
  192. /* Make sure the mikmod library is loaded */
  193. if ( !Mix_Init(MIX_INIT_MOD) ) {
  194. return NULL;
  195. }
  196. module = MikMod_LoadSongRW(rw,64);
  197. if (!module) {
  198. Mix_SetError("%s", mikmod.MikMod_strerror(*mikmod.MikMod_errno));
  199. return NULL;
  200. }
  201. /* Stop implicit looping, fade out and other flags. */
  202. module->extspd  = 1;
  203. module->panflag = 1;
  204. module->wrap    = 0;
  205. module->loop    = 0;
  206. #if 0 /* Don't set fade out by default - unfortunately there's no real way
  207. to query the status of the song or set trigger actions.  Hum. */
  208. module->fadeout = 1;
  209. #endif
  210. return module;
  211. }
  212. /* Start playback of a given MOD stream */
  213. void MOD_play(MODULE *music)
  214. {
  215. mikmod.Player_Start(music);
  216. }
  217. /* Return non-zero if a stream is currently playing */
  218. int MOD_playing(MODULE *music)
  219. {
  220. return mikmod.Player_Active();
  221. }
  222. /* Play some of a stream previously started with MOD_play() */
  223. int MOD_playAudio(MODULE *music, Uint8 *stream, int len)
  224. {
  225. if (current_output_channels > 2) {
  226. int small_len = 2 * len / current_output_channels;
  227. int i;
  228. Uint8 *src, *dst;
  229. mikmod.VC_WriteBytes((SBYTE *)stream, small_len);
  230. /* and extend to len by copying channels */
  231. src = stream + small_len;
  232. dst = stream + len;
  233. switch (current_output_format & 0xFF) {
  234. case 8:
  235. for ( i=small_len/2; i; --i ) {
  236. src -= 2;
  237. dst -= current_output_channels;
  238. dst[0] = src[0];
  239. dst[1] = src[1];
  240. dst[2] = src[0];
  241. dst[3] = src[1];
  242. if (current_output_channels == 6) {
  243. dst[4] = src[0];
  244. dst[5] = src[1];
  245. }
  246. }
  247. break;
  248. case 16:
  249. for ( i=small_len/4; i; --i ) {
  250. src -= 4;
  251. dst -= 2 * current_output_channels;
  252. dst[0] = src[0];
  253. dst[1] = src[1];
  254. dst[2] = src[2];
  255. dst[3] = src[3];
  256. dst[4] = src[0];
  257. dst[5] = src[1];
  258. dst[6] = src[2];
  259. dst[7] = src[3];
  260. if (current_output_channels == 6) {
  261. dst[8] = src[0];
  262. dst[9] = src[1];
  263. dst[10] = src[2];
  264. dst[11] = src[3];
  265. }
  266. }
  267. break;
  268. }
  269. } else {
  270. mikmod.VC_WriteBytes((SBYTE *)stream, len);
  271. }
  272. if ( music_swap8 ) {
  273. Uint8 *dst;
  274. int i;
  275. dst = stream;
  276. for ( i=len; i; --i ) {
  277. *dst++ ^= 0x80;
  278. }
  279. } else
  280. if ( music_swap16 ) {
  281. Uint8 *dst, tmp;
  282. int i;
  283. dst = stream;
  284. for ( i=(len/2); i; --i ) {
  285. tmp = dst[0];
  286. dst[0] = dst[1];
  287. dst[1] = tmp;
  288. dst += 2;
  289. }
  290. }
  291. return 0;
  292. }
  293. /* Stop playback of a stream previously started with MOD_play() */
  294. void MOD_stop(MODULE *music)
  295. {
  296. mikmod.Player_Stop();
  297. }
  298. /* Close the given MOD stream */
  299. void MOD_delete(MODULE *music)
  300. {
  301. mikmod.Player_Free(music);
  302. }
  303. /* Jump (seek) to a given position (time is in seconds) */
  304. void MOD_jump_to_time(MODULE *music, double time)
  305. {
  306. mikmod.Player_SetPosition((UWORD)time);
  307. }
  308. #endif /* MOD_MUSIC */