Blame src/libmpg123/gapless.h

Packit c32a2d
/*
Packit c32a2d
	sampleadjust: gapless sample offset math
Packit c32a2d
Packit c32a2d
	copyright 1995-2012 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
Packit c32a2d
	This is no stand-alone header, precisely to be able to fool it into using fake handle types for testing the math.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
#ifdef GAPLESS
Packit c32a2d
/* From internal sample number to external. */
Packit c32a2d
static off_t sample_adjust(mpg123_handle *mh, off_t x)
Packit c32a2d
{
Packit c32a2d
	off_t s;
Packit c32a2d
	if(mh->p.flags & MPG123_GAPLESS)
Packit c32a2d
	{
Packit c32a2d
		/* It's a bit tricky to do this computation for the padding samples.
Packit c32a2d
		   They are not there on the outside. */
Packit c32a2d
		if(x > mh->end_os)
Packit c32a2d
		{
Packit c32a2d
			if(x < mh->fullend_os)
Packit c32a2d
			s = mh->end_os - mh->begin_os;
Packit c32a2d
			else
Packit c32a2d
			s = x - (mh->fullend_os - mh->end_os + mh->begin_os);
Packit c32a2d
		}
Packit c32a2d
		else
Packit c32a2d
		s = x - mh->begin_os;
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	s = x;
Packit c32a2d
Packit c32a2d
	return s;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* from external samples to internal */
Packit c32a2d
static off_t sample_unadjust(mpg123_handle *mh, off_t x)
Packit c32a2d
{
Packit c32a2d
	off_t s;
Packit c32a2d
	if(mh->p.flags & MPG123_GAPLESS)
Packit c32a2d
	{
Packit c32a2d
		s = x + mh->begin_os;
Packit c32a2d
		/* There is a hole; we don't create sample positions in there.
Packit c32a2d
		   Jump from the end of the gapless track directly to after the padding. */
Packit c32a2d
		if(s >= mh->end_os)
Packit c32a2d
		s += mh->fullend_os - mh->end_os;
Packit c32a2d
	}
Packit c32a2d
	else s = x;
Packit c32a2d
Packit c32a2d
	return s;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out.
Packit c32a2d
	fr->buffer.fill may then be smaller than before...
Packit c32a2d
*/
Packit c32a2d
static void frame_buffercheck(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	/* When we have no accurate position, gapless code does not make sense. */
Packit c32a2d
	if(!(fr->state_flags & FRAME_ACCURATE)) return;
Packit c32a2d
Packit c32a2d
	/* Get a grip on dirty streams that start with a gapless header.
Packit c32a2d
	   Simply accept all data from frames that are too much,
Packit c32a2d
	   they are supposedly attached to the stream after the fact. */
Packit c32a2d
	if(fr->gapless_frames > 0 && fr->num >= fr->gapless_frames) return;
Packit c32a2d
Packit c32a2d
	/* Important: We first cut samples from the end, then cut from beginning (including left-shift of the buffer).
Packit c32a2d
	   This order works also for the case where firstframe == lastframe. */
Packit c32a2d
Packit c32a2d
	/* The last interesting (planned) frame: Only use some leading samples.
Packit c32a2d
	   Note a difference from the below: The last frame and offset are unchanges by seeks.
Packit c32a2d
	   The lastoff keeps being valid. */
Packit c32a2d
	if(fr->lastframe > -1 && fr->num >= fr->lastframe)
Packit c32a2d
	{
Packit c32a2d
		/* There can be more than one frame of padding at the end, so we ignore the whole frame if we are beyond lastframe. */
Packit c32a2d
		off_t byteoff = (fr->num == fr->lastframe) ? samples_to_bytes(fr, fr->lastoff) : 0;
Packit c32a2d
		if((off_t)fr->buffer.fill > byteoff)
Packit c32a2d
		{
Packit c32a2d
			fr->buffer.fill = byteoff;
Packit c32a2d
		}
Packit c32a2d
		if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on end of stream to %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)(fr->num == fr->lastframe ? fr->lastoff : 0), (size_p)fr->buffer.fill);
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	/* The first interesting frame: Skip some leading samples. */
Packit c32a2d
	if(fr->firstoff && fr->num == fr->firstframe)
Packit c32a2d
	{
Packit c32a2d
		off_t byteoff = samples_to_bytes(fr, fr->firstoff);
Packit c32a2d
		if((off_t)fr->buffer.fill > byteoff)
Packit c32a2d
		{
Packit c32a2d
			fr->buffer.fill -= byteoff;
Packit c32a2d
			/* buffer.p != buffer.data only for own buffer */
Packit c32a2d
			debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i",
Packit c32a2d
			        (long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]);
Packit c32a2d
			if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff;
Packit c32a2d
			else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill);
Packit c32a2d
			debug3("done cutting, buffer at %p =? %p, buf[1]=%i",
Packit c32a2d
			        (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]);
Packit c32a2d
		}
Packit c32a2d
		else fr->buffer.fill = 0;
Packit c32a2d
Packit c32a2d
		if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on beginning of stream by %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)fr->firstoff, (size_p)fr->buffer.fill);
Packit c32a2d
		/* We can only reach this frame again by seeking. And on seeking, firstoff will be recomputed.
Packit c32a2d
		   So it is safe to null it here (and it makes the if() decision abort earlier). */
Packit c32a2d
		fr->firstoff = 0;
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#define SAMPLE_ADJUST(mh,x)     sample_adjust(mh,x)
Packit c32a2d
#define SAMPLE_UNADJUST(mh,x)   sample_unadjust(mh,x)
Packit c32a2d
#define FRAME_BUFFERCHECK(mh) frame_buffercheck(mh)
Packit c32a2d
Packit c32a2d
#else /* no gapless code included */
Packit c32a2d
Packit c32a2d
#define SAMPLE_ADJUST(mh,x)   (x)
Packit c32a2d
#define SAMPLE_UNADJUST(mh,x) (x)
Packit c32a2d
#define FRAME_BUFFERCHECK(mh)
Packit c32a2d
Packit c32a2d
#endif