1 /* Extended Module Player 2 * Copyright (C) 1996-2016 Claudio Matsuoka and Hipolito Carraro Jr 3 * 4 * This file is part of the Extended Module Player and is distributed 5 * under the terms of the GNU General Public License. See the COPYING 6 * file for more information. 7 */ 8 9 /* Based on bsd.c and solaris.c */ 10 11 #include <sys/types.h> 12 #include <sys/param.h> 13 #include <sys/audioio.h> 14 #include <sys/mman.h> 15 #include <sys/ioctl.h> 16 #include <sys/stat.h> 17 #include <fcntl.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include "sound.h" 22 23 static int audio_fd; 24 static int audioctl_fd; 25 26 27 static int init(struct options *options) 28 { 29 char **parm = options->driver_parm; 30 audio_info_t ainfo; 31 int gain = 128; 32 int bsize = 32 * 1024; 33 34 parm_init(parm); 35 chkparm1("gain", gain = strtoul(token, NULL, 0)); 36 chkparm1("buffer", bsize = strtoul(token, NULL, 0)); 37 parm_end(); 38 39 if ((audio_fd = open("/dev/sound", O_WRONLY)) == -1) 40 return -1; 41 42 /* try to open audioctldevice */ 43 if ((audioctl_fd = open("/dev/audioctl", O_RDWR)) < 0) { 44 fprintf(stderr, "couldn't open audioctldevice\n"); 45 close(audio_fd); 46 return -1; 47 } 48 49 /* empty buffers before change config */ 50 ioctl(audio_fd, AUDIO_DRAIN, 0); /* drain everything out */ 51 ioctl(audio_fd, AUDIO_FLUSH); /* flush audio */ 52 ioctl(audioctl_fd, AUDIO_FLUSH); /* flush audioctl */ 53 OS2_Dart_UpdateBuffers(ULONG ulStatus,PMCI_MIX_BUFFER pBuffer,ULONG ulFlags)54 /* get audio parameters. */ 55 if (ioctl(audioctl_fd, AUDIO_GETINFO, &ainfo) < 0) { 56 fprintf(stderr, "AUDIO_GETINFO failed!\n"); 57 close(audio_fd); 58 close(audioctl_fd); 59 return -1; 60 } 61 62 close(audioctl_fd); 63 64 if (gain < AUDIO_MIN_GAIN) 65 gain = AUDIO_MIN_GAIN; 66 if (gain > AUDIO_MAX_GAIN) 67 gain = AUDIO_MAX_GAIN; 68 init(struct options * options)69 AUDIO_INITINFO(&ainfo); 70 71 ainfo.mode = AUMODE_PLAY_ALL; 72 ainfo.play.sample_rate = options->rate; 73 ainfo.play.channels = options->format & XMP_FORMAT_MONO ? 1 : 2; 74 75 if (options->format & XMP_FORMAT_8BIT) { 76 ainfo.play.precision = 8; 77 ainfo.play.encoding = AUDIO_ENCODING_ULINEAR; 78 options->format |= XMP_FORMAT_UNSIGNED; 79 } else { 80 ainfo.play.precision = 16; 81 ainfo.play.encoding = AUDIO_ENCODING_SLINEAR; 82 options->format &= ~XMP_FORMAT_UNSIGNED; 83 } 84 85 ainfo.play.gain = gain; 86 ainfo.play.buffer_size = bsize; 87 ainfo.blocksize = 0; 88 89 if (ioctl(audio_fd, AUDIO_SETINFO, &ainfo) == -1) { 90 close(audio_fd); 91 return -1; 92 } 93 94 return 0; 95 } 96 97 static void play(void *b, int i) 98 { 99 int j; 100 101 while (i) { 102 if ((j = write(audio_fd, b, i)) > 0) { 103 i -= j; 104 (char *)b += j; 105 } else 106 break; 107 } 108 } 109 110 static void deinit(void) 111 { 112 close(audio_fd); 113 } 114 115 static void flush(void) 116 { 117 } 118 119 static void onpause(void) 120 { 121 } 122 123 static void onresume(void) 124 { 125 } 126 127 static const char *const help[] = { 128 "gain=val", "Audio output gain (0 to 255)", 129 "buffer=val", "Audio buffer size (default is 32768)", 130 NULL 131 }; 132 133 struct sound_driver sound_netbsd = { 134 "netbsd", 135 "NetBSD PCM audio", 136 help, 137 init, 138 deinit, 139 play, 140 flush, 141 onpause, 142 onresume 143 }; 144