2 * libsndio sound handler
4 * Copyright (c) 2009 Alexandre Ratchov <alex@caoua.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 struct sio_hdl
*hdl
; /* handle to speak to libsndio */
24 struct sio_par par
; /* current device parameters */
25 #define SNDIO_BUFSZ 0x1000
26 unsigned char buf
[SNDIO_BUFSZ
]; /* temp buffer for converions */
30 * convert ``count'' samples from sox encoding to sndio encoding
32 static void encode(struct sio_par
*par
,
33 sox_sample_t
const *idata
, unsigned char *odata
, unsigned count
)
35 int obnext
, osnext
, s
, osigbit
;
36 unsigned oshift
, obps
, i
;
39 osigbit
= par
->sig
? 0 : 1 << (par
->bits
- 1);
40 oshift
= 32 - (par
->msb
? par
->bps
* 8 : par
->bits
);
45 odata
+= par
->bps
- 1;
47 osnext
= 2 * par
->bps
;
49 for (; count
> 0; count
--) {
50 s
= (*idata
++ >> oshift
) ^ osigbit
;
51 for (i
= obps
; i
> 0; i
--) {
52 *odata
= (unsigned char)s
;
61 * convert ``count'' samples from sndio encoding to sox encoding
63 static void decode(struct sio_par
*par
,
64 unsigned char *idata
, sox_sample_t
*odata
, unsigned count
)
66 unsigned ishift
, ibps
, i
;
67 int s
= 0xdeadbeef, ibnext
, isnext
, isigbit
;
70 isigbit
= par
->sig
? 0 : 1 << (par
->bits
- 1);
71 ishift
= 32 - (par
->msb
? par
->bps
* 8 : par
->bits
);
73 idata
+= par
->bps
- 1;
75 isnext
= 2 * par
->bps
;
80 for (; count
> 0; count
--) {
81 for (i
= ibps
; i
> 0; i
--) {
87 *odata
++ = (s
^ isigbit
) << ishift
;
91 static int startany(sox_format_t
*ft
, unsigned mode
)
93 struct sndio_priv
*p
= (struct sndio_priv
*)ft
->priv
;
94 struct sio_par reqpar
;
97 device
= ft
->filename
;
98 if (strcmp("default", device
) == 0)
101 p
->hdl
= sio_open(device
, mode
, 0);
105 * set specified parameters, leaving others to the defaults
107 sio_initpar(&reqpar
);
108 if (ft
->signal
.rate
> 0)
109 reqpar
.rate
= ft
->signal
.rate
;
110 if (ft
->signal
.channels
> 0) {
111 if (mode
== SIO_PLAY
)
112 reqpar
.pchan
= ft
->signal
.channels
;
114 reqpar
.rchan
= ft
->signal
.channels
;
116 switch (ft
->encoding
.encoding
) {
117 case SOX_ENCODING_SIGN2
:
120 case SOX_ENCODING_UNSIGNED
:
124 break; /* use device default */
126 if (ft
->encoding
.bits_per_sample
> 0)
127 reqpar
.bits
= ft
->encoding
.bits_per_sample
;
128 else if (ft
->signal
.precision
> 0)
129 reqpar
.bits
= ft
->signal
.precision
;
131 reqpar
.bits
= SOX_DEFAULT_PRECISION
;
132 reqpar
.bps
= (reqpar
.bits
+ 7) / 8;
134 if (ft
->encoding
.reverse_bytes
!= sox_option_default
) {
135 reqpar
.le
= SIO_LE_NATIVE
;
136 if (ft
->encoding
.reverse_bytes
)
137 reqpar
.le
= !reqpar
.le
;
139 if (!sio_setpar(p
->hdl
, &reqpar
) ||
140 !sio_getpar(p
->hdl
, &p
->par
))
142 ft
->signal
.channels
= (mode
== SIO_PLAY
) ? p
->par
.pchan
: p
->par
.rchan
;
143 ft
->signal
.precision
= p
->par
.bits
;
144 ft
->signal
.rate
= p
->par
.rate
;
145 ft
->encoding
.encoding
= p
->par
.sig
? SOX_ENCODING_SIGN2
: SOX_ENCODING_UNSIGNED
;
146 ft
->encoding
.bits_per_sample
= p
->par
.bps
* 8;
147 ft
->encoding
.reverse_bytes
= SIO_LE_NATIVE
? !p
->par
.le
: p
->par
.le
;
148 ft
->encoding
.reverse_nibbles
= sox_option_no
;
149 ft
->encoding
.reverse_bits
= sox_option_no
;
151 if (!sio_start(p
->hdl
))
159 static int stopany(sox_format_t
*ft
)
161 sio_close(((struct sndio_priv
*)ft
->priv
)->hdl
);
165 static int startread(sox_format_t
*ft
)
167 return startany(ft
, SIO_REC
);
170 static int startwrite(sox_format_t
*ft
)
172 return startany(ft
, SIO_PLAY
);
175 static size_t readsamples(sox_format_t
*ft
, sox_sample_t
*buf
, size_t len
)
177 struct sndio_priv
*p
= (struct sndio_priv
*)ft
->priv
;
178 unsigned char partial
[4];
179 unsigned cpb
, cc
, pc
;
183 todo
= len
* p
->par
.bps
;
184 cpb
= SNDIO_BUFSZ
- (SNDIO_BUFSZ
% p
->par
.bps
);
186 memcpy(p
->buf
, partial
, (size_t)pc
);
190 n
= sio_read(p
->hdl
, p
->buf
+ pc
, (size_t)cc
);
191 if (n
== 0 && sio_eof(p
->hdl
))
196 memcpy(partial
, p
->buf
+ n
, (size_t)pc
);
197 decode(&p
->par
, p
->buf
, buf
, (unsigned)(n
/ p
->par
.bps
));
198 buf
+= n
/ p
->par
.bps
;
201 return len
- todo
/ p
->par
.bps
;
204 static size_t writesamples(sox_format_t
*ft
, const sox_sample_t
*buf
, size_t len
)
206 struct sndio_priv
*p
= (struct sndio_priv
*)ft
->priv
;
211 spb
= SNDIO_BUFSZ
/ p
->par
.bps
;
216 encode(&p
->par
, buf
, p
->buf
, sc
);
217 n
= sio_write(p
->hdl
, p
->buf
, (size_t)(sc
* p
->par
.bps
));
218 if (n
== 0 && sio_eof(p
->hdl
))
227 LSX_FORMAT_HANDLER(sndio
)
229 static char const * const names
[] = {"sndio", NULL
};
230 static unsigned const write_encodings
[] = {
231 SOX_ENCODING_SIGN2
, 32, 24, 16, 8, 0,
232 SOX_ENCODING_UNSIGNED
, 32, 24, 16, 8, 0,
235 static sox_format_handler_t
const handler
= {
236 SOX_LIB_VERSION_CODE
,
237 "libsndio device driver",
239 SOX_FILE_DEVICE
| SOX_FILE_NOSTDIO
,
240 startread
, readsamples
, stopany
,
241 startwrite
, writesamples
, stopany
,
242 NULL
, write_encodings
, NULL
,
243 sizeof(struct sndio_priv
)