1 /* 2 * Sun 3 */ 4 #include <sys/ioctl.h> 5 #include <sys/audio.h> 6 #include "u.h" 7 #include "lib.h" 8 #include "dat.h" 9 #include "fns.h" 10 #include "error.h" 11 #include "devaudio.h" 12 13 enum 14 { 15 Channels = 2, 16 Rate = 44100, 17 Bits = 16, 18 }; 19 20 static char* afn = 0; 21 static char* cfn = 0; 22 static int afd = -1; 23 static int cfd = -1; 24 static int speed = Rate; 25 static int needswap = -1; 26 27 static void 28 audiodevinit(void) 29 { 30 uchar *p; 31 ushort leorder; 32 33 if ((afn = getenv("AUDIODEV")) == nil) 34 afn = "/dev/audio"; 35 cfn = (char*)malloc(strlen(afn) + 3 + 1); 36 if(cfn == nil) 37 panic("out of memory"); 38 strcpy(cfn, afn); 39 strcat(cfn, "ctl"); 40 41 /* 42 * Plan 9 /dev/audio is always little endian; 43 * solaris /dev/audio seems to expect native byte order, 44 * so on big endian machine (like sparc) we have to swap. 45 */ 46 leorder = (ushort) 0x0100; 47 p = (uchar*)&leorder; 48 if (p[0] == 0 && p[1] == 1) { 49 /* little-endian: nothing to do */ 50 needswap = 0; 51 } else { 52 /* big-endian: translate Plan 9 little-endian */ 53 needswap = 1; 54 } 55 } 56 57 /* maybe this should return -1 instead of sysfatal */ 58 void 59 audiodevopen(void) 60 { 61 audio_info_t info; 62 struct audio_device ad; 63 64 if (afn == nil || cfn == nil) 65 audiodevinit(); 66 if((afd = open(afn, O_WRONLY)) < 0) 67 goto err; 68 if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) 69 goto err; 70 71 AUDIO_INITINFO(&info); 72 info.play.precision = Bits; 73 info.play.channels = Channels; 74 info.play.sample_rate = speed; 75 info.play.encoding = AUDIO_ENCODING_LINEAR; 76 if(ioctl(afd, AUDIO_SETINFO, &info) < 0) 77 goto err; 78 79 return; 80 81 err: 82 if(afd >= 0) 83 close(afd); 84 afd = -1; 85 if(cfd >= 0) 86 close(cfd); 87 cfd = -1; 88 oserror(); 89 } 90 91 void 92 audiodevclose(void) 93 { 94 if(afd >= 0) 95 close(afd); 96 if(cfd >= 0) 97 close(cfd); 98 afd = -1; 99 cfd = -1; 100 } 101 102 static double 103 fromsun(double val, double min, double max) 104 { 105 return (val-min) / (max-min); 106 } 107 108 static double 109 tosun(double val, double min, double max) 110 { 111 return val*(max-min) + min; 112 } 113 114 static void 115 setvolbal(double left, double right) 116 { 117 audio_info_t info; 118 double vol, bal; 119 120 if (left < 0 || right < 0) { 121 /* should not happen */ 122 return; 123 } else if (left == right) { 124 vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); 125 bal = AUDIO_MID_BALANCE; 126 } else if (left < right) { 127 vol = tosun(right/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); 128 bal = tosun(1.0 - left/right, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE); 129 } else if (right < left) { 130 vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN); 131 bal = tosun(1.0 - right/left, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE); 132 } 133 AUDIO_INITINFO(&info); 134 info.play.gain = (long)(vol+0.5); 135 info.play.balance = (long)(bal+0.5); 136 if(ioctl(cfd, AUDIO_SETINFO, &info) < 0) 137 oserror(); 138 } 139 140 static void 141 getvolbal(int *left, int *right) 142 { 143 audio_info_t info; 144 double gain, bal, vol, l, r; 145 146 AUDIO_INITINFO(&info); 147 if (ioctl(cfd, AUDIO_GETINFO, &info) < 0) 148 oserror(); 149 150 gain = info.play.gain; 151 bal = info.play.balance; 152 vol = fromsun(gain, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN) * 100.0; 153 154 if (bal == AUDIO_MID_BALANCE) { 155 l = r = vol; 156 } else if (bal < AUDIO_MID_BALANCE) { 157 l = vol; 158 r = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE)); 159 } else { 160 r = vol; 161 l = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE)); 162 } 163 *left = (long)(l+0.5); 164 *right = (long)(r+0.5); 165 return; 166 } 167 168 void 169 audiodevsetvol(int what, int left, int right) 170 { 171 audio_info_t info; 172 ulong x; 173 int l, r; 174 175 if (afn == nil || cfn == nil) 176 audiodevinit(); 177 if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) { 178 cfd = -1; 179 oserror(); 180 } 181 182 if(what == Vspeed){ 183 x = left; 184 AUDIO_INITINFO(&info); 185 info.play.sample_rate = x; 186 if(ioctl(cfd, AUDIO_SETINFO, &info) < 0) 187 oserror(); 188 speed = x; 189 return; 190 } 191 if(what == Vaudio){ 192 getvolbal(&l, &r); 193 if (left < 0) 194 setvolbal(l, right); 195 else if (right < 0) 196 setvolbal(left, r); 197 else 198 setvolbal(left, right); 199 return; 200 } 201 } 202 203 void 204 audiodevgetvol(int what, int *left, int *right) 205 { 206 audio_info_t info; 207 208 if (afn == nil || cfn == nil) 209 audiodevinit(); 210 if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) { 211 cfd = -1; 212 oserror(); 213 } 214 switch(what) { 215 case Vspeed: 216 *left = *right = speed; 217 break; 218 case Vaudio: 219 getvolbal(left, right); 220 break; 221 case Vtreb: 222 case Vbass: 223 *left = *right = 50; 224 break; 225 default: 226 *left = *right = 0; 227 } 228 } 229 230 231 static uchar *buf = 0; 232 static int nbuf = 0; 233 234 int 235 audiodevwrite(void *v, int n) 236 { 237 int i, m, tot; 238 uchar *p; 239 240 if (needswap) { 241 if (nbuf < n) { 242 buf = (uchar*)erealloc(buf, n); 243 if(buf == nil) 244 panic("out of memory"); 245 nbuf = n; 246 } 247 248 p = (uchar*)v; 249 for(i=0; i+1<n; i+=2) { 250 buf[i] = p[i+1]; 251 buf[i+1] = p[i]; 252 } 253 p = buf; 254 } else 255 p = (uchar*)v; 256 257 for(tot=0; tot<n; tot+=m) 258 if((m = write(afd, p+tot, n-tot)) <= 0) 259 oserror(); 260 return tot; 261 } 262 263 int 264 audiodevread(void *v, int n) 265 { 266 error("no reading"); 267 return -1; 268 } 269