mp3: fix error handling in rewrite_tags()
[sox.git] / src / sndio.c
blob77785ce40e95722ef1687bfcc7d024fb62549677
1 /*
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.
18 #include "sox_i.h"
19 #include <string.h>
20 #include <sndio.h>
22 struct sndio_priv {
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;
38 obps = par->bps;
39 osigbit = par->sig ? 0 : 1 << (par->bits - 1);
40 oshift = 32 - (par->msb ? par->bps * 8 : par->bits);
41 if (par->le) {
42 obnext = 1;
43 osnext = 0;
44 } else {
45 odata += par->bps - 1;
46 obnext = -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;
53 s >>= 8;
54 odata += obnext;
56 odata += osnext;
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;
69 ibps = par->bps;
70 isigbit = par->sig ? 0 : 1 << (par->bits - 1);
71 ishift = 32 - (par->msb ? par->bps * 8 : par->bits);
72 if (par->le) {
73 idata += par->bps - 1;
74 ibnext = -1;
75 isnext = 2 * par->bps;
76 } else {
77 ibnext = 1;
78 isnext = 0;
80 for (; count > 0; count--) {
81 for (i = ibps; i > 0; i--) {
82 s <<= 8;
83 s |= *idata;
84 idata += ibnext;
86 idata += isnext;
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;
95 char *device;
97 device = ft->filename;
98 if (strcmp("default", device) == 0)
99 device = NULL;
101 p->hdl = sio_open(device, mode, 0);
102 if (p->hdl == NULL)
103 return SOX_EOF;
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;
113 else
114 reqpar.rchan = ft->signal.channels;
116 switch (ft->encoding.encoding) {
117 case SOX_ENCODING_SIGN2:
118 reqpar.sig = 1;
119 break;
120 case SOX_ENCODING_UNSIGNED:
121 reqpar.sig = 0;
122 break;
123 default:
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;
130 else
131 reqpar.bits = SOX_DEFAULT_PRECISION;
132 reqpar.bps = (reqpar.bits + 7) / 8;
133 reqpar.msb = 1;
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))
141 goto failed;
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))
152 goto failed;
153 return SOX_SUCCESS;
154 failed:
155 sio_close(p->hdl);
156 return SOX_EOF;
159 static int stopany(sox_format_t *ft)
161 sio_close(((struct sndio_priv *)ft->priv)->hdl);
162 return SOX_SUCCESS;
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;
180 size_t todo, n;
182 pc = 0;
183 todo = len * p->par.bps;
184 cpb = SNDIO_BUFSZ - (SNDIO_BUFSZ % p->par.bps);
185 while (todo > 0) {
186 memcpy(p->buf, partial, (size_t)pc);
187 cc = cpb - pc;
188 if (cc > todo)
189 cc = todo;
190 n = sio_read(p->hdl, p->buf + pc, (size_t)cc);
191 if (n == 0 && sio_eof(p->hdl))
192 break;
193 n += pc;
194 pc = n % p->par.bps;
195 n -= pc;
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;
199 todo -= n;
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;
207 unsigned sc, spb;
208 size_t n, todo;
210 todo = len;
211 spb = SNDIO_BUFSZ / p->par.bps;
212 while (todo > 0) {
213 sc = spb;
214 if (sc > todo)
215 sc = todo;
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))
219 break;
220 n /= p->par.bps;
221 todo -= n;
222 buf += n;
224 return len - todo;
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",
238 names,
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)
245 return &handler;