Blame src/libmpg123/frame.c

Packit c32a2d
/*
Packit c32a2d
	frame: Heap of routines dealing with the core mpg123 data structure.
Packit c32a2d
Packit c32a2d
	copyright 2008-2014 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Thomas Orgis
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
#include "getcpuflags.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
static void frame_fixed_reset(mpg123_handle *fr);
Packit c32a2d
Packit c32a2d
/* that's doubled in decode_ntom.c */
Packit c32a2d
#define NTOM_MUL (32768)
Packit c32a2d
Packit c32a2d
#define aligned_pointer(p, type, alignment) align_the_pointer(p, alignment)
Packit c32a2d
static void *align_the_pointer(void *base, unsigned int alignment)
Packit c32a2d
{
Packit c32a2d
	/*
Packit c32a2d
		Work in unsigned integer realm, explicitly.
Packit c32a2d
		Tricking the compiler into integer operations like % by invoking base-NULL is dangerous: It results into ptrdiff_t, which gets negative on big addresses. Big screw up, that.
Packit c32a2d
		I try to do it "properly" here: Casting only to uintptr_t and no artihmethic with void*.
Packit c32a2d
	*/
Packit c32a2d
	uintptr_t baseval = (uintptr_t)(char*)base;
Packit c32a2d
	uintptr_t aoff = baseval % alignment;
Packit c32a2d
Packit c32a2d
	debug3("align_the_pointer: pointer %p is off by %u from %u",
Packit c32a2d
	       base, (unsigned int)aoff, alignment);
Packit c32a2d
Packit c32a2d
	if(aoff) return (char*)base+alignment-aoff;
Packit c32a2d
	else     return base;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void frame_default_pars(mpg123_pars *mp)
Packit c32a2d
{
Packit c32a2d
	mp->outscale = 1.0;
Packit c32a2d
	mp->flags = 0;
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
	mp->flags |= MPG123_GAPLESS;
Packit c32a2d
#endif
Packit c32a2d
	mp->flags |= MPG123_AUTO_RESAMPLE;
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
	mp->force_rate = 0;
Packit c32a2d
#endif
Packit c32a2d
	mp->down_sample = 0;
Packit c32a2d
	mp->rva = 0;
Packit c32a2d
	mp->halfspeed = 0;
Packit c32a2d
	mp->doublespeed = 0;
Packit c32a2d
	mp->verbose = 0;
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	mp->icy_interval = 0;
Packit c32a2d
#endif
Packit c32a2d
	mp->timeout = 0;
Packit c32a2d
	mp->resync_limit = 1024;
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	mp->index_size = INDEX_SIZE;
Packit c32a2d
#endif
Packit c32a2d
	mp->preframes = 4; /* That's good  for layer 3 ISO compliance bitstream. */
Packit c32a2d
	mpg123_fmt_all(mp);
Packit c32a2d
	/* Default of keeping some 4K buffers at hand, should cover the "usual" use case (using 16K pipe buffers as role model). */
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	mp->feedpool = 5; 
Packit c32a2d
	mp->feedbuffer = 4096;
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void frame_init(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	frame_init_par(fr, NULL);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
Packit c32a2d
{
Packit c32a2d
	fr->own_buffer = TRUE;
Packit c32a2d
	fr->buffer.data = NULL;
Packit c32a2d
	fr->buffer.rdata = NULL;
Packit c32a2d
	fr->buffer.fill = 0;
Packit c32a2d
	fr->buffer.size = 0;
Packit c32a2d
	fr->rawbuffs = NULL;
Packit c32a2d
	fr->rawbuffss = 0;
Packit c32a2d
	fr->rawdecwin = NULL;
Packit c32a2d
	fr->rawdecwins = 0;
Packit c32a2d
#ifndef NO_8BIT
Packit c32a2d
	fr->conv16to8_buf = NULL;
Packit c32a2d
#endif
Packit c32a2d
#ifdef OPT_DITHER
Packit c32a2d
	fr->dithernoise = NULL;
Packit c32a2d
#endif
Packit c32a2d
	fr->layerscratch = NULL;
Packit c32a2d
	fr->xing_toc = NULL;
Packit c32a2d
	fr->cpu_opts.type = defdec();
Packit c32a2d
	fr->cpu_opts.class = decclass(fr->cpu_opts.type);
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
	/* these two look unnecessary, check guarantee for synth_ntom_set_step (in control_generic, even)! */
Packit c32a2d
	fr->ntom_val[0] = NTOM_MUL>>1;
Packit c32a2d
	fr->ntom_val[1] = NTOM_MUL>>1;
Packit c32a2d
	fr->ntom_step = NTOM_MUL;
Packit c32a2d
#endif
Packit c32a2d
	/* unnecessary: fr->buffer.size = fr->buffer.fill = 0; */
Packit c32a2d
	mpg123_reset_eq(fr);
Packit c32a2d
	init_icy(&fr->icy);
Packit c32a2d
	init_id3(fr);
Packit c32a2d
	/* frame_outbuffer is missing... */
Packit c32a2d
	/* frame_buffers is missing... that one needs cpu opt setting! */
Packit c32a2d
	/* after these... frame_reset is needed before starting full decode */
Packit c32a2d
	invalidate_format(&fr->af);
Packit c32a2d
	fr->rdat.r_read = NULL;
Packit c32a2d
	fr->rdat.r_lseek = NULL;
Packit c32a2d
	fr->rdat.iohandle = NULL;
Packit c32a2d
	fr->rdat.r_read_handle = NULL;
Packit c32a2d
	fr->rdat.r_lseek_handle = NULL;
Packit c32a2d
	fr->rdat.cleanup_handle = NULL;
Packit c32a2d
	fr->wrapperdata = NULL;
Packit c32a2d
	fr->wrapperclean = NULL;
Packit c32a2d
	fr->decoder_change = 1;
Packit c32a2d
	fr->err = MPG123_OK;
Packit c32a2d
	if(mp == NULL) frame_default_pars(&fr->p);
Packit c32a2d
	else memcpy(&fr->p, mp, sizeof(struct mpg123_pars_struct));
Packit c32a2d
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	bc_prepare(&fr->rdat.buffer, fr->p.feedpool, fr->p.feedbuffer);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	fr->down_sample = 0; /* Initialize to silence harmless errors when debugging. */
Packit c32a2d
	frame_fixed_reset(fr); /* Reset only the fixed data, dynamic buffers are not there yet! */
Packit c32a2d
	fr->synth = NULL;
Packit c32a2d
	fr->synth_mono = NULL;
Packit c32a2d
	fr->make_decode_tables = NULL;
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	fi_init(&fr->index);
Packit c32a2d
	frame_index_setup(fr); /* Apply the size setting. */
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifdef OPT_DITHER
Packit c32a2d
/* Also, only allocate the memory for the table on demand.
Packit c32a2d
   In future, one could create special noise for different sampling frequencies(?). */
Packit c32a2d
int frame_dither_init(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	/* run-time dither noise table generation */
Packit c32a2d
	if(fr->dithernoise == NULL)
Packit c32a2d
	{
Packit c32a2d
		fr->dithernoise = malloc(sizeof(float)*DITHERSIZE);
Packit c32a2d
		if(fr->dithernoise == NULL) return 0;
Packit c32a2d
Packit c32a2d
		dither_table_init(fr->dithernoise);
Packit c32a2d
	}
Packit c32a2d
	return 1;
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
mpg123_pars attribute_align_arg *mpg123_new_pars(int *error)
Packit c32a2d
{
Packit c32a2d
	mpg123_pars *mp = malloc(sizeof(struct mpg123_pars_struct));
Packit c32a2d
	if(mp != NULL){ frame_default_pars(mp); if(error != NULL) *error = MPG123_OK; }
Packit c32a2d
	else if(error != NULL) *error = MPG123_OUT_OF_MEM;
Packit c32a2d
	return mp;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void attribute_align_arg mpg123_delete_pars(mpg123_pars* mp)
Packit c32a2d
{
Packit c32a2d
	if(mp != NULL) free(mp);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_reset_eq(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	int i;
Packit c32a2d
	if(mh == NULL) return MPG123_BAD_HANDLE;
Packit c32a2d
#ifndef NO_EQUALIZER
Packit c32a2d
	mh->have_eq_settings = 0;
Packit c32a2d
	for(i=0; i < 32; ++i) mh->equalizer[0][i] = mh->equalizer[1][i] = DOUBLE_TO_REAL(1.0);
Packit c32a2d
#endif
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int frame_outbuffer(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	size_t size = fr->outblock;
Packit c32a2d
	if(!fr->own_buffer)
Packit c32a2d
	{
Packit c32a2d
		if(fr->buffer.size < size)
Packit c32a2d
		{
Packit c32a2d
			fr->err = MPG123_BAD_BUFFER;
Packit c32a2d
			if(NOQUIET) error2("have external buffer of size %"SIZE_P", need %"SIZE_P, (size_p)fr->buffer.size, (size_p)size);
Packit c32a2d
Packit c32a2d
			return MPG123_ERR;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	debug1("need frame buffer of %"SIZE_P, (size_p)size);
Packit c32a2d
	if(fr->buffer.rdata != NULL && fr->buffer.size != size)
Packit c32a2d
	{
Packit c32a2d
		free(fr->buffer.rdata);
Packit c32a2d
		fr->buffer.rdata = NULL;
Packit c32a2d
	}
Packit c32a2d
	fr->buffer.size = size;
Packit c32a2d
	fr->buffer.data = NULL;
Packit c32a2d
	/* be generous: use 16 byte alignment */
Packit c32a2d
	if(fr->buffer.rdata == NULL) fr->buffer.rdata = (unsigned char*) malloc(fr->buffer.size+15);
Packit c32a2d
	if(fr->buffer.rdata == NULL)
Packit c32a2d
	{
Packit c32a2d
		fr->err = MPG123_OUT_OF_MEM;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	fr->buffer.data = aligned_pointer(fr->buffer.rdata, unsigned char*, 16);
Packit c32a2d
	fr->own_buffer = TRUE;
Packit c32a2d
	fr->buffer.fill = 0;
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, unsigned char *data, size_t size)
Packit c32a2d
{
Packit c32a2d
	debug2("replace buffer with %p size %"SIZE_P, data, (size_p)size);
Packit c32a2d
	if(mh == NULL) return MPG123_BAD_HANDLE;
Packit c32a2d
	/* Will accept any size, the error comes later... */
Packit c32a2d
	if(data == NULL)
Packit c32a2d
	{
Packit c32a2d
		mh->err = MPG123_BAD_BUFFER;
Packit c32a2d
		return MPG123_ERR;
Packit c32a2d
	}
Packit c32a2d
	if(mh->buffer.rdata != NULL) free(mh->buffer.rdata);
Packit c32a2d
	mh->own_buffer = FALSE;
Packit c32a2d
	mh->buffer.rdata = NULL;
Packit c32a2d
	mh->buffer.data = data;
Packit c32a2d
	mh->buffer.size = size;
Packit c32a2d
	mh->buffer.fill = 0;
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
int frame_index_setup(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	int ret = MPG123_ERR;
Packit c32a2d
	if(fr->p.index_size >= 0)
Packit c32a2d
	{ /* Simple fixed index. */
Packit c32a2d
		fr->index.grow_size = 0;
Packit c32a2d
		debug1("resizing index to %li", fr->p.index_size);
Packit c32a2d
		ret = fi_resize(&fr->index, (size_t)fr->p.index_size);
Packit c32a2d
		debug2("index resized... %lu at %p", (unsigned long)fr->index.size, (void*)fr->index.data);
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{ /* A growing index. We give it a start, though. */
Packit c32a2d
		fr->index.grow_size = (size_t)(- fr->p.index_size);
Packit c32a2d
		if(fr->index.size < fr->index.grow_size)
Packit c32a2d
		ret = fi_resize(&fr->index, fr->index.grow_size);
Packit c32a2d
		else
Packit c32a2d
		ret = MPG123_OK; /* We have minimal size already... and since growing is OK... */
Packit c32a2d
	}
Packit c32a2d
	debug2("set up frame index of size %lu (ret=%i)", (unsigned long)fr->index.size, ret);
Packit c32a2d
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
static void frame_decode_buffers_reset(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->rawbuffs) /* memset(NULL, 0, 0) not desired */
Packit c32a2d
		memset(fr->rawbuffs, 0, fr->rawbuffss);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int frame_buffers(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	int buffssize = 0;
Packit c32a2d
	debug1("frame %p buffer", (void*)fr);
Packit c32a2d
/*
Packit c32a2d
	the used-to-be-static buffer of the synth functions, has some subtly different types/sizes
Packit c32a2d
Packit c32a2d
	2to1, 4to1, ntom, generic, i386: real[2][2][0x110]
Packit c32a2d
	mmx, sse: short[2][2][0x110]
Packit c32a2d
	i586(_dither): 4352 bytes; int/long[2][2][0x110]
Packit c32a2d
	i486: int[2][2][17*FIR_BUFFER_SIZE]
Packit c32a2d
	altivec: static real __attribute__ ((aligned (16))) buffs[4][4][0x110]
Packit c32a2d
Packit c32a2d
	Huh, altivec looks like fun. Well, let it be large... then, the 16 byte alignment seems to be implicit on MacOSX malloc anyway.
Packit c32a2d
	Let's make a reasonable attempt to allocate enough memory...
Packit c32a2d
	Keep in mind: biggest ones are i486 and altivec (mutually exclusive!), then follows i586 and normal real.
Packit c32a2d
	mmx/sse use short but also real for resampling.
Packit c32a2d
	Thus, minimum is 2*2*0x110*sizeof(real).
Packit c32a2d
*/
Packit c32a2d
	if(fr->cpu_opts.type == altivec) buffssize = 4*4*0x110*sizeof(real);
Packit c32a2d
#ifdef OPT_I486
Packit c32a2d
	else if(fr->cpu_opts.type == ivier) buffssize = 2*2*17*FIR_BUFFER_SIZE*sizeof(int);
Packit c32a2d
#endif
Packit c32a2d
	else if(fr->cpu_opts.type == ifuenf || fr->cpu_opts.type == ifuenf_dither || fr->cpu_opts.type == dreidnow)
Packit c32a2d
	buffssize = 2*2*0x110*4; /* don't rely on type real, we need 4352 bytes */
Packit c32a2d
Packit c32a2d
	if(2*2*0x110*sizeof(real) > buffssize)
Packit c32a2d
	buffssize = 2*2*0x110*sizeof(real);
Packit c32a2d
	buffssize += 15; /* For 16-byte alignment (SSE likes that). */
Packit c32a2d
Packit c32a2d
	if(fr->rawbuffs != NULL && fr->rawbuffss != buffssize)
Packit c32a2d
	{
Packit c32a2d
		free(fr->rawbuffs);
Packit c32a2d
		fr->rawbuffs = NULL;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	if(fr->rawbuffs == NULL) fr->rawbuffs = (unsigned char*) malloc(buffssize);
Packit c32a2d
	if(fr->rawbuffs == NULL) return -1;
Packit c32a2d
	fr->rawbuffss = buffssize;
Packit c32a2d
	fr->short_buffs[0][0] = aligned_pointer(fr->rawbuffs,short,16);
Packit c32a2d
	fr->short_buffs[0][1] = fr->short_buffs[0][0] + 0x110;
Packit c32a2d
	fr->short_buffs[1][0] = fr->short_buffs[0][1] + 0x110;
Packit c32a2d
	fr->short_buffs[1][1] = fr->short_buffs[1][0] + 0x110;
Packit c32a2d
	fr->real_buffs[0][0] = aligned_pointer(fr->rawbuffs,real,16);
Packit c32a2d
	fr->real_buffs[0][1] = fr->real_buffs[0][0] + 0x110;
Packit c32a2d
	fr->real_buffs[1][0] = fr->real_buffs[0][1] + 0x110;
Packit c32a2d
	fr->real_buffs[1][1] = fr->real_buffs[1][0] + 0x110;
Packit c32a2d
#ifdef OPT_I486
Packit c32a2d
	if(fr->cpu_opts.type == ivier)
Packit c32a2d
	{
Packit c32a2d
		fr->int_buffs[0][0] = (int*) fr->rawbuffs;
Packit c32a2d
		fr->int_buffs[0][1] = fr->int_buffs[0][0] + 17*FIR_BUFFER_SIZE;
Packit c32a2d
		fr->int_buffs[1][0] = fr->int_buffs[0][1] + 17*FIR_BUFFER_SIZE;
Packit c32a2d
		fr->int_buffs[1][1] = fr->int_buffs[1][0] + 17*FIR_BUFFER_SIZE;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
#ifdef OPT_ALTIVEC
Packit c32a2d
	if(fr->cpu_opts.type == altivec)
Packit c32a2d
	{
Packit c32a2d
		int i,j;
Packit c32a2d
		fr->areal_buffs[0][0] = (real*) fr->rawbuffs;
Packit c32a2d
		for(i=0; i<4; ++i) for(j=0; j<4; ++j)
Packit c32a2d
		fr->areal_buffs[i][j] = fr->areal_buffs[0][0] + (i*4+j)*0x110;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	/* now the different decwins... all of the same size, actually */
Packit c32a2d
	/* The MMX ones want 32byte alignment, which I'll try to ensure manually */
Packit c32a2d
	{
Packit c32a2d
		int decwin_size = (512+32)*sizeof(real);
Packit c32a2d
#ifdef OPT_MMXORSSE
Packit c32a2d
#ifdef OPT_MULTI
Packit c32a2d
		if(fr->cpu_opts.class == mmxsse)
Packit c32a2d
		{
Packit c32a2d
#endif
Packit c32a2d
			/* decwin_mmx will share, decwins will be appended ... sizeof(float)==4 */
Packit c32a2d
			if(decwin_size < (512+32)*4) decwin_size = (512+32)*4;
Packit c32a2d
Packit c32a2d
			/* the second window + alignment zone -- we align for 32 bytes for SSE as
Packit c32a2d
			   requirement, 64 byte for matching cache line size (that matters!) */
Packit c32a2d
			decwin_size += (512+32)*4 + 63;
Packit c32a2d
			/* (512+32)*4/32 == 2176/32 == 68, so one decwin block retains alignment for 32 or 64 bytes */
Packit c32a2d
#ifdef OPT_MULTI
Packit c32a2d
		}
Packit c32a2d
#endif
Packit c32a2d
#endif
Packit c32a2d
#if defined(OPT_ALTIVEC) || defined(OPT_ARM) 
Packit c32a2d
		/* sizeof(real) >= 4 ... yes, it could be 8, for example.
Packit c32a2d
		   We got it intialized to at least (512+32)*sizeof(real).*/
Packit c32a2d
		decwin_size += 512*sizeof(real);
Packit c32a2d
#endif
Packit c32a2d
		/* Hm, that's basically realloc() ... */
Packit c32a2d
		if(fr->rawdecwin != NULL && fr->rawdecwins != decwin_size)
Packit c32a2d
		{
Packit c32a2d
			free(fr->rawdecwin);
Packit c32a2d
			fr->rawdecwin = NULL;
Packit c32a2d
		}
Packit c32a2d
Packit c32a2d
		if(fr->rawdecwin == NULL)
Packit c32a2d
		fr->rawdecwin = (unsigned char*) malloc(decwin_size);
Packit c32a2d
Packit c32a2d
		if(fr->rawdecwin == NULL) return -1;
Packit c32a2d
Packit c32a2d
		fr->rawdecwins = decwin_size;
Packit c32a2d
		fr->decwin = (real*) fr->rawdecwin;
Packit c32a2d
#ifdef OPT_MMXORSSE
Packit c32a2d
#ifdef OPT_MULTI
Packit c32a2d
		if(fr->cpu_opts.class == mmxsse)
Packit c32a2d
		{
Packit c32a2d
#endif
Packit c32a2d
			/* align decwin, assign that to decwin_mmx, append decwins */
Packit c32a2d
			/* I need to add to decwin what is missing to the next full 64 byte -- also I want to make gcc -pedantic happy... */
Packit c32a2d
			fr->decwin = aligned_pointer(fr->rawdecwin,real,64);
Packit c32a2d
			debug1("aligned decwin: %p", (void*)fr->decwin);
Packit c32a2d
			fr->decwin_mmx = (float*)fr->decwin;
Packit c32a2d
			fr->decwins = fr->decwin_mmx+512+32;
Packit c32a2d
#ifdef OPT_MULTI
Packit c32a2d
		}
Packit c32a2d
		else debug("no decwins/decwin_mmx for that class");
Packit c32a2d
#endif
Packit c32a2d
#endif
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Layer scratch buffers are of compile-time fixed size, so allocate only once. */
Packit c32a2d
	if(fr->layerscratch == NULL)
Packit c32a2d
	{
Packit c32a2d
		/* Allocate specific layer1/2/3 buffers, so that we know they'll work for SSE. */
Packit c32a2d
		size_t scratchsize = 0;
Packit c32a2d
		real *scratcher;
Packit c32a2d
#ifndef NO_LAYER1
Packit c32a2d
		scratchsize += sizeof(real) * 2 * SBLIMIT;
Packit c32a2d
#endif
Packit c32a2d
#ifndef NO_LAYER2
Packit c32a2d
		scratchsize += sizeof(real) * 2 * 4 * SBLIMIT;
Packit c32a2d
#endif
Packit c32a2d
#ifndef NO_LAYER3
Packit c32a2d
		scratchsize += sizeof(real) * 2 * SBLIMIT * SSLIMIT; /* hybrid_in */
Packit c32a2d
		scratchsize += sizeof(real) * 2 * SSLIMIT * SBLIMIT; /* hybrid_out */
Packit c32a2d
#endif
Packit c32a2d
		/*
Packit c32a2d
			Now figure out correct alignment:
Packit c32a2d
			We need 16 byte minimum, smallest unit of the blocks is 2*SBLIMIT*sizeof(real), which is 64*4=256. Let's do 64bytes as heuristic for cache line (as proven useful in buffs above).
Packit c32a2d
		*/
Packit c32a2d
		fr->layerscratch = malloc(scratchsize+63);
Packit c32a2d
		if(fr->layerscratch == NULL) return -1;
Packit c32a2d
Packit c32a2d
		/* Get aligned part of the memory, then divide it up. */
Packit c32a2d
		scratcher = aligned_pointer(fr->layerscratch,real,64);
Packit c32a2d
		/* Those funky pointer casts silence compilers...
Packit c32a2d
		   One might change the code at hand to really just use 1D arrays, but in practice, that would not make a (positive) difference. */
Packit c32a2d
#ifndef NO_LAYER1
Packit c32a2d
		fr->layer1.fraction = (real(*)[SBLIMIT])scratcher;
Packit c32a2d
		scratcher += 2 * SBLIMIT;
Packit c32a2d
#endif
Packit c32a2d
#ifndef NO_LAYER2
Packit c32a2d
		fr->layer2.fraction = (real(*)[4][SBLIMIT])scratcher;
Packit c32a2d
		scratcher += 2 * 4 * SBLIMIT;
Packit c32a2d
#endif
Packit c32a2d
#ifndef NO_LAYER3
Packit c32a2d
		fr->layer3.hybrid_in = (real(*)[SBLIMIT][SSLIMIT])scratcher;
Packit c32a2d
		scratcher += 2 * SBLIMIT * SSLIMIT;
Packit c32a2d
		fr->layer3.hybrid_out = (real(*)[SSLIMIT][SBLIMIT])scratcher;
Packit c32a2d
		scratcher += 2 * SSLIMIT * SBLIMIT;
Packit c32a2d
#endif
Packit c32a2d
		/* Note: These buffers don't need resetting here. */
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* Only reset the buffers we created just now. */
Packit c32a2d
	frame_decode_buffers_reset(fr);
Packit c32a2d
Packit c32a2d
	debug1("frame %p buffer done", (void*)fr);
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int frame_buffers_reset(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	fr->buffer.fill = 0; /* hm, reset buffer fill... did we do a flush? */
Packit c32a2d
	fr->bsnum = 0;
Packit c32a2d
	/* Wondering: could it be actually _wanted_ to retain buffer contents over different files? (special gapless / cut stuff) */
Packit c32a2d
	fr->bsbuf = fr->bsspace[1];
Packit c32a2d
	fr->bsbufold = fr->bsbuf;
Packit c32a2d
	fr->bitreservoir = 0;
Packit c32a2d
	frame_decode_buffers_reset(fr);
Packit c32a2d
	memset(fr->bsspace, 0, 2*(MAXFRAMESIZE+512));
Packit c32a2d
	memset(fr->ssave, 0, 34);
Packit c32a2d
	fr->hybrid_blc[0] = fr->hybrid_blc[1] = 0;
Packit c32a2d
	memset(fr->hybrid_block, 0, sizeof(real)*2*2*SBLIMIT*SSLIMIT);
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void frame_icy_reset(mpg123_handle* fr)
Packit c32a2d
{
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	if(fr->icy.data != NULL) free(fr->icy.data);
Packit c32a2d
	fr->icy.data = NULL;
Packit c32a2d
	fr->icy.interval = 0;
Packit c32a2d
	fr->icy.next = 0;
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void frame_free_toc(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->xing_toc != NULL){ free(fr->xing_toc); fr->xing_toc = NULL; }
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Just copy the Xing TOC over... */
Packit c32a2d
int frame_fill_toc(mpg123_handle *fr, unsigned char* in)
Packit c32a2d
{
Packit c32a2d
	if(fr->xing_toc == NULL) fr->xing_toc = malloc(100);
Packit c32a2d
	if(fr->xing_toc != NULL)
Packit c32a2d
	{
Packit c32a2d
		memcpy(fr->xing_toc, in, 100);
Packit c32a2d
#ifdef DEBUG
Packit c32a2d
		debug("Got a TOC! Showing the values...");
Packit c32a2d
		{
Packit c32a2d
			int i;
Packit c32a2d
			for(i=0; i<100; ++i)
Packit c32a2d
			debug2("entry %i = %i", i, fr->xing_toc[i]);
Packit c32a2d
		}
Packit c32a2d
#endif
Packit c32a2d
		return TRUE;
Packit c32a2d
	}
Packit c32a2d
	return FALSE;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Prepare the handle for a new track.
Packit c32a2d
   Reset variables, buffers... */
Packit c32a2d
int frame_reset(mpg123_handle* fr)
Packit c32a2d
{
Packit c32a2d
	frame_buffers_reset(fr);
Packit c32a2d
	frame_fixed_reset(fr);
Packit c32a2d
	frame_free_toc(fr);
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	fi_reset(&fr->index);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Reset everythign except dynamic memory. */
Packit c32a2d
static void frame_fixed_reset(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	frame_icy_reset(fr);
Packit c32a2d
	open_bad(fr);
Packit c32a2d
	fr->to_decode = FALSE;
Packit c32a2d
	fr->to_ignore = FALSE;
Packit c32a2d
	fr->metaflags = 0;
Packit c32a2d
	fr->outblock = 0; /* This will be set before decoding! */
Packit c32a2d
	fr->num = -1;
Packit c32a2d
	fr->input_offset = -1;
Packit c32a2d
	fr->playnum = -1;
Packit c32a2d
	fr->state_flags = FRAME_ACCURATE;
Packit c32a2d
	fr->silent_resync = 0;
Packit c32a2d
	fr->audio_start = 0;
Packit c32a2d
	fr->clip = 0;
Packit c32a2d
	fr->oldhead = 0;
Packit c32a2d
	fr->firsthead = 0;
Packit c32a2d
	fr->lay = 0;
Packit c32a2d
	fr->vbr = MPG123_CBR;
Packit c32a2d
	fr->abr_rate = 0;
Packit c32a2d
	fr->track_frames = 0;
Packit c32a2d
	fr->track_samples = -1;
Packit c32a2d
	fr->framesize=0; 
Packit c32a2d
	fr->mean_frames = 0;
Packit c32a2d
	fr->mean_framesize = 0;
Packit c32a2d
	fr->freesize = 0;
Packit c32a2d
	fr->lastscale = -1;
Packit c32a2d
	fr->rva.level[0] = -1;
Packit c32a2d
	fr->rva.level[1] = -1;
Packit c32a2d
	fr->rva.gain[0] = 0;
Packit c32a2d
	fr->rva.gain[1] = 0;
Packit c32a2d
	fr->rva.peak[0] = 0;
Packit c32a2d
	fr->rva.peak[1] = 0;
Packit c32a2d
	fr->fsizeold = 0;
Packit c32a2d
	fr->firstframe = 0;
Packit c32a2d
	fr->ignoreframe = fr->firstframe-fr->p.preframes;
Packit c32a2d
	fr->header_change = 0;
Packit c32a2d
	fr->lastframe = -1;
Packit c32a2d
	fr->fresh = 1;
Packit c32a2d
	fr->new_format = 0;
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
	frame_gapless_init(fr,-1,0,0);
Packit c32a2d
	fr->lastoff = 0;
Packit c32a2d
	fr->firstoff = 0;
Packit c32a2d
#endif
Packit c32a2d
#ifdef OPT_I486
Packit c32a2d
	fr->i486bo[0] = fr->i486bo[1] = FIR_SIZE-1;
Packit c32a2d
#endif
Packit c32a2d
	fr->bo = 1; /* the usual bo */
Packit c32a2d
#ifdef OPT_DITHER
Packit c32a2d
	fr->ditherindex = 0;
Packit c32a2d
#endif
Packit c32a2d
	reset_id3(fr);
Packit c32a2d
	reset_icy(&fr->icy);
Packit c32a2d
	/* ICY stuff should go into icy.c, eh? */
Packit c32a2d
#ifndef NO_ICY
Packit c32a2d
	fr->icy.interval = 0;
Packit c32a2d
	fr->icy.next = 0;
Packit c32a2d
#endif
Packit c32a2d
	fr->halfphase = 0; /* here or indeed only on first-time init? */
Packit c32a2d
	fr->error_protection = 0;
Packit c32a2d
	fr->freeformat_framesize = -1;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static void frame_free_buffers(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->rawbuffs != NULL) free(fr->rawbuffs);
Packit c32a2d
	fr->rawbuffs = NULL;
Packit c32a2d
	fr->rawbuffss = 0;
Packit c32a2d
	if(fr->rawdecwin != NULL) free(fr->rawdecwin);
Packit c32a2d
	fr->rawdecwin = NULL;
Packit c32a2d
	fr->rawdecwins = 0;
Packit c32a2d
#ifndef NO_8BIT
Packit c32a2d
	if(fr->conv16to8_buf != NULL) free(fr->conv16to8_buf);
Packit c32a2d
	fr->conv16to8_buf = NULL;
Packit c32a2d
#endif
Packit c32a2d
	if(fr->layerscratch != NULL) free(fr->layerscratch);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void frame_exit(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	if(fr->buffer.rdata != NULL)
Packit c32a2d
	{
Packit c32a2d
		debug1("freeing buffer at %p", (void*)fr->buffer.rdata);
Packit c32a2d
		free(fr->buffer.rdata);
Packit c32a2d
	}
Packit c32a2d
	fr->buffer.rdata = NULL;
Packit c32a2d
	frame_free_buffers(fr);
Packit c32a2d
	frame_free_toc(fr);
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	fi_exit(&fr->index);
Packit c32a2d
#endif
Packit c32a2d
#ifdef OPT_DITHER
Packit c32a2d
	if(fr->dithernoise != NULL)
Packit c32a2d
	{
Packit c32a2d
		free(fr->dithernoise);
Packit c32a2d
		fr->dithernoise = NULL;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	exit_id3(fr);
Packit c32a2d
	clear_icy(&fr->icy);
Packit c32a2d
	/* Clean up possible mess from LFS wrapper. */
Packit c32a2d
	if(fr->wrapperclean != NULL)
Packit c32a2d
	{
Packit c32a2d
		fr->wrapperclean(fr->wrapperdata);
Packit c32a2d
		fr->wrapperdata = NULL;
Packit c32a2d
	}
Packit c32a2d
#ifndef NO_FEEDER
Packit c32a2d
	bc_cleanup(&fr->rdat.buffer);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_framedata(mpg123_handle *mh, unsigned long *header, unsigned char **bodydata, size_t *bodybytes)
Packit c32a2d
{
Packit c32a2d
	if(mh == NULL)     return MPG123_BAD_HANDLE;
Packit c32a2d
	if(!mh->to_decode) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	if(header    != NULL) *header    = mh->oldhead;
Packit c32a2d
	if(bodydata  != NULL) *bodydata  = mh->bsbuf;
Packit c32a2d
	if(bodybytes != NULL) *bodybytes = mh->framesize;
Packit c32a2d
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Fuzzy frame offset searching (guessing).
Packit c32a2d
	When we don't have an accurate position, we may use an inaccurate one.
Packit c32a2d
	Possibilities:
Packit c32a2d
		- use approximate positions from Xing TOC (not yet parsed)
Packit c32a2d
		- guess wildly from mean framesize and offset of first frame / beginning of file.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
Packit c32a2d
{
Packit c32a2d
	/* Default is to go to the beginning. */
Packit c32a2d
	off_t ret = fr->audio_start;
Packit c32a2d
	*get_frame = 0;
Packit c32a2d
Packit c32a2d
	/* But we try to find something better. */
Packit c32a2d
	/* Xing VBR TOC works with relative positions, both in terms of audio frames and stream bytes.
Packit c32a2d
	   Thus, it only works when whe know the length of things.
Packit c32a2d
	   Oh... I assume the offsets are relative to the _total_ file length. */
Packit c32a2d
	if(fr->xing_toc != NULL && fr->track_frames > 0 && fr->rdat.filelen > 0)
Packit c32a2d
	{
Packit c32a2d
		/* One could round... */
Packit c32a2d
		int toc_entry = (int) ((double)want_frame*100./fr->track_frames);
Packit c32a2d
		/* It is an index in the 100-entry table. */
Packit c32a2d
		if(toc_entry < 0)  toc_entry = 0;
Packit c32a2d
		if(toc_entry > 99) toc_entry = 99;
Packit c32a2d
Packit c32a2d
		/* Now estimate back what frame we get. */
Packit c32a2d
		*get_frame = (off_t) ((double)toc_entry/100. * fr->track_frames);
Packit c32a2d
		fr->state_flags &= ~FRAME_ACCURATE;
Packit c32a2d
		fr->silent_resync = 1;
Packit c32a2d
		/* Question: Is the TOC for whole file size (with/without ID3) or the "real" audio data only?
Packit c32a2d
		   ID3v1 info could also matter. */
Packit c32a2d
		ret = (off_t) ((double)fr->xing_toc[toc_entry]/256.* fr->rdat.filelen);
Packit c32a2d
	}
Packit c32a2d
	else if(fr->mean_framesize > 0)
Packit c32a2d
	{	/* Just guess with mean framesize (may be exact with CBR files). */
Packit c32a2d
		/* Query filelen here or not? */
Packit c32a2d
		fr->state_flags &= ~FRAME_ACCURATE; /* Fuzzy! */
Packit c32a2d
		fr->silent_resync = 1;
Packit c32a2d
		*get_frame = want_frame;
Packit c32a2d
		ret = (off_t) (fr->audio_start+fr->mean_framesize*want_frame);
Packit c32a2d
	}
Packit c32a2d
	debug5("fuzzy: want %li of %li, get %li at %li B of %li B",
Packit c32a2d
		(long)want_frame, (long)fr->track_frames, (long)*get_frame, (long)ret, (long)(fr->rdat.filelen-fr->audio_start));
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	find the best frame in index just before the wanted one, seek to there
Packit c32a2d
	then step to just before wanted one with read_frame
Packit c32a2d
	do not care tabout the stuff that was in buffer but not played back
Packit c32a2d
	everything that left the decoder is counted as played
Packit c32a2d
	
Packit c32a2d
	Decide if you want low latency reaction and accurate timing info or stable long-time playback with buffer!
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
off_t frame_index_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
Packit c32a2d
{
Packit c32a2d
	/* default is file start if no index position */
Packit c32a2d
	off_t gopos = 0;
Packit c32a2d
	*get_frame = 0;
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	/* Possibly use VBRI index, too? I'd need an example for this... */
Packit c32a2d
	if(fr->index.fill)
Packit c32a2d
	{
Packit c32a2d
		/* find in index */
Packit c32a2d
		size_t fi;
Packit c32a2d
		/* at index fi there is frame step*fi... */
Packit c32a2d
		fi = want_frame/fr->index.step;
Packit c32a2d
		if(fi >= fr->index.fill) /* If we are beyond the end of frame index...*/
Packit c32a2d
		{
Packit c32a2d
			/* When fuzzy seek is allowed, we have some limited tolerance for the frames we want to read rather then jump over. */
Packit c32a2d
			if(fr->p.flags & MPG123_FUZZY && want_frame - (fr->index.fill-1)*fr->index.step > 10)
Packit c32a2d
			{
Packit c32a2d
				gopos = frame_fuzzy_find(fr, want_frame, get_frame);
Packit c32a2d
				if(gopos > fr->audio_start) return gopos; /* Only in that case, we have a useful guess. */
Packit c32a2d
				/* Else... just continue, fuzzyness didn't help. */
Packit c32a2d
			}
Packit c32a2d
			/* Use the last available position, slowly advancing from that one. */
Packit c32a2d
			fi = fr->index.fill - 1;
Packit c32a2d
		}
Packit c32a2d
		/* We have index position, that yields frame and byte offsets. */
Packit c32a2d
		*get_frame = fi*fr->index.step;
Packit c32a2d
		gopos = fr->index.data[fi];
Packit c32a2d
		fr->state_flags |= FRAME_ACCURATE; /* When using the frame index, we are accurate. */
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
#endif
Packit c32a2d
		if(fr->p.flags & MPG123_FUZZY)
Packit c32a2d
		return frame_fuzzy_find(fr, want_frame, get_frame);
Packit c32a2d
		/* A bit hackish here... but we need to be fresh when looking for the first header again. */
Packit c32a2d
		fr->firsthead = 0;
Packit c32a2d
		fr->oldhead = 0;
Packit c32a2d
#ifdef FRAME_INDEX
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	debug2("index: 0x%lx for frame %li", (unsigned long)gopos, (long) *get_frame);
Packit c32a2d
	return gopos;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t frame_ins2outs(mpg123_handle *fr, off_t ins)
Packit c32a2d
{	
Packit c32a2d
	off_t outs = 0;
Packit c32a2d
	switch(fr->down_sample)
Packit c32a2d
	{
Packit c32a2d
		case 0:
Packit c32a2d
#		ifndef NO_DOWNSAMPLE
Packit c32a2d
		case 1:
Packit c32a2d
		case 2:
Packit c32a2d
#		endif
Packit c32a2d
			outs = ins>>fr->down_sample;
Packit c32a2d
		break;
Packit c32a2d
#		ifndef NO_NTOM
Packit c32a2d
		case 3: outs = ntom_ins2outs(fr, ins); break;
Packit c32a2d
#		endif
Packit c32a2d
		default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
Packit c32a2d
	}
Packit c32a2d
	return outs;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t frame_outs(mpg123_handle *fr, off_t num)
Packit c32a2d
{
Packit c32a2d
	off_t outs = 0;
Packit c32a2d
	switch(fr->down_sample)
Packit c32a2d
	{
Packit c32a2d
		case 0:
Packit c32a2d
#		ifndef NO_DOWNSAMPLE
Packit c32a2d
		case 1:
Packit c32a2d
		case 2:
Packit c32a2d
#		endif
Packit c32a2d
			outs = (fr->spf>>fr->down_sample)*num;
Packit c32a2d
		break;
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
		case 3: outs = ntom_frmouts(fr, num); break;
Packit c32a2d
#endif
Packit c32a2d
		default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
Packit c32a2d
	}
Packit c32a2d
	return outs;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Compute the number of output samples we expect from this frame.
Packit c32a2d
   This is either simple spf() or a tad more elaborate for ntom. */
Packit c32a2d
off_t frame_expect_outsamples(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	off_t outs = 0;
Packit c32a2d
	switch(fr->down_sample)
Packit c32a2d
	{
Packit c32a2d
		case 0:
Packit c32a2d
#		ifndef NO_DOWNSAMPLE
Packit c32a2d
		case 1:
Packit c32a2d
		case 2:
Packit c32a2d
#		endif
Packit c32a2d
			outs = fr->spf>>fr->down_sample;
Packit c32a2d
		break;
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
		case 3: outs = ntom_frame_outsamples(fr); break;
Packit c32a2d
#endif
Packit c32a2d
		default: error1("Bad down_sample (%i) ... should not be possible!!", fr->down_sample);
Packit c32a2d
	}
Packit c32a2d
	return outs;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t frame_offset(mpg123_handle *fr, off_t outs)
Packit c32a2d
{
Packit c32a2d
	off_t num = 0;
Packit c32a2d
	switch(fr->down_sample)
Packit c32a2d
	{
Packit c32a2d
		case 0:
Packit c32a2d
#		ifndef NO_DOWNSAMPLE
Packit c32a2d
		case 1:
Packit c32a2d
		case 2:
Packit c32a2d
#		endif
Packit c32a2d
			num = outs/(fr->spf>>fr->down_sample);
Packit c32a2d
		break;
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
		case 3: num = ntom_frameoff(fr, outs); break;
Packit c32a2d
#endif
Packit c32a2d
		default: error("Bad down_sample ... should not be possible!!");
Packit c32a2d
	}
Packit c32a2d
	return num;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
/* input in _input_ samples */
Packit c32a2d
void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip)
Packit c32a2d
{
Packit c32a2d
	debug3("frame_gapless_init: given %"OFF_P" frames, skip %"OFF_P" and %"OFF_P, (off_p)framecount, (off_p)bskip, (off_p)eskip);
Packit c32a2d
	fr->gapless_frames = framecount;
Packit c32a2d
	if(fr->gapless_frames > 0 && bskip >=0 && eskip >= 0)
Packit c32a2d
	{
Packit c32a2d
		fr->begin_s = bskip+GAPLESS_DELAY;
Packit c32a2d
		fr->end_s = framecount*fr->spf-eskip+GAPLESS_DELAY;
Packit c32a2d
	}
Packit c32a2d
	else fr->begin_s = fr->end_s = 0;
Packit c32a2d
	/* These will get proper values later, from above plus resampling info. */
Packit c32a2d
	fr->begin_os = 0;
Packit c32a2d
	fr->end_os = 0;
Packit c32a2d
	fr->fullend_os = 0;
Packit c32a2d
	debug2("frame_gapless_init: from %"OFF_P" to %"OFF_P" samples", (off_p)fr->begin_s, (off_p)fr->end_s);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void frame_gapless_realinit(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	fr->begin_os = frame_ins2outs(fr, fr->begin_s);
Packit c32a2d
	fr->end_os   = frame_ins2outs(fr, fr->end_s);
Packit c32a2d
	if(fr->gapless_frames > 0)
Packit c32a2d
	fr->fullend_os = frame_ins2outs(fr, fr->gapless_frames*fr->spf);
Packit c32a2d
	else fr->fullend_os = 0;
Packit c32a2d
Packit c32a2d
	debug4("frame_gapless_realinit: from %"OFF_P" to %"OFF_P" samples (%"OFF_P", %"OFF_P")", (off_p)fr->begin_os, (off_p)fr->end_os, (off_p)fr->fullend_os, (off_p)fr->gapless_frames);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* At least note when there is trouble... */
Packit c32a2d
void frame_gapless_update(mpg123_handle *fr, off_t total_samples)
Packit c32a2d
{
Packit c32a2d
	off_t gapless_samples = fr->gapless_frames*fr->spf;
Packit c32a2d
	if(fr->gapless_frames < 1) return;
Packit c32a2d
Packit c32a2d
	debug2("gapless update with new sample count %"OFF_P" as opposed to known %"OFF_P, total_samples, gapless_samples);
Packit c32a2d
	if(NOQUIET && total_samples != gapless_samples)
Packit c32a2d
	fprintf(stderr, "\nWarning: Real sample count %"OFF_P" differs from given gapless sample count %"OFF_P". Frankenstein stream?\n"
Packit c32a2d
	, total_samples, gapless_samples);
Packit c32a2d
Packit c32a2d
	if(gapless_samples > total_samples)
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET) error2("End sample count smaller than gapless end! (%"OFF_P" < %"OFF_P"). Disabling gapless mode from now on.", (off_p)total_samples, (off_p)fr->end_s);
Packit c32a2d
		/* This invalidates the current position... but what should I do? */
Packit c32a2d
		frame_gapless_init(fr, -1, 0, 0);
Packit c32a2d
		frame_gapless_realinit(fr);
Packit c32a2d
		fr->lastframe = -1;
Packit c32a2d
		fr->lastoff = 0;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
/* Compute the needed frame to ignore from, for getting accurate/consistent output for intended firstframe. */
Packit c32a2d
static off_t ignoreframe(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	off_t preshift = fr->p.preframes;
Packit c32a2d
	/* Layer 3 _really_ needs at least one frame before. */
Packit c32a2d
	if(fr->lay==3 && preshift < 1) preshift = 1;
Packit c32a2d
	/* Layer 1 & 2 reall do not need more than 2. */
Packit c32a2d
	if(fr->lay!=3 && preshift > 2) preshift = 2;
Packit c32a2d
Packit c32a2d
	return fr->firstframe - preshift;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* The frame seek... This is not simply the seek to fe*fr->spf samples in output because we think of _input_ frames here.
Packit c32a2d
   Seek to frame offset 1 may be just seek to 200 samples offset in output since the beginning of first frame is delay/padding.
Packit c32a2d
   Hm, is that right? OK for the padding stuff, but actually, should the decoder delay be better totally hidden or not?
Packit c32a2d
   With gapless, even the whole frame position could be advanced further than requested (since Homey don't play dat). */
Packit c32a2d
void frame_set_frameseek(mpg123_handle *fr, off_t fe)
Packit c32a2d
{
Packit c32a2d
	fr->firstframe = fe;
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
	if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0)
Packit c32a2d
	{
Packit c32a2d
		/* Take care of the beginning... */
Packit c32a2d
		off_t beg_f = frame_offset(fr, fr->begin_os);
Packit c32a2d
		if(fe <= beg_f)
Packit c32a2d
		{
Packit c32a2d
			fr->firstframe = beg_f;
Packit c32a2d
			fr->firstoff   = fr->begin_os - frame_outs(fr, beg_f);
Packit c32a2d
		}
Packit c32a2d
		else fr->firstoff = 0;
Packit c32a2d
		/* The end is set once for a track at least, on the frame_set_frameseek called in get_next_frame() */
Packit c32a2d
		if(fr->end_os > 0)
Packit c32a2d
		{
Packit c32a2d
			fr->lastframe  = frame_offset(fr,fr->end_os);
Packit c32a2d
			fr->lastoff    = fr->end_os - frame_outs(fr, fr->lastframe);
Packit c32a2d
		} else {fr->lastframe = -1; fr->lastoff = 0; }
Packit c32a2d
	} else { fr->firstoff = fr->lastoff = 0; fr->lastframe = -1; }
Packit c32a2d
#endif
Packit c32a2d
	fr->ignoreframe = ignoreframe(fr);
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
	debug5("frame_set_frameseek: begin at %li frames and %li samples, end at %li and %li; ignore from %li",
Packit c32a2d
	       (long) fr->firstframe, (long) fr->firstoff,
Packit c32a2d
	       (long) fr->lastframe,  (long) fr->lastoff, (long) fr->ignoreframe);
Packit c32a2d
#else
Packit c32a2d
	debug3("frame_set_frameseek: begin at %li frames, end at %li; ignore from %li",
Packit c32a2d
	       (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void frame_skip(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
#ifndef NO_LAYER3
Packit c32a2d
	if(fr->lay == 3) set_pointer(fr, 512);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Sample accurate seek prepare for decoder. */
Packit c32a2d
/* This gets unadjusted output samples and takes resampling into account */
Packit c32a2d
void frame_set_seek(mpg123_handle *fr, off_t sp)
Packit c32a2d
{
Packit c32a2d
	fr->firstframe = frame_offset(fr, sp);
Packit c32a2d
	debug1("frame_set_seek: from %"OFF_P, fr->num);
Packit c32a2d
#ifndef NO_NTOM
Packit c32a2d
	if(fr->down_sample == 3) ntom_set_ntom(fr, fr->firstframe);
Packit c32a2d
#endif
Packit c32a2d
	fr->ignoreframe = ignoreframe(fr);
Packit c32a2d
#ifdef GAPLESS /* The sample offset is used for non-gapless mode, too! */
Packit c32a2d
	fr->firstoff = sp - frame_outs(fr, fr->firstframe);
Packit c32a2d
	debug5("frame_set_seek: begin at %li frames and %li samples, end at %li and %li; ignore from %li",
Packit c32a2d
	       (long) fr->firstframe, (long) fr->firstoff,
Packit c32a2d
	       (long) fr->lastframe,  (long) fr->lastoff, (long) fr->ignoreframe);
Packit c32a2d
#else
Packit c32a2d
	debug3("frame_set_seek: begin at %li frames, end at %li; ignore from %li",
Packit c32a2d
	       (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_volume_change(mpg123_handle *mh, double change)
Packit c32a2d
{
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
	return mpg123_volume(mh, change + (double) mh->p.outscale);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_volume(mpg123_handle *mh, double vol)
Packit c32a2d
{
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	if(vol >= 0) mh->p.outscale = vol;
Packit c32a2d
	else mh->p.outscale = 0.;
Packit c32a2d
Packit c32a2d
	do_rva(mh);
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
static int get_rva(mpg123_handle *fr, double *peak, double *gain)
Packit c32a2d
{
Packit c32a2d
	double p = -1;
Packit c32a2d
	double g = 0;
Packit c32a2d
	int ret = 0;
Packit c32a2d
	if(fr->p.rva)
Packit c32a2d
	{
Packit c32a2d
		int rt = 0;
Packit c32a2d
		/* Should one assume a zero RVA as no RVA? */
Packit c32a2d
		if(fr->p.rva == 2 && fr->rva.level[1] != -1) rt = 1;
Packit c32a2d
		if(fr->rva.level[rt] != -1)
Packit c32a2d
		{
Packit c32a2d
			p = fr->rva.peak[rt];
Packit c32a2d
			g = fr->rva.gain[rt];
Packit c32a2d
			ret = 1; /* Success. */
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	if(peak != NULL) *peak = p;
Packit c32a2d
	if(gain != NULL) *gain = g;
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* adjust the volume, taking both fr->outscale and rva values into account */
Packit c32a2d
void do_rva(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	double peak = 0;
Packit c32a2d
	double gain = 0;
Packit c32a2d
	double newscale;
Packit c32a2d
	double rvafact = 1;
Packit c32a2d
	if(get_rva(fr, &peak, &gain))
Packit c32a2d
	{
Packit c32a2d
		if(NOQUIET && fr->p.verbose > 1) fprintf(stderr, "Note: doing RVA with gain %f\n", gain);
Packit c32a2d
		rvafact = pow(10,gain/20);
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	newscale = fr->p.outscale*rvafact;
Packit c32a2d
Packit c32a2d
	/* if peak is unknown (== 0) this check won't hurt */
Packit c32a2d
	if((peak*newscale) > 1.0)
Packit c32a2d
	{
Packit c32a2d
		newscale = 1.0/peak;
Packit c32a2d
		warning2("limiting scale value to %f to prevent clipping with indicated peak factor of %f", newscale, peak);
Packit c32a2d
	}
Packit c32a2d
	/* first rva setting is forced with fr->lastscale < 0 */
Packit c32a2d
	if(newscale != fr->lastscale || fr->decoder_change)
Packit c32a2d
	{
Packit c32a2d
		debug3("changing scale value from %f to %f (peak estimated to %f)", fr->lastscale != -1 ? fr->lastscale : fr->p.outscale, newscale, (double) (newscale*peak));
Packit c32a2d
		fr->lastscale = newscale;
Packit c32a2d
		/* It may be too early, actually. */
Packit c32a2d
		if(fr->make_decode_tables != NULL) fr->make_decode_tables(fr); /* the actual work */
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
Packit c32a2d
int attribute_align_arg mpg123_getvolume(mpg123_handle *mh, double *base, double *really, double *rva_db)
Packit c32a2d
{
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
	if(base)   *base   = mh->p.outscale;
Packit c32a2d
	if(really) *really = mh->lastscale;
Packit c32a2d
	get_rva(mh, NULL, rva_db);
Packit c32a2d
	return MPG123_OK;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
off_t attribute_align_arg mpg123_framepos(mpg123_handle *mh)
Packit c32a2d
{
Packit c32a2d
	if(mh == NULL) return MPG123_ERR;
Packit c32a2d
Packit c32a2d
	return mh->input_offset;
Packit c32a2d
}