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

Windows CE

开发平台:

C/C++

  1. /* MikMod sound library
  2. (c) 1998, 1999, 2000, 2001, 2002 Miodrag Vallat and others - see file
  3. AUTHORS for 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_sun.c,v 1.3 2004/02/10 14:02:24 raph Exp $
  21.   Driver for output on the Sun audio device (/dev/audio).
  22.   Also works under NetBSD and OpenBSD
  23. ==============================================================================*/
  24. /*
  25. Written by Valtteri Vuorikoski <vuori@sci.fi>
  26. NetBSD/OpenBSD code from Miodrag Vallat <miod@mikmod.org>
  27. */
  28. #ifdef HAVE_CONFIG_H
  29. #include "config.h"
  30. #endif
  31. #include "mikmod_internals.h"
  32. #ifdef DRV_SUN
  33. #ifdef HAVE_UNISTD_H
  34. #include <unistd.h>
  35. #endif
  36. #ifdef HAVE_FCNTL_H
  37. #include <fcntl.h>
  38. #endif
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #ifdef HAVE_SYS_IOCTL_H
  43. #include <sys/ioctl.h>
  44. #endif
  45. #include <sys/types.h>
  46. #ifdef HAVE_SUN_AUDIOIO_H
  47. #include <sun/audioio.h>
  48. #endif
  49. #ifdef HAVE_SYS_AUDIOIO_H
  50. #include <sys/audioio.h>
  51. #endif
  52. #ifdef SUNOS
  53. extern int ioctl(int, unsigned long, ...);
  54. extern int fputs(const char *, FILE *);
  55. #endif
  56. #define DEFAULT_FRAGSIZE 12
  57. #if !defined __NetBSD__  && !defined __OpenBSD__
  58. #ifdef HAVE_SUN_AUDIOIO_H
  59. #define SUNOS4
  60. #else
  61. #define SOLARIS
  62. #endif
  63. #endif
  64. /* Sound device to open */
  65. #ifdef SUNOS4
  66. #define SOUNDDEVICE "/dev/sound"
  67. #else /* Solaris, *BSD */
  68. #define SOUNDDEVICE "/dev/audio"
  69. #endif
  70. /* Solaris doesn't have these */
  71. #ifdef SOLARIS
  72. #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_LINEAR
  73. #define AUDIO_ENCODING_ULINEAR AUDIO_ENCODING_LINEAR8
  74. #endif
  75. /* Compatibility defines, for old *BSD or SunOS systems */
  76. #ifndef AUDIO_ENCODING_PCM16
  77. #define AUDIO_ENCODING_PCM16 AUDIO_ENCODING_LINEAR
  78. #endif
  79. #ifndef AUDIO_ENCODING_PCM8
  80. #define AUDIO_ENCODING_PCM8 AUDIO_ENCODING_LINEAR8
  81. #endif
  82. #ifndef AUDIO_ENCODING_SLINEAR_LE
  83. #define AUDIO_ENCODING_SLINEAR_LE AUDIO_ENCODING_PCM16
  84. #endif
  85. #ifndef AUDIO_ENCODING_ULINEAR_LE
  86. #define AUDIO_ENCODING_ULINEAR_LE AUDIO_ENCODING_PCM8
  87. #endif
  88. #ifndef AUDIO_ENCODING_SLINEAR
  89. #if BYTE_ORDER == BIG_ENDIAN
  90. #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_SLINEAR_BE
  91. #else
  92. #define AUDIO_ENCODING_SLINEAR AUDIO_ENCODING_SLINEAR_LE
  93. #endif
  94. #endif
  95. #ifndef AUDIO_ENCODING_ULINEAR
  96. #if BYTE_ORDER == BIG_ENDIAN
  97. #define AUDIO_ENCODING_ULINEAR AUDIO_ENCODING_ULINEAR_BE
  98. #else
  99. #define AUDIO_ENCODING_ULINEAR AUDIO_ENCODING_ULINEAR_LE
  100. #endif
  101. #endif
  102. /* Compatibility defines, for old *BSD systems */
  103. #ifndef AUDIO_SPEAKER
  104. #define AUDIO_SPEAKER 0x01
  105. #endif
  106. #ifndef AUDIO_HEADPHONE
  107. #define AUDIO_HEADPHONE 0x02
  108. #endif
  109. /* ``normalize'' AUDIO_ENCODING_xxx values for comparison */
  110. static int normalize(int encoding)
  111. {
  112. switch (encoding) {
  113. #ifdef AUDIO_ENCODING_LINEAR
  114. case AUDIO_ENCODING_LINEAR:
  115. return AUDIO_ENCODING_PCM16;
  116. #endif
  117. #ifdef AUDIO_ENCODING_LINEAR8
  118. case AUDIO_ENCODING_LINEAR8:
  119. return AUDIO_ENCODING_PCM8;
  120. #endif
  121. #if BYTE_ORDER == BIG_ENDIAN
  122. #ifdef AUDIO_ENCODING_SLINEAR_BE
  123. case AUDIO_ENCODING_SLINEAR:
  124. return AUDIO_ENCODING_SLINEAR_BE;
  125. #endif
  126. #ifdef AUDIO_ENCODING_ULINEAR_BE
  127. case AUDIO_ENCODING_ULINEAR:
  128. return AUDIO_ENCODING_ULINEAR_BE;
  129. #endif
  130. #else
  131. #ifdef AUDIO_ENCODING_SLINEAR_LE
  132. case AUDIO_ENCODING_SLINEAR:
  133. return AUDIO_ENCODING_SLINEAR_LE;
  134. #endif
  135. #ifdef AUDIO_ENCODING_ULINEAR_LE
  136. case AUDIO_ENCODING_ULINEAR:
  137. return AUDIO_ENCODING_ULINEAR_LE;
  138. #endif
  139. #endif
  140. default:
  141. return encoding;
  142. }
  143. }
  144. static int sndfd = -1;
  145. static unsigned int port = 0;
  146. static int play_encoding;
  147. static int play_precision;
  148. static int fragsize = 1 << DEFAULT_FRAGSIZE;
  149. static SBYTE *audiobuffer = NULL;
  150. static void Sun_CommandLine(CHAR *cmdline)
  151. {
  152. CHAR *ptr;
  153. if ((ptr = MD_GetAtom("buffer", cmdline, 0))) {
  154. int buf = atoi(ptr);
  155. if (buf >= 7 && buf <= 17)
  156. fragsize = 1 << buf;
  157. free(ptr);
  158. }
  159. if ((ptr = MD_GetAtom("headphone", cmdline, 1))) {
  160. port = AUDIO_HEADPHONE;
  161. free(ptr);
  162. } else if ((ptr = MD_GetAtom("speaker", cmdline, 1))) {
  163. port = AUDIO_SPEAKER;
  164. free(ptr);
  165. }
  166. }
  167. static BOOL Sun_IsThere(void)
  168. {
  169. if (getenv("AUDIODEV"))
  170. return (access(getenv("AUDIODEV"), W_OK) == 0);
  171. else {
  172. if (access(SOUNDDEVICE, W_OK) == 0)
  173. return 1;
  174. #if defined __NetBSD__ || defined __OpenBSD__
  175. /* old OpenBSD/sparc installation program creates /dev/audio0 but no
  176.    /dev/audio. Didn't check NetBSD behaviour */
  177. if (access(SOUNDDEVICE "0", W_OK) == 0)
  178. return 1;
  179. #endif
  180. }
  181. return 0;
  182. }
  183. static BOOL Sun_Init(void)
  184. {
  185. int play_stereo, play_rate;
  186. #ifdef SUNOS4
  187. int audiotype;
  188. #else
  189. audio_device_t audiotype;
  190. #endif
  191. struct audio_info audioinfo;
  192. if (getenv("AUDIODEV"))
  193. sndfd = open(getenv("AUDIODEV"), O_WRONLY);
  194. else {
  195. sndfd = open(SOUNDDEVICE, O_WRONLY);
  196. #if defined __NetBSD__ || defined __OpenBSD__
  197. if (sndfd < 0)
  198. sndfd = open(SOUNDDEVICE "0", O_WRONLY);
  199. #endif
  200. }
  201. if (sndfd < 0) {
  202. _mm_errno = MMERR_OPENING_AUDIO;
  203. return 1;
  204. }
  205. if (!(audiobuffer = (SBYTE *)_mm_malloc(fragsize)))
  206. return 1;
  207. play_precision = (md_mode & DMODE_16BITS) ? 16 : 8;
  208. play_stereo = (md_mode & DMODE_STEREO) ? 2 : 1;
  209. play_rate = md_mixfreq;
  210. /* attempt to guess the encoding */
  211. play_encoding = -1;
  212. if (ioctl(sndfd, AUDIO_GETDEV, &audiotype) < 0) {
  213. #ifdef MIKMOD_DEBUG
  214. fputs("rSun driver warning: could not determine audio device typen",
  215.   stderr);
  216. #endif
  217. } else {
  218. #if defined SUNOS4 /* SunOS 4 */
  219. switch (audiotype) {
  220.   case AUDIO_DEV_AMD:
  221. /* AMD 79C30 */
  222. /* 8bit mono ulaw 8kHz */
  223.    play_rate = md_mixfreq = 8000;
  224. md_mode &= ~(DMODE_STEREO | DMODE_16BITS);
  225. play_precision = 8;
  226. play_stereo = 1;
  227. play_encoding = AUDIO_ENCODING_ULAW;
  228. break;
  229.   case AUDIO_DEV_SPEAKERBOX:
  230.   case AUDIO_DEV_CODEC:
  231. /* CS 4231 or DBRI or speaker box */
  232. /* 16bit mono/stereo linear 8kHz - 48kHz */
  233. if (play_precision == 16)
  234. play_encoding = AUDIO_ENCODING_LINEAR;
  235. /* 8bit mono ulaw 8kHz - 48kHz */
  236. else if (play_precision == 8) {
  237. md_mode &= ~(DMODE_STEREO);
  238. play_stereo = 1;
  239. play_encoding = AUDIO_ENCODING_ULAW;
  240. } else {
  241. _mm_errno = MMERR_SUN_INIT;
  242. return 1;
  243. }
  244. break;
  245. }
  246. #elif defined SOLARIS /* Solaris */
  247. if (!strcmp(audiotype.name, "SUNW,am79c30")) {
  248. /* AMD 79C30 */
  249. /* 8bit mono ulaw 8kHz */
  250.    play_rate = md_mixfreq = 8000;
  251. md_mode &= ~(DMODE_STEREO | DMODE_16BITS);
  252. play_precision = 8;
  253. play_stereo = 1;
  254. play_encoding = AUDIO_ENCODING_ULAW;
  255. } else
  256. if ((!strcmp(audiotype.name, "SUNW,CS4231")) ||
  257. (!strcmp(audiotype.name, "SUNW,dbri")) ||
  258. (!strcmp(audiotype.name, "speakerbox"))) {
  259. /* CS 4231 or DBRI or speaker box */
  260. /* 16bit mono/stereo linear 8kHz - 48kHz */
  261. if (play_precision == 16)
  262. play_encoding = AUDIO_ENCODING_LINEAR;
  263. /* 8bit mono ulaw 8kHz - 48kHz */
  264. else if (play_precision == 8) {
  265. md_mode &= ~(DMODE_STEREO);
  266. play_stereo = 1;
  267. play_encoding = AUDIO_ENCODING_ULAW;
  268. } else {
  269. _mm_errno = MMERR_SUN_INIT;
  270. return 1;
  271. }
  272. }
  273. #else /* NetBSD, OpenBSD */
  274. if (!strcmp(audiotype.name, "amd7930")) {
  275. /* AMD 79C30 */
  276. /* 8bit mono ulaw 8kHz */
  277.    play_rate = md_mixfreq = 8000;
  278. md_mode &= ~(DMODE_STEREO | DMODE_16BITS);
  279. play_precision = 8;
  280. play_stereo = 1;
  281. play_encoding = AUDIO_ENCODING_ULAW;
  282. }
  283. if ((!strcmp(audiotype.name, "Am78C201")) ||
  284. (!strcmp(audiotype.name, "UltraSound")) 
  285.    ) {
  286. /* Gravis UltraSound, AMD Interwave and compatible cards */
  287. /* 16bit stereo linear 44kHz */
  288.    play_rate = md_mixfreq = 44100;
  289. md_mode |= (DMODE_STEREO | DMODE_16BITS);
  290. play_precision = 16;
  291. play_stereo = 2;
  292. play_encoding = AUDIO_ENCODING_SLINEAR;
  293. }
  294. #endif
  295. }
  296. /* Sound devices which were not handled above don't have specific
  297.    limitations, so try and guess optimal settings */
  298. if (play_encoding == -1) {
  299. if ((play_precision == 8) && (play_stereo == 1) &&
  300. (play_rate <= 8000)) play_encoding = AUDIO_ENCODING_ULAW;
  301. else
  302. #ifdef SUNOS4
  303. play_encoding = AUDIO_ENCODING_LINEAR;
  304. #else
  305. play_encoding =
  306. (play_precision ==
  307.  16) ? AUDIO_ENCODING_SLINEAR : AUDIO_ENCODING_ULINEAR;
  308. #endif
  309. }
  310. /* get current audio settings if we want to keep the playback output
  311.    port */
  312. if (!port) {
  313. AUDIO_INITINFO(&audioinfo);
  314. if (ioctl(sndfd, AUDIO_GETINFO, &audioinfo) < 0) {
  315. _mm_errno = MMERR_SUN_INIT;
  316. return 1;
  317. }
  318. port = audioinfo.play.port;
  319. }
  320. AUDIO_INITINFO(&audioinfo);
  321. audioinfo.play.precision = play_precision;
  322. audioinfo.play.channels = play_stereo;
  323. audioinfo.play.sample_rate = play_rate;
  324. audioinfo.play.encoding = play_encoding;
  325. audioinfo.play.port = port;
  326. #if defined __NetBSD__ || defined __OpenBSD__
  327. #if defined AUMODE_PLAY_ALL
  328. audioinfo.mode = AUMODE_PLAY | AUMODE_PLAY_ALL;
  329. #else
  330. audioinfo.mode = AUMODE_PLAY;
  331. #endif
  332. #endif
  333. if (ioctl(sndfd, AUDIO_SETINFO, &audioinfo) < 0) {
  334. _mm_errno = MMERR_SUN_INIT;
  335. return 1;
  336. }
  337. /* check if our changes were accepted */
  338. if (ioctl(sndfd, AUDIO_GETINFO, &audioinfo) < 0) {
  339. _mm_errno = MMERR_SUN_INIT;
  340. return 1;
  341. }
  342. if ((audioinfo.play.precision != play_precision) ||
  343. (audioinfo.play.channels != play_stereo) ||
  344. (normalize(audioinfo.play.encoding) != normalize(play_encoding))) {
  345. _mm_errno = MMERR_SUN_INIT;
  346. return 1;
  347. }
  348. if (audioinfo.play.sample_rate != play_rate) {
  349. /* Accept a shift inferior to 5% of the expected rate */
  350. int delta = audioinfo.play.sample_rate - play_rate;
  351. if (delta < 0)
  352. delta = -delta;
  353. if (delta * 20 > play_rate) {
  354. _mm_errno = MMERR_SUN_INIT;
  355. return 1;
  356. }
  357. /* Align to what the card gave us */
  358. md_mixfreq = audioinfo.play.sample_rate;
  359. }
  360. return VC_Init();
  361. }
  362. static void Sun_Exit(void)
  363. {
  364. VC_Exit();
  365. _mm_free(audiobuffer);
  366. if (sndfd >= 0) {
  367. close(sndfd);
  368. sndfd = -1;
  369. }
  370. }
  371. static void Sun_Update(void)
  372. {
  373. int done;
  374. done = VC_WriteBytes((char *)audiobuffer, fragsize);
  375. if (play_encoding == AUDIO_ENCODING_ULAW)
  376. unsignedtoulaw(audiobuffer, done);
  377. write(sndfd, audiobuffer, done);
  378. }
  379. static void Sun_Pause(void)
  380. {
  381. int done;
  382. done = VC_SilenceBytes((char *)audiobuffer, fragsize);
  383. write(sndfd, audiobuffer, done);
  384. }
  385. static BOOL Sun_PlayStart(void)
  386. {
  387. struct audio_info audioinfo;
  388. AUDIO_INITINFO(&audioinfo);
  389. audioinfo.play.pause = 0;
  390. if (ioctl(sndfd, AUDIO_SETINFO, &audioinfo) < 0)
  391. return 1;
  392. return VC_PlayStart();
  393. }
  394. static void Sun_PlayStop(void)
  395. {
  396. struct audio_info audioinfo;
  397. VC_PlayStop();
  398. if (ioctl(sndfd, AUDIO_DRAIN) < 0)
  399. return;
  400. AUDIO_INITINFO(&audioinfo);
  401. audioinfo.play.pause = 1;
  402. ioctl(sndfd, AUDIO_SETINFO, &audioinfo);
  403. }
  404. MIKMODAPI MDRIVER drv_sun = {
  405. NULL,
  406. #if defined __OpenBSD__
  407. "OpenBSD Audio",
  408. "OpenBSD audio driver v1.0",
  409. #elif defined __NetBSD__
  410. "NetBSD Audio",
  411. "NetBSD audio driver v1.0",
  412. #elif defined SUNOS4
  413. "SunOS Audio",
  414. "SunOS audio driver v1.4",
  415. #elif defined SOLARIS
  416. "Solaris Audio",
  417. "Solaris audio driver v1.4",
  418. #endif
  419. 0, 255,
  420. "audio",
  421.         "buffer:r:7,17,12:Audio buffer log2 sizen"
  422. #if defined(SUNOS) || defined(SOLARIS)
  423.         "headphone:b:0:Use headphonen"
  424.         "speaker:b:0:Use speakern"
  425. #endif
  426. ,
  427. Sun_CommandLine,
  428. Sun_IsThere,
  429. VC_SampleLoad,
  430. VC_SampleUnload,
  431. VC_SampleSpace,
  432. VC_SampleLength,
  433. Sun_Init,
  434. Sun_Exit,
  435. NULL,
  436. VC_SetNumVoices,
  437. Sun_PlayStart,
  438. Sun_PlayStop,
  439. Sun_Update,
  440. Sun_Pause,
  441. VC_VoiceSetVolume,
  442. VC_VoiceGetVolume,
  443. VC_VoiceSetFrequency,
  444. VC_VoiceGetFrequency,
  445. VC_VoiceSetPanning,
  446. VC_VoiceGetPanning,
  447. VC_VoicePlay,
  448. VC_VoiceStop,
  449. VC_VoiceStopped,
  450. VC_VoiceGetPosition,
  451. VC_VoiceRealVolume
  452. };
  453. #else
  454. MISSING(drv_sun);
  455. #endif
  456. /* ex:set ts=4: */