#define WANT_GETCPUFLAGS
#include "mpg123lib_intern.h"
#include "getcpuflags.h"
#include "../common/debug.h"
static void frame_fixed_reset(mpg123_handle *fr);
#define NTOM_MUL (32768)
#define aligned_pointer(p, type, alignment) align_the_pointer(p, alignment)
static void *align_the_pointer(void *base, unsigned int alignment)
{
uintptr_t baseval = (uintptr_t)(char*)base;
uintptr_t aoff = baseval % alignment;
debug3("align_the_pointer: pointer %p is off by %u from %u",
base, (unsigned int)aoff, alignment);
if(aoff) return (char*)base+alignment-aoff;
else return base;
}
static void frame_default_pars(mpg123_pars *mp)
{
mp->outscale = 1.0;
mp->flags = 0;
#ifdef GAPLESS
mp->flags |= MPG123_GAPLESS;
#endif
mp->flags |= MPG123_AUTO_RESAMPLE|MPG123_FLOAT_FALLBACK;
#ifndef NO_NTOM
mp->force_rate = 0;
#endif
mp->down_sample = 0;
mp->rva = 0;
mp->halfspeed = 0;
mp->doublespeed = 0;
mp->verbose = 0;
#ifndef NO_ICY
mp->icy_interval = 0;
#endif
mp->timeout = 0;
mp->resync_limit = 1024;
#ifdef FRAME_INDEX
mp->index_size = INDEX_SIZE;
#endif
mp->preframes = 4;
mpg123_fmt_all(mp);
#ifndef NO_FEEDER
mp->feedpool = 5;
mp->feedbuffer = 4096;
#endif
mp->freeformat_framesize = -1;
}
void INT123_frame_init(mpg123_handle *fr)
{
INT123_frame_init_par(fr, NULL);
}
void INT123_frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
{
fr->own_buffer = TRUE;
fr->buffer.data = NULL;
fr->buffer.rdata = NULL;
fr->buffer.fill = 0;
fr->buffer.size = 0;
fr->rawbuffs = NULL;
fr->rawbuffss = 0;
fr->rawdecwin = NULL;
fr->rawdecwins = 0;
#ifdef REAL_IS_FIXED
fr->gainpow2 = NULL;
#endif
#ifndef NO_8BIT
fr->conv16to8_buf = NULL;
#endif
#ifdef OPT_DITHER
fr->dithernoise = NULL;
#endif
fr->layerscratch = NULL;
fr->xing_toc = NULL;
#ifdef OPT_CPU_FLAGS
wrap_getcpuflags(&(fr->cpu_flags));
#endif
fr->cpu_opts.type = INT123_defdec();
fr->cpu_opts.class = INT123_decclass(fr->cpu_opts.type);
#ifndef NO_NTOM
fr->INT123_ntom_val[0] = NTOM_MUL>>1;
fr->INT123_ntom_val[1] = NTOM_MUL>>1;
fr->ntom_step = NTOM_MUL;
#endif
mpg123_reset_eq(fr);
INT123_init_icy(&fr->icy);
INT123_init_id3(fr);
INT123_invalidate_format(&fr->af);
fr->rdat.iohandle = NULL;
fr->rdat.r_read64 = NULL;
fr->rdat.r_lseek64 = NULL;
fr->rdat.cleanup_handle = NULL;
fr->wrapperdata = NULL;
fr->decoder_change = 1;
fr->err = MPG123_OK;
if(mp == NULL) frame_default_pars(&fr->p);
else memcpy(&fr->p, mp, sizeof(struct mpg123_pars_struct));
#ifndef NO_FEEDER
INT123_bc_prepare(&fr->rdat.buffer, fr->p.feedpool, fr->p.feedbuffer);
#endif
fr->down_sample = 0;
fr->id3v2_raw = NULL;
frame_fixed_reset(fr);
fr->synth = NULL;
fr->synth_mono = NULL;
fr->INT123_make_decode_tables = NULL;
#ifdef FRAME_INDEX
INT123_fi_init(&fr->index);
INT123_frame_index_setup(fr);
#endif
#ifndef NO_MOREINFO
fr->pinfo = NULL;
#endif
}
#ifdef OPT_DITHER
int INT123_frame_dither_init(mpg123_handle *fr)
{
if(fr->dithernoise == NULL)
{
fr->dithernoise = malloc(sizeof(float)*DITHERSIZE);
if(fr->dithernoise == NULL) return 0;
INT123_dither_table_init(fr->dithernoise);
}
return 1;
}
#endif
mpg123_pars attribute_align_arg *mpg123_new_pars(int *error)
{
mpg123_pars *mp = malloc(sizeof(struct mpg123_pars_struct));
if(mp != NULL){ frame_default_pars(mp); if(error != NULL) *error = MPG123_OK; }
else if(error != NULL) *error = MPG123_OUT_OF_MEM;
return mp;
}
void attribute_align_arg mpg123_delete_pars(mpg123_pars* mp)
{
if(mp != NULL) free(mp);
}
int attribute_align_arg mpg123_reset_eq(mpg123_handle *mh)
{
if(mh == NULL) return MPG123_BAD_HANDLE;
#ifndef NO_EQUALIZER
int i;
mh->have_eq_settings = 0;
for(i=0; i < 32; ++i) mh->equalizer[0][i] = mh->equalizer[1][i] = DOUBLE_TO_REAL(1.0);
#endif
return MPG123_OK;
}
int INT123_frame_outbuffer(mpg123_handle *fr)
{
size_t size = fr->outblock;
if(!fr->own_buffer)
{
if(fr->buffer.size < size)
{
fr->err = MPG123_BAD_BUFFER;
if(NOQUIET)
merror("have external buffer of size %zu, need %zu", fr->buffer.size, size);
return MPG123_ERR;
}
}
debug1("need frame buffer of %zu", size);
if(fr->buffer.rdata != NULL && fr->buffer.size != size)
{
free(fr->buffer.rdata);
fr->buffer.rdata = NULL;
}
fr->buffer.size = size;
fr->buffer.data = NULL;
if(fr->buffer.rdata == NULL) fr->buffer.rdata = (unsigned char*) malloc(fr->buffer.size+15);
if(fr->buffer.rdata == NULL)
{
fr->err = MPG123_OUT_OF_MEM;
return MPG123_ERR;
}
fr->buffer.data = aligned_pointer(fr->buffer.rdata, unsigned char*, 16);
fr->own_buffer = TRUE;
fr->buffer.fill = 0;
return MPG123_OK;
}
int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, void *data, size_t size)
{
debug2("replace buffer with %p size %zu", data, size);
if(mh == NULL) return MPG123_BAD_HANDLE;
if(data == NULL)
{
mh->err = MPG123_BAD_BUFFER;
return MPG123_ERR;
}
if(mh->buffer.rdata != NULL) free(mh->buffer.rdata);
mh->own_buffer = FALSE;
mh->buffer.rdata = NULL;
mh->buffer.data = data;
mh->buffer.size = size;
mh->buffer.fill = 0;
return MPG123_OK;
}
#ifdef FRAME_INDEX
int INT123_frame_index_setup(mpg123_handle *fr)
{
int ret = MPG123_ERR;
if(fr->p.index_size >= 0)
{
fr->index.grow_size = 0;
ret = INT123_fi_resize(&fr->index, (size_t)fr->p.index_size);
}
else
{
fr->index.grow_size = (size_t)(- fr->p.index_size);
if(fr->index.size < fr->index.grow_size)
ret = INT123_fi_resize(&fr->index, fr->index.grow_size);
else
ret = MPG123_OK;
}
debug2("set up frame index of size %lu (ret=%i)", (unsigned long)fr->index.size, ret);
if(ret && NOQUIET)
error("frame index setup (initial resize) failed");
return ret;
}
#endif
static void frame_decode_buffers_reset(mpg123_handle *fr)
{
if(fr->rawbuffs)
memset(fr->rawbuffs, 0, fr->rawbuffss);
}
int INT123_frame_buffers(mpg123_handle *fr)
{
int buffssize = 0;
debug1("frame %p buffer", (void*)fr);
if(fr->cpu_opts.type == altivec) buffssize = 4*4*0x110*sizeof(real);
#ifdef OPT_I486
else if(fr->cpu_opts.type == ivier) buffssize = 2*2*17*FIR_BUFFER_SIZE*sizeof(int);
#endif
else if(fr->cpu_opts.type == ifuenf || fr->cpu_opts.type == ifuenf_dither || fr->cpu_opts.type == dreidnow)
buffssize = 2*2*0x110*4;
if(2*2*0x110*sizeof(real) > buffssize)
buffssize = 2*2*0x110*sizeof(real);
buffssize += 15;
if(fr->rawbuffs != NULL && fr->rawbuffss != buffssize)
{
free(fr->rawbuffs);
fr->rawbuffs = NULL;
}
if(fr->rawbuffs == NULL) fr->rawbuffs = (unsigned char*) malloc(buffssize);
if(fr->rawbuffs == NULL) return -1;
fr->rawbuffss = buffssize;
fr->short_buffs[0][0] = aligned_pointer(fr->rawbuffs,short,16);
fr->short_buffs[0][1] = fr->short_buffs[0][0] + 0x110;
fr->short_buffs[1][0] = fr->short_buffs[0][1] + 0x110;
fr->short_buffs[1][1] = fr->short_buffs[1][0] + 0x110;
fr->real_buffs[0][0] = aligned_pointer(fr->rawbuffs,real,16);
fr->real_buffs[0][1] = fr->real_buffs[0][0] + 0x110;
fr->real_buffs[1][0] = fr->real_buffs[0][1] + 0x110;
fr->real_buffs[1][1] = fr->real_buffs[1][0] + 0x110;
#ifdef OPT_I486
if(fr->cpu_opts.type == ivier)
{
fr->int_buffs[0][0] = (int*) fr->rawbuffs;
fr->int_buffs[0][1] = fr->int_buffs[0][0] + 17*FIR_BUFFER_SIZE;
fr->int_buffs[1][0] = fr->int_buffs[0][1] + 17*FIR_BUFFER_SIZE;
fr->int_buffs[1][1] = fr->int_buffs[1][0] + 17*FIR_BUFFER_SIZE;
}
#endif
#ifdef OPT_ALTIVEC
if(fr->cpu_opts.type == altivec)
{
int i,j;
fr->areal_buffs[0][0] = (real*) fr->rawbuffs;
for(i=0; i<4; ++i) for(j=0; j<4; ++j)
fr->areal_buffs[i][j] = fr->areal_buffs[0][0] + (i*4+j)*0x110;
}
#endif
{
int decwin_size = (512+32)*sizeof(real);
#ifdef OPT_MMXORSSE
#ifdef OPT_MULTI
if(fr->cpu_opts.class == mmxsse)
{
#endif
if(decwin_size < (512+32)*4) decwin_size = (512+32)*4;
decwin_size += (512+32)*4 + 63;
#ifdef OPT_MULTI
}
#endif
#endif
#if defined(OPT_ALTIVEC) || defined(OPT_ARM)
decwin_size += 512*sizeof(real);
#endif
if(fr->rawdecwin != NULL && fr->rawdecwins != decwin_size)
{
free(fr->rawdecwin);
fr->rawdecwin = NULL;
}
if(fr->rawdecwin == NULL)
fr->rawdecwin = (unsigned char*) malloc(decwin_size);
if(fr->rawdecwin == NULL) return -1;
fr->rawdecwins = decwin_size;
fr->decwin = (real*) fr->rawdecwin;
#ifdef OPT_MMXORSSE
#ifdef OPT_MULTI
if(fr->cpu_opts.class == mmxsse)
{
#endif
fr->decwin = aligned_pointer(fr->rawdecwin,real,64);
debug1("aligned decwin: %p", (void*)fr->decwin);
fr->decwin_mmx = (float*)fr->decwin;
fr->decwins = fr->decwin_mmx+512+32;
#ifdef OPT_MULTI
}
else debug("no decwins/decwin_mmx for that class");
#endif
#endif
}
if(fr->layerscratch == NULL)
{
size_t scratchsize = 0;
real *scratcher;
#ifndef NO_LAYER1
scratchsize += sizeof(real) * 2 * SBLIMIT;
#endif
#ifndef NO_LAYER2
scratchsize += sizeof(real) * 2 * 4 * SBLIMIT;
#endif
#ifndef NO_LAYER3
scratchsize += sizeof(real) * 2 * SBLIMIT * SSLIMIT;
scratchsize += sizeof(real) * 2 * SSLIMIT * SBLIMIT;
#endif
fr->layerscratch = malloc(scratchsize+63);
if(fr->layerscratch == NULL) return -1;
scratcher = aligned_pointer(fr->layerscratch,real,64);
#ifndef NO_LAYER1
fr->layer1.fraction = (real(*)[SBLIMIT])scratcher;
scratcher += 2 * SBLIMIT;
#endif
#ifndef NO_LAYER2
fr->layer2.fraction = (real(*)[4][SBLIMIT])scratcher;
scratcher += 2 * 4 * SBLIMIT;
#endif
#ifndef NO_LAYER3
fr->layer3.hybrid_in = (real(*)[SBLIMIT][SSLIMIT])scratcher;
scratcher += 2 * SBLIMIT * SSLIMIT;
fr->layer3.hybrid_out = (real(*)[SSLIMIT][SBLIMIT])scratcher;
scratcher += 2 * SSLIMIT * SBLIMIT;
#endif
}
frame_decode_buffers_reset(fr);
debug1("frame %p buffer done", (void*)fr);
return 0;
}
int INT123_frame_buffers_reset(mpg123_handle *fr)
{
fr->buffer.fill = 0;
fr->bsnum = 0;
fr->bsbuf = fr->bsspace[1];
fr->bsbufold = fr->bsbuf;
fr->bitreservoir = 0;
frame_decode_buffers_reset(fr);
memset(fr->bsspace, 0, 2*(MAXFRAMESIZE+512));
memset(fr->ssave, 0, 34);
fr->hybrid_blc[0] = fr->hybrid_blc[1] = 0;
memset(fr->hybrid_block, 0, sizeof(real)*2*2*SBLIMIT*SSLIMIT);
return 0;
}
static void frame_icy_reset(mpg123_handle* fr)
{
#ifndef NO_ICY
if(fr->icy.data != NULL) free(fr->icy.data);
fr->icy.data = NULL;
fr->icy.interval = 0;
fr->icy.next = 0;
#endif
}
static void frame_free_toc(mpg123_handle *fr)
{
if(fr->xing_toc != NULL){ free(fr->xing_toc); fr->xing_toc = NULL; }
}
int INT123_frame_fill_toc(mpg123_handle *fr, unsigned char* in)
{
if(fr->xing_toc == NULL) fr->xing_toc = malloc(100);
if(fr->xing_toc != NULL)
{
memcpy(fr->xing_toc, in, 100);
#ifdef DEBUG
debug("Got a TOC! Showing the values...");
{
int i;
for(i=0; i<100; ++i)
debug2("entry %i = %i", i, fr->xing_toc[i]);
}
#endif
return TRUE;
}
return FALSE;
}
int INT123_frame_reset(mpg123_handle* fr)
{
INT123_frame_buffers_reset(fr);
frame_fixed_reset(fr);
frame_free_toc(fr);
#ifdef FRAME_INDEX
INT123_fi_reset(&fr->index);
#endif
return 0;
}
static void frame_fixed_reset(mpg123_handle *fr)
{
frame_icy_reset(fr);
INT123_open_bad(fr);
memset(&(fr->hdr), 0, sizeof(fr->hdr));
fr->to_decode = FALSE;
fr->to_ignore = FALSE;
fr->metaflags = 0;
fr->outblock = 0;
fr->num = -1;
fr->input_offset = -1;
fr->playnum = -1;
fr->state_flags = FRAME_ACCURATE;
fr->silent_resync = 0;
fr->audio_start = 0;
fr->clip = 0;
fr->oldhead = 0;
fr->firsthead = 0;
fr->vbr = MPG123_CBR;
fr->abr_rate = 0;
fr->track_frames = 0;
fr->track_samples = -1;
fr->mean_frames = 0;
fr->mean_framesize = 0;
fr->lastscale = -1;
fr->rva.level[0] = -1;
fr->rva.level[1] = -1;
fr->rva.gain[0] = 0;
fr->rva.gain[1] = 0;
fr->rva.peak[0] = 0;
fr->rva.peak[1] = 0;
fr->fsizeold = 0;
fr->firstframe = 0;
fr->ignoreframe = fr->firstframe-fr->p.preframes;
fr->header_change = 0;
fr->lastframe = -1;
fr->fresh = 1;
fr->new_format = 0;
#ifdef GAPLESS
INT123_frame_gapless_init(fr,-1,0,0);
fr->lastoff = 0;
fr->firstoff = 0;
#endif
#ifdef OPT_I486
fr->i486bo[0] = fr->i486bo[1] = FIR_SIZE-1;
#endif
fr->bo = 1;
#ifdef OPT_DITHER
fr->ditherindex = 0;
#endif
INT123_reset_id3(fr);
INT123_reset_icy(&fr->icy);
#ifndef NO_ICY
fr->icy.interval = 0;
fr->icy.next = 0;
#endif
fr->halfphase = 0;
fr->hdr.freeformat_framesize = fr->p.freeformat_framesize;
fr->enc_delay = -1;
fr->enc_padding = -1;
memset(fr->id3buf, 0, sizeof(fr->id3buf));
if(fr->id3v2_raw)
free(fr->id3v2_raw);
fr->id3v2_raw = NULL;
fr->id3v2_size = 0;
}
static void frame_free_buffers(mpg123_handle *fr)
{
if(fr->rawbuffs != NULL) free(fr->rawbuffs);
fr->rawbuffs = NULL;
fr->rawbuffss = 0;
if(fr->rawdecwin != NULL) free(fr->rawdecwin);
fr->rawdecwin = NULL;
fr->rawdecwins = 0;
#ifndef NO_8BIT
if(fr->conv16to8_buf != NULL) free(fr->conv16to8_buf);
fr->conv16to8_buf = NULL;
#endif
if(fr->layerscratch != NULL) free(fr->layerscratch);
}
void INT123_frame_exit(mpg123_handle *fr)
{
if(fr->buffer.rdata != NULL)
{
debug1("freeing buffer at %p", (void*)fr->buffer.rdata);
free(fr->buffer.rdata);
}
fr->buffer.rdata = NULL;
frame_free_buffers(fr);
frame_free_toc(fr);
#ifdef FRAME_INDEX
INT123_fi_exit(&fr->index);
#endif
#ifdef OPT_DITHER
if(fr->dithernoise != NULL)
{
free(fr->dithernoise);
fr->dithernoise = NULL;
}
#endif
INT123_exit_id3(fr);
INT123_clear_icy(&fr->icy);
#ifndef NO_FEEDER
INT123_bc_cleanup(&fr->rdat.buffer);
#endif
}
int attribute_align_arg mpg123_framedata(mpg123_handle *mh, unsigned long *header, unsigned char **bodydata, size_t *bodybytes)
{
if(mh == NULL) return MPG123_BAD_HANDLE;
if(!mh->to_decode) return MPG123_ERR;
if(header != NULL) *header = mh->oldhead;
if(bodydata != NULL) *bodydata = mh->bsbuf;
if(bodybytes != NULL) *bodybytes = mh->hdr.framesize;
return MPG123_OK;
}
int attribute_align_arg mpg123_set_moreinfo( mpg123_handle *mh
, struct mpg123_moreinfo *mi)
{
#ifndef NO_MOREINFO
mh->pinfo = mi;
return MPG123_OK;
#else
mh->err = MPG123_MISSING_FEATURE;
return MPG123_ERR;
#endif
}
static int64_t frame_fuzzy_find(mpg123_handle *fr, int64_t want_frame, int64_t* get_frame)
{
int64_t ret = fr->audio_start;
*get_frame = 0;
if(fr->xing_toc != NULL && fr->track_frames > 0 && fr->rdat.filelen > 0)
{
int toc_entry = (int) ((double)want_frame*100./fr->track_frames);
if(toc_entry < 0) toc_entry = 0;
if(toc_entry > 99) toc_entry = 99;
*get_frame = (int64_t) ((double)toc_entry/100. * fr->track_frames);
fr->state_flags &= ~FRAME_ACCURATE;
fr->silent_resync = 1;
ret = (int64_t) ((double)fr->xing_toc[toc_entry]/256.* fr->rdat.filelen);
}
else if(fr->mean_framesize > 0)
{
fr->state_flags &= ~FRAME_ACCURATE;
fr->silent_resync = 1;
*get_frame = want_frame;
ret = (int64_t) (fr->audio_start+fr->mean_framesize*want_frame);
}
debug5("fuzzy: want %" PRIi64 " of %" PRIi64
", get %" PRIi64 " at %" PRIi64 " B of %" PRIi64 " B"
, want_frame, fr->track_frames, *get_frame, ret
, (fr->rdat.filelen-fr->audio_start));
return ret;
}
int64_t INT123_frame_index_find(mpg123_handle *fr, int64_t want_frame, int64_t* get_frame)
{
int64_t gopos = 0;
*get_frame = 0;
#ifdef FRAME_INDEX
if(fr->index.fill)
{
size_t fi;
fi = want_frame/fr->index.step;
if(fi >= fr->index.fill)
{
if(fr->p.flags & MPG123_FUZZY && want_frame - (fr->index.fill-1)*fr->index.step > 10)
{
gopos = frame_fuzzy_find(fr, want_frame, get_frame);
if(gopos > fr->audio_start) return gopos;
}
fi = fr->index.fill - 1;
}
*get_frame = fi*fr->index.step;
gopos = fr->index.data[fi];
fr->state_flags |= FRAME_ACCURATE;
}
else
{
#endif
if(fr->p.flags & MPG123_FUZZY)
return frame_fuzzy_find(fr, want_frame, get_frame);
fr->firsthead = 0;
fr->oldhead = 0;
#ifdef FRAME_INDEX
}
#endif
debug2("index: 0x%" PRIx64 " for frame %" PRIi64, (uint64_t)gopos, *get_frame);
return gopos;
}
int64_t INT123_frame_ins2outs(mpg123_handle *fr, int64_t ins)
{
int64_t outs = 0;
switch(fr->down_sample)
{
case 0:
# ifndef NO_DOWNSAMPLE
case 1:
case 2:
# endif
outs = ins>>fr->down_sample;
break;
# ifndef NO_NTOM
case 3: outs = INT123_ntom_ins2outs(fr, ins); break;
# endif
default: if(NOQUIET)
merror( "Bad down_sample (%i) ... should not be possible!!"
, fr->down_sample );
}
return outs;
}
int64_t INT123_frame_outs(mpg123_handle *fr, int64_t num)
{
int64_t outs = 0;
switch(fr->down_sample)
{
case 0:
# ifndef NO_DOWNSAMPLE
case 1:
case 2:
# endif
outs = (fr->spf>>fr->down_sample)*num;
break;
#ifndef NO_NTOM
case 3: outs = INT123_ntom_frmouts(fr, num); break;
#endif
default: if(NOQUIET)
merror( "Bad down_sample (%i) ... should not be possible!!"
, fr->down_sample );
}
return outs;
}
int64_t INT123_frame_expect_outsamples(mpg123_handle *fr)
{
int64_t outs = 0;
switch(fr->down_sample)
{
case 0:
# ifndef NO_DOWNSAMPLE
case 1:
case 2:
# endif
outs = fr->spf>>fr->down_sample;
break;
#ifndef NO_NTOM
case 3: outs = INT123_ntom_frame_outsamples(fr); break;
#endif
default: if(NOQUIET)
merror( "Bad down_sample (%i) ... should not be possible!!"
, fr->down_sample );
}
return outs;
}
int64_t INT123_frame_offset(mpg123_handle *fr, int64_t outs)
{
int64_t num = 0;
switch(fr->down_sample)
{
case 0:
# ifndef NO_DOWNSAMPLE
case 1:
case 2:
# endif
num = outs/(fr->spf>>fr->down_sample);
break;
#ifndef NO_NTOM
case 3: num = INT123_ntom_frameoff(fr, outs); break;
#endif
default: if(NOQUIET)
error("Bad down_sample ... should not be possible!!");
}
return num;
}
#ifdef GAPLESS
void INT123_frame_gapless_init(mpg123_handle *fr, int64_t framecount, int64_t bskip, int64_t eskip)
{
debug3("INT123_frame_gapless_init: given %"PRIi64" frames, skip %"PRIi64" and %"PRIi64, framecount, bskip, eskip);
fr->gapless_frames = framecount;
if(fr->gapless_frames > 0 && bskip >=0 && eskip >= 0)
{
fr->begin_s = bskip+GAPLESS_DELAY;
fr->end_s = framecount*fr->spf-eskip+GAPLESS_DELAY;
}
else fr->begin_s = fr->end_s = 0;
fr->begin_os = 0;
fr->end_os = 0;
fr->fullend_os = 0;
debug2("INT123_frame_gapless_init: from %"PRIi64" to %"PRIi64" samples", fr->begin_s, fr->end_s);
}
void INT123_frame_gapless_realinit(mpg123_handle *fr)
{
fr->begin_os = INT123_frame_ins2outs(fr, fr->begin_s);
fr->end_os = INT123_frame_ins2outs(fr, fr->end_s);
if(fr->gapless_frames > 0)
fr->fullend_os = INT123_frame_ins2outs(fr, fr->gapless_frames*fr->spf);
else fr->fullend_os = 0;
debug4("INT123_frame_gapless_realinit: from %"PRIi64" to %"PRIi64" samples (%"PRIi64", %"PRIi64")"
, fr->begin_os, fr->end_os, fr->fullend_os, fr->gapless_frames);
}
void INT123_frame_gapless_update(mpg123_handle *fr, int64_t total_samples)
{
int64_t gapless_samples = fr->gapless_frames*fr->spf;
if(fr->gapless_frames < 1) return;
debug2("gapless update with new sample count %"PRIi64" as opposed to known %"PRIi64, total_samples, gapless_samples);
if(NOQUIET && total_samples != gapless_samples)
fprintf(stderr, "\nWarning: Real sample count %" PRIi64
" differs from given gapless sample count %" PRIi64
". Frankenstein stream?\n", total_samples, gapless_samples);
if(gapless_samples > total_samples)
{
if(NOQUIET)
merror( "End sample count smaller than gapless end! (%" PRIi64
" < %"PRIi64"). Disabling gapless mode from now on."
, total_samples, fr->end_s );
INT123_frame_gapless_init(fr, -1, 0, 0);
INT123_frame_gapless_realinit(fr);
fr->lastframe = -1;
fr->lastoff = 0;
}
}
#endif
static int64_t ignoreframe(mpg123_handle *fr)
{
int64_t preshift = fr->p.preframes;
if(fr->hdr.lay==3 && preshift < 1) preshift = 1;
if(fr->hdr.lay!=3 && preshift > 2) preshift = 2;
return fr->firstframe - preshift;
}
void INT123_frame_set_frameseek(mpg123_handle *fr, int64_t fe)
{
fr->firstframe = fe;
#ifdef GAPLESS
if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0)
{
int64_t beg_f = INT123_frame_offset(fr, fr->begin_os);
if(fe <= beg_f)
{
fr->firstframe = beg_f;
fr->firstoff = fr->begin_os - INT123_frame_outs(fr, beg_f);
}
else fr->firstoff = 0;
if(fr->end_os > 0)
{
fr->lastframe = INT123_frame_offset(fr,fr->end_os);
fr->lastoff = fr->end_os - INT123_frame_outs(fr, fr->lastframe);
} else {fr->lastframe = -1; fr->lastoff = 0; }
} else { fr->firstoff = fr->lastoff = 0; fr->lastframe = -1; }
#endif
fr->ignoreframe = ignoreframe(fr);
#ifdef GAPLESS
debug5("INT123_frame_set_frameseek: begin at %" PRIi64 " frames and %" PRIi64
" samples, end at %" PRIi64 " and %" PRIi64 "; ignore from %" PRIi64,
fr->firstframe, fr->firstoff
, fr->lastframe, fr->lastoff, fr->ignoreframe);
#else
debug3("INT123_frame_set_frameseek: begin at %" PRIi64 " frames, end at %" PRIi64
"; ignore from %" PRIi64
, fr->firstframe, fr->lastframe, fr->ignoreframe);
#endif
}
void INT123_frame_skip(mpg123_handle *fr)
{
#ifndef NO_LAYER3
if(fr->hdr.lay == 3) INT123_set_pointer(fr, 1, 512);
#endif
}
void INT123_frame_set_seek(mpg123_handle *fr, int64_t sp)
{
fr->firstframe = INT123_frame_offset(fr, sp);
debug1("INT123_frame_set_seek: from %" PRIi64, fr->num);
#ifndef NO_NTOM
if(fr->down_sample == 3) INT123_ntom_set_ntom(fr, fr->firstframe);
#endif
fr->ignoreframe = ignoreframe(fr);
#ifdef GAPLESS
fr->firstoff = sp - INT123_frame_outs(fr, fr->firstframe);
debug5("INT123_frame_set_seek: begin at %" PRIi64 " frames and %" PRIi64
" samples, end at %" PRIi64 " and %" PRIi64 "; ignore from %" PRIi64,
fr->firstframe, fr->firstoff
, fr->lastframe, fr->lastoff, fr->ignoreframe);
#else
debug3("INT123_frame_set_seek: begin at %" PRIi64 " frames, end at %" PRIi64
"; ignore from %" PRIi64
, fr->firstframe, fr->lastframe, fr->ignoreframe);
#endif
}
int attribute_align_arg mpg123_volume_change(mpg123_handle *mh, double change)
{
if(mh == NULL) return MPG123_ERR;
return mpg123_volume(mh, change + (double) mh->p.outscale);
}
int attribute_align_arg mpg123_volume_change_db(mpg123_handle *mh, double change)
{
if(mh == NULL) return MPG123_ERR;
return mpg123_volume(mh, dbchange(mh->p.outscale, change));
}
int attribute_align_arg mpg123_volume(mpg123_handle *mh, double vol)
{
if(mh == NULL) return MPG123_ERR;
if(vol >= 0) mh->p.outscale = vol;
else mh->p.outscale = 0.;
INT123_do_rva(mh);
return MPG123_OK;
}
static int get_rva(mpg123_handle *fr, double *peak, double *gain)
{
double p = -1;
double g = 0;
int ret = 0;
if(fr->p.rva)
{
int rt = 0;
if(fr->p.rva == 2 && fr->rva.level[1] != -1) rt = 1;
if(fr->rva.level[rt] != -1)
{
p = fr->rva.peak[rt];
g = fr->rva.gain[rt];
ret = 1;
}
}
if(peak != NULL) *peak = p;
if(gain != NULL) *gain = g;
return ret;
}
void INT123_do_rva(mpg123_handle *fr)
{
double peak = 0;
double gain = 0;
double newscale;
double rvafact = 1;
if(get_rva(fr, &peak, &gain))
{
if(NOQUIET && fr->p.verbose > 1) fprintf(stderr, "Note: doing RVA with gain %f\n", gain);
rvafact = pow(10,gain/20);
}
newscale = fr->p.outscale*rvafact;
if((peak*newscale) > 1.0)
{
newscale = 1.0/peak;
warning2("limiting scale value to %f to prevent clipping with indicated peak factor of %f", newscale, peak);
}
if(newscale != fr->lastscale || fr->decoder_change)
{
debug3("changing scale value from %f to %f (peak estimated to %f)", fr->lastscale != -1 ? fr->lastscale : fr->p.outscale, newscale, (double) (newscale*peak));
fr->lastscale = newscale;
if(fr->INT123_make_decode_tables != NULL) fr->INT123_make_decode_tables(fr);
}
}
int attribute_align_arg mpg123_getvolume(mpg123_handle *mh, double *base, double *really, double *rva_db)
{
if(mh == NULL) return MPG123_ERR;
if(base) *base = mh->p.outscale;
if(really) *really = mh->lastscale;
get_rva(mh, NULL, rva_db);
return MPG123_OK;
}
int64_t attribute_align_arg mpg123_framepos64(mpg123_handle *mh)
{
if(mh == NULL) return MPG123_ERR;
return mh->input_offset;
}