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

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_oss.c,v 1.4 2004/01/31 22:39:40 raph Exp $
  21.   Driver for output on Linux and FreeBSD Open Sound System (OSS) (/dev/dsp) 
  22. ==============================================================================*/
  23. /*
  24. Written by Chris Conn <cconn@tohs.abacom.com>
  25. Extended by Miodrag Vallat:
  26. - compatible with all OSS/Voxware versions on Linux/i386, at least
  27. - support for uLaw output (for sparc systems)
  28. */
  29. #ifdef HAVE_CONFIG_H
  30. #include "config.h"
  31. #endif
  32. #include "mikmod_internals.h"
  33. #ifdef DRV_OSS
  34. #ifdef HAVE_UNISTD_H
  35. #include <unistd.h>
  36. #endif
  37. #include <errno.h>
  38. #ifdef HAVE_FCNTL_H
  39. #include <fcntl.h>
  40. #endif
  41. #include <string.h>
  42. #include <stdlib.h>
  43. #ifdef HAVE_SYS_IOCTL_H
  44. #include <sys/ioctl.h>
  45. #endif
  46. #ifdef HAVE_MACHINE_SOUNDCARD_H
  47. #include <machine/soundcard.h>
  48. #endif
  49. #ifdef HAVE_SYS_SOUNDCARD_H
  50. #include <sys/soundcard.h>
  51. #endif
  52. /* Compatibility with old versions of OSS
  53.    (Voxware <= 2.03, Linux kernel < 1.1.31) */
  54. #ifndef AFMT_S16_LE
  55. #define AFMT_S16_LE 16
  56. #endif
  57. #ifndef AFMT_S16_BE
  58. #define AFMT_S16_BE 0x20
  59. #endif
  60. #ifndef AFMT_U8
  61. #define AFMT_U8 8
  62. #endif
  63. #ifndef SNDCTL_DSP_SETFMT
  64. #define SNDCTL_DSP_SETFMT SNDCTL_DSP_SAMPLESIZE
  65. #endif
  66. /* Compatibility with not-so-old versions of OSS
  67.    (OSS < 3.7, Linux kernel < 2.1.16) */
  68. #ifndef AFMT_S16_NE
  69. #if defined(_AIX) || defined(AIX) || defined(sparc) || defined(HPPA) || defined(PPC)
  70. #define AFMT_S16_NE AFMT_S16_BE
  71. #else
  72. #define AFMT_S16_NE AFMT_S16_LE
  73. #endif
  74. #endif
  75. static int sndfd=-1;
  76. static SBYTE *audiobuffer=NULL;
  77. static int buffersize;
  78. static int play_precision;
  79. #define DEFAULT_CARD 0
  80. static int card=DEFAULT_CARD;
  81. #ifdef SNDCTL_DSP_SETFRAGMENT
  82. #define DEFAULT_FRAGSIZE 14
  83. #define DEFAULT_NUMFRAGS 16
  84. static int fragsize=DEFAULT_FRAGSIZE;
  85. static int numfrags=DEFAULT_NUMFRAGS;
  86. #endif
  87. static void OSS_CommandLine(CHAR *cmdline)
  88. {
  89. CHAR *ptr;
  90. #ifdef SNDCTL_DSP_SETFRAGMENT
  91. if((ptr=MD_GetAtom("buffer",cmdline,0))) {
  92. fragsize=atoi(ptr);
  93. if((fragsize<7)||(fragsize>17)) fragsize=DEFAULT_FRAGSIZE;
  94. free(ptr);
  95. }
  96. if((ptr=MD_GetAtom("count",cmdline,0))) {
  97. numfrags=atoi(ptr);
  98. if((numfrags<2)||(numfrags>255)) numfrags=DEFAULT_NUMFRAGS;
  99. free(ptr);
  100. }
  101. #endif
  102. if((ptr=MD_GetAtom("card",cmdline,0))) {
  103. card = atoi(ptr);
  104. if((card<0)||(card>99)) card=DEFAULT_CARD;
  105. free(ptr);
  106. }
  107. }
  108. static char *OSS_GetDeviceName(void)
  109. {
  110. static char sounddevice[20];
  111. /* First test for devfs enabled Linux sound devices */
  112. if (card)
  113. sprintf(sounddevice,"/dev/sound/dsp%d",card);
  114. else
  115. strcpy(sounddevice,"/dev/sound/dsp");
  116. if(!access(sounddevice,F_OK))
  117. return sounddevice;
  118. sprintf(sounddevice,"/dev/dsp%d",card);
  119. if (!card) {
  120. /* prefer /dev/dsp0 over /dev/dsp, as /dev/dsp might be a symbolic link
  121.    to something else than /dev/dsp0. Revert to /dev/dsp if /dev/dsp0
  122.    does not exist. */
  123. if(access("/dev/dsp0",F_OK))
  124. strcpy(sounddevice,"/dev/dsp");
  125. }
  126. return sounddevice;
  127. }
  128. static BOOL OSS_IsThere(void)
  129. {
  130. /* under Linux, and perhaps other Unixes, access()ing the device is not
  131.    enough since it won't fail if the machine doesn't have sound support
  132.    in the kernel or sound hardware                                      */
  133. int fd;
  134. if((fd=open(OSS_GetDeviceName(),O_WRONLY))>=0) {
  135. close(fd);
  136. return 1;
  137. }
  138. return (errno==EACCES?1:0);
  139. }
  140. static BOOL OSS_Init_internal(void)
  141. {
  142. int play_stereo,play_rate;
  143. int orig_precision,orig_stereo;
  144. long formats;
  145. #if SOUND_VERSION >= 301
  146. audio_buf_info buffinf;
  147. #endif
  148. #ifdef SNDCTL_DSP_GETFMTS
  149. /* Ask device for supported formats */
  150. if(ioctl(sndfd,SNDCTL_DSP_GETFMTS,&formats)<0) {
  151. _mm_errno=MMERR_OPENING_AUDIO;
  152. return 1;
  153. }
  154. #else
  155. formats=AFMT_S16_NE|AFMT_U8;
  156. #endif
  157. orig_precision=play_precision=(md_mode&DMODE_16BITS)?AFMT_S16_NE:AFMT_U8;
  158.     /* Device does not support the format we would prefer... */
  159.     if(!(formats & play_precision)) {
  160.         /* We could try 8 bit sound if available */
  161.         if(play_precision==AFMT_S16_NE &&(formats&AFMT_U8)) {
  162.             _mm_errno=MMERR_8BIT_ONLY;
  163.             return 1;
  164.         }
  165. #ifdef AFMT_MU_LAW
  166.         /* We could try uLaw if available */
  167.         if(formats&AFMT_MU_LAW) {
  168.             if((md_mode&DMODE_STEREO)||(md_mode&DMODE_16BITS)||
  169.                 md_mixfreq!=8000) {
  170.                 _mm_errno=MMERR_ULAW;
  171.                 return 1;
  172.             } else
  173.                 orig_precision=play_precision=AFMT_MU_LAW;
  174.         } else
  175. #endif
  176.             /* Otherwise, just abort */
  177.         {
  178.             _mm_errno=MMERR_OSS_SETSAMPLESIZE;
  179.             return 1;
  180.         }
  181.     }
  182. if((ioctl(sndfd,SNDCTL_DSP_SETFMT,&play_precision)<0)||
  183.    (orig_precision!=play_precision)) {
  184. _mm_errno=MMERR_OSS_SETSAMPLESIZE;
  185. return 1;
  186. }
  187. #ifdef SNDCTL_DSP_CHANNELS
  188. orig_stereo=play_stereo=(md_mode&DMODE_STEREO)?2:1;
  189. if((ioctl(sndfd,SNDCTL_DSP_CHANNELS,&play_stereo)<0)||
  190.    (orig_stereo!=play_stereo)) {
  191. _mm_errno=MMERR_OSS_SETSTEREO;
  192. return 1;
  193. }
  194. #else
  195. orig_stereo=play_stereo=(md_mode&DMODE_STEREO)?1:0;
  196. if((ioctl(sndfd,SNDCTL_DSP_STEREO,&play_stereo)<0)||
  197.    (orig_stereo!=play_stereo)) {
  198. _mm_errno=MMERR_OSS_SETSTEREO;
  199. return 1;
  200. }
  201. #endif
  202. play_rate=md_mixfreq;
  203. if((ioctl(sndfd,SNDCTL_DSP_SPEED,&play_rate)<0)) {
  204. _mm_errno=MMERR_OSS_SETSPEED;
  205. return 1;
  206. }
  207. md_mixfreq=play_rate;
  208. #if SOUND_VERSION >= 301
  209. /* This call fails on Linux/PPC */
  210. if((ioctl(sndfd,SNDCTL_DSP_GETOSPACE,&buffinf)<0))
  211. ioctl(sndfd,SNDCTL_DSP_GETBLKSIZE,&buffinf.fragsize);
  212. if(!(audiobuffer=(SBYTE*)_mm_malloc(buffinf.fragsize)))
  213. return 1;
  214. buffersize = buffinf.fragsize;
  215. #else
  216. ioctl(sndfd,SNDCTL_DSP_GETBLKSIZE,&buffersize);
  217. if(!(audiobuffer=(SBYTE*)_mm_malloc(buffersize)))
  218. return 1;
  219. #endif
  220. return VC_Init();
  221. }
  222. static BOOL OSS_Init(void)
  223. {
  224. #ifdef SNDCTL_DSP_SETFRAGMENT
  225. int fragmentsize;
  226. #endif
  227. if((sndfd=open(OSS_GetDeviceName(),O_WRONLY))<0) {
  228. _mm_errno=MMERR_OPENING_AUDIO;
  229. return 1;
  230. }
  231. #ifdef SNDCTL_DSP_SETFRAGMENT
  232. if((fragsize==DEFAULT_FRAGSIZE)&&(getenv("MM_FRAGSIZE"))) {
  233. fragsize=atoi(getenv("MM_FRAGSIZE"));
  234. if((fragsize<7)||(fragsize>17)) fragsize=DEFAULT_FRAGSIZE;
  235. }
  236. if((numfrags==DEFAULT_NUMFRAGS)&&(getenv("MM_NUMFRAGS"))) {
  237. numfrags=atoi(getenv("MM_NUMFRAGS"));
  238. if((numfrags<2)||(numfrags>255)) numfrags=DEFAULT_NUMFRAGS;
  239. }
  240. fragmentsize=(numfrags<<16)|fragsize;
  241. if(ioctl(sndfd,SNDCTL_DSP_SETFRAGMENT,&fragmentsize)<0) {
  242. _mm_errno=MMERR_OSS_SETFRAGMENT;
  243. return 1;
  244. }
  245. #endif
  246. return OSS_Init_internal();
  247. }
  248. static void OSS_Exit_internal(void)
  249. {
  250. VC_Exit();
  251. _mm_free(audiobuffer);
  252. }
  253. static void OSS_Exit(void)
  254. {
  255. OSS_Exit_internal();
  256. if (sndfd>=0) {
  257. close(sndfd);
  258. sndfd=-1;
  259. }
  260. }
  261. static void OSS_PlayStop(void)
  262. {
  263. VC_PlayStop();
  264. ioctl(sndfd,SNDCTL_DSP_POST);
  265. }
  266. static void OSS_Update(void)
  267. {
  268. int done;
  269. #if SOUND_VERSION >= 301
  270. audio_buf_info buffinf;
  271. buffinf.fragments = 2;
  272. for(;;) {
  273. /* This call fails on Linux/PPC */
  274. if ((ioctl(sndfd,SNDCTL_DSP_GETOSPACE,&buffinf)<0)) {
  275. buffinf.fragments--;
  276. buffinf.fragsize = buffinf.bytes = buffersize;
  277. }
  278. if(!buffinf.fragments)
  279. break;
  280. done=VC_WriteBytes(audiobuffer,buffinf.fragsize>buffinf.bytes?
  281.    buffinf.bytes:buffinf.fragsize);
  282. #ifdef AFMT_MU_LAW
  283. if (play_precision==AFMT_MU_LAW)
  284. unsignedtoulaw(audiobuffer,done);
  285. #endif
  286. write(sndfd,audiobuffer,done);
  287. }
  288. #else
  289. done=VC_WriteBytes(audiobuffer,buffersize);
  290. #ifdef AFMT_MU_LAW
  291. if (play_precision==AFMT_MU_LAW)
  292. unsignedtoulaw(audiobuffer,done);
  293. #endif
  294. write(sndfd,audiobuffer,done);
  295. #endif
  296. }
  297. static BOOL OSS_Reset(void)
  298. {
  299. OSS_Exit_internal();
  300. ioctl(sndfd,SNDCTL_DSP_RESET);
  301. return OSS_Init_internal();
  302. }
  303. MIKMODAPI MDRIVER drv_oss={
  304. NULL,
  305. "Open Sound System",
  306. "Open Sound System driver v1.7",
  307. 0,255,
  308. "oss",
  309. #ifdef SNDCTL_DSP_SETFRAGMENT
  310.         "buffer:r:7,17,14:Audio buffer log2 sizen"
  311.         "count:r:2,255,16:Audio buffer countn",
  312. #else
  313.         NULL,
  314. #endif
  315. #ifdef SNDCTL_DSP_SETFRAGMENT
  316. OSS_CommandLine,
  317. #else
  318. NULL,
  319. #endif
  320. OSS_IsThere,
  321. VC_SampleLoad,
  322. VC_SampleUnload,
  323. VC_SampleSpace,
  324. VC_SampleLength,
  325. OSS_Init,
  326. OSS_Exit,
  327. OSS_Reset,
  328. VC_SetNumVoices,
  329. VC_PlayStart,
  330. OSS_PlayStop,
  331. OSS_Update,
  332. NULL,
  333. VC_VoiceSetVolume,
  334. VC_VoiceGetVolume,
  335. VC_VoiceSetFrequency,
  336. VC_VoiceGetFrequency,
  337. VC_VoiceSetPanning,
  338. VC_VoiceGetPanning,
  339. VC_VoicePlay,
  340. VC_VoiceStop,
  341. VC_VoiceStopped,
  342. VC_VoiceGetPosition,
  343. VC_VoiceRealVolume
  344. };
  345. #else
  346. MISSING(drv_oss);
  347. #endif
  348. /* ex:set ts=4: */