1 /* libSoX direct to Sun Audio Driver
3 * Added by Chris Bagwell (cbagwell@sprynet.com) on 2/26/96
4 * Based on oss handler.
6 * Cleaned up changes of format somewhat in sunstartwrite on 03/31/98
11 * Copyright 1997 Chris Bagwell And Sundry Contributors
12 * This source code is freely redistributable and may be used for
13 * any purpose. This copyright notice must be maintained.
14 * Rick Richardson, Lance Norskog And Sundry Contributors are not
15 * responsible for the consequences of using this software.
21 #include <sys/ioctl.h>
22 #include <sys/types.h>
23 #ifdef HAVE_SUN_AUDIOIO_H
24 #include <sun/audioio.h>
26 #include <sys/audioio.h>
29 #if !defined(__NetBSD__) && !defined(__OpenBSD__)
44 unsigned sample_shift
;
48 * Do anything required before you start reading samples.
50 * Find out sampling rate,
51 * size and encoding of samples,
54 static int sunstartread(sox_format_t
* ft
)
56 char const* szDevname
;
57 priv_t
* pPriv
= (priv_t
*)ft
->priv
;
59 size_t samplesize
, encoding
;
60 audio_info_t audio_if
;
62 audio_device_t audio_dev
;
66 lsx_set_signal_defaults(ft
);
68 if (ft
->filename
== 0 || ft
->filename
[0] == 0 || !strcasecmp("default", ft
->filename
)) {
69 szDevname
= "/dev/audio";
71 szDevname
= ft
->filename
;
74 pPriv
->device
= open(szDevname
, O_RDONLY
);
75 if (pPriv
->device
< 0) {
76 lsx_fail_errno(ft
, errno
, "open failed for device %s", szDevname
);
80 if (ft
->encoding
.encoding
== SOX_ENCODING_UNKNOWN
) ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
83 /* Read in old values, change to what we need and then send back */
84 if (ioctl(pPriv
->device
, AUDIO_GETDEV
, &audio_dev
) < 0) {
85 lsx_fail_errno(ft
,errno
,"Unable to get information for device %s", szDevname
);
88 lsx_report("Hardware detected: %s",audio_dev
.name
);
89 if (strcmp("SUNW,am79c30",audio_dev
.name
) == 0)
95 /* If simple hardware detected in force data to ulaw. */
98 if (ft
->encoding
.bits_per_sample
== 8)
100 if (ft
->encoding
.encoding
!= SOX_ENCODING_ULAW
&&
101 ft
->encoding
.encoding
!= SOX_ENCODING_ALAW
)
103 lsx_report("Warning: Detected simple hardware. Forcing output to ULAW");
104 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
107 else if (ft
->encoding
.bits_per_sample
== 16)
109 lsx_report("Warning: Detected simple hardware. Forcing output to ULAW");
110 ft
->encoding
.bits_per_sample
= 8;
111 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
115 if (ft
->encoding
.bits_per_sample
== 8) {
117 pPriv
->sample_shift
= 0;
118 if (ft
->encoding
.encoding
!= SOX_ENCODING_ULAW
&&
119 ft
->encoding
.encoding
!= SOX_ENCODING_ALAW
&&
120 ft
->encoding
.encoding
!= SOX_ENCODING_SIGN2
) {
121 lsx_fail_errno(ft
,SOX_EFMT
,"Sun audio driver only supports ULAW, ALAW, and signed linear for bytes.");
124 if ((ft
->encoding
.encoding
== SOX_ENCODING_ULAW
||
125 ft
->encoding
.encoding
== SOX_ENCODING_ALAW
) &&
126 ft
->signal
.channels
== 2)
128 lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono.");
129 ft
->signal
.channels
= 1;
132 else if (ft
->encoding
.bits_per_sample
== 16) {
134 pPriv
->sample_shift
= 1;
135 if (ft
->encoding
.encoding
!= SOX_ENCODING_SIGN2
) {
136 lsx_fail_errno(ft
,SOX_EFMT
,"Sun audio driver only supports signed linear for words.");
141 lsx_fail_errno(ft
,SOX_EFMT
,"Sun audio driver only supports bytes and words");
145 if (ft
->signal
.channels
== 0)
146 ft
->signal
.channels
= 1;
147 else if (ft
->signal
.channels
> 1) {
148 lsx_report("Warning: some Sun audio devices can not play stereo");
149 lsx_report("at all or sometimes only with signed words. If the");
150 lsx_report("sound seems sluggish then this is probably the case.");
151 lsx_report("Try forcing output to signed words or use the avg");
152 lsx_report("filter to reduce the number of channels.");
153 ft
->signal
.channels
= 2;
156 /* Read in old values, change to what we need and then send back */
157 if (ioctl(pPriv
->device
, AUDIO_GETINFO
, &audio_if
) < 0) {
158 lsx_fail_errno(ft
,errno
,"Unable to initialize %s", szDevname
);
161 audio_if
.record
.precision
= samplesize
;
162 audio_if
.record
.channels
= ft
->signal
.channels
;
163 audio_if
.record
.sample_rate
= ft
->signal
.rate
;
164 if (ft
->encoding
.encoding
== SOX_ENCODING_ULAW
)
165 encoding
= AUDIO_ENCODING_ULAW
;
166 else if (ft
->encoding
.encoding
== SOX_ENCODING_ALAW
)
167 encoding
= AUDIO_ENCODING_ALAW
;
169 encoding
= AUDIO_ENCODING_LINEAR
;
170 audio_if
.record
.encoding
= encoding
;
172 ioctl(pPriv
->device
, AUDIO_SETINFO
, &audio_if
);
173 if (audio_if
.record
.precision
!= samplesize
) {
174 lsx_fail_errno(ft
,errno
,"Unable to initialize sample size for %s", szDevname
);
177 if (audio_if
.record
.channels
!= ft
->signal
.channels
) {
178 lsx_fail_errno(ft
,errno
,"Unable to initialize number of channels for %s", szDevname
);
181 if (audio_if
.record
.sample_rate
!= ft
->signal
.rate
) {
182 lsx_fail_errno(ft
,errno
,"Unable to initialize rate for %s", szDevname
);
185 if (audio_if
.record
.encoding
!= encoding
) {
186 lsx_fail_errno(ft
,errno
,"Unable to initialize encoding for %s", szDevname
);
189 /* Flush any data in the buffers - its probably in the wrong format */
190 #if defined(__NetBSD__) || defined(__OpenBSD__)
191 ioctl(pPriv
->device
, AUDIO_FLUSH
);
192 #elif defined __GLIBC__
193 ioctl(pPriv
->device
, (unsigned long int)I_FLUSH
, FLUSHR
);
195 ioctl(pPriv
->device
, I_FLUSH
, FLUSHR
);
199 pPriv
->pOutput
= NULL
;
201 return (SOX_SUCCESS
);
204 static int sunstartwrite(sox_format_t
* ft
)
206 size_t samplesize
, encoding
;
207 audio_info_t audio_if
;
209 audio_device_t audio_dev
;
212 char const* szDevname
;
213 priv_t
* pPriv
= (priv_t
*)ft
->priv
;
215 if (ft
->filename
== 0 || ft
->filename
[0] == 0 || !strcasecmp("default", ft
->filename
)) {
216 szDevname
= "/dev/audio";
218 szDevname
= ft
->filename
;
221 pPriv
->device
= open(szDevname
, O_WRONLY
);
222 if (pPriv
->device
< 0) {
223 lsx_fail_errno(ft
, errno
, "open failed for device: %s", szDevname
);
228 /* Read in old values, change to what we need and then send back */
229 if (ioctl(pPriv
->device
, AUDIO_GETDEV
, &audio_dev
) < 0) {
230 lsx_fail_errno(ft
,errno
,"Unable to get device information.");
233 lsx_report("Hardware detected: %s",audio_dev
.name
);
234 if (strcmp("SUNW,am79c30",audio_dev
.name
) == 0)
242 if (ft
->encoding
.bits_per_sample
== 8)
244 if (ft
->encoding
.encoding
!= SOX_ENCODING_ULAW
&&
245 ft
->encoding
.encoding
!= SOX_ENCODING_ALAW
)
247 lsx_report("Warning: Detected simple hardware. Forcing output to ULAW");
248 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
251 else if (ft
->encoding
.bits_per_sample
== 16)
253 lsx_report("Warning: Detected simple hardware. Forcing output to ULAW");
254 ft
->encoding
.bits_per_sample
= 8;
255 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
259 if (ft
->encoding
.bits_per_sample
== 8)
262 pPriv
->sample_shift
= 0;
263 if (ft
->encoding
.encoding
== SOX_ENCODING_UNKNOWN
)
264 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
265 else if (ft
->encoding
.encoding
!= SOX_ENCODING_ULAW
&&
266 ft
->encoding
.encoding
!= SOX_ENCODING_ALAW
&&
267 ft
->encoding
.encoding
!= SOX_ENCODING_SIGN2
) {
268 lsx_report("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes.");
269 lsx_report("Forcing to ULAW");
270 ft
->encoding
.encoding
= SOX_ENCODING_ULAW
;
272 if ((ft
->encoding
.encoding
== SOX_ENCODING_ULAW
||
273 ft
->encoding
.encoding
== SOX_ENCODING_ALAW
) &&
274 ft
->signal
.channels
== 2)
276 lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono.");
277 ft
->signal
.channels
= 1;
281 else if (ft
->encoding
.bits_per_sample
== 16) {
283 pPriv
->sample_shift
= 1;
284 if (ft
->encoding
.encoding
== SOX_ENCODING_UNKNOWN
)
285 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
286 else if (ft
->encoding
.encoding
!= SOX_ENCODING_SIGN2
) {
287 lsx_report("Sun Audio driver only supports Signed Linear for words.");
288 lsx_report("Forcing to Signed Linear");
289 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
293 lsx_report("Sun Audio driver only supports bytes and words");
294 ft
->encoding
.bits_per_sample
= 16;
295 ft
->encoding
.encoding
= SOX_ENCODING_SIGN2
;
297 pPriv
->sample_shift
= 1;
300 if (ft
->signal
.channels
> 1) ft
->signal
.channels
= 2;
302 /* Read in old values, change to what we need and then send back */
303 if (ioctl(pPriv
->device
, AUDIO_GETINFO
, &audio_if
) < 0) {
304 lsx_fail_errno(ft
,errno
,"Unable to initialize /dev/audio");
307 audio_if
.play
.precision
= samplesize
;
308 audio_if
.play
.channels
= ft
->signal
.channels
;
309 audio_if
.play
.sample_rate
= ft
->signal
.rate
;
310 if (ft
->encoding
.encoding
== SOX_ENCODING_ULAW
)
311 encoding
= AUDIO_ENCODING_ULAW
;
312 else if (ft
->encoding
.encoding
== SOX_ENCODING_ALAW
)
313 encoding
= AUDIO_ENCODING_ALAW
;
315 encoding
= AUDIO_ENCODING_LINEAR
;
316 audio_if
.play
.encoding
= encoding
;
318 ioctl(pPriv
->device
, AUDIO_SETINFO
, &audio_if
);
319 if (audio_if
.play
.precision
!= samplesize
) {
320 lsx_fail_errno(ft
,errno
,"Unable to initialize sample size for /dev/audio");
323 if (audio_if
.play
.channels
!= ft
->signal
.channels
) {
324 lsx_fail_errno(ft
,errno
,"Unable to initialize number of channels for /dev/audio");
327 if (audio_if
.play
.sample_rate
!= ft
->signal
.rate
) {
328 lsx_fail_errno(ft
,errno
,"Unable to initialize rate for /dev/audio");
331 if (audio_if
.play
.encoding
!= encoding
) {
332 lsx_fail_errno(ft
,errno
,"Unable to initialize encoding for /dev/audio");
336 pPriv
->cOutput
= sox_globals
.bufsiz
>> pPriv
->sample_shift
;
337 pPriv
->pOutput
= lsx_malloc((size_t)pPriv
->cOutput
<< pPriv
->sample_shift
);
339 return (SOX_SUCCESS
);
342 static int sunstop(sox_format_t
* ft
)
344 priv_t
* pPriv
= (priv_t
*)ft
->priv
;
345 if (pPriv
->device
>= 0) {
346 close(pPriv
->device
);
348 if (pPriv
->pOutput
) {
349 free(pPriv
->pOutput
);
354 typedef sox_uint16_t sox_uint14_t
;
355 typedef sox_uint16_t sox_uint13_t
;
356 typedef sox_int16_t sox_int14_t
;
357 typedef sox_int16_t sox_int13_t
;
358 #define SOX_ULAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips)
359 #define SOX_ALAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips)
360 #define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000)
361 #define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000)
363 static size_t sunread(sox_format_t
* ft
, sox_sample_t
* pOutput
, size_t cOutput
)
365 priv_t
* pPriv
= (priv_t
*)ft
->priv
;
366 char* pbOutput
= (char*)pOutput
;
367 size_t cbOutputLeft
= cOutput
<< pPriv
->sample_shift
;
371 LSX_USE_VAR(sox_macro_temp_double
);
373 while (cbOutputLeft
) {
374 cbRead
= read(pPriv
->device
, pbOutput
, cbOutputLeft
);
377 lsx_fail_errno(ft
, errno
, "Error reading from device");
382 cbOutputLeft
-= cbRead
;
386 /* Convert in-place (backwards) */
387 cRead
= cOutput
- (cbOutputLeft
>> pPriv
->sample_shift
);
388 switch (pPriv
->sample_shift
)
391 switch (ft
->encoding
.encoding
)
393 case SOX_ENCODING_SIGN2
:
394 for (i
= cRead
; i
!= 0; i
--) {
395 pOutput
[i
- 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE(
396 ((sox_uint8_t
*)pOutput
)[i
- 1],
400 case SOX_ENCODING_ULAW
:
401 for (i
= cRead
; i
!= 0; i
--) {
402 pOutput
[i
- 1] = SOX_ULAW_BYTE_TO_SAMPLE(
403 ((sox_uint8_t
*)pOutput
)[i
- 1],
407 case SOX_ENCODING_ALAW
:
408 for (i
= cRead
; i
!= 0; i
--) {
409 pOutput
[i
- 1] = SOX_ALAW_BYTE_TO_SAMPLE(
410 ((sox_uint8_t
*)pOutput
)[i
- 1],
419 for (i
= cRead
; i
!= 0; i
--) {
420 pOutput
[i
- 1] = SOX_SIGNED_16BIT_TO_SAMPLE(
421 ((sox_int16_t
*)pOutput
)[i
- 1],
430 static size_t sunwrite(
432 const sox_sample_t
* pInput
,
435 priv_t
* pPriv
= (priv_t
*)ft
->priv
;
436 size_t cInputRemaining
= cInput
;
440 while (cInputRemaining
) {
446 cStride
= cInputRemaining
;
447 if (cStride
> pPriv
->cOutput
) {
448 cStride
= pPriv
->cOutput
;
451 switch (pPriv
->sample_shift
)
454 switch (ft
->encoding
.encoding
)
456 case SOX_ENCODING_SIGN2
:
457 for (i
= 0; i
!= cStride
; i
++) {
458 ((sox_uint8_t
*)pPriv
->pOutput
)[i
] =
459 SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput
[i
], cClips
);
462 case SOX_ENCODING_ULAW
:
463 for (i
= 0; i
!= cStride
; i
++) {
464 ((sox_uint8_t
*)pPriv
->pOutput
)[i
] =
465 SOX_SAMPLE_TO_ULAW_BYTE(pInput
[i
], cClips
);
468 case SOX_ENCODING_ALAW
:
469 for (i
= 0; i
!= cStride
; i
++) {
470 ((sox_uint8_t
*)pPriv
->pOutput
)[i
] =
471 SOX_SAMPLE_TO_ALAW_BYTE(pInput
[i
], cClips
);
479 for (i
= 0; i
!= cStride
; i
++) {
480 ((sox_int16_t
*)pPriv
->pOutput
)[i
] =
481 SOX_SAMPLE_TO_SIGNED_16BIT(pInput
[i
], cClips
);
486 cbStride
= cStride
<< pPriv
->sample_shift
;
489 cbWritten
= write(pPriv
->device
, &pPriv
->pOutput
[i
], cbStride
- i
);
491 if (cbWritten
<= 0) {
492 lsx_fail_errno(ft
, errno
, "Error writing to device");
495 } while (i
!= cbStride
);
497 cInputRemaining
-= cStride
;
504 LSX_FORMAT_HANDLER(sunau
)
506 static char const * const names
[] = {"sunau", NULL
};
507 static unsigned const write_encodings
[] = {
508 SOX_ENCODING_ULAW
, 8, 0,
509 SOX_ENCODING_ALAW
, 8, 0,
510 SOX_ENCODING_SIGN2
, 8, 16, 0,
512 static sox_format_handler_t
const handler
= {SOX_LIB_VERSION_CODE
,
513 "Sun audio device driver",
514 names
, SOX_FILE_DEVICE
| SOX_FILE_NOSTDIO
,
515 sunstartread
, sunread
, sunstop
,
516 sunstartwrite
, sunwrite
, sunstop
,
517 NULL
, write_encodings
, NULL
, sizeof(priv_t
)