drv_alsa.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000 Miodrag Vallat and others - see file AUTHORS for
  3. complete list.
  4. This library is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of
  7. the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  17. 02111-1307, USA.
  18. */
  19. /*==============================================================================
  20.   $Id: drv_alsa.c,v 1.2 2004/01/31 22:39:40 raph Exp $
  21.   Driver for Advanced Linux Sound Architecture (ALSA)
  22. ==============================================================================*/
  23. #ifdef HAVE_CONFIG_H
  24. #include "config.h"
  25. #endif
  26. #include "mikmod_internals.h"
  27. #ifdef DRV_ALSA
  28. #ifdef HAVE_UNISTD_H
  29. #include <unistd.h>
  30. #endif
  31. #ifdef HAVE_MEMORY_H
  32. #include <memory.h>
  33. #endif
  34. #ifdef MIKMOD_DYNAMIC
  35. #include <dlfcn.h>
  36. #endif
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sys/asoundlib.h>
  40. #if defined(SND_LIB_VERSION) && (SND_LIB_VERSION >= 0x500)
  41. #undef DRV_ALSA
  42. #endif
  43. #endif
  44. #ifdef DRV_ALSA
  45. #ifdef MIKMOD_DYNAMIC
  46. /* runtime link with libasound */
  47. static unsigned int(*alsa_cards_mask)(void);
  48. static int(*alsa_ctl_close)(snd_ctl_t*);
  49. static int(*alsa_ctl_hw_info)(snd_ctl_t*,struct snd_ctl_hw_info*);
  50. static int(*alsa_ctl_open)(snd_ctl_t**,int);
  51. static int(*alsa_ctl_pcm_info)(snd_ctl_t*,int,snd_pcm_info_t*);
  52. #if defined(SND_LIB_VERSION) && (SND_LIB_VERSION >= 0x400)
  53. static int(*alsa_ctl_pcm_playback_info)(snd_ctl_t*,int,int,snd_pcm_playback_info_t*);
  54. #else
  55. static int(*alsa_ctl_pcm_playback_info)(snd_ctl_t*,int,snd_pcm_playback_info_t*);
  56. #endif
  57. static int(*alsa_pcm_close)(snd_pcm_t*);
  58. static int(*alsa_pcm_drain_playback)(snd_pcm_t*);
  59. static int(*alsa_pcm_flush_playback)(snd_pcm_t*);
  60. static int(*alsa_pcm_open)(snd_pcm_t**,int,int,int);
  61. static int(*alsa_pcm_playback_format)(snd_pcm_t*,snd_pcm_format_t*);
  62. static int(*alsa_pcm_playback_info)(snd_pcm_t*,snd_pcm_playback_info_t*);
  63. static int(*alsa_pcm_playback_params)(snd_pcm_t*,snd_pcm_playback_params_t*);
  64. static int(*alsa_pcm_playback_status)(snd_pcm_t*,snd_pcm_playback_status_t*);
  65. static int(*alsa_pcm_write)(snd_pcm_t*,const void*,size_t);
  66. static void* libasound=NULL;
  67. #ifndef HAVE_RTLD_GLOBAL
  68. #define RTLD_GLOBAL (0)
  69. #endif
  70. #else
  71. /* compile-time link with libasound */
  72. #define alsa_cards_mask snd_cards_mask
  73. #define alsa_ctl_close snd_ctl_close
  74. #define alsa_ctl_hw_info snd_ctl_hw_info
  75. #define alsa_ctl_open snd_ctl_open
  76. #define alsa_ctl_pcm_info snd_ctl_pcm_info
  77. #define alsa_ctl_pcm_playback_info snd_ctl_pcm_playback_info
  78. #define alsa_pcm_close snd_pcm_close
  79. #define alsa_pcm_drain_playback snd_pcm_drain_playback
  80. #define alsa_pcm_flush_playback snd_pcm_flush_playback
  81. #define alsa_pcm_open snd_pcm_open
  82. #define alsa_pcm_playback_format snd_pcm_playback_format
  83. #define alsa_pcm_playback_info snd_pcm_playback_info
  84. #define alsa_pcm_playback_params snd_pcm_playback_params
  85. #define alsa_pcm_playback_status snd_pcm_playback_status
  86. #define alsa_pcm_write snd_pcm_write
  87. #endif /* MIKMOD_DYNAMIC */
  88. #define DEFAULT_NUMFRAGS 4
  89. static snd_pcm_t *pcm_h=NULL;
  90. static int fragmentsize,numfrags=DEFAULT_NUMFRAGS;
  91. static SBYTE *audiobuffer=NULL;
  92. static int cardmin=0,cardmax=SND_CARDS;
  93. static int device=-1;
  94. #ifdef MIKMOD_DYNAMIC
  95. static BOOL ALSA_Link(void)
  96. {
  97. if(libasound) return 0;
  98. /* load libasound.so */
  99. libasound=dlopen("libasound.so",RTLD_LAZY|RTLD_GLOBAL);
  100. if(!libasound) return 1;
  101. /* resolve function references */
  102. if(!(alsa_cards_mask           =dlsym(libasound,"snd_cards_mask"))) return 1;
  103. if(!(alsa_ctl_close            =dlsym(libasound,"snd_ctl_close"))) return 1;
  104. if(!(alsa_ctl_hw_info          =dlsym(libasound,"snd_ctl_hw_info"))) return 1;
  105. if(!(alsa_ctl_open             =dlsym(libasound,"snd_ctl_open"))) return 1;
  106. if(!(alsa_ctl_pcm_info         =dlsym(libasound,"snd_ctl_pcm_info"))) return 1;
  107. if(!(alsa_ctl_pcm_playback_info=dlsym(libasound,"snd_ctl_pcm_playback_info"))) return 1;
  108. if(!(alsa_pcm_close            =dlsym(libasound,"snd_pcm_close"))) return 1;
  109. if(!(alsa_pcm_drain_playback   =dlsym(libasound,"snd_pcm_drain_playback"))) return 1;
  110. if(!(alsa_pcm_flush_playback   =dlsym(libasound,"snd_pcm_flush_playback"))) return 1;
  111. if(!(alsa_pcm_open             =dlsym(libasound,"snd_pcm_open"))) return 1;
  112. if(!(alsa_pcm_playback_format  =dlsym(libasound,"snd_pcm_playback_format"))) return 1;
  113. if(!(alsa_pcm_playback_info    =dlsym(libasound,"snd_pcm_playback_info"))) return 1;
  114. if(!(alsa_pcm_playback_params  =dlsym(libasound,"snd_pcm_playback_params"))) return 1;
  115. if(!(alsa_pcm_playback_status  =dlsym(libasound,"snd_pcm_playback_status"))) return 1;
  116. if(!(alsa_pcm_write            =dlsym(libasound,"snd_pcm_write"))) return 1;
  117. return 0;
  118. }
  119. static void ALSA_Unlink(void)
  120. {
  121. alsa_cards_mask           =NULL;
  122. alsa_ctl_close            =NULL;
  123. alsa_ctl_hw_info          =NULL;
  124. alsa_ctl_open             =NULL;
  125. alsa_ctl_pcm_info         =NULL;
  126. alsa_ctl_pcm_playback_info=NULL;
  127. alsa_pcm_close            =NULL;
  128. alsa_pcm_drain_playback   =NULL;
  129. alsa_pcm_flush_playback   =NULL;
  130. alsa_pcm_open             =NULL;
  131. alsa_pcm_playback_format  =NULL;
  132. alsa_pcm_playback_info    =NULL;
  133. alsa_pcm_playback_params  =NULL;
  134. alsa_pcm_playback_status  =NULL;
  135. alsa_pcm_write            =NULL;
  136. if(libasound) {
  137. dlclose(libasound);
  138. libasound=NULL;
  139. }
  140. }
  141. #endif /* MIKMOD_DYNAMIC */
  142. static void ALSA_CommandLine(CHAR *cmdline)
  143. {
  144. CHAR *ptr;
  145. if((ptr=MD_GetAtom("card",cmdline,0))) {
  146. cardmin=atoi(ptr);cardmax=cardmin+1;
  147. free(ptr);
  148. } else {
  149. cardmin=0;cardmax=SND_CARDS;
  150. }
  151. if((ptr=MD_GetAtom("pcm",cmdline,0))) {
  152. device=atoi(ptr);
  153. free(ptr);
  154. } else device=-1;
  155. if((ptr=MD_GetAtom("buffer",cmdline,0))) {
  156. numfrags=atoi(ptr);
  157. if ((numfrags<2)||(numfrags>16)) numfrags=DEFAULT_NUMFRAGS;
  158. free(ptr);
  159. } else numfrags=DEFAULT_NUMFRAGS;
  160. }
  161. static BOOL ALSA_IsThere(void)
  162. {
  163. int retval;
  164. #ifdef MIKMOD_DYNAMIC
  165. if (ALSA_Link()) return 0;
  166. #endif
  167. retval=(alsa_cards_mask())?1:0;
  168. #ifdef MIKMOD_DYNAMIC
  169. ALSA_Unlink();
  170. #endif
  171. return retval;
  172. }
  173. static BOOL ALSA_Init_internal(void)
  174. {
  175. snd_pcm_format_t pformat;
  176. int mask,card;
  177. /* adjust user-configurable settings */
  178. if((getenv("MM_NUMFRAGS"))&&(numfrags==DEFAULT_NUMFRAGS)) {
  179. numfrags=atoi(getenv("MM_NUMFRAGS"));
  180. if ((numfrags<2)||(numfrags>16)) numfrags=DEFAULT_NUMFRAGS;
  181. }
  182. if((getenv("ALSA_CARD"))&&(!cardmin)&&(cardmax==SND_CARDS)) {
  183. cardmin=atoi(getenv("ALSA_CARD"));
  184. cardmax=cardmin+1;
  185. if(getenv("ALSA_PCM"))
  186. device=atoi(getenv("ALSA_PCM"));
  187. }
  188. /* setup playback format structure */
  189. memset(&pformat,0,sizeof(pformat));
  190. #ifdef SND_LITTLE_ENDIAN
  191. pformat.format=(md_mode&DMODE_16BITS)?SND_PCM_SFMT_S16_LE:SND_PCM_SFMT_U8;
  192. #else
  193. pformat.format=(md_mode&DMODE_16BITS)?SND_PCM_SFMT_S16_BE:SND_PCM_SFMT_U8;
  194. #endif
  195. pformat.channels=(md_mode&DMODE_STEREO)?2:1;
  196. pformat.rate=md_mixfreq;
  197. /* scan for appropriate sound card */
  198. mask=alsa_cards_mask();
  199. _mm_errno=MMERR_OPENING_AUDIO;
  200. for (card=cardmin;card<cardmax;card++) {
  201. struct snd_ctl_hw_info info;
  202. snd_ctl_t *ctl_h;
  203. int dev,devmin,devmax;
  204. /* no card here, onto the next */
  205. if (!(mask&(1<<card))) continue;
  206. /* try to open the card in query mode */
  207. if(alsa_ctl_open(&ctl_h,card)<0)
  208. continue;
  209. /* get hardware information */
  210. if(alsa_ctl_hw_info(ctl_h,&info)<0) {
  211. alsa_ctl_close(ctl_h);
  212. continue;
  213. }
  214. /* scan subdevices */
  215. if(device==-1) {
  216. devmin=0;devmax=info.pcmdevs;
  217. } else
  218. devmin=devmax=device;
  219. for(dev=devmin;dev<devmax;dev++) {
  220. snd_pcm_info_t pcminfo;
  221. snd_pcm_playback_info_t ctlinfo;
  222. struct snd_pcm_playback_info pinfo;
  223. struct snd_pcm_playback_params pparams;
  224. int size,bps;
  225. /* get PCM capabilities */
  226. if(alsa_ctl_pcm_info(ctl_h,dev,&pcminfo)<0)
  227. continue;
  228. /* look for playback capability */
  229. if(!(pcminfo.flags&SND_PCM_INFO_PLAYBACK))
  230. continue;
  231. /* get playback information */
  232. #if defined(SND_LIB_VERSION) && (SND_LIB_VERSION >= 0x400)
  233. if(alsa_ctl_pcm_playback_info(ctl_h,dev,0,&ctlinfo)<0)
  234. continue;
  235. #else
  236. if(alsa_ctl_pcm_playback_info(ctl_h,dev,&ctlinfo)<0)
  237. continue;
  238. #endif
  239. /*
  240.    If control goes here, we have found a sound device able to play PCM data.
  241.    Let's open in in playback mode and see if we have compatible playback
  242.    settings.
  243. */
  244. if (alsa_pcm_open(&pcm_h,card,dev,SND_PCM_OPEN_PLAYBACK)<0)
  245. continue;
  246. if (alsa_pcm_playback_info(pcm_h,&pinfo)<0) {
  247. alsa_pcm_close(pcm_h);
  248. pcm_h=NULL;
  249. continue;
  250. }
  251. /* check we have compatible settings */
  252. if((pinfo.min_rate>pformat.rate)||(pinfo.max_rate<pformat.rate)||
  253.    (!(pinfo.formats&(1<<pformat.format)))) {
  254. alsa_pcm_close(pcm_h);
  255. pcm_h=NULL;
  256. continue;
  257. }
  258. fragmentsize=pinfo.buffer_size/numfrags;
  259. #ifdef MIKMOD_DEBUG
  260. if ((fragmentsize<512)||(fragmentsize>16777216L))
  261. fprintf(stderr,"rweird pinfo.buffer_size:%dn",pinfo.buffer_size);
  262. #endif
  263. alsa_pcm_flush_playback(pcm_h);
  264. /* set new parameters */
  265. if(alsa_pcm_playback_format(pcm_h,&pformat)<0) {
  266. alsa_pcm_close(pcm_h);
  267. pcm_h=NULL;
  268. continue;
  269. }
  270. /* compute a fragmentsize hint
  271.    each fragment should be shorter than, but close to, half a
  272.    second of playback */
  273. bps=(pformat.rate*pformat.channels*(md_mode&DMODE_16BITS?2:1))>>1;
  274. size=fragmentsize;while (size>bps) size>>=1;
  275. #ifdef MIKMOD_DEBUG
  276. if (size < 16) {
  277. fprintf(stderr,"rweird hint result:%d from %d, bps=%dn",size,fragmentsize,bps);
  278. size=16;
  279. }
  280. #endif
  281. memset(&pparams,0,sizeof(pparams));
  282. pparams.fragment_size=size;
  283. pparams.fragments_max=-1; /* choose the best */
  284. pparams.fragments_room=-1;
  285. if(alsa_pcm_playback_params(pcm_h,&pparams)<0) {
  286. alsa_pcm_close(pcm_h);
  287. pcm_h=NULL;
  288. continue;
  289. }
  290. if (!(audiobuffer=(SBYTE*)_mm_malloc(fragmentsize))) {
  291. alsa_ctl_close(ctl_h);
  292. return 1;
  293. }
  294. /* sound device is ready to work */
  295. if (VC_Init()) {
  296. alsa_ctl_close(ctl_h);
  297. return 1;
  298. } else
  299.   return 0;
  300. }
  301. alsa_ctl_close(ctl_h);
  302. }
  303. return 1;
  304. }
  305. static BOOL ALSA_Init(void)
  306. {
  307. #ifdef MIKMOD_DYNAMIC
  308. if (ALSA_Link()) {
  309. _mm_errno=MMERR_DYNAMIC_LINKING;
  310. return 1;
  311. }
  312. #endif
  313. return ALSA_Init_internal();
  314. }
  315. static void ALSA_Exit_internal(void)
  316. {
  317. VC_Exit();
  318. if (pcm_h) {
  319. alsa_pcm_drain_playback(pcm_h);
  320. alsa_pcm_close(pcm_h);
  321. pcm_h=NULL;
  322. }
  323. _mm_free(audiobuffer);
  324. }
  325. static void ALSA_Exit(void)
  326. {
  327. ALSA_Exit_internal();
  328. #ifdef MIKMOD_DYNAMIC
  329. ALSA_Unlink();
  330. #endif
  331. }
  332. static void ALSA_Update(void)
  333. {
  334. snd_pcm_playback_status_t status;
  335. int total, count;
  336. if (alsa_pcm_playback_status(pcm_h, &status) >= 0) {
  337. /* Update md_mixfreq if necessary */
  338. if (md_mixfreq != status.rate)
  339. md_mixfreq = status.rate;
  340. /* Using status.count would cause clicks, as this is always less than
  341.    the freespace  in the buffer - so compute how many bytes we can
  342.    afford */
  343. total = status.fragments * status.fragment_size - status.queue;
  344. if (total < fragmentsize)
  345. total = fragmentsize;
  346. } else
  347. total = fragmentsize;
  348. /* Don't send data if ALSA is too busy */
  349. while (total) {
  350. count = fragmentsize > total ? total : fragmentsize;
  351. total -= count;
  352. alsa_pcm_write(pcm_h,audiobuffer,VC_WriteBytes(audiobuffer,count));
  353. }
  354. }
  355. static void ALSA_PlayStop(void)
  356. {
  357. VC_PlayStop();
  358. alsa_pcm_flush_playback(pcm_h);
  359. }
  360. static BOOL ALSA_Reset(void)
  361. {
  362. ALSA_Exit_internal();
  363. return ALSA_Init_internal();
  364. }
  365. MIKMODAPI MDRIVER drv_alsa={
  366. NULL,
  367. "ALSA",
  368. "Advanced Linux Sound Architecture (ALSA) driver v0.4",
  369. 0,255,
  370. "alsa",
  371. "card:r:0,31,0:Soundcard numbern"
  372.         "pcm:r:0,3,0:PCM device numbern"
  373.         "buffer:r:2,16,4:Number of buffer fragmentsn",
  374. ALSA_CommandLine,
  375. ALSA_IsThere,
  376. VC_SampleLoad,
  377. VC_SampleUnload,
  378. VC_SampleSpace,
  379. VC_SampleLength,
  380. ALSA_Init,
  381. ALSA_Exit,
  382. ALSA_Reset,
  383. VC_SetNumVoices,
  384. VC_PlayStart,
  385. ALSA_PlayStop,
  386. ALSA_Update,
  387. NULL,
  388. VC_VoiceSetVolume,
  389. VC_VoiceGetVolume,
  390. VC_VoiceSetFrequency,
  391. VC_VoiceGetFrequency,
  392. VC_VoiceSetPanning,
  393. VC_VoiceGetPanning,
  394. VC_VoicePlay,
  395. VC_VoiceStop,
  396. VC_VoiceStopped,
  397. VC_VoiceGetPosition,
  398. VC_VoiceRealVolume
  399. };
  400. #else
  401. MISSING(drv_alsa);
  402. #endif
  403. /* ex:set ts=4: */