Blame src/libmpg123/ntom.c

Packit c32a2d
/*
Packit c32a2d
	ntom.c: N->M down/up sampling; the setup code.
Packit c32a2d
Packit c32a2d
	copyright 1995-2008 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 Michael Hipp
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#define SAFE_NTOM /* Do not depend on off_t*off_t with big values still being in the range... */
Packit c32a2d
#include "mpg123lib_intern.h"
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
int synth_ntom_set_step(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	long m,n;
Packit c32a2d
	m = frame_freq(fr);
Packit c32a2d
	n = fr->af.rate;
Packit c32a2d
	if(VERBOSE2)
Packit c32a2d
		fprintf(stderr,"Init rate converter: %ld->%ld\n",m,n);
Packit c32a2d
Packit c32a2d
	if(n > NTOM_MAX_FREQ || m > NTOM_MAX_FREQ || m <= 0 || n <= 0) {
Packit c32a2d
		if(NOQUIET) error("NtoM converter: illegal rates");
Packit c32a2d
		fr->err = MPG123_BAD_RATE;
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	n *= NTOM_MUL;
Packit c32a2d
	fr->ntom_step = (unsigned long) n / m;
Packit c32a2d
Packit c32a2d
	if(fr->ntom_step > (unsigned long)NTOM_MAX*NTOM_MUL) {
Packit c32a2d
		if(NOQUIET) error3("max. 1:%i conversion allowed (%lu vs %lu)!", NTOM_MAX, fr->ntom_step, (unsigned long)8*NTOM_MUL);
Packit c32a2d
		fr->err = MPG123_BAD_RATE;
Packit c32a2d
		return -1;
Packit c32a2d
	}
Packit c32a2d
Packit c32a2d
	fr->ntom_val[0] = fr->ntom_val[1] = ntom_val(fr, fr->num);
Packit c32a2d
	return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	The SAFE_NTOM does iterative loops instead of straight multiplication.
Packit c32a2d
	The safety is not just about the algorithm closely mimicking the decoder instead of applying some formula,
Packit c32a2d
	it is more about avoiding multiplication of possibly big sample offsets (a 32bit off_t could overflow too easily).
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
unsigned long ntom_val(mpg123_handle *fr, off_t frame)
Packit c32a2d
{
Packit c32a2d
	off_t ntm;
Packit c32a2d
#ifdef SAFE_NTOM /* Carry out the loop, without the threatening integer overflow. */
Packit c32a2d
	off_t f;
Packit c32a2d
	ntm = NTOM_MUL>>1; /* for frame 0 */
Packit c32a2d
	for(f=0; f<frame; ++f)   /* for frame > 0 */
Packit c32a2d
	{
Packit c32a2d
		ntm += fr->spf*fr->ntom_step;
Packit c32a2d
		ntm -= (ntm/NTOM_MUL)*NTOM_MUL;
Packit c32a2d
	}
Packit c32a2d
#else /* Just make one computation with overall sample offset. */
Packit c32a2d
	ntm  = (NTOM_MUL>>1) + fr->spf*frame*fr->ntom_step;
Packit c32a2d
	ntm -= (ntm/NTOM_MUL)*NTOM_MUL;
Packit c32a2d
#endif
Packit c32a2d
	return (unsigned long) ntm;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Set the ntom value for next expected frame to be decoded.
Packit c32a2d
   This is for keeping output consistent across seeks. */
Packit c32a2d
void ntom_set_ntom(mpg123_handle *fr, off_t num)
Packit c32a2d
{
Packit c32a2d
	fr->ntom_val[1] = fr->ntom_val[0] = ntom_val(fr, num);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Carry out the ntom sample count operation for this one frame. 
Packit c32a2d
   No fear of integer overflow here. */
Packit c32a2d
off_t ntom_frame_outsamples(mpg123_handle *fr)
Packit c32a2d
{
Packit c32a2d
	/* The do this before decoding the separate channels, so there is only one common ntom value. */
Packit c32a2d
	int ntm = fr->ntom_val[0];
Packit c32a2d
	ntm += fr->spf*fr->ntom_step;
Packit c32a2d
	return ntm/NTOM_MUL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Convert frame offset to unadjusted output sample offset. */
Packit c32a2d
off_t ntom_frmouts(mpg123_handle *fr, off_t frame)
Packit c32a2d
{
Packit c32a2d
#ifdef SAFE_NTOM
Packit c32a2d
	off_t f;
Packit c32a2d
#endif
Packit c32a2d
	off_t soff = 0;
Packit c32a2d
	off_t ntm = ntom_val(fr,0);
Packit c32a2d
#ifdef SAFE_NTOM
Packit c32a2d
	if(frame <= 0) return 0;
Packit c32a2d
	for(f=0; f
Packit c32a2d
	{
Packit c32a2d
		ntm  += fr->spf*fr->ntom_step;
Packit c32a2d
		soff += ntm/NTOM_MUL;
Packit c32a2d
		ntm  -= (ntm/NTOM_MUL)*NTOM_MUL;
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	soff = (ntm + frame*(off_t)fr->spf*(off_t)fr->ntom_step)/(off_t)NTOM_MUL;
Packit c32a2d
#endif
Packit c32a2d
	return soff;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Convert input samples to unadjusted output samples. */
Packit c32a2d
off_t ntom_ins2outs(mpg123_handle *fr, off_t ins)
Packit c32a2d
{
Packit c32a2d
	off_t soff = 0;
Packit c32a2d
	off_t ntm = ntom_val(fr,0);
Packit c32a2d
#ifdef SAFE_NTOM
Packit c32a2d
	{
Packit c32a2d
		off_t block = fr->spf;
Packit c32a2d
		if(ins <= 0) return 0;
Packit c32a2d
		do
Packit c32a2d
		{
Packit c32a2d
			off_t nowblock = ins > block ? block : ins;
Packit c32a2d
			ntm  += nowblock*fr->ntom_step;
Packit c32a2d
			soff += ntm/NTOM_MUL;
Packit c32a2d
			ntm  -= (ntm/NTOM_MUL)*NTOM_MUL;
Packit c32a2d
			ins -= nowblock;
Packit c32a2d
		} while(ins > 0);
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	/* Beware of overflows: when off_t is 32bits, the multiplication blows too easily.
Packit c32a2d
	   Of course, it blows for 64bits, too, in theory, but that's for _really_ large files. */
Packit c32a2d
	soff = ((off_t)ntm + (off_t)ins*(off_t)fr->ntom_step)/(off_t)NTOM_MUL;
Packit c32a2d
#endif
Packit c32a2d
	return soff;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Determine frame offset from unadjusted output sample offset. */
Packit c32a2d
off_t ntom_frameoff(mpg123_handle *fr, off_t soff)
Packit c32a2d
{
Packit c32a2d
	off_t ioff = 0; /* frames or samples */
Packit c32a2d
	off_t ntm = ntom_val(fr,0);
Packit c32a2d
#ifdef SAFE_NTOM
Packit c32a2d
	if(soff <= 0) return 0;
Packit c32a2d
	for(ioff=0; 1; ++ioff)
Packit c32a2d
	{
Packit c32a2d
		ntm  += fr->spf*fr->ntom_step;
Packit c32a2d
		if(ntm/NTOM_MUL > soff) break;
Packit c32a2d
		soff -= ntm/NTOM_MUL;
Packit c32a2d
		ntm  -= (ntm/NTOM_MUL)*NTOM_MUL;
Packit c32a2d
	}
Packit c32a2d
	return ioff;
Packit c32a2d
#else
Packit c32a2d
	ioff = (soff*(off_t)NTOM_MUL-ntm)/(off_t)fr->ntom_step;
Packit c32a2d
	return ioff/(off_t)fr->spf;
Packit c32a2d
#endif
Packit c32a2d
}