xref: /reactos/sdk/lib/3rdparty/libmpg123/libmpg123.c (revision 34593d93)
1c2c66affSColin Finck /*
2c2c66affSColin Finck 	libmpg123: MPEG Audio Decoder library
3c2c66affSColin Finck 
4*aa811c00SThomas Faber 	copyright 1995-2020 by the mpg123 project - free software under the terms of the LGPL 2.1
5c2c66affSColin Finck 	see COPYING and AUTHORS files in distribution or http://mpg123.org
6c2c66affSColin Finck 
7c2c66affSColin Finck */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include "mpg123lib_intern.h"
10c2c66affSColin Finck #include "icy2utf8.h"
11c2c66affSColin Finck #include "debug.h"
12c2c66affSColin Finck 
13c2c66affSColin Finck #include "gapless.h"
14c2c66affSColin Finck /* Want accurate rounding function regardless of decoder setup. */
15c2c66affSColin Finck #define FORCE_ACCURATE
16c2c66affSColin Finck #include "sample.h"
17*aa811c00SThomas Faber #include "parse.h"
18c2c66affSColin Finck 
19c2c66affSColin Finck #define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe)
20c2c66affSColin Finck 
21c2c66affSColin Finck static int initialized = 0;
22c2c66affSColin Finck 
mpg123_init(void)23c2c66affSColin Finck int attribute_align_arg mpg123_init(void)
24c2c66affSColin Finck {
25c2c66affSColin Finck 	if((sizeof(short) != 2) || (sizeof(long) < 4)) return MPG123_BAD_TYPES;
26c2c66affSColin Finck 
27c2c66affSColin Finck 	if(initialized) return MPG123_OK; /* no need to initialize twice */
28c2c66affSColin Finck 
29c2c66affSColin Finck #ifndef NO_LAYER12
30c2c66affSColin Finck 	init_layer12(); /* inits also shared tables with layer1 */
31c2c66affSColin Finck #endif
32c2c66affSColin Finck #ifndef NO_LAYER3
33c2c66affSColin Finck 	init_layer3();
34c2c66affSColin Finck #endif
35c2c66affSColin Finck 	prepare_decode_tables();
36c2c66affSColin Finck 	check_decoders();
37c2c66affSColin Finck 	initialized = 1;
38c2c66affSColin Finck #if (defined REAL_IS_FLOAT) && (defined IEEE_FLOAT)
39c2c66affSColin Finck 	/* This is rather pointless but it eases my mind to check that we did
40c2c66affSColin Finck 	   not enable the special rounding on a VAX or something. */
41c2c66affSColin Finck 	if(12346 != REAL_TO_SHORT_ACCURATE(12345.67f))
42c2c66affSColin Finck 	{
43c2c66affSColin Finck 		error("Bad IEEE 754 rounding. Re-build libmpg123 properly.");
44c2c66affSColin Finck 		return MPG123_ERR;
45c2c66affSColin Finck 	}
46c2c66affSColin Finck #endif
47c2c66affSColin Finck 	return MPG123_OK;
48c2c66affSColin Finck }
49c2c66affSColin Finck 
mpg123_exit(void)50c2c66affSColin Finck void attribute_align_arg mpg123_exit(void)
51c2c66affSColin Finck {
52c2c66affSColin Finck 	/* nothing yet, but something later perhaps */
53*aa811c00SThomas Faber 	/* Nope. This is dead space. */
54c2c66affSColin Finck }
55c2c66affSColin Finck 
56c2c66affSColin Finck /* create a new handle with specified decoder, decoder can be "", "auto" or NULL for auto-detection */
mpg123_new(const char * decoder,int * error)57c2c66affSColin Finck mpg123_handle attribute_align_arg *mpg123_new(const char* decoder, int *error)
58c2c66affSColin Finck {
59c2c66affSColin Finck 	return mpg123_parnew(NULL, decoder, error);
60c2c66affSColin Finck }
61c2c66affSColin Finck 
62c2c66affSColin Finck /* ...the full routine with optional initial parameters to override defaults. */
mpg123_parnew(mpg123_pars * mp,const char * decoder,int * error)63c2c66affSColin Finck mpg123_handle attribute_align_arg *mpg123_parnew(mpg123_pars *mp, const char* decoder, int *error)
64c2c66affSColin Finck {
65c2c66affSColin Finck 	mpg123_handle *fr = NULL;
66c2c66affSColin Finck 	int err = MPG123_OK;
67c2c66affSColin Finck 
68c2c66affSColin Finck 	if(initialized) fr = (mpg123_handle*) malloc(sizeof(mpg123_handle));
69c2c66affSColin Finck 	else err = MPG123_NOT_INITIALIZED;
70c2c66affSColin Finck 	if(fr != NULL)
71c2c66affSColin Finck 	{
72c2c66affSColin Finck 		frame_init_par(fr, mp);
73c2c66affSColin Finck 		debug("cpu opt setting");
74c2c66affSColin Finck 		if(frame_cpu_opt(fr, decoder) != 1)
75c2c66affSColin Finck 		{
76c2c66affSColin Finck 			err = MPG123_BAD_DECODER;
77c2c66affSColin Finck 			frame_exit(fr);
78c2c66affSColin Finck 			free(fr);
79c2c66affSColin Finck 			fr = NULL;
80c2c66affSColin Finck 		}
81c2c66affSColin Finck 	}
82c2c66affSColin Finck 	if(fr != NULL)
83c2c66affSColin Finck 	{
84c2c66affSColin Finck 		fr->decoder_change = 1;
85c2c66affSColin Finck 	}
86c2c66affSColin Finck 	else if(err == MPG123_OK) err = MPG123_OUT_OF_MEM;
87c2c66affSColin Finck 
88c2c66affSColin Finck 	if(error != NULL) *error = err;
89c2c66affSColin Finck 	return fr;
90c2c66affSColin Finck }
91c2c66affSColin Finck 
mpg123_decoder(mpg123_handle * mh,const char * decoder)92c2c66affSColin Finck int attribute_align_arg mpg123_decoder(mpg123_handle *mh, const char* decoder)
93c2c66affSColin Finck {
94c2c66affSColin Finck 	enum optdec dt = dectype(decoder);
95c2c66affSColin Finck 
96c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
97c2c66affSColin Finck 
98c2c66affSColin Finck 	if(dt == nodec)
99c2c66affSColin Finck 	{
100c2c66affSColin Finck 		mh->err = MPG123_BAD_DECODER;
101c2c66affSColin Finck 		return MPG123_ERR;
102c2c66affSColin Finck 	}
103c2c66affSColin Finck 	if(dt == mh->cpu_opts.type) return MPG123_OK;
104c2c66affSColin Finck 
105c2c66affSColin Finck 	/* Now really change. */
106c2c66affSColin Finck 	/* frame_exit(mh);
107c2c66affSColin Finck 	frame_init(mh); */
108c2c66affSColin Finck 	debug("cpu opt setting");
109c2c66affSColin Finck 	if(frame_cpu_opt(mh, decoder) != 1)
110c2c66affSColin Finck 	{
111c2c66affSColin Finck 		mh->err = MPG123_BAD_DECODER;
112c2c66affSColin Finck 		frame_exit(mh);
113c2c66affSColin Finck 		return MPG123_ERR;
114c2c66affSColin Finck 	}
115c2c66affSColin Finck 	/* New buffers for decoder are created in frame_buffers() */
116c2c66affSColin Finck 	if((frame_outbuffer(mh) != 0))
117c2c66affSColin Finck 	{
118c2c66affSColin Finck 		mh->err = MPG123_NO_BUFFERS;
119c2c66affSColin Finck 		frame_exit(mh);
120c2c66affSColin Finck 		return MPG123_ERR;
121c2c66affSColin Finck 	}
122c2c66affSColin Finck 	/* Do _not_ call decode_update here! That is only allowed after a first MPEG frame has been met. */
123c2c66affSColin Finck 	mh->decoder_change = 1;
124c2c66affSColin Finck 	return MPG123_OK;
125c2c66affSColin Finck }
126c2c66affSColin Finck 
mpg123_param(mpg123_handle * mh,enum mpg123_parms key,long val,double fval)127c2c66affSColin Finck int attribute_align_arg mpg123_param(mpg123_handle *mh, enum mpg123_parms key, long val, double fval)
128c2c66affSColin Finck {
129c2c66affSColin Finck 	int r;
130c2c66affSColin Finck 
131c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
132c2c66affSColin Finck 	r = mpg123_par(&mh->p, key, val, fval);
133c2c66affSColin Finck 	if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
134c2c66affSColin Finck 	else
135c2c66affSColin Finck 	{ /* Special treatment for some settings. */
136c2c66affSColin Finck #ifdef FRAME_INDEX
137c2c66affSColin Finck 		if(key == MPG123_INDEX_SIZE)
138c2c66affSColin Finck 		{ /* Apply frame index size and grow property on the fly. */
139c2c66affSColin Finck 			r = frame_index_setup(mh);
140c2c66affSColin Finck 			if(r != MPG123_OK) mh->err = MPG123_INDEX_FAIL;
141c2c66affSColin Finck 		}
142c2c66affSColin Finck #endif
143c2c66affSColin Finck #ifndef NO_FEEDER
144c2c66affSColin Finck 		/* Feeder pool size is applied right away, reader will react to that. */
145c2c66affSColin Finck 		if(key == MPG123_FEEDPOOL || key == MPG123_FEEDBUFFER)
146c2c66affSColin Finck 		bc_poolsize(&mh->rdat.buffer, mh->p.feedpool, mh->p.feedbuffer);
147c2c66affSColin Finck #endif
148c2c66affSColin Finck 	}
149c2c66affSColin Finck 	return r;
150c2c66affSColin Finck }
151c2c66affSColin Finck 
mpg123_par(mpg123_pars * mp,enum mpg123_parms key,long val,double fval)152c2c66affSColin Finck int attribute_align_arg mpg123_par(mpg123_pars *mp, enum mpg123_parms key, long val, double fval)
153c2c66affSColin Finck {
154c2c66affSColin Finck 	int ret = MPG123_OK;
155c2c66affSColin Finck 
156c2c66affSColin Finck 	if(mp == NULL) return MPG123_BAD_PARS;
157c2c66affSColin Finck 	switch(key)
158c2c66affSColin Finck 	{
159c2c66affSColin Finck 		case MPG123_VERBOSE:
160c2c66affSColin Finck 			mp->verbose = val;
161c2c66affSColin Finck 		break;
162c2c66affSColin Finck 		case MPG123_FLAGS:
163c2c66affSColin Finck #ifndef GAPLESS
164c2c66affSColin Finck 			if(val & MPG123_GAPLESS) ret = MPG123_NO_GAPLESS;
165c2c66affSColin Finck #endif
166c2c66affSColin Finck 			if(ret == MPG123_OK) mp->flags = val;
167c2c66affSColin Finck 			debug1("set flags to 0x%lx", (unsigned long) mp->flags);
168c2c66affSColin Finck 		break;
169c2c66affSColin Finck 		case MPG123_ADD_FLAGS:
170c2c66affSColin Finck #ifndef GAPLESS
171c2c66affSColin Finck 			/* Enabling of gapless mode doesn't work when it's not there, but disabling (below) is no problem. */
172c2c66affSColin Finck 			if(val & MPG123_GAPLESS) ret = MPG123_NO_GAPLESS;
173c2c66affSColin Finck 			else
174c2c66affSColin Finck #endif
175c2c66affSColin Finck 			mp->flags |= val;
176c2c66affSColin Finck 			debug1("set flags to 0x%lx", (unsigned long) mp->flags);
177c2c66affSColin Finck 		break;
178c2c66affSColin Finck 		case MPG123_REMOVE_FLAGS:
179c2c66affSColin Finck 			mp->flags &= ~val;
180c2c66affSColin Finck 			debug1("set flags to 0x%lx", (unsigned long) mp->flags);
181c2c66affSColin Finck 		break;
182c2c66affSColin Finck 		case MPG123_FORCE_RATE: /* should this trigger something? */
183c2c66affSColin Finck #ifdef NO_NTOM
184c2c66affSColin Finck 			if(val > 0)
185c2c66affSColin Finck 			ret = MPG123_BAD_RATE;
186c2c66affSColin Finck #else
187c2c66affSColin Finck 			if(val > 96000) ret = MPG123_BAD_RATE;
188c2c66affSColin Finck 			else mp->force_rate = val < 0 ? 0 : val; /* >0 means enable, 0 disable */
189c2c66affSColin Finck #endif
190c2c66affSColin Finck 		break;
191c2c66affSColin Finck 		case MPG123_DOWN_SAMPLE:
192c2c66affSColin Finck #ifdef NO_DOWNSAMPLE
193c2c66affSColin Finck 			if(val != 0) ret = MPG123_BAD_RATE;
194c2c66affSColin Finck #else
195c2c66affSColin Finck 			if(val < 0 || val > 2) ret = MPG123_BAD_RATE;
196c2c66affSColin Finck 			else mp->down_sample = (int)val;
197c2c66affSColin Finck #endif
198c2c66affSColin Finck 		break;
199c2c66affSColin Finck 		case MPG123_RVA:
200c2c66affSColin Finck 			if(val < 0 || val > MPG123_RVA_MAX) ret = MPG123_BAD_RVA;
201c2c66affSColin Finck 			else mp->rva = (int)val;
202c2c66affSColin Finck 		break;
203c2c66affSColin Finck 		case MPG123_DOWNSPEED:
204c2c66affSColin Finck 			mp->halfspeed = val < 0 ? 0 : val;
205c2c66affSColin Finck 		break;
206c2c66affSColin Finck 		case MPG123_UPSPEED:
207c2c66affSColin Finck 			mp->doublespeed = val < 0 ? 0 : val;
208c2c66affSColin Finck 		break;
209c2c66affSColin Finck 		case MPG123_ICY_INTERVAL:
210c2c66affSColin Finck #ifndef NO_ICY
211c2c66affSColin Finck 			mp->icy_interval = val > 0 ? val : 0;
212c2c66affSColin Finck #else
213c2c66affSColin Finck 			if(val > 0) ret = MPG123_BAD_PARAM;
214c2c66affSColin Finck #endif
215c2c66affSColin Finck 		break;
216c2c66affSColin Finck 		case MPG123_OUTSCALE:
217c2c66affSColin Finck 			/* Choose the value that is non-zero, if any.
218c2c66affSColin Finck 			   Downscaling integers to 1.0 . */
219c2c66affSColin Finck 			mp->outscale = val == 0 ? fval : (double)val/SHORT_SCALE;
220c2c66affSColin Finck 		break;
221c2c66affSColin Finck 		case MPG123_TIMEOUT:
222c2c66affSColin Finck #ifdef TIMEOUT_READ
223c2c66affSColin Finck 			mp->timeout = val >= 0 ? val : 0;
224c2c66affSColin Finck #else
225c2c66affSColin Finck 			if(val > 0) ret = MPG123_NO_TIMEOUT;
226c2c66affSColin Finck #endif
227c2c66affSColin Finck 		break;
228c2c66affSColin Finck 		case MPG123_RESYNC_LIMIT:
229c2c66affSColin Finck 			mp->resync_limit = val;
230c2c66affSColin Finck 		break;
231c2c66affSColin Finck 		case MPG123_INDEX_SIZE:
232c2c66affSColin Finck #ifdef FRAME_INDEX
233c2c66affSColin Finck 			mp->index_size = val;
234c2c66affSColin Finck #else
235*aa811c00SThomas Faber 			if(val) // It is only an eror if you want to enable the index.
236c2c66affSColin Finck 				ret = MPG123_NO_INDEX;
237c2c66affSColin Finck #endif
238c2c66affSColin Finck 		break;
239c2c66affSColin Finck 		case MPG123_PREFRAMES:
240c2c66affSColin Finck 			if(val >= 0) mp->preframes = val;
241c2c66affSColin Finck 			else ret = MPG123_BAD_VALUE;
242c2c66affSColin Finck 		break;
243c2c66affSColin Finck 		case MPG123_FEEDPOOL:
244c2c66affSColin Finck #ifndef NO_FEEDER
245c2c66affSColin Finck 			if(val >= 0) mp->feedpool = val;
246c2c66affSColin Finck 			else ret = MPG123_BAD_VALUE;
247c2c66affSColin Finck #else
248c2c66affSColin Finck 			ret = MPG123_MISSING_FEATURE;
249c2c66affSColin Finck #endif
250c2c66affSColin Finck 		break;
251c2c66affSColin Finck 		case MPG123_FEEDBUFFER:
252c2c66affSColin Finck #ifndef NO_FEEDER
253c2c66affSColin Finck 			if(val > 0) mp->feedbuffer = val;
254c2c66affSColin Finck 			else ret = MPG123_BAD_VALUE;
255c2c66affSColin Finck #else
256c2c66affSColin Finck 			ret = MPG123_MISSING_FEATURE;
257c2c66affSColin Finck #endif
258c2c66affSColin Finck 		break;
259*aa811c00SThomas Faber 		case MPG123_FREEFORMAT_SIZE:
260*aa811c00SThomas Faber 			mp->freeformat_framesize = val;
261*aa811c00SThomas Faber 		break;
262c2c66affSColin Finck 		default:
263c2c66affSColin Finck 			ret = MPG123_BAD_PARAM;
264c2c66affSColin Finck 	}
265c2c66affSColin Finck 	return ret;
266c2c66affSColin Finck }
267c2c66affSColin Finck 
mpg123_getparam(mpg123_handle * mh,enum mpg123_parms key,long * val,double * fval)268c2c66affSColin Finck int attribute_align_arg mpg123_getparam(mpg123_handle *mh, enum mpg123_parms key, long *val, double *fval)
269c2c66affSColin Finck {
270c2c66affSColin Finck 	int r;
271c2c66affSColin Finck 
272c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
273c2c66affSColin Finck 	r = mpg123_getpar(&mh->p, key, val, fval);
274c2c66affSColin Finck 	if(r != MPG123_OK){ mh->err = r; r = MPG123_ERR; }
275c2c66affSColin Finck 	return r;
276c2c66affSColin Finck }
277c2c66affSColin Finck 
mpg123_getpar(mpg123_pars * mp,enum mpg123_parms key,long * val,double * fval)278c2c66affSColin Finck int attribute_align_arg mpg123_getpar(mpg123_pars *mp, enum mpg123_parms key, long *val, double *fval)
279c2c66affSColin Finck {
280c2c66affSColin Finck 	int ret = 0;
281c2c66affSColin Finck 
282c2c66affSColin Finck 	if(mp == NULL) return MPG123_BAD_PARS;
283c2c66affSColin Finck 	switch(key)
284c2c66affSColin Finck 	{
285c2c66affSColin Finck 		case MPG123_VERBOSE:
286c2c66affSColin Finck 			if(val) *val = mp->verbose;
287c2c66affSColin Finck 		break;
288c2c66affSColin Finck 		case MPG123_FLAGS:
289c2c66affSColin Finck 		case MPG123_ADD_FLAGS:
290c2c66affSColin Finck 			if(val) *val = mp->flags;
291c2c66affSColin Finck 		break;
292c2c66affSColin Finck 		case MPG123_FORCE_RATE:
293c2c66affSColin Finck 			if(val)
294c2c66affSColin Finck #ifdef NO_NTOM
295c2c66affSColin Finck 			*val = 0;
296c2c66affSColin Finck #else
297c2c66affSColin Finck 			*val = mp->force_rate;
298c2c66affSColin Finck #endif
299c2c66affSColin Finck 		break;
300c2c66affSColin Finck 		case MPG123_DOWN_SAMPLE:
301c2c66affSColin Finck 			if(val) *val = mp->down_sample;
302c2c66affSColin Finck 		break;
303c2c66affSColin Finck 		case MPG123_RVA:
304c2c66affSColin Finck 			if(val) *val = mp->rva;
305c2c66affSColin Finck 		break;
306c2c66affSColin Finck 		case MPG123_DOWNSPEED:
307c2c66affSColin Finck 			if(val) *val = mp->halfspeed;
308c2c66affSColin Finck 		break;
309c2c66affSColin Finck 		case MPG123_UPSPEED:
310c2c66affSColin Finck 			if(val) *val = mp->doublespeed;
311c2c66affSColin Finck 		break;
312c2c66affSColin Finck 		case MPG123_ICY_INTERVAL:
313c2c66affSColin Finck #ifndef NO_ICY
314c2c66affSColin Finck 			if(val) *val = (long)mp->icy_interval;
315c2c66affSColin Finck #else
316c2c66affSColin Finck 			if(val) *val = 0;
317c2c66affSColin Finck #endif
318c2c66affSColin Finck 		break;
319c2c66affSColin Finck 		case MPG123_OUTSCALE:
320c2c66affSColin Finck 			if(fval) *fval = mp->outscale;
321c2c66affSColin Finck 			if(val) *val = (long)(mp->outscale*SHORT_SCALE);
322c2c66affSColin Finck 		break;
323c2c66affSColin Finck 		case MPG123_RESYNC_LIMIT:
324c2c66affSColin Finck 			if(val) *val = mp->resync_limit;
325c2c66affSColin Finck 		break;
326c2c66affSColin Finck 		case MPG123_INDEX_SIZE:
327c2c66affSColin Finck 			if(val)
328c2c66affSColin Finck #ifdef FRAME_INDEX
329c2c66affSColin Finck 			*val = mp->index_size;
330c2c66affSColin Finck #else
331c2c66affSColin Finck 			*val = 0; /* graceful fallback: no index is index of zero size */
332c2c66affSColin Finck #endif
333c2c66affSColin Finck 		break;
334c2c66affSColin Finck 		case MPG123_PREFRAMES:
335c2c66affSColin Finck 			*val = mp->preframes;
336c2c66affSColin Finck 		break;
337c2c66affSColin Finck 		case MPG123_FEEDPOOL:
338c2c66affSColin Finck #ifndef NO_FEEDER
339c2c66affSColin Finck 			*val = mp->feedpool;
340c2c66affSColin Finck #else
341c2c66affSColin Finck 			ret = MPG123_MISSING_FEATURE;
342c2c66affSColin Finck #endif
343c2c66affSColin Finck 		break;
344c2c66affSColin Finck 		case MPG123_FEEDBUFFER:
345c2c66affSColin Finck #ifndef NO_FEEDER
346c2c66affSColin Finck 			*val = mp->feedbuffer;
347c2c66affSColin Finck #else
348c2c66affSColin Finck 			ret = MPG123_MISSING_FEATURE;
349c2c66affSColin Finck #endif
350c2c66affSColin Finck 		break;
351*aa811c00SThomas Faber 		case MPG123_FREEFORMAT_SIZE:
352*aa811c00SThomas Faber 			*val = mp->freeformat_framesize;
353*aa811c00SThomas Faber 		break;
354c2c66affSColin Finck 		default:
355c2c66affSColin Finck 			ret = MPG123_BAD_PARAM;
356c2c66affSColin Finck 	}
357c2c66affSColin Finck 	return ret;
358c2c66affSColin Finck }
359c2c66affSColin Finck 
mpg123_getstate(mpg123_handle * mh,enum mpg123_state key,long * val,double * fval)360c2c66affSColin Finck int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key, long *val, double *fval)
361c2c66affSColin Finck {
362c2c66affSColin Finck 	int ret = MPG123_OK;
363c2c66affSColin Finck 	long theval = 0;
364c2c66affSColin Finck 	double thefval = 0.;
365c2c66affSColin Finck 
366c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
367c2c66affSColin Finck 
368c2c66affSColin Finck 	switch(key)
369c2c66affSColin Finck 	{
370c2c66affSColin Finck 		case MPG123_ACCURATE:
371c2c66affSColin Finck 			theval = mh->state_flags & FRAME_ACCURATE;
372c2c66affSColin Finck 		break;
373c2c66affSColin Finck 		case MPG123_FRANKENSTEIN:
374c2c66affSColin Finck 			theval = mh->state_flags & FRAME_FRANKENSTEIN;
375c2c66affSColin Finck 		break;
376c2c66affSColin Finck 		case MPG123_BUFFERFILL:
377c2c66affSColin Finck #ifndef NO_FEEDER
378c2c66affSColin Finck 		{
379c2c66affSColin Finck 			size_t sval = bc_fill(&mh->rdat.buffer);
380c2c66affSColin Finck 			theval = (long)sval;
381c2c66affSColin Finck 			if(theval < 0 || (size_t)theval != sval)
382c2c66affSColin Finck 			{
383c2c66affSColin Finck 				mh->err = MPG123_INT_OVERFLOW;
384c2c66affSColin Finck 				ret = MPG123_ERR;
385c2c66affSColin Finck 			}
386c2c66affSColin Finck 		}
387c2c66affSColin Finck #else
388c2c66affSColin Finck 			mh->err = MPG123_MISSING_FEATURE;
389c2c66affSColin Finck 			ret = MPG123_ERR;
390c2c66affSColin Finck #endif
391c2c66affSColin Finck 		break;
392c2c66affSColin Finck 		case MPG123_FRESH_DECODER:
393c2c66affSColin Finck 			theval = mh->state_flags & FRAME_FRESH_DECODER;
394c2c66affSColin Finck 			mh->state_flags &= ~FRAME_FRESH_DECODER;
395c2c66affSColin Finck 		break;
396*aa811c00SThomas Faber 		case MPG123_ENC_DELAY:
397*aa811c00SThomas Faber 			theval = mh->enc_delay;
398*aa811c00SThomas Faber 		break;
399*aa811c00SThomas Faber 		case MPG123_ENC_PADDING:
400*aa811c00SThomas Faber 			theval = mh->enc_padding;
401*aa811c00SThomas Faber 		break;
402*aa811c00SThomas Faber 		case MPG123_DEC_DELAY:
403*aa811c00SThomas Faber 			theval = mh->lay == 3 ? GAPLESS_DELAY : -1;
404*aa811c00SThomas Faber 		break;
405c2c66affSColin Finck 		default:
406c2c66affSColin Finck 			mh->err = MPG123_BAD_KEY;
407c2c66affSColin Finck 			ret = MPG123_ERR;
408c2c66affSColin Finck 	}
409c2c66affSColin Finck 
410c2c66affSColin Finck 	if(val  != NULL) *val  = theval;
411c2c66affSColin Finck 	if(fval != NULL) *fval = thefval;
412c2c66affSColin Finck 
413c2c66affSColin Finck 	return ret;
414c2c66affSColin Finck }
415*aa811c00SThomas Faber 
mpg123_eq(mpg123_handle * mh,enum mpg123_channels channel,int band,double val)416c2c66affSColin Finck int attribute_align_arg mpg123_eq(mpg123_handle *mh, enum mpg123_channels channel, int band, double val)
417c2c66affSColin Finck {
418c2c66affSColin Finck #ifndef NO_EQUALIZER
419c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
420c2c66affSColin Finck 	if(band < 0 || band > 31){ mh->err = MPG123_BAD_BAND; return MPG123_ERR; }
421c2c66affSColin Finck 	switch(channel)
422c2c66affSColin Finck 	{
423c2c66affSColin Finck 		case MPG123_LEFT|MPG123_RIGHT:
424c2c66affSColin Finck 			mh->equalizer[0][band] = mh->equalizer[1][band] = DOUBLE_TO_REAL(val);
425c2c66affSColin Finck 		break;
426c2c66affSColin Finck 		case MPG123_LEFT:  mh->equalizer[0][band] = DOUBLE_TO_REAL(val); break;
427c2c66affSColin Finck 		case MPG123_RIGHT: mh->equalizer[1][band] = DOUBLE_TO_REAL(val); break;
428c2c66affSColin Finck 		default:
429c2c66affSColin Finck 			mh->err=MPG123_BAD_CHANNEL;
430c2c66affSColin Finck 			return MPG123_ERR;
431c2c66affSColin Finck 	}
432c2c66affSColin Finck 	mh->have_eq_settings = TRUE;
433c2c66affSColin Finck #endif
434c2c66affSColin Finck 	return MPG123_OK;
435c2c66affSColin Finck }
436c2c66affSColin Finck 
mpg123_geteq(mpg123_handle * mh,enum mpg123_channels channel,int band)437c2c66affSColin Finck double attribute_align_arg mpg123_geteq(mpg123_handle *mh, enum mpg123_channels channel, int band)
438c2c66affSColin Finck {
439c2c66affSColin Finck 	double ret = 0.;
440c2c66affSColin Finck #ifndef NO_EQUALIZER
441c2c66affSColin Finck 
442c2c66affSColin Finck 	/* Handle this gracefully. When there is no band, it has no volume. */
443c2c66affSColin Finck 	if(mh != NULL && band > -1 && band < 32)
444c2c66affSColin Finck 	switch(channel)
445c2c66affSColin Finck 	{
446c2c66affSColin Finck 		case MPG123_LEFT|MPG123_RIGHT:
447c2c66affSColin Finck 			ret = 0.5*(REAL_TO_DOUBLE(mh->equalizer[0][band])+REAL_TO_DOUBLE(mh->equalizer[1][band]));
448c2c66affSColin Finck 		break;
449c2c66affSColin Finck 		case MPG123_LEFT:  ret = REAL_TO_DOUBLE(mh->equalizer[0][band]); break;
450c2c66affSColin Finck 		case MPG123_RIGHT: ret = REAL_TO_DOUBLE(mh->equalizer[1][band]); break;
451c2c66affSColin Finck 		/* Default case is already handled: ret = 0 */
452c2c66affSColin Finck 	}
453c2c66affSColin Finck #endif
454c2c66affSColin Finck 	return ret;
455c2c66affSColin Finck }
456c2c66affSColin Finck 
457c2c66affSColin Finck /* plain file access, no http! */
mpg123_open(mpg123_handle * mh,const char * path)458c2c66affSColin Finck int attribute_align_arg mpg123_open(mpg123_handle *mh, const char *path)
459c2c66affSColin Finck {
460c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
461c2c66affSColin Finck 
462c2c66affSColin Finck 	mpg123_close(mh);
463c2c66affSColin Finck 	return open_stream(mh, path, -1);
464c2c66affSColin Finck }
465c2c66affSColin Finck 
466*aa811c00SThomas Faber // The convenience function mpg123_open_fixed() wraps over acual mpg123_open
467*aa811c00SThomas Faber // and hence needs to have the exact same code in lfs_wrap.c. The flesh is
468*aa811c00SThomas Faber // in open_fixed_pre() and open_fixed_post(), wich are only defined here.
open_fixed_pre(mpg123_handle * mh,int channels,int encoding)469*aa811c00SThomas Faber int open_fixed_pre(mpg123_handle *mh, int channels, int encoding)
470*aa811c00SThomas Faber {
471*aa811c00SThomas Faber 	if(!mh)
472*aa811c00SThomas Faber 		return MPG123_BAD_HANDLE;
473*aa811c00SThomas Faber 	mh->p.flags |= MPG123_NO_FRANKENSTEIN;
474*aa811c00SThomas Faber 	int err = mpg123_format_none(mh);
475*aa811c00SThomas Faber 	if(err == MPG123_OK)
476*aa811c00SThomas Faber 		err = mpg123_format2(mh, 0, channels, encoding);
477*aa811c00SThomas Faber 	return err;
478*aa811c00SThomas Faber }
479*aa811c00SThomas Faber 
open_fixed_post(mpg123_handle * mh,int channels,int encoding)480*aa811c00SThomas Faber int open_fixed_post(mpg123_handle *mh, int channels, int encoding)
481*aa811c00SThomas Faber {
482*aa811c00SThomas Faber 	if(!mh)
483*aa811c00SThomas Faber 		return MPG123_BAD_HANDLE;
484*aa811c00SThomas Faber 	long rate;
485*aa811c00SThomas Faber 	int err = mpg123_getformat(mh, &rate, &channels, &encoding);
486*aa811c00SThomas Faber 	if(err == MPG123_OK)
487*aa811c00SThomas Faber 		err = mpg123_format_none(mh);
488*aa811c00SThomas Faber 	if(err == MPG123_OK)
489*aa811c00SThomas Faber 		err = mpg123_format(mh, rate, channels, encoding);
490*aa811c00SThomas Faber 	if(err == MPG123_OK)
491*aa811c00SThomas Faber 	{
492*aa811c00SThomas Faber 		if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE))
493*aa811c00SThomas Faber 		{
494*aa811c00SThomas Faber 			debug("open_fixed_post: scan because we can seek and do not know track_frames");
495*aa811c00SThomas Faber 			err = mpg123_scan(mh);
496*aa811c00SThomas Faber 		}
497*aa811c00SThomas Faber 	}
498*aa811c00SThomas Faber 	if(err != MPG123_OK)
499*aa811c00SThomas Faber 		mpg123_close(mh);
500*aa811c00SThomas Faber 	return err;
501*aa811c00SThomas Faber }
502*aa811c00SThomas Faber 
mpg123_open_fixed(mpg123_handle * mh,const char * path,int channels,int encoding)503*aa811c00SThomas Faber int attribute_align_arg mpg123_open_fixed( mpg123_handle *mh, const char *path
504*aa811c00SThomas Faber ,	int channels, int encoding )
505*aa811c00SThomas Faber {
506*aa811c00SThomas Faber 	int err = open_fixed_pre(mh, channels, encoding);
507*aa811c00SThomas Faber 	if(err == MPG123_OK)
508*aa811c00SThomas Faber 		err = mpg123_open(mh, path);
509*aa811c00SThomas Faber 	if(err == MPG123_OK)
510*aa811c00SThomas Faber 		err = open_fixed_post(mh, channels, encoding);
511*aa811c00SThomas Faber 	return err;
512*aa811c00SThomas Faber }
513*aa811c00SThomas Faber 
mpg123_open_fd(mpg123_handle * mh,int fd)514c2c66affSColin Finck int attribute_align_arg mpg123_open_fd(mpg123_handle *mh, int fd)
515c2c66affSColin Finck {
516c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
517c2c66affSColin Finck 
518c2c66affSColin Finck 	mpg123_close(mh);
519c2c66affSColin Finck 	return open_stream(mh, NULL, fd);
520c2c66affSColin Finck }
521c2c66affSColin Finck 
mpg123_open_handle(mpg123_handle * mh,void * iohandle)522c2c66affSColin Finck int attribute_align_arg mpg123_open_handle(mpg123_handle *mh, void *iohandle)
523c2c66affSColin Finck {
524c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
525c2c66affSColin Finck 
526c2c66affSColin Finck 	mpg123_close(mh);
527c2c66affSColin Finck 	if(mh->rdat.r_read_handle == NULL)
528c2c66affSColin Finck 	{
529c2c66affSColin Finck 		mh->err = MPG123_BAD_CUSTOM_IO;
530c2c66affSColin Finck 		return MPG123_ERR;
531c2c66affSColin Finck 	}
532c2c66affSColin Finck 	return open_stream_handle(mh, iohandle);
533c2c66affSColin Finck }
534c2c66affSColin Finck 
mpg123_open_feed(mpg123_handle * mh)535c2c66affSColin Finck int attribute_align_arg mpg123_open_feed(mpg123_handle *mh)
536c2c66affSColin Finck {
537c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
538c2c66affSColin Finck 
539c2c66affSColin Finck 	mpg123_close(mh);
540c2c66affSColin Finck 	return open_feed(mh);
541c2c66affSColin Finck }
542c2c66affSColin Finck 
mpg123_replace_reader(mpg123_handle * mh,ssize_t (* r_read)(int,void *,size_t),off_t (* r_lseek)(int,off_t,int))543c2c66affSColin Finck int attribute_align_arg mpg123_replace_reader( mpg123_handle *mh,
544c2c66affSColin Finck                            ssize_t (*r_read) (int, void *, size_t),
545c2c66affSColin Finck                            off_t   (*r_lseek)(int, off_t, int) )
546c2c66affSColin Finck {
547c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
548c2c66affSColin Finck 
549c2c66affSColin Finck 	mpg123_close(mh);
550c2c66affSColin Finck 	mh->rdat.r_read = r_read;
551c2c66affSColin Finck 	mh->rdat.r_lseek = r_lseek;
552c2c66affSColin Finck 	return MPG123_OK;
553c2c66affSColin Finck }
554c2c66affSColin Finck 
mpg123_replace_reader_handle(mpg123_handle * mh,ssize_t (* r_read)(void *,void *,size_t),off_t (* r_lseek)(void *,off_t,int),void (* cleanup)(void *))555c2c66affSColin Finck int attribute_align_arg mpg123_replace_reader_handle( mpg123_handle *mh,
556c2c66affSColin Finck                            ssize_t (*r_read) (void*, void *, size_t),
557c2c66affSColin Finck                            off_t   (*r_lseek)(void*, off_t, int),
558c2c66affSColin Finck                            void    (*cleanup)(void*)  )
559c2c66affSColin Finck {
560c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
561c2c66affSColin Finck 
562c2c66affSColin Finck 	mpg123_close(mh);
563c2c66affSColin Finck 	mh->rdat.r_read_handle = r_read;
564c2c66affSColin Finck 	mh->rdat.r_lseek_handle = r_lseek;
565c2c66affSColin Finck 	mh->rdat.cleanup_handle = cleanup;
566c2c66affSColin Finck 	return MPG123_OK;
567c2c66affSColin Finck }
568c2c66affSColin Finck 
569c2c66affSColin Finck /* Update decoding engine for
570c2c66affSColin Finck    a) a new choice of decoder
571c2c66affSColin Finck    b) a changed native format of the MPEG stream
572c2c66affSColin Finck    ... calls are only valid after parsing some MPEG frame! */
decode_update(mpg123_handle * mh)573c2c66affSColin Finck int decode_update(mpg123_handle *mh)
574c2c66affSColin Finck {
575c2c66affSColin Finck 	long native_rate;
576c2c66affSColin Finck 	int b;
577c2c66affSColin Finck 
578c2c66affSColin Finck 	if(mh->num < 0)
579c2c66affSColin Finck 	{
580c2c66affSColin Finck 		if(!(mh->p.flags & MPG123_QUIET)) error("decode_update() has been called before reading the first MPEG frame! Internal programming error.");
581c2c66affSColin Finck 
582c2c66affSColin Finck 		mh->err = MPG123_BAD_DECODER_SETUP;
583c2c66affSColin Finck 		return MPG123_ERR;
584c2c66affSColin Finck 	}
585c2c66affSColin Finck 
586c2c66affSColin Finck 	mh->state_flags |= FRAME_FRESH_DECODER;
587c2c66affSColin Finck 	native_rate = frame_freq(mh);
588c2c66affSColin Finck 
589c2c66affSColin Finck 	b = frame_output_format(mh); /* Select the new output format based on given constraints. */
590c2c66affSColin Finck 	if(b < 0) return MPG123_ERR;
591c2c66affSColin Finck 
592c2c66affSColin Finck 	if(b == 1) mh->new_format = 1; /* Store for later... */
593c2c66affSColin Finck 
594c2c66affSColin Finck 	debug3("updating decoder structure with native rate %li and af.rate %li (new format: %i)", native_rate, mh->af.rate, mh->new_format);
595c2c66affSColin Finck 	if(mh->af.rate == native_rate) mh->down_sample = 0;
596c2c66affSColin Finck 	else if(mh->af.rate == native_rate>>1) mh->down_sample = 1;
597c2c66affSColin Finck 	else if(mh->af.rate == native_rate>>2) mh->down_sample = 2;
598c2c66affSColin Finck 	else mh->down_sample = 3; /* flexible (fixed) rate */
599c2c66affSColin Finck 	switch(mh->down_sample)
600c2c66affSColin Finck 	{
601c2c66affSColin Finck 		case 0:
602c2c66affSColin Finck 		case 1:
603c2c66affSColin Finck 		case 2:
604c2c66affSColin Finck 			mh->down_sample_sblimit = SBLIMIT>>(mh->down_sample);
605c2c66affSColin Finck 			/* With downsampling I get less samples per frame */
606c2c66affSColin Finck 			mh->outblock = outblock_bytes(mh, (mh->spf>>mh->down_sample));
607c2c66affSColin Finck 		break;
608c2c66affSColin Finck #ifndef NO_NTOM
609c2c66affSColin Finck 		case 3:
610c2c66affSColin Finck 		{
611c2c66affSColin Finck 			if(synth_ntom_set_step(mh) != 0) return -1;
612c2c66affSColin Finck 			if(frame_freq(mh) > mh->af.rate)
613c2c66affSColin Finck 			{
614c2c66affSColin Finck 				mh->down_sample_sblimit = SBLIMIT * mh->af.rate;
615c2c66affSColin Finck 				mh->down_sample_sblimit /= frame_freq(mh);
616*aa811c00SThomas Faber 				if(mh->down_sample_sblimit < 1)
617*aa811c00SThomas Faber 					mh->down_sample_sblimit = 1;
618c2c66affSColin Finck 			}
619c2c66affSColin Finck 			else mh->down_sample_sblimit = SBLIMIT;
620c2c66affSColin Finck 			mh->outblock = outblock_bytes(mh,
621c2c66affSColin Finck 			                 ( ( NTOM_MUL-1+mh->spf
622c2c66affSColin Finck 			                   * (((size_t)NTOM_MUL*mh->af.rate)/frame_freq(mh))
623c2c66affSColin Finck 			                 )/NTOM_MUL ));
624c2c66affSColin Finck 		}
625c2c66affSColin Finck 		break;
626c2c66affSColin Finck #endif
627c2c66affSColin Finck 	}
628c2c66affSColin Finck 
629c2c66affSColin Finck 	if(!(mh->p.flags & MPG123_FORCE_MONO))
630c2c66affSColin Finck 	{
631c2c66affSColin Finck 		if(mh->af.channels == 1) mh->single = SINGLE_MIX;
632c2c66affSColin Finck 		else mh->single = SINGLE_STEREO;
633c2c66affSColin Finck 	}
634c2c66affSColin Finck 	else mh->single = (mh->p.flags & MPG123_FORCE_MONO)-1;
635c2c66affSColin Finck 	if(set_synth_functions(mh) != 0) return -1;;
636c2c66affSColin Finck 
637c2c66affSColin Finck 	/* The needed size of output buffer may have changed. */
638c2c66affSColin Finck 	if(frame_outbuffer(mh) != MPG123_OK) return -1;
639c2c66affSColin Finck 
640c2c66affSColin Finck 	do_rva(mh);
641c2c66affSColin Finck 	debug3("done updating decoder structure with native rate %li and af.rate %li and down_sample %i", frame_freq(mh), mh->af.rate, mh->down_sample);
642c2c66affSColin Finck 
643*aa811c00SThomas Faber 	mh->decoder_change = 0;
644c2c66affSColin Finck 	return 0;
645c2c66affSColin Finck }
646c2c66affSColin Finck 
mpg123_safe_buffer(void)647c2c66affSColin Finck size_t attribute_align_arg mpg123_safe_buffer(void)
648c2c66affSColin Finck {
649c2c66affSColin Finck 	/* real is the largest possible output (it's 32bit float, 32bit int or 64bit double). */
650c2c66affSColin Finck 	return sizeof(real)*2*1152*NTOM_MAX;
651c2c66affSColin Finck }
652c2c66affSColin Finck 
mpg123_outblock(mpg123_handle * mh)653c2c66affSColin Finck size_t attribute_align_arg mpg123_outblock(mpg123_handle *mh)
654c2c66affSColin Finck {
655c2c66affSColin Finck 	/* Try to be helpful and never return zero output block size. */
656c2c66affSColin Finck 	if(mh != NULL && mh->outblock > 0) return mh->outblock;
657c2c66affSColin Finck 	else return mpg123_safe_buffer();
658c2c66affSColin Finck }
659c2c66affSColin Finck 
660c2c66affSColin Finck /* Read in the next frame we actually want for decoding.
661c2c66affSColin Finck    This includes skipping/ignoring frames, in additon to skipping junk in the parser. */
get_next_frame(mpg123_handle * mh)662c2c66affSColin Finck static int get_next_frame(mpg123_handle *mh)
663c2c66affSColin Finck {
664c2c66affSColin Finck 	int change = mh->decoder_change;
665c2c66affSColin Finck 	/* Ensure we got proper decoder for ignoring frames.
666c2c66affSColin Finck 	   Header can be changed from seeking around. But be careful: Only after at
667c2c66affSColin Finck 	   least one frame got read, decoder update makes sense. */
668c2c66affSColin Finck 	if(mh->header_change > 1 && mh->num >= 0)
669c2c66affSColin Finck 	{
670c2c66affSColin Finck 		change = 1;
671c2c66affSColin Finck 		mh->header_change = 0;
672c2c66affSColin Finck 		debug("starting with big header change");
673c2c66affSColin Finck 		if(decode_update(mh) < 0)
674c2c66affSColin Finck 		return MPG123_ERR;
675c2c66affSColin Finck 	}
676c2c66affSColin Finck 
677c2c66affSColin Finck 	do
678c2c66affSColin Finck 	{
679c2c66affSColin Finck 		int b;
680c2c66affSColin Finck 		/* Decode & discard some frame(s) before beginning. */
681c2c66affSColin Finck 		if(mh->to_ignore && mh->num < mh->firstframe && mh->num >= mh->ignoreframe)
682c2c66affSColin Finck 		{
683c2c66affSColin Finck 			debug1("ignoring frame %li", (long)mh->num);
684c2c66affSColin Finck 			/* Decoder structure must be current! decode_update has been called before... */
685c2c66affSColin Finck 			(mh->do_layer)(mh); mh->buffer.fill = 0;
686c2c66affSColin Finck #ifndef NO_NTOM
687c2c66affSColin Finck 			/* The ignored decoding may have failed. Make sure ntom stays consistent. */
688c2c66affSColin Finck 			if(mh->down_sample == 3) ntom_set_ntom(mh, mh->num+1);
689c2c66affSColin Finck #endif
690c2c66affSColin Finck 			mh->to_ignore = mh->to_decode = FALSE;
691c2c66affSColin Finck 		}
692c2c66affSColin Finck 		/* Read new frame data; possibly breaking out here for MPG123_NEED_MORE. */
693c2c66affSColin Finck 		debug("read frame");
694c2c66affSColin Finck 		mh->to_decode = FALSE;
695c2c66affSColin Finck 		b = read_frame(mh); /* That sets to_decode only if a full frame was read. */
696c2c66affSColin Finck 		debug4("read of frame %li returned %i (to_decode=%i) at sample %li", (long)mh->num, b, mh->to_decode, (long)mpg123_tell(mh));
697c2c66affSColin Finck 		if(b == MPG123_NEED_MORE) return MPG123_NEED_MORE; /* need another call with data */
698c2c66affSColin Finck 		else if(b <= 0)
699c2c66affSColin Finck 		{
700c2c66affSColin Finck 			/* More sophisticated error control? */
701c2c66affSColin Finck 			if(b==0 || (mh->rdat.filelen >= 0 && mh->rdat.filepos == mh->rdat.filelen))
702c2c66affSColin Finck 			{ /* We simply reached the end. */
703c2c66affSColin Finck 				mh->track_frames = mh->num + 1;
704c2c66affSColin Finck 				debug("What about updating/checking gapless sample count here?");
705c2c66affSColin Finck 				return MPG123_DONE;
706c2c66affSColin Finck 			}
707c2c66affSColin Finck 			else return MPG123_ERR; /* Some real error. */
708c2c66affSColin Finck 		}
709c2c66affSColin Finck 		/* Now, there should be new data to decode ... and also possibly new stream properties */
710*aa811c00SThomas Faber 		if(mh->header_change > 1 || mh->decoder_change)
711c2c66affSColin Finck 		{
712*aa811c00SThomas Faber 			debug("big header or decoder change");
713c2c66affSColin Finck 			change = 1;
714c2c66affSColin Finck 			mh->header_change = 0;
715c2c66affSColin Finck 			/* Need to update decoder structure right away since frame might need to
716c2c66affSColin Finck 			   be decoded on next loop iteration for properly ignoring its output. */
717c2c66affSColin Finck 			if(decode_update(mh) < 0)
718c2c66affSColin Finck 			return MPG123_ERR;
719c2c66affSColin Finck 		}
720c2c66affSColin Finck 		/* Now some accounting: Look at the numbers and decide if we want this frame. */
721c2c66affSColin Finck 		++mh->playnum;
722c2c66affSColin Finck 		/* Plain skipping without decoding, only when frame is not ignored on next cycle. */
723c2c66affSColin Finck 		if(mh->num < mh->firstframe || (mh->p.doublespeed && (mh->playnum % mh->p.doublespeed)))
724c2c66affSColin Finck 		{
725c2c66affSColin Finck 			if(!(mh->to_ignore && mh->num < mh->firstframe && mh->num >= mh->ignoreframe))
726c2c66affSColin Finck 			{
727c2c66affSColin Finck 				frame_skip(mh);
728c2c66affSColin Finck 				/* Should one fix NtoM here or not?
729c2c66affSColin Finck 				   It is not work the trouble for doublespeed, but what with leading frames? */
730c2c66affSColin Finck 			}
731c2c66affSColin Finck 		}
732c2c66affSColin Finck 		/* Or, we are finally done and have a new frame. */
733c2c66affSColin Finck 		else break;
734c2c66affSColin Finck 	} while(1);
735c2c66affSColin Finck 
736c2c66affSColin Finck 	/* If we reach this point, we got a new frame ready to be decoded.
737c2c66affSColin Finck 	   All other situations resulted in returns from the loop. */
738c2c66affSColin Finck 	if(change)
739c2c66affSColin Finck 	{
740c2c66affSColin Finck 		if(mh->fresh)
741c2c66affSColin Finck 		{
742c2c66affSColin Finck #ifdef GAPLESS
743c2c66affSColin Finck 			int b=0;
744c2c66affSColin Finck 			/* Prepare offsets for gapless decoding. */
745c2c66affSColin Finck 			debug1("preparing gapless stuff with native rate %li", frame_freq(mh));
746c2c66affSColin Finck 			frame_gapless_realinit(mh);
747c2c66affSColin Finck 			frame_set_frameseek(mh, mh->num);
748c2c66affSColin Finck #endif
749c2c66affSColin Finck 			mh->fresh = 0;
750c2c66affSColin Finck #ifdef GAPLESS
751c2c66affSColin Finck 			/* Could this possibly happen? With a real big gapless offset... */
752c2c66affSColin Finck 			if(mh->num < mh->firstframe) b = get_next_frame(mh);
753c2c66affSColin Finck 			if(b < 0) return b; /* Could be error, need for more, new format... */
754c2c66affSColin Finck #endif
755c2c66affSColin Finck 		}
756c2c66affSColin Finck 	}
757c2c66affSColin Finck 	return MPG123_OK;
758c2c66affSColin Finck }
759c2c66affSColin Finck 
760c2c66affSColin Finck /* Assumption: A buffer full of zero samples can be constructed by repetition of this byte.
761c2c66affSColin Finck    Oh, and it handles some format conversion.
762c2c66affSColin Finck    Only to be used by decode_the_frame() ... */
zero_byte(mpg123_handle * fr)763c2c66affSColin Finck static int zero_byte(mpg123_handle *fr)
764c2c66affSColin Finck {
765c2c66affSColin Finck #ifndef NO_8BIT
766c2c66affSColin Finck 	return fr->af.encoding & MPG123_ENC_8 ? fr->conv16to8[0] : 0;
767c2c66affSColin Finck #else
768c2c66affSColin Finck 	return 0; /* All normal signed formats have the zero here (even in byte form -- that may be an assumption for your funny machine...). */
769c2c66affSColin Finck #endif
770c2c66affSColin Finck }
771c2c66affSColin Finck 
772c2c66affSColin Finck /*
773c2c66affSColin Finck 	Not part of the api. This just decodes the frame and fills missing bits with zeroes.
774c2c66affSColin Finck 	There can be frames that are broken and thus make do_layer() fail.
775c2c66affSColin Finck */
decode_the_frame(mpg123_handle * fr)776c2c66affSColin Finck static void decode_the_frame(mpg123_handle *fr)
777c2c66affSColin Finck {
778c2c66affSColin Finck 	size_t needed_bytes = decoder_synth_bytes(fr, frame_expect_outsamples(fr));
779c2c66affSColin Finck 	fr->clip += (fr->do_layer)(fr);
780c2c66affSColin Finck 	/*fprintf(stderr, "frame %"OFF_P": got %"SIZE_P" / %"SIZE_P"\n", fr->num,(size_p)fr->buffer.fill, (size_p)needed_bytes);*/
781c2c66affSColin Finck 	/* There could be less data than promised.
782c2c66affSColin Finck 	   Also, then debugging, we look out for coding errors that could result in _more_ data than expected. */
783c2c66affSColin Finck #ifdef DEBUG
784c2c66affSColin Finck 	if(fr->buffer.fill != needed_bytes)
785c2c66affSColin Finck 	{
786c2c66affSColin Finck #endif
787c2c66affSColin Finck 		if(fr->buffer.fill < needed_bytes)
788c2c66affSColin Finck 		{
789c2c66affSColin Finck 			if(VERBOSE2)
790c2c66affSColin Finck 			fprintf(stderr, "Note: broken frame %li, filling up with %"SIZE_P" zeroes, from %"SIZE_P"\n", (long)fr->num, (size_p)(needed_bytes-fr->buffer.fill), (size_p)fr->buffer.fill);
791c2c66affSColin Finck 
792c2c66affSColin Finck 			/*
793c2c66affSColin Finck 				One could do a loop with individual samples instead... but zero is zero
794c2c66affSColin Finck 				Actually, that is wrong: zero is mostly a series of null bytes,
795c2c66affSColin Finck 				but we have funny 8bit formats that have a different opinion on zero...
796c2c66affSColin Finck 				Unsigned 16 or 32 bit formats are handled later.
797c2c66affSColin Finck 			*/
798c2c66affSColin Finck 			memset( fr->buffer.data + fr->buffer.fill, zero_byte(fr), needed_bytes - fr->buffer.fill );
799c2c66affSColin Finck 
800c2c66affSColin Finck 			fr->buffer.fill = needed_bytes;
801c2c66affSColin Finck #ifndef NO_NTOM
802c2c66affSColin Finck 			/* ntom_val will be wrong when the decoding wasn't carried out completely */
803c2c66affSColin Finck 			ntom_set_ntom(fr, fr->num+1);
804c2c66affSColin Finck #endif
805c2c66affSColin Finck 		}
806c2c66affSColin Finck #ifdef DEBUG
807c2c66affSColin Finck 		else
808c2c66affSColin Finck 		{
809c2c66affSColin Finck 			if(NOQUIET)
810c2c66affSColin Finck 			error2("I got _more_ bytes than expected (%"SIZE_P" / %"SIZE_P"), that should not be possible!", (size_p)fr->buffer.fill, (size_p)needed_bytes);
811c2c66affSColin Finck 		}
812c2c66affSColin Finck 	}
813c2c66affSColin Finck #endif
814c2c66affSColin Finck 	postprocess_buffer(fr);
815c2c66affSColin Finck }
816c2c66affSColin Finck 
817c2c66affSColin Finck /*
818c2c66affSColin Finck 	Decode the current frame into the frame structure's buffer, accessible at the location stored in <audio>, with <bytes> bytes available.
819c2c66affSColin Finck 	<num> will contain the last decoded frame number. This function should be called after mpg123_framebyframe_next positioned the stream at a
820c2c66affSColin Finck 	valid mp3 frame. The buffer contents will get lost on the next call to mpg123_framebyframe_next or mpg123_framebyframe_decode.
821c2c66affSColin Finck 	returns
822c2c66affSColin Finck 	MPG123_OK -- successfully decoded or ignored the frame, you get your output data or in case of ignored frames 0 bytes
823c2c66affSColin Finck 	MPG123_DONE -- decoding finished, should not happen
824c2c66affSColin Finck 	MPG123_ERR -- some error occured.
825c2c66affSColin Finck 	MPG123_ERR_NULL -- audio or bytes are not pointing to valid storage addresses
826c2c66affSColin Finck 	MPG123_BAD_HANDLE -- mh has not been initialized
827c2c66affSColin Finck 	MPG123_NO_SPACE -- not enough space in buffer for safe decoding, should not happen
828c2c66affSColin Finck */
mpg123_framebyframe_decode(mpg123_handle * mh,off_t * num,unsigned char ** audio,size_t * bytes)829c2c66affSColin Finck int attribute_align_arg mpg123_framebyframe_decode(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
830c2c66affSColin Finck {
831c2c66affSColin Finck 	if(bytes == NULL) return MPG123_ERR_NULL;
832c2c66affSColin Finck 	if(audio == NULL) return MPG123_ERR_NULL;
833c2c66affSColin Finck 	if(mh == NULL)    return MPG123_BAD_HANDLE;
834c2c66affSColin Finck 	if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE;
835c2c66affSColin Finck 
836c2c66affSColin Finck 	*bytes = 0;
837c2c66affSColin Finck 	mh->buffer.fill = 0; /* always start fresh */
838c2c66affSColin Finck 	if(!mh->to_decode) return MPG123_OK;
839c2c66affSColin Finck 
840c2c66affSColin Finck 	if(num != NULL) *num = mh->num;
841c2c66affSColin Finck 	debug("decoding");
842c2c66affSColin Finck 	decode_the_frame(mh);
843c2c66affSColin Finck 	mh->to_decode = mh->to_ignore = FALSE;
844c2c66affSColin Finck 	mh->buffer.p = mh->buffer.data;
845c2c66affSColin Finck 	FRAME_BUFFERCHECK(mh);
846c2c66affSColin Finck 	*audio = mh->buffer.p;
847c2c66affSColin Finck 	*bytes = mh->buffer.fill;
848c2c66affSColin Finck 	return MPG123_OK;
849c2c66affSColin Finck }
850c2c66affSColin Finck 
851c2c66affSColin Finck /*
852c2c66affSColin Finck 	Find, read and parse the next mp3 frame while skipping junk and parsing id3 tags, lame headers, etc.
853c2c66affSColin Finck 	Prepares everything for decoding using mpg123_framebyframe_decode.
854c2c66affSColin Finck 	returns
855c2c66affSColin Finck 	MPG123_OK -- new frame was read and parsed, call mpg123_framebyframe_decode to actually decode
856c2c66affSColin Finck 	MPG123_NEW_FORMAT -- new frame was read, it results in changed output format, call mpg123_framebyframe_decode to actually decode
857c2c66affSColin Finck 	MPG123_BAD_HANDLE -- mh has not been initialized
858c2c66affSColin Finck 	MPG123_NEED_MORE  -- more input data is needed to advance to the next frame. supply more input data using mpg123_feed
859c2c66affSColin Finck */
mpg123_framebyframe_next(mpg123_handle * mh)860c2c66affSColin Finck int attribute_align_arg mpg123_framebyframe_next(mpg123_handle *mh)
861c2c66affSColin Finck {
862c2c66affSColin Finck 	int b;
863c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
864c2c66affSColin Finck 
865c2c66affSColin Finck 	mh->to_decode = mh->to_ignore = FALSE;
866c2c66affSColin Finck 	mh->buffer.fill = 0;
867c2c66affSColin Finck 
868c2c66affSColin Finck 	b = get_next_frame(mh);
869c2c66affSColin Finck 	if(b < 0) return b;
870c2c66affSColin Finck 	debug1("got next frame, %i", mh->to_decode);
871c2c66affSColin Finck 
872c2c66affSColin Finck 	/* mpg123_framebyframe_decode will return MPG123_OK with 0 bytes decoded if mh->to_decode is 0 */
873c2c66affSColin Finck 	if(!mh->to_decode)
874c2c66affSColin Finck 		return MPG123_OK;
875c2c66affSColin Finck 
876c2c66affSColin Finck 	if(mh->new_format)
877c2c66affSColin Finck 	{
878c2c66affSColin Finck 		debug("notifiying new format");
879c2c66affSColin Finck 		mh->new_format = 0;
880c2c66affSColin Finck 		return MPG123_NEW_FORMAT;
881c2c66affSColin Finck 	}
882c2c66affSColin Finck 
883c2c66affSColin Finck 	return MPG123_OK;
884c2c66affSColin Finck }
885c2c66affSColin Finck 
886c2c66affSColin Finck /*
887c2c66affSColin Finck 	Put _one_ decoded frame into the frame structure's buffer, accessible at the location stored in <audio>, with <bytes> bytes available.
888c2c66affSColin Finck 	The buffer contents will be lost on next call to mpg123_decode_frame.
889c2c66affSColin Finck 	MPG123_OK -- successfully decoded the frame, you get your output data
890c2c66affSColin Finck 	MPg123_DONE -- This is it. End.
891c2c66affSColin Finck 	MPG123_ERR -- some error occured...
892c2c66affSColin Finck 	MPG123_NEW_FORMAT -- new frame was read, it results in changed output format -> will be decoded on next call
893c2c66affSColin Finck 	MPG123_NEED_MORE  -- that should not happen as this function is intended for in-library stream reader but if you force it...
894c2c66affSColin Finck 	MPG123_NO_SPACE   -- not enough space in buffer for safe decoding, also should not happen
895c2c66affSColin Finck 
896c2c66affSColin Finck 	num will be updated to the last decoded frame number (may possibly _not_ increase, p.ex. when format changed).
897c2c66affSColin Finck */
mpg123_decode_frame(mpg123_handle * mh,off_t * num,unsigned char ** audio,size_t * bytes)898c2c66affSColin Finck int attribute_align_arg mpg123_decode_frame(mpg123_handle *mh, off_t *num, unsigned char **audio, size_t *bytes)
899c2c66affSColin Finck {
900c2c66affSColin Finck 	if(bytes != NULL) *bytes = 0;
901c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
902c2c66affSColin Finck 	if(mh->buffer.size < mh->outblock) return MPG123_NO_SPACE;
903c2c66affSColin Finck 	mh->buffer.fill = 0; /* always start fresh */
904*aa811c00SThomas Faber 	/* Be nice: Set these also for sensible values in case of error. */
905*aa811c00SThomas Faber 	if(audio) *audio = NULL;
906*aa811c00SThomas Faber 	if(bytes) *bytes = 0;
907c2c66affSColin Finck 	while(TRUE)
908c2c66affSColin Finck 	{
909c2c66affSColin Finck 		/* decode if possible */
910c2c66affSColin Finck 		if(mh->to_decode)
911c2c66affSColin Finck 		{
912*aa811c00SThomas Faber 			if(num != NULL) *num = mh->num;
913c2c66affSColin Finck 			if(mh->new_format)
914c2c66affSColin Finck 			{
915c2c66affSColin Finck 				debug("notifiying new format");
916c2c66affSColin Finck 				mh->new_format = 0;
917c2c66affSColin Finck 				return MPG123_NEW_FORMAT;
918c2c66affSColin Finck 			}
919c2c66affSColin Finck 			debug("decoding");
920c2c66affSColin Finck 
921*aa811c00SThomas Faber 			if(mh->decoder_change && decode_update(mh) < 0)
922*aa811c00SThomas Faber 				return MPG123_ERR;
923c2c66affSColin Finck 			decode_the_frame(mh);
924c2c66affSColin Finck 
925c2c66affSColin Finck 			mh->to_decode = mh->to_ignore = FALSE;
926c2c66affSColin Finck 			mh->buffer.p = mh->buffer.data;
927c2c66affSColin Finck 			FRAME_BUFFERCHECK(mh);
928c2c66affSColin Finck 			if(audio != NULL) *audio = mh->buffer.p;
929c2c66affSColin Finck 			if(bytes != NULL) *bytes = mh->buffer.fill;
930c2c66affSColin Finck 
931c2c66affSColin Finck 			return MPG123_OK;
932c2c66affSColin Finck 		}
933c2c66affSColin Finck 		else
934c2c66affSColin Finck 		{
935c2c66affSColin Finck 			int b = get_next_frame(mh);
936c2c66affSColin Finck 			if(b < 0) return b;
937c2c66affSColin Finck 			debug1("got next frame, %i", mh->to_decode);
938c2c66affSColin Finck 		}
939c2c66affSColin Finck 	}
940c2c66affSColin Finck }
941c2c66affSColin Finck 
mpg123_read(mpg123_handle * mh,void * out,size_t size,size_t * done)942*aa811c00SThomas Faber int attribute_align_arg mpg123_read(mpg123_handle *mh, void *out, size_t size, size_t *done)
943c2c66affSColin Finck {
944c2c66affSColin Finck 	return mpg123_decode(mh, NULL, 0, out, size, done);
945c2c66affSColin Finck }
946c2c66affSColin Finck 
mpg123_feed(mpg123_handle * mh,const unsigned char * in,size_t size)947c2c66affSColin Finck int attribute_align_arg mpg123_feed(mpg123_handle *mh, const unsigned char *in, size_t size)
948c2c66affSColin Finck {
949c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
950c2c66affSColin Finck #ifndef NO_FEEDER
951c2c66affSColin Finck 	if(size > 0)
952c2c66affSColin Finck 	{
953c2c66affSColin Finck 		if(in != NULL)
954c2c66affSColin Finck 		{
955c2c66affSColin Finck 			if(feed_more(mh, in, size) != 0) return MPG123_ERR;
956c2c66affSColin Finck 			else
957c2c66affSColin Finck 			{
958c2c66affSColin Finck 				/* The need for more data might have triggered an error.
959c2c66affSColin Finck 				   This one is outdated now with the new data. */
960c2c66affSColin Finck 				if(mh->err == MPG123_ERR_READER) mh->err = MPG123_OK;
961c2c66affSColin Finck 
962c2c66affSColin Finck 				return MPG123_OK;
963c2c66affSColin Finck 			}
964c2c66affSColin Finck 		}
965c2c66affSColin Finck 		else
966c2c66affSColin Finck 		{
967c2c66affSColin Finck 			mh->err = MPG123_NULL_BUFFER;
968c2c66affSColin Finck 			return MPG123_ERR;
969c2c66affSColin Finck 		}
970c2c66affSColin Finck 	}
971c2c66affSColin Finck 	return MPG123_OK;
972c2c66affSColin Finck #else
973c2c66affSColin Finck 	mh->err = MPG123_MISSING_FEATURE;
974c2c66affSColin Finck 	return MPG123_ERR;
975c2c66affSColin Finck #endif
976c2c66affSColin Finck }
977c2c66affSColin Finck 
978c2c66affSColin Finck /*
979c2c66affSColin Finck 	The old picture:
980c2c66affSColin Finck 	while(1) {
981c2c66affSColin Finck 		len = read(0,buf,16384);
982c2c66affSColin Finck 		if(len <= 0)
983c2c66affSColin Finck 			break;
984c2c66affSColin Finck 		ret = decodeMP3(&mp,buf,len,out,8192,&size);
985c2c66affSColin Finck 		while(ret == MP3_OK) {
986c2c66affSColin Finck 			write(1,out,size);
987c2c66affSColin Finck 			ret = decodeMP3(&mp,NULL,0,out,8192,&size);
988c2c66affSColin Finck 		}
989c2c66affSColin Finck 	}
990c2c66affSColin Finck */
991c2c66affSColin Finck 
mpg123_decode(mpg123_handle * mh,const unsigned char * inmemory,size_t inmemsize,void * outmem,size_t outmemsize,size_t * done)992*aa811c00SThomas Faber int attribute_align_arg mpg123_decode(mpg123_handle *mh, const unsigned char *inmemory, size_t inmemsize, void *outmem, size_t outmemsize, size_t *done)
993c2c66affSColin Finck {
994c2c66affSColin Finck 	int ret = MPG123_OK;
995c2c66affSColin Finck 	size_t mdone = 0;
996*aa811c00SThomas Faber 	unsigned char *outmemory = outmem;
997c2c66affSColin Finck 
998c2c66affSColin Finck 	if(done != NULL) *done = 0;
999c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1000c2c66affSColin Finck 	if(inmemsize > 0 && mpg123_feed(mh, inmemory, inmemsize) != MPG123_OK)
1001c2c66affSColin Finck 	{
1002c2c66affSColin Finck 		ret = MPG123_ERR;
1003c2c66affSColin Finck 		goto decodeend;
1004c2c66affSColin Finck 	}
1005c2c66affSColin Finck 	if(outmemory == NULL) outmemsize = 0; /* Not just give error, give chance to get a status message. */
1006c2c66affSColin Finck 
1007c2c66affSColin Finck 	while(ret == MPG123_OK)
1008c2c66affSColin Finck 	{
1009c2c66affSColin Finck 		debug4("decode loop, fill %i (%li vs. %li); to_decode: %i", (int)mh->buffer.fill, (long)mh->num, (long)mh->firstframe, mh->to_decode);
1010c2c66affSColin Finck 		/* Decode a frame that has been read before.
1011c2c66affSColin Finck 		   This only happens when buffer is empty! */
1012c2c66affSColin Finck 		if(mh->to_decode)
1013c2c66affSColin Finck 		{
1014c2c66affSColin Finck 			if(mh->new_format)
1015c2c66affSColin Finck 			{
1016c2c66affSColin Finck 				debug("notifiying new format");
1017c2c66affSColin Finck 				mh->new_format = 0;
1018c2c66affSColin Finck 				ret = MPG123_NEW_FORMAT;
1019c2c66affSColin Finck 				goto decodeend;
1020c2c66affSColin Finck 			}
1021c2c66affSColin Finck 			if(mh->buffer.size - mh->buffer.fill < mh->outblock)
1022c2c66affSColin Finck 			{
1023c2c66affSColin Finck 				ret = MPG123_NO_SPACE;
1024c2c66affSColin Finck 				goto decodeend;
1025c2c66affSColin Finck 			}
1026*aa811c00SThomas Faber 			if(mh->decoder_change && decode_update(mh) < 0)
1027*aa811c00SThomas Faber 			{
1028*aa811c00SThomas Faber 				ret = MPG123_ERR;
1029*aa811c00SThomas Faber 				goto decodeend;
1030*aa811c00SThomas Faber 			}
1031c2c66affSColin Finck 			decode_the_frame(mh);
1032c2c66affSColin Finck 			mh->to_decode = mh->to_ignore = FALSE;
1033c2c66affSColin Finck 			mh->buffer.p = mh->buffer.data;
1034c2c66affSColin Finck 			debug2("decoded frame %li, got %li samples in buffer", (long)mh->num, (long)(mh->buffer.fill / (samples_to_bytes(mh, 1))));
1035c2c66affSColin Finck 			FRAME_BUFFERCHECK(mh);
1036c2c66affSColin Finck 		}
1037c2c66affSColin Finck 		if(mh->buffer.fill) /* Copy (part of) the decoded data to the caller's buffer. */
1038c2c66affSColin Finck 		{
1039c2c66affSColin Finck 			/* get what is needed - or just what is there */
1040c2c66affSColin Finck 			int a = mh->buffer.fill > (outmemsize - mdone) ? outmemsize - mdone : mh->buffer.fill;
1041c2c66affSColin Finck 			debug4("buffer fill: %i; copying %i (%i - %li)", (int)mh->buffer.fill, a, (int)outmemsize, (long)mdone);
1042c2c66affSColin Finck 			memcpy(outmemory, mh->buffer.p, a);
1043c2c66affSColin Finck 			/* less data in frame buffer, less needed, output pointer increase, more data given... */
1044c2c66affSColin Finck 			mh->buffer.fill -= a;
1045c2c66affSColin Finck 			outmemory  += a;
1046c2c66affSColin Finck 			mdone += a;
1047c2c66affSColin Finck 			mh->buffer.p += a;
1048c2c66affSColin Finck 			if(!(outmemsize > mdone)) goto decodeend;
1049c2c66affSColin Finck 		}
1050c2c66affSColin Finck 		else /* If we didn't have data, get a new frame. */
1051c2c66affSColin Finck 		{
1052c2c66affSColin Finck 			int b = get_next_frame(mh);
1053c2c66affSColin Finck 			if(b < 0){ ret = b; goto decodeend; }
1054c2c66affSColin Finck 		}
1055c2c66affSColin Finck 	}
1056c2c66affSColin Finck decodeend:
1057c2c66affSColin Finck 	if(done != NULL) *done = mdone;
1058c2c66affSColin Finck 	return ret;
1059c2c66affSColin Finck }
1060c2c66affSColin Finck 
mpg123_clip(mpg123_handle * mh)1061c2c66affSColin Finck long attribute_align_arg mpg123_clip(mpg123_handle *mh)
1062c2c66affSColin Finck {
1063c2c66affSColin Finck 	long ret = 0;
1064c2c66affSColin Finck 
1065c2c66affSColin Finck 	if(mh != NULL)
1066c2c66affSColin Finck 	{
1067c2c66affSColin Finck 		ret = mh->clip;
1068c2c66affSColin Finck 		mh->clip = 0;
1069c2c66affSColin Finck 	}
1070c2c66affSColin Finck 	return ret;
1071c2c66affSColin Finck }
1072c2c66affSColin Finck 
1073c2c66affSColin Finck /* Simples: Track needs initializtion if no initial frame has been read yet. */
1074c2c66affSColin Finck #define track_need_init(mh) ((mh)->num < 0)
1075c2c66affSColin Finck 
init_track(mpg123_handle * mh)1076c2c66affSColin Finck static int init_track(mpg123_handle *mh)
1077c2c66affSColin Finck {
1078c2c66affSColin Finck 	if(track_need_init(mh))
1079c2c66affSColin Finck 	{
1080c2c66affSColin Finck 		/* Fresh track, need first frame for basic info. */
1081c2c66affSColin Finck 		int b = get_next_frame(mh);
1082c2c66affSColin Finck 		if(b < 0) return b;
1083c2c66affSColin Finck 	}
1084c2c66affSColin Finck 	return 0;
1085c2c66affSColin Finck }
1086c2c66affSColin Finck 
mpg123_info(mpg123_handle * mh,struct mpg123_frameinfo * mi)1087c2c66affSColin Finck int attribute_align_arg mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *mi)
1088c2c66affSColin Finck {
1089c2c66affSColin Finck 	int b;
1090c2c66affSColin Finck 
1091c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1092c2c66affSColin Finck 	if(mi == NULL)
1093c2c66affSColin Finck 	{
1094c2c66affSColin Finck 		mh->err = MPG123_ERR_NULL;
1095c2c66affSColin Finck 		return MPG123_ERR;
1096c2c66affSColin Finck 	}
1097c2c66affSColin Finck 	b = init_track(mh);
1098c2c66affSColin Finck 	if(b < 0) return b;
1099c2c66affSColin Finck 
1100c2c66affSColin Finck 	mi->version = mh->mpeg25 ? MPG123_2_5 : (mh->lsf ? MPG123_2_0 : MPG123_1_0);
1101c2c66affSColin Finck 	mi->layer = mh->lay;
1102c2c66affSColin Finck 	mi->rate = frame_freq(mh);
1103c2c66affSColin Finck 	switch(mh->mode)
1104c2c66affSColin Finck 	{
1105c2c66affSColin Finck 		case 0: mi->mode = MPG123_M_STEREO; break;
1106c2c66affSColin Finck 		case 1: mi->mode = MPG123_M_JOINT;  break;
1107c2c66affSColin Finck 		case 2: mi->mode = MPG123_M_DUAL;   break;
1108c2c66affSColin Finck 		case 3: mi->mode = MPG123_M_MONO;   break;
1109*aa811c00SThomas Faber 		default: mi->mode = 0; // Nothing good to do here.
1110c2c66affSColin Finck 	}
1111c2c66affSColin Finck 	mi->mode_ext = mh->mode_ext;
1112c2c66affSColin Finck 	mi->framesize = mh->framesize+4; /* Include header. */
1113c2c66affSColin Finck 	mi->flags = 0;
1114c2c66affSColin Finck 	if(mh->error_protection) mi->flags |= MPG123_CRC;
1115c2c66affSColin Finck 	if(mh->copyright)        mi->flags |= MPG123_COPYRIGHT;
1116c2c66affSColin Finck 	if(mh->extension)        mi->flags |= MPG123_PRIVATE;
1117c2c66affSColin Finck 	if(mh->original)         mi->flags |= MPG123_ORIGINAL;
1118c2c66affSColin Finck 	mi->emphasis = mh->emphasis;
1119c2c66affSColin Finck 	mi->bitrate  = frame_bitrate(mh);
1120c2c66affSColin Finck 	mi->abr_rate = mh->abr_rate;
1121c2c66affSColin Finck 	mi->vbr = mh->vbr;
1122c2c66affSColin Finck 	return MPG123_OK;
1123c2c66affSColin Finck }
1124c2c66affSColin Finck 
mpg123_getformat2(mpg123_handle * mh,long * rate,int * channels,int * encoding,int clear_flag)1125c2c66affSColin Finck int attribute_align_arg mpg123_getformat2( mpg123_handle *mh
1126c2c66affSColin Finck ,	long *rate, int *channels, int *encoding, int clear_flag )
1127c2c66affSColin Finck {
1128c2c66affSColin Finck 	int b;
1129c2c66affSColin Finck 
1130c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1131c2c66affSColin Finck 	b = init_track(mh);
1132c2c66affSColin Finck 	if(b < 0) return b;
1133c2c66affSColin Finck 
1134c2c66affSColin Finck 	if(rate != NULL) *rate = mh->af.rate;
1135c2c66affSColin Finck 	if(channels != NULL) *channels = mh->af.channels;
1136c2c66affSColin Finck 	if(encoding != NULL) *encoding = mh->af.encoding;
1137c2c66affSColin Finck 	if(clear_flag) mh->new_format = 0;
1138c2c66affSColin Finck 	return MPG123_OK;
1139c2c66affSColin Finck }
1140c2c66affSColin Finck 
mpg123_getformat(mpg123_handle * mh,long * rate,int * channels,int * encoding)1141c2c66affSColin Finck int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding)
1142c2c66affSColin Finck {
1143c2c66affSColin Finck 	return mpg123_getformat2(mh, rate, channels, encoding, 1);
1144c2c66affSColin Finck }
1145c2c66affSColin Finck 
mpg123_timeframe(mpg123_handle * mh,double seconds)1146c2c66affSColin Finck off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds)
1147c2c66affSColin Finck {
1148c2c66affSColin Finck 	off_t b;
1149c2c66affSColin Finck 
1150c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1151c2c66affSColin Finck 	b = init_track(mh);
1152c2c66affSColin Finck 	if(b<0) return b;
1153c2c66affSColin Finck 	return (off_t)(seconds/mpg123_tpf(mh));
1154c2c66affSColin Finck }
1155c2c66affSColin Finck 
1156c2c66affSColin Finck /*
1157c2c66affSColin Finck 	Now, where are we? We need to know the last decoded frame... and what's left of it in buffer.
1158c2c66affSColin Finck 	The current frame number can mean the last decoded frame or the to-be-decoded frame.
1159c2c66affSColin Finck 	If mh->to_decode, then mh->num frames have been decoded, the frame mh->num now coming next.
1160c2c66affSColin Finck 	If not, we have the possibility of mh->num+1 frames being decoded or nothing at all.
1161c2c66affSColin Finck 	Then, there is firstframe...when we didn't reach it yet, then the next data will come from there.
1162c2c66affSColin Finck 	mh->num starts with -1
1163c2c66affSColin Finck */
mpg123_tell(mpg123_handle * mh)1164c2c66affSColin Finck off_t attribute_align_arg mpg123_tell(mpg123_handle *mh)
1165c2c66affSColin Finck {
1166c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1167c2c66affSColin Finck 	if(track_need_init(mh)) return 0;
1168c2c66affSColin Finck 	/* Now we have all the info at hand. */
1169c2c66affSColin Finck 	debug5("tell: %li/%i first %li buffer %lu; frame_outs=%li", (long)mh->num, mh->to_decode, (long)mh->firstframe, (unsigned long)mh->buffer.fill, (long)frame_outs(mh, mh->num));
1170c2c66affSColin Finck 
1171c2c66affSColin Finck 	{ /* Funny block to keep C89 happy. */
1172c2c66affSColin Finck 		off_t pos = 0;
1173c2c66affSColin Finck 		if((mh->num < mh->firstframe) || (mh->num == mh->firstframe && mh->to_decode))
1174c2c66affSColin Finck 		{ /* We are at the beginning, expect output from firstframe on. */
1175c2c66affSColin Finck 			pos = frame_outs(mh, mh->firstframe);
1176c2c66affSColin Finck #ifdef GAPLESS
1177c2c66affSColin Finck 			pos += mh->firstoff;
1178c2c66affSColin Finck #endif
1179c2c66affSColin Finck 		}
1180c2c66affSColin Finck 		else if(mh->to_decode)
1181c2c66affSColin Finck 		{ /* We start fresh with this frame. Buffer should be empty, but we make sure to count it in.  */
1182c2c66affSColin Finck 			pos = frame_outs(mh, mh->num) - bytes_to_samples(mh, mh->buffer.fill);
1183c2c66affSColin Finck 		}
1184c2c66affSColin Finck 		else
1185c2c66affSColin Finck 		{ /* We serve what we have in buffer and then the beginning of next frame... */
1186c2c66affSColin Finck 			pos = frame_outs(mh, mh->num+1) - bytes_to_samples(mh, mh->buffer.fill);
1187c2c66affSColin Finck 		}
1188c2c66affSColin Finck 		/* Substract padding and delay from the beginning. */
1189c2c66affSColin Finck 		pos = SAMPLE_ADJUST(mh,pos);
1190c2c66affSColin Finck 		/* Negative sample offsets are not right, less than nothing is still nothing. */
1191c2c66affSColin Finck 		return pos>0 ? pos : 0;
1192c2c66affSColin Finck 	}
1193c2c66affSColin Finck }
1194c2c66affSColin Finck 
mpg123_tellframe(mpg123_handle * mh)1195c2c66affSColin Finck off_t attribute_align_arg mpg123_tellframe(mpg123_handle *mh)
1196c2c66affSColin Finck {
1197c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1198c2c66affSColin Finck 	if(mh->num < mh->firstframe) return mh->firstframe;
1199c2c66affSColin Finck 	if(mh->to_decode) return mh->num;
1200c2c66affSColin Finck 	/* Consider firstoff? */
1201c2c66affSColin Finck 	return mh->buffer.fill ? mh->num : mh->num + 1;
1202c2c66affSColin Finck }
1203c2c66affSColin Finck 
mpg123_tell_stream(mpg123_handle * mh)1204c2c66affSColin Finck off_t attribute_align_arg mpg123_tell_stream(mpg123_handle *mh)
1205c2c66affSColin Finck {
1206c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1207c2c66affSColin Finck 	/* mh->rd is at least a bad_reader, so no worry. */
1208c2c66affSColin Finck 	return mh->rd->tell(mh);
1209c2c66affSColin Finck }
1210c2c66affSColin Finck 
do_the_seek(mpg123_handle * mh)1211c2c66affSColin Finck static int do_the_seek(mpg123_handle *mh)
1212c2c66affSColin Finck {
1213c2c66affSColin Finck 	int b;
1214c2c66affSColin Finck 	off_t fnum = SEEKFRAME(mh);
1215c2c66affSColin Finck 	mh->buffer.fill = 0;
1216c2c66affSColin Finck 
1217c2c66affSColin Finck 	/* If we are inside the ignoreframe - firstframe window, we may get away without actual seeking. */
1218c2c66affSColin Finck 	if(mh->num < mh->firstframe)
1219c2c66affSColin Finck 	{
1220c2c66affSColin Finck 		mh->to_decode = FALSE; /* In any case, don't decode the current frame, perhaps ignore instead. */
1221c2c66affSColin Finck 		if(mh->num > fnum) return MPG123_OK;
1222c2c66affSColin Finck 	}
1223c2c66affSColin Finck 
1224c2c66affSColin Finck 	/* If we are already there, we are fine either for decoding or for ignoring. */
1225c2c66affSColin Finck 	if(mh->num == fnum && (mh->to_decode || fnum < mh->firstframe)) return MPG123_OK;
1226c2c66affSColin Finck 	/* We have the frame before... just go ahead as normal. */
1227c2c66affSColin Finck 	if(mh->num == fnum-1)
1228c2c66affSColin Finck 	{
1229c2c66affSColin Finck 		mh->to_decode = FALSE;
1230c2c66affSColin Finck 		return MPG123_OK;
1231c2c66affSColin Finck 	}
1232c2c66affSColin Finck 
1233c2c66affSColin Finck 	/* OK, real seeking follows... clear buffers and go for it. */
1234c2c66affSColin Finck 	frame_buffers_reset(mh);
1235c2c66affSColin Finck #ifndef NO_NTOM
1236c2c66affSColin Finck 	if(mh->down_sample == 3)
1237c2c66affSColin Finck 	{
1238c2c66affSColin Finck 		ntom_set_ntom(mh, fnum);
1239c2c66affSColin Finck 		debug3("fixed ntom for frame %"OFF_P" to %lu, num=%"OFF_P, (off_p)fnum, mh->ntom_val[0], (off_p)mh->num);
1240c2c66affSColin Finck 	}
1241c2c66affSColin Finck #endif
1242c2c66affSColin Finck 	b = mh->rd->seek_frame(mh, fnum);
1243c2c66affSColin Finck 	if(mh->header_change > 1)
1244c2c66affSColin Finck 	{
1245c2c66affSColin Finck 		if(decode_update(mh) < 0) return MPG123_ERR;
1246c2c66affSColin Finck 		mh->header_change = 0;
1247c2c66affSColin Finck 	}
1248c2c66affSColin Finck 	debug1("seek_frame returned: %i", b);
1249c2c66affSColin Finck 	if(b<0) return b;
1250c2c66affSColin Finck 	/* Only mh->to_ignore is TRUE. */
1251c2c66affSColin Finck 	if(mh->num < mh->firstframe) mh->to_decode = FALSE;
1252c2c66affSColin Finck 
1253c2c66affSColin Finck 	mh->playnum = mh->num;
1254c2c66affSColin Finck 	return 0;
1255c2c66affSColin Finck }
1256c2c66affSColin Finck 
mpg123_seek(mpg123_handle * mh,off_t sampleoff,int whence)1257c2c66affSColin Finck off_t attribute_align_arg mpg123_seek(mpg123_handle *mh, off_t sampleoff, int whence)
1258c2c66affSColin Finck {
1259c2c66affSColin Finck 	int b;
1260c2c66affSColin Finck 	off_t pos;
1261c2c66affSColin Finck 
1262c2c66affSColin Finck 	pos = mpg123_tell(mh); /* adjusted samples */
1263c2c66affSColin Finck 	/* pos < 0 also can mean that simply a former seek failed at the lower levels.
1264c2c66affSColin Finck 	  In that case, we only allow absolute seeks. */
1265c2c66affSColin Finck 	if(pos < 0 && whence != SEEK_SET)
1266c2c66affSColin Finck 	{ /* Unless we got the obvious error of NULL handle, this is a special seek failure. */
1267c2c66affSColin Finck 		if(mh != NULL) mh->err = MPG123_NO_RELSEEK;
1268c2c66affSColin Finck 		return MPG123_ERR;
1269c2c66affSColin Finck 	}
1270c2c66affSColin Finck 	if((b=init_track(mh)) < 0) return b;
1271c2c66affSColin Finck 	switch(whence)
1272c2c66affSColin Finck 	{
1273c2c66affSColin Finck 		case SEEK_CUR: pos += sampleoff; break;
1274c2c66affSColin Finck 		case SEEK_SET: pos  = sampleoff; break;
1275c2c66affSColin Finck 		case SEEK_END:
1276c2c66affSColin Finck 			/* When we do not know the end already, we can try to find it. */
1277c2c66affSColin Finck 			if(mh->track_frames < 1 && (mh->rdat.flags & READER_SEEKABLE))
1278c2c66affSColin Finck 			mpg123_scan(mh);
1279c2c66affSColin Finck 			if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff;
1280c2c66affSColin Finck #ifdef GAPLESS
1281c2c66affSColin Finck 			else if(mh->end_os > 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff;
1282c2c66affSColin Finck #endif
1283c2c66affSColin Finck 			else
1284c2c66affSColin Finck 			{
1285c2c66affSColin Finck 				mh->err = MPG123_NO_SEEK_FROM_END;
1286c2c66affSColin Finck 				return MPG123_ERR;
1287c2c66affSColin Finck 			}
1288c2c66affSColin Finck 		break;
1289c2c66affSColin Finck 		default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR;
1290c2c66affSColin Finck 	}
1291c2c66affSColin Finck 	if(pos < 0) pos = 0;
1292c2c66affSColin Finck 	/* pos now holds the wanted sample offset in adjusted samples */
1293c2c66affSColin Finck 	frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos));
1294c2c66affSColin Finck 	pos = do_the_seek(mh);
1295c2c66affSColin Finck 	if(pos < 0) return pos;
1296c2c66affSColin Finck 
1297c2c66affSColin Finck 	return mpg123_tell(mh);
1298c2c66affSColin Finck }
1299c2c66affSColin Finck 
1300c2c66affSColin Finck /*
1301c2c66affSColin Finck 	A bit more tricky... libmpg123 does not do the seeking itself.
1302c2c66affSColin Finck 	All it can do is to ignore frames until the wanted one is there.
1303c2c66affSColin Finck 	The caller doesn't know where a specific frame starts and mpg123 also only knows the general region after it scanned the file.
1304c2c66affSColin Finck 	Well, it is tricky...
1305c2c66affSColin Finck */
mpg123_feedseek(mpg123_handle * mh,off_t sampleoff,int whence,off_t * input_offset)1306c2c66affSColin Finck off_t attribute_align_arg mpg123_feedseek(mpg123_handle *mh, off_t sampleoff, int whence, off_t *input_offset)
1307c2c66affSColin Finck {
1308c2c66affSColin Finck 	int b;
1309c2c66affSColin Finck 	off_t pos;
1310c2c66affSColin Finck 
1311c2c66affSColin Finck 	pos = mpg123_tell(mh); /* adjusted samples */
1312c2c66affSColin Finck 	debug3("seek from %li to %li (whence=%i)", (long)pos, (long)sampleoff, whence);
1313c2c66affSColin Finck 	/* The special seek error handling does not apply here... there is no lowlevel I/O. */
1314c2c66affSColin Finck 	if(pos < 0) return pos; /* mh == NULL is covered in mpg123_tell() */
1315c2c66affSColin Finck #ifndef NO_FEEDER
1316c2c66affSColin Finck 	if(input_offset == NULL)
1317c2c66affSColin Finck 	{
1318c2c66affSColin Finck 		mh->err = MPG123_NULL_POINTER;
1319c2c66affSColin Finck 		return MPG123_ERR;
1320c2c66affSColin Finck 	}
1321c2c66affSColin Finck 
1322c2c66affSColin Finck 	if((b=init_track(mh)) < 0) return b; /* May need more to do anything at all. */
1323c2c66affSColin Finck 
1324c2c66affSColin Finck 	switch(whence)
1325c2c66affSColin Finck 	{
1326c2c66affSColin Finck 		case SEEK_CUR: pos += sampleoff; break;
1327c2c66affSColin Finck 		case SEEK_SET: pos  = sampleoff; break;
1328c2c66affSColin Finck 		case SEEK_END:
1329c2c66affSColin Finck 			if(mh->track_frames > 0) pos = SAMPLE_ADJUST(mh,frame_outs(mh, mh->track_frames)) - sampleoff;
1330c2c66affSColin Finck #ifdef GAPLESS
1331c2c66affSColin Finck 			else if(mh->end_os >= 0) pos = SAMPLE_ADJUST(mh,mh->end_os) - sampleoff;
1332c2c66affSColin Finck #endif
1333c2c66affSColin Finck 			else
1334c2c66affSColin Finck 			{
1335c2c66affSColin Finck 				mh->err = MPG123_NO_SEEK_FROM_END;
1336c2c66affSColin Finck 				return MPG123_ERR;
1337c2c66affSColin Finck 			}
1338c2c66affSColin Finck 		break;
1339c2c66affSColin Finck 		default: mh->err = MPG123_BAD_WHENCE; return MPG123_ERR;
1340c2c66affSColin Finck 	}
1341c2c66affSColin Finck 	if(pos < 0) pos = 0;
1342c2c66affSColin Finck 	frame_set_seek(mh, SAMPLE_UNADJUST(mh,pos));
1343c2c66affSColin Finck 	pos = SEEKFRAME(mh);
1344c2c66affSColin Finck 	mh->buffer.fill = 0;
1345c2c66affSColin Finck 
1346c2c66affSColin Finck 	/* Shortcuts without modifying input stream. */
1347c2c66affSColin Finck 	*input_offset = mh->rdat.buffer.fileoff + mh->rdat.buffer.size;
1348c2c66affSColin Finck 	if(mh->num < mh->firstframe) mh->to_decode = FALSE;
1349c2c66affSColin Finck 	if(mh->num == pos && mh->to_decode) goto feedseekend;
1350c2c66affSColin Finck 	if(mh->num == pos-1) goto feedseekend;
1351c2c66affSColin Finck 	/* Whole way. */
1352c2c66affSColin Finck 	*input_offset = feed_set_pos(mh, frame_index_find(mh, SEEKFRAME(mh), &pos));
1353c2c66affSColin Finck 	mh->num = pos-1; /* The next read frame will have num = pos. */
1354c2c66affSColin Finck 	if(*input_offset < 0) return MPG123_ERR;
1355c2c66affSColin Finck 
1356c2c66affSColin Finck feedseekend:
1357c2c66affSColin Finck 	return mpg123_tell(mh);
1358c2c66affSColin Finck #else
1359c2c66affSColin Finck 	mh->err = MPG123_MISSING_FEATURE;
1360c2c66affSColin Finck 	return MPG123_ERR;
1361c2c66affSColin Finck #endif
1362c2c66affSColin Finck }
1363c2c66affSColin Finck 
mpg123_seek_frame(mpg123_handle * mh,off_t offset,int whence)1364c2c66affSColin Finck off_t attribute_align_arg mpg123_seek_frame(mpg123_handle *mh, off_t offset, int whence)
1365c2c66affSColin Finck {
1366c2c66affSColin Finck 	int b;
1367c2c66affSColin Finck 	off_t pos = 0;
1368c2c66affSColin Finck 
1369c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1370c2c66affSColin Finck 	if((b=init_track(mh)) < 0) return b;
1371c2c66affSColin Finck 
1372c2c66affSColin Finck 	/* Could play games here with to_decode... */
1373c2c66affSColin Finck 	pos = mh->num;
1374c2c66affSColin Finck 	switch(whence)
1375c2c66affSColin Finck 	{
1376c2c66affSColin Finck 		case SEEK_CUR: pos += offset; break;
1377c2c66affSColin Finck 		case SEEK_SET: pos  = offset; break;
1378c2c66affSColin Finck 		case SEEK_END:
1379c2c66affSColin Finck 			if(mh->track_frames > 0) pos = mh->track_frames - offset;
1380c2c66affSColin Finck 			else
1381c2c66affSColin Finck 			{
1382c2c66affSColin Finck 				mh->err = MPG123_NO_SEEK_FROM_END;
1383c2c66affSColin Finck 				return MPG123_ERR;
1384c2c66affSColin Finck 			}
1385c2c66affSColin Finck 		break;
1386c2c66affSColin Finck 		default:
1387c2c66affSColin Finck 			mh->err = MPG123_BAD_WHENCE;
1388c2c66affSColin Finck 			return MPG123_ERR;
1389c2c66affSColin Finck 	}
1390c2c66affSColin Finck 	if(pos < 0) pos = 0;
1391c2c66affSColin Finck 	/* Not limiting the possible position on end for the chance that there might be more to the stream than announced via track_frames. */
1392c2c66affSColin Finck 
1393c2c66affSColin Finck 	frame_set_frameseek(mh, pos);
1394c2c66affSColin Finck 	pos = do_the_seek(mh);
1395c2c66affSColin Finck 	if(pos < 0) return pos;
1396c2c66affSColin Finck 
1397c2c66affSColin Finck 	return mpg123_tellframe(mh);
1398c2c66affSColin Finck }
1399c2c66affSColin Finck 
mpg123_set_filesize(mpg123_handle * mh,off_t size)1400c2c66affSColin Finck int attribute_align_arg mpg123_set_filesize(mpg123_handle *mh, off_t size)
1401c2c66affSColin Finck {
1402c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1403c2c66affSColin Finck 
1404c2c66affSColin Finck 	mh->rdat.filelen = size;
1405c2c66affSColin Finck 	return MPG123_OK;
1406c2c66affSColin Finck }
1407c2c66affSColin Finck 
mpg123_framelength(mpg123_handle * mh)1408c2c66affSColin Finck off_t attribute_align_arg mpg123_framelength(mpg123_handle *mh)
1409c2c66affSColin Finck {
1410c2c66affSColin Finck 	int b;
1411c2c66affSColin Finck 	if(mh == NULL)
1412c2c66affSColin Finck 		return MPG123_ERR;
1413c2c66affSColin Finck 	b = init_track(mh);
1414c2c66affSColin Finck 	if(b<0)
1415c2c66affSColin Finck 		return b;
1416c2c66affSColin Finck 	if(mh->track_frames > 0)
1417c2c66affSColin Finck 		return mh->track_frames;
1418c2c66affSColin Finck 	if(mh->rdat.filelen > 0)
1419c2c66affSColin Finck 	{ /* A bad estimate. Ignoring tags 'n stuff. */
1420c2c66affSColin Finck 		double bpf = mh->mean_framesize > 0.
1421c2c66affSColin Finck 			? mh->mean_framesize
1422c2c66affSColin Finck 			: compute_bpf(mh);
1423c2c66affSColin Finck 		return (off_t)((double)(mh->rdat.filelen)/bpf+0.5);
1424c2c66affSColin Finck 	}
1425c2c66affSColin Finck 	/* Last resort: No view of the future, can at least count the frames that
1426c2c66affSColin Finck 	   were already parsed. */
1427c2c66affSColin Finck 	if(mh->num > -1)
1428c2c66affSColin Finck 		return mh->num+1;
1429c2c66affSColin Finck 	/* Giving up. */
1430c2c66affSColin Finck 	return MPG123_ERR;
1431c2c66affSColin Finck }
1432c2c66affSColin Finck 
mpg123_length(mpg123_handle * mh)1433c2c66affSColin Finck off_t attribute_align_arg mpg123_length(mpg123_handle *mh)
1434c2c66affSColin Finck {
1435c2c66affSColin Finck 	int b;
1436c2c66affSColin Finck 	off_t length;
1437c2c66affSColin Finck 
1438c2c66affSColin Finck 	if(mh == NULL) return MPG123_ERR;
1439c2c66affSColin Finck 	b = init_track(mh);
1440c2c66affSColin Finck 	if(b<0) return b;
1441c2c66affSColin Finck 	if(mh->track_samples > -1) length = mh->track_samples;
1442c2c66affSColin Finck 	else if(mh->track_frames > 0) length = mh->track_frames*mh->spf;
1443c2c66affSColin Finck 	else if(mh->rdat.filelen > 0) /* Let the case of 0 length just fall through. */
1444c2c66affSColin Finck 	{
1445c2c66affSColin Finck 		/* A bad estimate. Ignoring tags 'n stuff. */
1446c2c66affSColin Finck 		double bpf = mh->mean_framesize ? mh->mean_framesize : compute_bpf(mh);
1447c2c66affSColin Finck 		length = (off_t)((double)(mh->rdat.filelen)/bpf*mh->spf);
1448c2c66affSColin Finck 	}
1449c2c66affSColin Finck 	else if(mh->rdat.filelen == 0) return mpg123_tell(mh); /* we could be in feeder mode */
1450c2c66affSColin Finck 	else return MPG123_ERR; /* No length info there! */
1451c2c66affSColin Finck 
1452c2c66affSColin Finck 	debug1("mpg123_length: internal sample length: %"OFF_P, (off_p)length);
1453c2c66affSColin Finck 
1454c2c66affSColin Finck 	length = frame_ins2outs(mh, length);
1455c2c66affSColin Finck 	debug1("mpg123_length: external sample length: %"OFF_P, (off_p)length);
1456c2c66affSColin Finck 	length = SAMPLE_ADJUST(mh,length);
1457c2c66affSColin Finck 	return length;
1458c2c66affSColin Finck }
1459c2c66affSColin Finck 
1460c2c66affSColin Finck 
mpg123_scan(mpg123_handle * mh)1461c2c66affSColin Finck int attribute_align_arg mpg123_scan(mpg123_handle *mh)
1462c2c66affSColin Finck {
1463c2c66affSColin Finck 	int b;
1464c2c66affSColin Finck 	off_t oldpos;
1465c2c66affSColin Finck 	off_t track_frames = 0;
1466c2c66affSColin Finck 	off_t track_samples = 0;
1467c2c66affSColin Finck 
1468c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1469c2c66affSColin Finck 	if(!(mh->rdat.flags & READER_SEEKABLE)){ mh->err = MPG123_NO_SEEK; return MPG123_ERR; }
1470c2c66affSColin Finck 	/* Scan through the _whole_ file, since the current position is no count but computed assuming constant samples per frame. */
1471c2c66affSColin Finck 	/* Also, we can just keep the current buffer and seek settings. Just operate on input frames here. */
1472c2c66affSColin Finck 	debug("issuing scan");
1473c2c66affSColin Finck 	b = init_track(mh); /* mh->num >= 0 !! */
1474c2c66affSColin Finck 	if(b<0)
1475c2c66affSColin Finck 	{
1476c2c66affSColin Finck 		if(b == MPG123_DONE) return MPG123_OK;
1477c2c66affSColin Finck 		else return MPG123_ERR; /* Must be error here, NEED_MORE is not for seekable streams. */
1478c2c66affSColin Finck 	}
1479c2c66affSColin Finck 	oldpos = mpg123_tell(mh);
1480c2c66affSColin Finck 	b = mh->rd->seek_frame(mh, 0);
1481c2c66affSColin Finck 	if(b<0 || mh->num != 0) return MPG123_ERR;
1482c2c66affSColin Finck 	/* One frame must be there now. */
1483c2c66affSColin Finck 	track_frames = 1;
1484c2c66affSColin Finck 	track_samples = mh->spf; /* Internal samples. */
1485c2c66affSColin Finck 	debug("TODO: We should disable gapless code when encountering inconsistent mh->spf!");
1486c2c66affSColin Finck 	debug("      ... at least unset MPG123_ACCURATE.");
1487c2c66affSColin Finck 	/* Do not increment mh->track_frames in the loop as tha would confuse Frankenstein detection. */
1488c2c66affSColin Finck 	while(read_frame(mh) == 1)
1489c2c66affSColin Finck 	{
1490c2c66affSColin Finck 		++track_frames;
1491c2c66affSColin Finck 		track_samples += mh->spf;
1492c2c66affSColin Finck 	}
1493c2c66affSColin Finck 	mh->track_frames = track_frames;
1494c2c66affSColin Finck 	mh->track_samples = track_samples;
1495c2c66affSColin Finck 	debug2("Scanning yielded %"OFF_P" track samples, %"OFF_P" frames.", (off_p)mh->track_samples, (off_p)mh->track_frames);
1496c2c66affSColin Finck #ifdef GAPLESS
1497c2c66affSColin Finck 	/* Also, think about usefulness of that extra value track_samples ... it could be used for consistency checking. */
1498c2c66affSColin Finck 	if(mh->p.flags & MPG123_GAPLESS) frame_gapless_update(mh, mh->track_samples);
1499c2c66affSColin Finck #endif
1500c2c66affSColin Finck 	return mpg123_seek(mh, oldpos, SEEK_SET) >= 0 ? MPG123_OK : MPG123_ERR;
1501c2c66affSColin Finck }
1502c2c66affSColin Finck 
mpg123_meta_check(mpg123_handle * mh)1503c2c66affSColin Finck int attribute_align_arg mpg123_meta_check(mpg123_handle *mh)
1504c2c66affSColin Finck {
1505c2c66affSColin Finck 	if(mh != NULL) return mh->metaflags;
1506c2c66affSColin Finck 	else return 0;
1507c2c66affSColin Finck }
1508c2c66affSColin Finck 
mpg123_meta_free(mpg123_handle * mh)1509c2c66affSColin Finck void attribute_align_arg mpg123_meta_free(mpg123_handle *mh)
1510c2c66affSColin Finck {
1511c2c66affSColin Finck 	if(mh == NULL) return;
1512c2c66affSColin Finck 
1513c2c66affSColin Finck 	reset_id3(mh);
1514c2c66affSColin Finck 	reset_icy(&mh->icy);
1515c2c66affSColin Finck }
1516c2c66affSColin Finck 
mpg123_id3(mpg123_handle * mh,mpg123_id3v1 ** v1,mpg123_id3v2 ** v2)1517c2c66affSColin Finck int attribute_align_arg mpg123_id3(mpg123_handle *mh, mpg123_id3v1 **v1, mpg123_id3v2 **v2)
1518c2c66affSColin Finck {
1519c2c66affSColin Finck 	if(v1 != NULL) *v1 = NULL;
1520c2c66affSColin Finck 	if(v2 != NULL) *v2 = NULL;
1521c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1522c2c66affSColin Finck 
1523c2c66affSColin Finck 	if(mh->metaflags & MPG123_ID3)
1524c2c66affSColin Finck 	{
1525c2c66affSColin Finck 		id3_link(mh);
1526c2c66affSColin Finck 		if(v1 != NULL && mh->rdat.flags & READER_ID3TAG) *v1 = (mpg123_id3v1*) mh->id3buf;
1527c2c66affSColin Finck 		if(v2 != NULL)
1528c2c66affSColin Finck #ifdef NO_ID3V2
1529c2c66affSColin Finck 		*v2 = NULL;
1530c2c66affSColin Finck #else
1531c2c66affSColin Finck 		*v2 = &mh->id3v2;
1532c2c66affSColin Finck #endif
1533c2c66affSColin Finck 
1534c2c66affSColin Finck 		mh->metaflags |= MPG123_ID3;
1535c2c66affSColin Finck 		mh->metaflags &= ~MPG123_NEW_ID3;
1536c2c66affSColin Finck 	}
1537c2c66affSColin Finck 	return MPG123_OK;
1538c2c66affSColin Finck }
1539c2c66affSColin Finck 
mpg123_id3_raw(mpg123_handle * mh,unsigned char ** v1,size_t * v1_size,unsigned char ** v2,size_t * v2_size)1540*aa811c00SThomas Faber int attribute_align_arg mpg123_id3_raw( mpg123_handle *mh
1541*aa811c00SThomas Faber ,	unsigned char **v1, size_t *v1_size
1542*aa811c00SThomas Faber ,	unsigned char **v2, size_t *v2_size )
1543*aa811c00SThomas Faber {
1544*aa811c00SThomas Faber 	if(!mh)
1545*aa811c00SThomas Faber 		return MPG123_ERR;
1546*aa811c00SThomas Faber 	if(v1 != NULL)
1547*aa811c00SThomas Faber 		*v1 = mh->id3buf[0] ? mh->id3buf : NULL;
1548*aa811c00SThomas Faber 	if(v1_size != NULL)
1549*aa811c00SThomas Faber 		*v1_size = mh->id3buf[0] ? 128 : 0;
1550*aa811c00SThomas Faber 	if(v2 != NULL)
1551*aa811c00SThomas Faber 		*v2 = mh->id3v2_raw;
1552*aa811c00SThomas Faber 	if(v2_size != NULL)
1553*aa811c00SThomas Faber 		*v2_size = mh->id3v2_size;
1554*aa811c00SThomas Faber 	return MPG123_OK;
1555*aa811c00SThomas Faber }
1556*aa811c00SThomas Faber 
mpg123_icy(mpg123_handle * mh,char ** icy_meta)1557c2c66affSColin Finck int attribute_align_arg mpg123_icy(mpg123_handle *mh, char **icy_meta)
1558c2c66affSColin Finck {
1559c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1560c2c66affSColin Finck #ifndef NO_ICY
1561c2c66affSColin Finck 	if(icy_meta == NULL)
1562c2c66affSColin Finck 	{
1563c2c66affSColin Finck 		mh->err = MPG123_NULL_POINTER;
1564c2c66affSColin Finck 		return MPG123_ERR;
1565c2c66affSColin Finck 	}
1566c2c66affSColin Finck 	*icy_meta = NULL;
1567c2c66affSColin Finck 
1568c2c66affSColin Finck 	if(mh->metaflags & MPG123_ICY)
1569c2c66affSColin Finck 	{
1570c2c66affSColin Finck 		*icy_meta = mh->icy.data;
1571c2c66affSColin Finck 		mh->metaflags |= MPG123_ICY;
1572c2c66affSColin Finck 		mh->metaflags &= ~MPG123_NEW_ICY;
1573c2c66affSColin Finck 	}
1574c2c66affSColin Finck 	return MPG123_OK;
1575c2c66affSColin Finck #else
1576c2c66affSColin Finck 	mh->err = MPG123_MISSING_FEATURE;
1577c2c66affSColin Finck 	return MPG123_ERR;
1578c2c66affSColin Finck #endif
1579c2c66affSColin Finck }
1580c2c66affSColin Finck 
mpg123_icy2utf8(const char * icy_text)1581c2c66affSColin Finck char* attribute_align_arg mpg123_icy2utf8(const char* icy_text)
1582c2c66affSColin Finck {
1583c2c66affSColin Finck #ifndef NO_ICY
1584c2c66affSColin Finck 	return icy2utf8(icy_text, 0);
1585c2c66affSColin Finck #else
1586c2c66affSColin Finck 	return NULL;
1587c2c66affSColin Finck #endif
1588c2c66affSColin Finck }
1589c2c66affSColin Finck 
1590c2c66affSColin Finck /* That one is always defined... it's not worth it to remove it for NO_ID3V2. */
mpg123_enc_from_id3(unsigned char id3_enc_byte)1591c2c66affSColin Finck enum mpg123_text_encoding attribute_align_arg mpg123_enc_from_id3(unsigned char id3_enc_byte)
1592c2c66affSColin Finck {
1593c2c66affSColin Finck 	switch(id3_enc_byte)
1594c2c66affSColin Finck 	{
1595c2c66affSColin Finck 		case mpg123_id3_latin1:   return mpg123_text_latin1;
1596c2c66affSColin Finck 		case mpg123_id3_utf16bom: return mpg123_text_utf16bom; /* ID3v2.3 has UCS-2 with BOM here. */
1597c2c66affSColin Finck 		case mpg123_id3_utf16be:  return mpg123_text_utf16be;
1598c2c66affSColin Finck 		case mpg123_id3_utf8:     return mpg123_text_utf8;
1599c2c66affSColin Finck 		default: return mpg123_text_unknown;
1600c2c66affSColin Finck 	}
1601c2c66affSColin Finck }
1602c2c66affSColin Finck 
1603c2c66affSColin Finck #ifndef NO_STRING
mpg123_store_utf8(mpg123_string * sb,enum mpg123_text_encoding enc,const unsigned char * source,size_t source_size)1604c2c66affSColin Finck int mpg123_store_utf8(mpg123_string *sb, enum mpg123_text_encoding enc, const unsigned char *source, size_t source_size)
1605c2c66affSColin Finck {
1606c2c66affSColin Finck 	switch(enc)
1607c2c66affSColin Finck 	{
1608c2c66affSColin Finck #ifndef NO_ID3V2
1609c2c66affSColin Finck 		/* The encodings we get from ID3v2 tags. */
1610c2c66affSColin Finck 		case mpg123_text_utf8:
1611c2c66affSColin Finck 			id3_to_utf8(sb, mpg123_id3_utf8, source, source_size, 0);
1612c2c66affSColin Finck 		break;
1613c2c66affSColin Finck 		case mpg123_text_latin1:
1614c2c66affSColin Finck 			id3_to_utf8(sb, mpg123_id3_latin1, source, source_size, 0);
1615c2c66affSColin Finck 		break;
1616c2c66affSColin Finck 		case mpg123_text_utf16bom:
1617c2c66affSColin Finck 		case mpg123_text_utf16:
1618c2c66affSColin Finck 			id3_to_utf8(sb, mpg123_id3_utf16bom, source, source_size, 0);
1619c2c66affSColin Finck 		break;
1620c2c66affSColin Finck 		/* Special because one cannot skip zero bytes here. */
1621c2c66affSColin Finck 		case mpg123_text_utf16be:
1622c2c66affSColin Finck 			id3_to_utf8(sb, mpg123_id3_utf16be, source, source_size, 0);
1623c2c66affSColin Finck 		break;
1624c2c66affSColin Finck #endif
1625c2c66affSColin Finck #ifndef NO_ICY
1626c2c66affSColin Finck 		/* ICY encoding... */
1627c2c66affSColin Finck 		case mpg123_text_icy:
1628c2c66affSColin Finck 		case mpg123_text_cp1252:
1629c2c66affSColin Finck 		{
1630c2c66affSColin Finck 			mpg123_free_string(sb);
1631c2c66affSColin Finck 			/* Paranoia: Make sure that the string ends inside the buffer... */
1632c2c66affSColin Finck 			if(source[source_size-1] == 0)
1633c2c66affSColin Finck 			{
1634c2c66affSColin Finck 				/* Convert from ICY encoding... with force applied or not. */
1635c2c66affSColin Finck 				char *tmpstring = icy2utf8((const char*)source, enc == mpg123_text_cp1252 ? 1 : 0);
1636c2c66affSColin Finck 				if(tmpstring != NULL)
1637c2c66affSColin Finck 				{
1638c2c66affSColin Finck 					mpg123_set_string(sb, tmpstring);
1639c2c66affSColin Finck 					free(tmpstring);
1640c2c66affSColin Finck 				}
1641c2c66affSColin Finck 			}
1642c2c66affSColin Finck 		}
1643c2c66affSColin Finck 		break;
1644c2c66affSColin Finck #endif
1645c2c66affSColin Finck 		default:
1646c2c66affSColin Finck 			mpg123_free_string(sb);
1647c2c66affSColin Finck 	}
1648c2c66affSColin Finck 	/* At least a trailing null of some form should be there... */
1649c2c66affSColin Finck 	return (sb->fill > 0) ? 1 : 0;
1650c2c66affSColin Finck }
1651c2c66affSColin Finck #endif
1652c2c66affSColin Finck 
mpg123_index(mpg123_handle * mh,off_t ** offsets,off_t * step,size_t * fill)1653c2c66affSColin Finck int attribute_align_arg mpg123_index(mpg123_handle *mh, off_t **offsets, off_t *step, size_t *fill)
1654c2c66affSColin Finck {
1655c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1656c2c66affSColin Finck 	if(offsets == NULL || step == NULL || fill == NULL)
1657c2c66affSColin Finck 	{
1658c2c66affSColin Finck 		mh->err = MPG123_BAD_INDEX_PAR;
1659c2c66affSColin Finck 		return MPG123_ERR;
1660c2c66affSColin Finck 	}
1661c2c66affSColin Finck #ifdef FRAME_INDEX
1662c2c66affSColin Finck 	*offsets = mh->index.data;
1663c2c66affSColin Finck 	*step    = mh->index.step;
1664c2c66affSColin Finck 	*fill    = mh->index.fill;
1665c2c66affSColin Finck #else
1666c2c66affSColin Finck 	*offsets = NULL;
1667c2c66affSColin Finck 	*step    = 0;
1668c2c66affSColin Finck 	*fill    = 0;
1669c2c66affSColin Finck #endif
1670c2c66affSColin Finck 	return MPG123_OK;
1671c2c66affSColin Finck }
1672c2c66affSColin Finck 
mpg123_set_index(mpg123_handle * mh,off_t * offsets,off_t step,size_t fill)1673c2c66affSColin Finck int attribute_align_arg mpg123_set_index(mpg123_handle *mh, off_t *offsets, off_t step, size_t fill)
1674c2c66affSColin Finck {
1675c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1676c2c66affSColin Finck #ifdef FRAME_INDEX
1677c2c66affSColin Finck 	if(step == 0)
1678c2c66affSColin Finck 	{
1679c2c66affSColin Finck 		mh->err = MPG123_BAD_INDEX_PAR;
1680c2c66affSColin Finck 		return MPG123_ERR;
1681c2c66affSColin Finck 	}
1682c2c66affSColin Finck 	if(fi_set(&mh->index, offsets, step, fill) == -1)
1683c2c66affSColin Finck 	{
1684c2c66affSColin Finck 		mh->err = MPG123_OUT_OF_MEM;
1685c2c66affSColin Finck 		return MPG123_ERR;
1686c2c66affSColin Finck 	}
1687c2c66affSColin Finck 	return MPG123_OK;
1688c2c66affSColin Finck #else
1689c2c66affSColin Finck 	mh->err = MPG123_MISSING_FEATURE;
1690c2c66affSColin Finck 	return MPG123_ERR;
1691c2c66affSColin Finck #endif
1692c2c66affSColin Finck }
1693c2c66affSColin Finck 
mpg123_close(mpg123_handle * mh)1694c2c66affSColin Finck int attribute_align_arg mpg123_close(mpg123_handle *mh)
1695c2c66affSColin Finck {
1696c2c66affSColin Finck 	if(mh == NULL) return MPG123_BAD_HANDLE;
1697c2c66affSColin Finck 
1698c2c66affSColin Finck 	/* mh->rd is never NULL! */
1699c2c66affSColin Finck 	if(mh->rd->close != NULL) mh->rd->close(mh);
1700c2c66affSColin Finck 
1701c2c66affSColin Finck 	if(mh->new_format)
1702c2c66affSColin Finck 	{
1703c2c66affSColin Finck 		debug("Hey, we are closing a track before the new format has been queried...");
1704c2c66affSColin Finck 		invalidate_format(&mh->af);
1705c2c66affSColin Finck 		mh->new_format = 0;
1706c2c66affSColin Finck 	}
1707c2c66affSColin Finck 	/* Always reset the frame buffers on close, so we cannot forget it in funky opening routines (wrappers, even). */
1708c2c66affSColin Finck 	frame_reset(mh);
1709c2c66affSColin Finck 	return MPG123_OK;
1710c2c66affSColin Finck }
1711c2c66affSColin Finck 
mpg123_delete(mpg123_handle * mh)1712c2c66affSColin Finck void attribute_align_arg mpg123_delete(mpg123_handle *mh)
1713c2c66affSColin Finck {
1714c2c66affSColin Finck 	if(mh != NULL)
1715c2c66affSColin Finck 	{
1716c2c66affSColin Finck 		mpg123_close(mh);
1717c2c66affSColin Finck 		frame_exit(mh); /* free buffers in frame */
1718c2c66affSColin Finck 		free(mh); /* free struct; cast? */
1719c2c66affSColin Finck 	}
1720c2c66affSColin Finck }
1721c2c66affSColin Finck 
mpg123_free(void * ptr)1722*aa811c00SThomas Faber void attribute_align_arg mpg123_free(void *ptr)
1723*aa811c00SThomas Faber {
1724*aa811c00SThomas Faber 	free(ptr);
1725*aa811c00SThomas Faber }
1726*aa811c00SThomas Faber 
1727c2c66affSColin Finck static const char *mpg123_error[] =
1728c2c66affSColin Finck {
1729c2c66affSColin Finck 	"No error... (code 0)",
1730c2c66affSColin Finck 	"Unable to set up output format! (code 1)",
1731c2c66affSColin Finck 	"Invalid channel number specified. (code 2)",
1732c2c66affSColin Finck 	"Invalid sample rate specified. (code 3)",
1733c2c66affSColin Finck 	"Unable to allocate memory for 16 to 8 converter table! (code 4)",
1734c2c66affSColin Finck 	"Bad parameter id! (code 5)",
1735c2c66affSColin Finck 	"Bad buffer given -- invalid pointer or too small size. (code 6)",
1736c2c66affSColin Finck 	"Out of memory -- some malloc() failed. (code 7)",
1737c2c66affSColin Finck 	"You didn't initialize the library! (code 8)",
1738c2c66affSColin Finck 	"Invalid decoder choice. (code 9)",
1739c2c66affSColin Finck 	"Invalid mpg123 handle. (code 10)",
1740c2c66affSColin Finck 	"Unable to initialize frame buffers (out of memory?)! (code 11)",
1741c2c66affSColin Finck 	"Invalid RVA mode. (code 12)",
1742c2c66affSColin Finck 	"This build doesn't support gapless decoding. (code 13)",
1743c2c66affSColin Finck 	"Not enough buffer space. (code 14)",
1744c2c66affSColin Finck 	"Incompatible numeric data types. (code 15)",
1745c2c66affSColin Finck 	"Bad equalizer band. (code 16)",
1746c2c66affSColin Finck 	"Null pointer given where valid storage address needed. (code 17)",
1747c2c66affSColin Finck 	"Error reading the stream. (code 18)",
1748c2c66affSColin Finck 	"Cannot seek from end (end is not known). (code 19)",
1749c2c66affSColin Finck 	"Invalid 'whence' for seek function. (code 20)",
1750c2c66affSColin Finck 	"Build does not support stream timeouts. (code 21)",
1751c2c66affSColin Finck 	"File access error. (code 22)",
1752c2c66affSColin Finck 	"Seek not supported by stream. (code 23)",
1753c2c66affSColin Finck 	"No stream opened. (code 24)",
1754c2c66affSColin Finck 	"Bad parameter handle. (code 25)",
1755c2c66affSColin Finck 	"Invalid parameter addresses for index retrieval. (code 26)",
1756c2c66affSColin Finck 	"Lost track in the bytestream and did not attempt resync. (code 27)",
1757c2c66affSColin Finck 	"Failed to find valid MPEG data within limit on resync. (code 28)",
1758c2c66affSColin Finck 	"No 8bit encoding possible. (code 29)",
1759c2c66affSColin Finck 	"Stack alignment is not good. (code 30)",
1760c2c66affSColin Finck 	"You gave me a NULL buffer? (code 31)",
1761c2c66affSColin Finck 	"File position is screwed up, please do an absolute seek (code 32)",
1762c2c66affSColin Finck 	"Inappropriate NULL-pointer provided.",
1763c2c66affSColin Finck 	"Bad key value given.",
1764c2c66affSColin Finck 	"There is no frame index (disabled in this build).",
1765c2c66affSColin Finck 	"Frame index operation failed.",
1766c2c66affSColin Finck 	"Decoder setup failed (invalid combination of settings?)",
1767c2c66affSColin Finck 	"Feature not in this build."
1768c2c66affSColin Finck 	,"Some bad value has been provided."
1769c2c66affSColin Finck 	,"Low-level seeking has failed (call to lseek(), usually)."
1770c2c66affSColin Finck 	,"Custom I/O obviously not prepared."
1771c2c66affSColin Finck 	,"Overflow in LFS (large file support) conversion."
1772c2c66affSColin Finck 	,"Overflow in integer conversion."
1773c2c66affSColin Finck };
1774c2c66affSColin Finck 
mpg123_plain_strerror(int errcode)1775c2c66affSColin Finck const char* attribute_align_arg mpg123_plain_strerror(int errcode)
1776c2c66affSColin Finck {
1777c2c66affSColin Finck 	if(errcode >= 0 && errcode < sizeof(mpg123_error)/sizeof(char*))
1778c2c66affSColin Finck 	return mpg123_error[errcode];
1779c2c66affSColin Finck 	else switch(errcode)
1780c2c66affSColin Finck 	{
1781c2c66affSColin Finck 		case MPG123_ERR:
1782c2c66affSColin Finck 			return "A generic mpg123 error.";
1783c2c66affSColin Finck 		case MPG123_DONE:
1784c2c66affSColin Finck 			return "Message: I am done with this track.";
1785c2c66affSColin Finck 		case MPG123_NEED_MORE:
1786c2c66affSColin Finck 			return "Message: Feed me more input data!";
1787c2c66affSColin Finck 		case MPG123_NEW_FORMAT:
1788c2c66affSColin Finck 			return "Message: Prepare for a changed audio format (query the new one)!";
1789c2c66affSColin Finck 		default:
1790c2c66affSColin Finck 			return "I have no idea - an unknown error code!";
1791c2c66affSColin Finck 	}
1792c2c66affSColin Finck }
1793c2c66affSColin Finck 
mpg123_errcode(mpg123_handle * mh)1794c2c66affSColin Finck int attribute_align_arg mpg123_errcode(mpg123_handle *mh)
1795c2c66affSColin Finck {
1796c2c66affSColin Finck 	if(mh != NULL) return mh->err;
1797c2c66affSColin Finck 	return MPG123_BAD_HANDLE;
1798c2c66affSColin Finck }
1799c2c66affSColin Finck 
mpg123_strerror(mpg123_handle * mh)1800c2c66affSColin Finck const char* attribute_align_arg mpg123_strerror(mpg123_handle *mh)
1801c2c66affSColin Finck {
1802c2c66affSColin Finck 	return mpg123_plain_strerror(mpg123_errcode(mh));
1803c2c66affSColin Finck }
1804