Coverage Report

Created: 2023-03-26 06:17

/src/mpg123/src/libmpg123/frame.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
  frame: Heap of routines dealing with the core mpg123 data structure.
3
4
  copyright 2008-2021 by the mpg123 project - free software under the terms of the LGPL 2.1
5
  see COPYING and AUTHORS files in distribution or http://mpg123.org
6
  initially written by Thomas Orgis
7
*/
8
9
#define WANT_GETCPUFLAGS
10
#include "mpg123lib_intern.h"
11
#include "getcpuflags.h"
12
#include "debug.h"
13
14
static void frame_fixed_reset(mpg123_handle *fr);
15
16
/* that's doubled in decode_ntom.c */
17
0
#define NTOM_MUL (32768)
18
19
0
#define aligned_pointer(p, type, alignment) align_the_pointer(p, alignment)
20
static void *align_the_pointer(void *base, unsigned int alignment)
21
0
{
22
  /*
23
    Work in unsigned integer realm, explicitly.
24
    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.
25
    I try to do it "properly" here: Casting only to uintptr_t and no artihmethic with void*.
26
  */
27
0
  uintptr_t baseval = (uintptr_t)(char*)base;
28
0
  uintptr_t aoff = baseval % alignment;
29
30
0
  debug3("align_the_pointer: pointer %p is off by %u from %u",
31
0
         base, (unsigned int)aoff, alignment);
32
33
0
  if(aoff) return (char*)base+alignment-aoff;
34
0
  else     return base;
35
0
}
36
37
static void frame_default_pars(mpg123_pars *mp)
38
0
{
39
0
  mp->outscale = 1.0;
40
0
  mp->flags = 0;
41
0
#ifdef GAPLESS
42
0
  mp->flags |= MPG123_GAPLESS;
43
0
#endif
44
0
  mp->flags |= MPG123_AUTO_RESAMPLE|MPG123_FLOAT_FALLBACK;
45
0
#ifndef NO_NTOM
46
0
  mp->force_rate = 0;
47
0
#endif
48
0
  mp->down_sample = 0;
49
0
  mp->rva = 0;
50
0
  mp->halfspeed = 0;
51
0
  mp->doublespeed = 0;
52
0
  mp->verbose = 0;
53
0
#ifndef NO_ICY
54
0
  mp->icy_interval = 0;
55
0
#endif
56
0
  mp->timeout = 0;
57
0
  mp->resync_limit = 1024;
58
0
#ifdef FRAME_INDEX
59
0
  mp->index_size = INDEX_SIZE;
60
0
#endif
61
0
  mp->preframes = 4; /* That's good  for layer 3 ISO compliance bitstream. */
62
0
  mpg123_fmt_all(mp);
63
  /* Default of keeping some 4K buffers at hand, should cover the "usual" use case (using 16K pipe buffers as role model). */
64
0
#ifndef NO_FEEDER
65
0
  mp->feedpool = 5; 
66
0
  mp->feedbuffer = 4096;
67
0
#endif
68
0
  mp->freeformat_framesize = -1;
69
0
}
70
71
void frame_init(mpg123_handle *fr)
72
0
{
73
0
  frame_init_par(fr, NULL);
74
0
}
75
76
void frame_init_par(mpg123_handle *fr, mpg123_pars *mp)
77
0
{
78
0
  fr->own_buffer = TRUE;
79
0
  fr->buffer.data = NULL;
80
0
  fr->buffer.rdata = NULL;
81
0
  fr->buffer.fill = 0;
82
0
  fr->buffer.size = 0;
83
0
  fr->rawbuffs = NULL;
84
0
  fr->rawbuffss = 0;
85
0
  fr->rawdecwin = NULL;
86
0
  fr->rawdecwins = 0;
87
#ifdef REAL_IS_FIXED
88
  fr->gainpow2 = NULL; // At least crash early if I get it wrong.
89
#endif
90
0
#ifndef NO_8BIT
91
0
  fr->conv16to8_buf = NULL;
92
0
#endif
93
0
#ifdef OPT_DITHER
94
0
  fr->dithernoise = NULL;
95
0
#endif
96
0
  fr->layerscratch = NULL;
97
0
  fr->xing_toc = NULL;
98
0
#ifdef OPT_CPU_FLAGS
99
0
  wrap_getcpuflags(&(fr->cpu_flags));
100
0
#endif
101
0
  fr->cpu_opts.type = defdec();
102
0
  fr->cpu_opts.class = decclass(fr->cpu_opts.type);
103
0
#ifndef NO_NTOM
104
  /* these two look unnecessary, check guarantee for synth_ntom_set_step (in control_generic, even)! */
105
0
  fr->ntom_val[0] = NTOM_MUL>>1;
106
0
  fr->ntom_val[1] = NTOM_MUL>>1;
107
0
  fr->ntom_step = NTOM_MUL;
108
0
#endif
109
  /* unnecessary: fr->buffer.size = fr->buffer.fill = 0; */
110
0
  mpg123_reset_eq(fr);
111
0
  init_icy(&fr->icy);
112
0
  init_id3(fr);
113
  /* frame_outbuffer is missing... */
114
  /* frame_buffers is missing... that one needs cpu opt setting! */
115
  /* after these... frame_reset is needed before starting full decode */
116
0
  invalidate_format(&fr->af);
117
0
  fr->rdat.r_read = NULL;
118
0
  fr->rdat.r_lseek = NULL;
119
0
  fr->rdat.iohandle = NULL;
120
0
  fr->rdat.r_read_handle = NULL;
121
0
  fr->rdat.r_lseek_handle = NULL;
122
0
  fr->rdat.cleanup_handle = NULL;
123
0
  fr->wrapperdata = NULL;
124
0
  fr->wrapperclean = NULL;
125
0
  fr->decoder_change = 1;
126
0
  fr->err = MPG123_OK;
127
0
  if(mp == NULL) frame_default_pars(&fr->p);
128
0
  else memcpy(&fr->p, mp, sizeof(struct mpg123_pars_struct));
129
130
0
#ifndef NO_FEEDER
131
0
  bc_prepare(&fr->rdat.buffer, fr->p.feedpool, fr->p.feedbuffer);
132
0
#endif
133
134
0
  fr->down_sample = 0; /* Initialize to silence harmless errors when debugging. */
135
0
  fr->id3v2_raw = NULL;
136
0
  frame_fixed_reset(fr); /* Reset only the fixed data, dynamic buffers are not there yet! */
137
0
  fr->synth = NULL;
138
0
  fr->synth_mono = NULL;
139
0
  fr->make_decode_tables = NULL;
140
0
#ifdef FRAME_INDEX
141
0
  fi_init(&fr->index);
142
0
  frame_index_setup(fr); /* Apply the size setting. */
143
0
#endif
144
0
#ifndef NO_MOREINFO
145
0
  fr->pinfo = NULL;
146
0
#endif
147
0
}
148
149
#ifdef OPT_DITHER
150
/* Also, only allocate the memory for the table on demand.
151
   In future, one could create special noise for different sampling frequencies(?). */
152
int frame_dither_init(mpg123_handle *fr)
153
0
{
154
  /* run-time dither noise table generation */
155
0
  if(fr->dithernoise == NULL)
156
0
  {
157
0
    fr->dithernoise = malloc(sizeof(float)*DITHERSIZE);
158
0
    if(fr->dithernoise == NULL) return 0;
159
160
0
    dither_table_init(fr->dithernoise);
161
0
  }
162
0
  return 1;
163
0
}
164
#endif
165
166
mpg123_pars attribute_align_arg *mpg123_new_pars(int *error)
167
0
{
168
0
  mpg123_pars *mp = malloc(sizeof(struct mpg123_pars_struct));
169
0
  if(mp != NULL){ frame_default_pars(mp); if(error != NULL) *error = MPG123_OK; }
170
0
  else if(error != NULL) *error = MPG123_OUT_OF_MEM;
171
0
  return mp;
172
0
}
173
174
void attribute_align_arg mpg123_delete_pars(mpg123_pars* mp)
175
0
{
176
0
  if(mp != NULL) free(mp);
177
0
}
178
179
int attribute_align_arg mpg123_reset_eq(mpg123_handle *mh)
180
0
{
181
0
  if(mh == NULL) return MPG123_BAD_HANDLE;
182
0
#ifndef NO_EQUALIZER
183
0
  int i;
184
0
  mh->have_eq_settings = 0;
185
0
  for(i=0; i < 32; ++i) mh->equalizer[0][i] = mh->equalizer[1][i] = DOUBLE_TO_REAL(1.0);
186
0
#endif
187
0
  return MPG123_OK;
188
0
}
189
190
int frame_outbuffer(mpg123_handle *fr)
191
0
{
192
0
  size_t size = fr->outblock;
193
0
  if(!fr->own_buffer)
194
0
  {
195
0
    if(fr->buffer.size < size)
196
0
    {
197
0
      fr->err = MPG123_BAD_BUFFER;
198
0
      if(NOQUIET)
199
0
        merror( "have external buffer of size %"SIZE_P", need %"SIZE_P
200
0
        , (size_p)fr->buffer.size, (size_p)size );
201
0
      return MPG123_ERR;
202
0
    }
203
0
  }
204
205
0
  debug1("need frame buffer of %"SIZE_P, (size_p)size);
206
0
  if(fr->buffer.rdata != NULL && fr->buffer.size != size)
207
0
  {
208
0
    free(fr->buffer.rdata);
209
0
    fr->buffer.rdata = NULL;
210
0
  }
211
0
  fr->buffer.size = size;
212
0
  fr->buffer.data = NULL;
213
  /* be generous: use 16 byte alignment */
214
0
  if(fr->buffer.rdata == NULL) fr->buffer.rdata = (unsigned char*) malloc(fr->buffer.size+15);
215
0
  if(fr->buffer.rdata == NULL)
216
0
  {
217
0
    fr->err = MPG123_OUT_OF_MEM;
218
0
    return MPG123_ERR;
219
0
  }
220
0
  fr->buffer.data = aligned_pointer(fr->buffer.rdata, unsigned char*, 16);
221
0
  fr->own_buffer = TRUE;
222
0
  fr->buffer.fill = 0;
223
0
  return MPG123_OK;
224
0
}
225
226
int attribute_align_arg mpg123_replace_buffer(mpg123_handle *mh, void *data, size_t size)
227
0
{
228
0
  debug2("replace buffer with %p size %"SIZE_P, data, (size_p)size);
229
0
  if(mh == NULL) return MPG123_BAD_HANDLE;
230
  /* Will accept any size, the error comes later... */
231
0
  if(data == NULL)
232
0
  {
233
0
    mh->err = MPG123_BAD_BUFFER;
234
0
    return MPG123_ERR;
235
0
  }
236
0
  if(mh->buffer.rdata != NULL) free(mh->buffer.rdata);
237
0
  mh->own_buffer = FALSE;
238
0
  mh->buffer.rdata = NULL;
239
0
  mh->buffer.data = data;
240
0
  mh->buffer.size = size;
241
0
  mh->buffer.fill = 0;
242
0
  return MPG123_OK;
243
0
}
244
245
#ifdef FRAME_INDEX
246
int frame_index_setup(mpg123_handle *fr)
247
0
{
248
0
  int ret = MPG123_ERR;
249
0
  if(fr->p.index_size >= 0)
250
0
  { /* Simple fixed index. */
251
0
    fr->index.grow_size = 0;
252
0
    ret = fi_resize(&fr->index, (size_t)fr->p.index_size);
253
0
  }
254
0
  else
255
0
  { /* A growing index. We give it a start, though. */
256
0
    fr->index.grow_size = (size_t)(- fr->p.index_size);
257
0
    if(fr->index.size < fr->index.grow_size)
258
0
      ret = fi_resize(&fr->index, fr->index.grow_size);
259
0
    else
260
0
      ret = MPG123_OK; /* We have minimal size already... and since growing is OK... */
261
0
  }
262
0
  debug2("set up frame index of size %lu (ret=%i)", (unsigned long)fr->index.size, ret);
263
0
  if(ret && NOQUIET)
264
0
    error("frame index setup (initial resize) failed");
265
0
  return ret;
266
0
}
267
#endif
268
269
static void frame_decode_buffers_reset(mpg123_handle *fr)
270
0
{
271
0
  if(fr->rawbuffs) /* memset(NULL, 0, 0) not desired */
272
0
    memset(fr->rawbuffs, 0, fr->rawbuffss);
273
0
}
274
275
int frame_buffers(mpg123_handle *fr)
276
0
{
277
0
  int buffssize = 0;
278
0
  debug1("frame %p buffer", (void*)fr);
279
/*
280
  the used-to-be-static buffer of the synth functions, has some subtly different types/sizes
281
282
  2to1, 4to1, ntom, generic, i386: real[2][2][0x110]
283
  mmx, sse: short[2][2][0x110]
284
  i586(_dither): 4352 bytes; int/long[2][2][0x110]
285
  i486: int[2][2][17*FIR_BUFFER_SIZE]
286
  altivec: static real __attribute__ ((aligned (16))) buffs[4][4][0x110]
287
288
  Huh, altivec looks like fun. Well, let it be large... then, the 16 byte alignment seems to be implicit on MacOSX malloc anyway.
289
  Let's make a reasonable attempt to allocate enough memory...
290
  Keep in mind: biggest ones are i486 and altivec (mutually exclusive!), then follows i586 and normal real.
291
  mmx/sse use short but also real for resampling.
292
  Thus, minimum is 2*2*0x110*sizeof(real).
293
*/
294
0
  if(fr->cpu_opts.type == altivec) buffssize = 4*4*0x110*sizeof(real);
295
#ifdef OPT_I486
296
  else if(fr->cpu_opts.type == ivier) buffssize = 2*2*17*FIR_BUFFER_SIZE*sizeof(int);
297
#endif
298
0
  else if(fr->cpu_opts.type == ifuenf || fr->cpu_opts.type == ifuenf_dither || fr->cpu_opts.type == dreidnow)
299
0
  buffssize = 2*2*0x110*4; /* don't rely on type real, we need 4352 bytes */
300
301
0
  if(2*2*0x110*sizeof(real) > buffssize)
302
0
  buffssize = 2*2*0x110*sizeof(real);
303
0
  buffssize += 15; /* For 16-byte alignment (SSE likes that). */
304
305
0
  if(fr->rawbuffs != NULL && fr->rawbuffss != buffssize)
306
0
  {
307
0
    free(fr->rawbuffs);
308
0
    fr->rawbuffs = NULL;
309
0
  }
310
311
0
  if(fr->rawbuffs == NULL) fr->rawbuffs = (unsigned char*) malloc(buffssize);
312
0
  if(fr->rawbuffs == NULL) return -1;
313
0
  fr->rawbuffss = buffssize;
314
0
  fr->short_buffs[0][0] = aligned_pointer(fr->rawbuffs,short,16);
315
0
  fr->short_buffs[0][1] = fr->short_buffs[0][0] + 0x110;
316
0
  fr->short_buffs[1][0] = fr->short_buffs[0][1] + 0x110;
317
0
  fr->short_buffs[1][1] = fr->short_buffs[1][0] + 0x110;
318
0
  fr->real_buffs[0][0] = aligned_pointer(fr->rawbuffs,real,16);
319
0
  fr->real_buffs[0][1] = fr->real_buffs[0][0] + 0x110;
320
0
  fr->real_buffs[1][0] = fr->real_buffs[0][1] + 0x110;
321
0
  fr->real_buffs[1][1] = fr->real_buffs[1][0] + 0x110;
322
#ifdef OPT_I486
323
  if(fr->cpu_opts.type == ivier)
324
  {
325
    fr->int_buffs[0][0] = (int*) fr->rawbuffs;
326
    fr->int_buffs[0][1] = fr->int_buffs[0][0] + 17*FIR_BUFFER_SIZE;
327
    fr->int_buffs[1][0] = fr->int_buffs[0][1] + 17*FIR_BUFFER_SIZE;
328
    fr->int_buffs[1][1] = fr->int_buffs[1][0] + 17*FIR_BUFFER_SIZE;
329
  }
330
#endif
331
#ifdef OPT_ALTIVEC
332
  if(fr->cpu_opts.type == altivec)
333
  {
334
    int i,j;
335
    fr->areal_buffs[0][0] = (real*) fr->rawbuffs;
336
    for(i=0; i<4; ++i) for(j=0; j<4; ++j)
337
    fr->areal_buffs[i][j] = fr->areal_buffs[0][0] + (i*4+j)*0x110;
338
  }
339
#endif
340
  /* now the different decwins... all of the same size, actually */
341
  /* The MMX ones want 32byte alignment, which I'll try to ensure manually */
342
0
  {
343
0
    int decwin_size = (512+32)*sizeof(real);
344
0
#ifdef OPT_MMXORSSE
345
0
#ifdef OPT_MULTI
346
0
    if(fr->cpu_opts.class == mmxsse)
347
0
    {
348
0
#endif
349
      /* decwin_mmx will share, decwins will be appended ... sizeof(float)==4 */
350
0
      if(decwin_size < (512+32)*4) decwin_size = (512+32)*4;
351
352
      /* the second window + alignment zone -- we align for 32 bytes for SSE as
353
         requirement, 64 byte for matching cache line size (that matters!) */
354
0
      decwin_size += (512+32)*4 + 63;
355
      /* (512+32)*4/32 == 2176/32 == 68, so one decwin block retains alignment for 32 or 64 bytes */
356
0
#ifdef OPT_MULTI
357
0
    }
358
0
#endif
359
0
#endif
360
#if defined(OPT_ALTIVEC) || defined(OPT_ARM) 
361
    /* sizeof(real) >= 4 ... yes, it could be 8, for example.
362
       We got it intialized to at least (512+32)*sizeof(real).*/
363
    decwin_size += 512*sizeof(real);
364
#endif
365
    /* Hm, that's basically realloc() ... */
366
0
    if(fr->rawdecwin != NULL && fr->rawdecwins != decwin_size)
367
0
    {
368
0
      free(fr->rawdecwin);
369
0
      fr->rawdecwin = NULL;
370
0
    }
371
372
0
    if(fr->rawdecwin == NULL)
373
0
    fr->rawdecwin = (unsigned char*) malloc(decwin_size);
374
375
0
    if(fr->rawdecwin == NULL) return -1;
376
377
0
    fr->rawdecwins = decwin_size;
378
0
    fr->decwin = (real*) fr->rawdecwin;
379
0
#ifdef OPT_MMXORSSE
380
0
#ifdef OPT_MULTI
381
0
    if(fr->cpu_opts.class == mmxsse)
382
0
    {
383
0
#endif
384
      /* align decwin, assign that to decwin_mmx, append decwins */
385
      /* I need to add to decwin what is missing to the next full 64 byte -- also I want to make gcc -pedantic happy... */
386
0
      fr->decwin = aligned_pointer(fr->rawdecwin,real,64);
387
0
      debug1("aligned decwin: %p", (void*)fr->decwin);
388
0
      fr->decwin_mmx = (float*)fr->decwin;
389
0
      fr->decwins = fr->decwin_mmx+512+32;
390
0
#ifdef OPT_MULTI
391
0
    }
392
0
    else debug("no decwins/decwin_mmx for that class");
393
0
#endif
394
0
#endif
395
0
  }
396
397
  /* Layer scratch buffers are of compile-time fixed size, so allocate only once. */
398
0
  if(fr->layerscratch == NULL)
399
0
  {
400
    /* Allocate specific layer1/2/3 buffers, so that we know they'll work for SSE. */
401
0
    size_t scratchsize = 0;
402
0
    real *scratcher;
403
0
#ifndef NO_LAYER1
404
0
    scratchsize += sizeof(real) * 2 * SBLIMIT;
405
0
#endif
406
0
#ifndef NO_LAYER2
407
0
    scratchsize += sizeof(real) * 2 * 4 * SBLIMIT;
408
0
#endif
409
0
#ifndef NO_LAYER3
410
0
    scratchsize += sizeof(real) * 2 * SBLIMIT * SSLIMIT; /* hybrid_in */
411
0
    scratchsize += sizeof(real) * 2 * SSLIMIT * SBLIMIT; /* hybrid_out */
412
0
#endif
413
    /*
414
      Now figure out correct alignment:
415
      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).
416
    */
417
0
    fr->layerscratch = malloc(scratchsize+63);
418
0
    if(fr->layerscratch == NULL) return -1;
419
420
    /* Get aligned part of the memory, then divide it up. */
421
0
    scratcher = aligned_pointer(fr->layerscratch,real,64);
422
    /* Those funky pointer casts silence compilers...
423
       One might change the code at hand to really just use 1D arrays, but in practice, that would not make a (positive) difference. */
424
0
#ifndef NO_LAYER1
425
0
    fr->layer1.fraction = (real(*)[SBLIMIT])scratcher;
426
0
    scratcher += 2 * SBLIMIT;
427
0
#endif
428
0
#ifndef NO_LAYER2
429
0
    fr->layer2.fraction = (real(*)[4][SBLIMIT])scratcher;
430
0
    scratcher += 2 * 4 * SBLIMIT;
431
0
#endif
432
0
#ifndef NO_LAYER3
433
0
    fr->layer3.hybrid_in = (real(*)[SBLIMIT][SSLIMIT])scratcher;
434
0
    scratcher += 2 * SBLIMIT * SSLIMIT;
435
0
    fr->layer3.hybrid_out = (real(*)[SSLIMIT][SBLIMIT])scratcher;
436
0
    scratcher += 2 * SSLIMIT * SBLIMIT;
437
0
#endif
438
    /* Note: These buffers don't need resetting here. */
439
0
  }
440
441
  /* Only reset the buffers we created just now. */
442
0
  frame_decode_buffers_reset(fr);
443
444
0
  debug1("frame %p buffer done", (void*)fr);
445
0
  return 0;
446
0
}
447
448
int frame_buffers_reset(mpg123_handle *fr)
449
0
{
450
0
  fr->buffer.fill = 0; /* hm, reset buffer fill... did we do a flush? */
451
0
  fr->bsnum = 0;
452
  /* Wondering: could it be actually _wanted_ to retain buffer contents over different files? (special gapless / cut stuff) */
453
0
  fr->bsbuf = fr->bsspace[1];
454
0
  fr->bsbufold = fr->bsbuf;
455
0
  fr->bitreservoir = 0;
456
0
  frame_decode_buffers_reset(fr);
457
0
  memset(fr->bsspace, 0, 2*(MAXFRAMESIZE+512));
458
0
  memset(fr->ssave, 0, 34);
459
0
  fr->hybrid_blc[0] = fr->hybrid_blc[1] = 0;
460
0
  memset(fr->hybrid_block, 0, sizeof(real)*2*2*SBLIMIT*SSLIMIT);
461
0
  return 0;
462
0
}
463
464
static void frame_icy_reset(mpg123_handle* fr)
465
0
{
466
0
#ifndef NO_ICY
467
0
  if(fr->icy.data != NULL) free(fr->icy.data);
468
0
  fr->icy.data = NULL;
469
0
  fr->icy.interval = 0;
470
0
  fr->icy.next = 0;
471
0
#endif
472
0
}
473
474
static void frame_free_toc(mpg123_handle *fr)
475
0
{
476
0
  if(fr->xing_toc != NULL){ free(fr->xing_toc); fr->xing_toc = NULL; }
477
0
}
478
479
/* Just copy the Xing TOC over... */
480
int frame_fill_toc(mpg123_handle *fr, unsigned char* in)
481
0
{
482
0
  if(fr->xing_toc == NULL) fr->xing_toc = malloc(100);
483
0
  if(fr->xing_toc != NULL)
484
0
  {
485
0
    memcpy(fr->xing_toc, in, 100);
486
#ifdef DEBUG
487
    debug("Got a TOC! Showing the values...");
488
    {
489
      int i;
490
      for(i=0; i<100; ++i)
491
      debug2("entry %i = %i", i, fr->xing_toc[i]);
492
    }
493
#endif
494
0
    return TRUE;
495
0
  }
496
0
  return FALSE;
497
0
}
498
499
/* Prepare the handle for a new track.
500
   Reset variables, buffers... */
501
int frame_reset(mpg123_handle* fr)
502
0
{
503
0
  frame_buffers_reset(fr);
504
0
  frame_fixed_reset(fr);
505
0
  frame_free_toc(fr);
506
0
#ifdef FRAME_INDEX
507
0
  fi_reset(&fr->index);
508
0
#endif
509
510
0
  return 0;
511
0
}
512
513
/* Reset everythign except dynamic memory. */
514
static void frame_fixed_reset(mpg123_handle *fr)
515
0
{
516
0
  frame_icy_reset(fr);
517
0
  open_bad(fr);
518
0
  fr->to_decode = FALSE;
519
0
  fr->to_ignore = FALSE;
520
0
  fr->metaflags = 0;
521
0
  fr->outblock = 0; /* This will be set before decoding! */
522
0
  fr->num = -1;
523
0
  fr->input_offset = -1;
524
0
  fr->playnum = -1;
525
0
  fr->state_flags = FRAME_ACCURATE;
526
0
  fr->silent_resync = 0;
527
0
  fr->audio_start = 0;
528
0
  fr->clip = 0;
529
0
  fr->oldhead = 0;
530
0
  fr->firsthead = 0;
531
0
  fr->lay = 0;
532
0
  fr->vbr = MPG123_CBR;
533
0
  fr->abr_rate = 0;
534
0
  fr->track_frames = 0;
535
0
  fr->track_samples = -1;
536
0
  fr->framesize=0; 
537
0
  fr->mean_frames = 0;
538
0
  fr->mean_framesize = 0;
539
0
  fr->freesize = 0;
540
0
  fr->lastscale = -1;
541
0
  fr->rva.level[0] = -1;
542
0
  fr->rva.level[1] = -1;
543
0
  fr->rva.gain[0] = 0;
544
0
  fr->rva.gain[1] = 0;
545
0
  fr->rva.peak[0] = 0;
546
0
  fr->rva.peak[1] = 0;
547
0
  fr->fsizeold = 0;
548
0
  fr->firstframe = 0;
549
0
  fr->ignoreframe = fr->firstframe-fr->p.preframes;
550
0
  fr->header_change = 0;
551
0
  fr->lastframe = -1;
552
0
  fr->fresh = 1;
553
0
  fr->new_format = 0;
554
0
#ifdef GAPLESS
555
0
  frame_gapless_init(fr,-1,0,0);
556
0
  fr->lastoff = 0;
557
0
  fr->firstoff = 0;
558
0
#endif
559
#ifdef OPT_I486
560
  fr->i486bo[0] = fr->i486bo[1] = FIR_SIZE-1;
561
#endif
562
0
  fr->bo = 1; /* the usual bo */
563
0
#ifdef OPT_DITHER
564
0
  fr->ditherindex = 0;
565
0
#endif
566
0
  reset_id3(fr);
567
0
  reset_icy(&fr->icy);
568
  /* ICY stuff should go into icy.c, eh? */
569
0
#ifndef NO_ICY
570
0
  fr->icy.interval = 0;
571
0
  fr->icy.next = 0;
572
0
#endif
573
0
  fr->halfphase = 0; /* here or indeed only on first-time init? */
574
0
  fr->error_protection = 0;
575
0
  fr->freeformat_framesize = fr->p.freeformat_framesize;
576
0
  fr->enc_delay = -1;
577
0
  fr->enc_padding = -1;
578
0
  memset(fr->id3buf, 0, sizeof(fr->id3buf));
579
0
  if(fr->id3v2_raw)
580
0
    free(fr->id3v2_raw);
581
0
  fr->id3v2_raw = NULL;
582
0
  fr->id3v2_size = 0;
583
0
}
584
585
static void frame_free_buffers(mpg123_handle *fr)
586
0
{
587
0
  if(fr->rawbuffs != NULL) free(fr->rawbuffs);
588
0
  fr->rawbuffs = NULL;
589
0
  fr->rawbuffss = 0;
590
0
  if(fr->rawdecwin != NULL) free(fr->rawdecwin);
591
0
  fr->rawdecwin = NULL;
592
0
  fr->rawdecwins = 0;
593
0
#ifndef NO_8BIT
594
0
  if(fr->conv16to8_buf != NULL) free(fr->conv16to8_buf);
595
0
  fr->conv16to8_buf = NULL;
596
0
#endif
597
0
  if(fr->layerscratch != NULL) free(fr->layerscratch);
598
0
}
599
600
void frame_exit(mpg123_handle *fr)
601
0
{
602
0
  if(fr->buffer.rdata != NULL)
603
0
  {
604
0
    debug1("freeing buffer at %p", (void*)fr->buffer.rdata);
605
0
    free(fr->buffer.rdata);
606
0
  }
607
0
  fr->buffer.rdata = NULL;
608
0
  frame_free_buffers(fr);
609
0
  frame_free_toc(fr);
610
0
#ifdef FRAME_INDEX
611
0
  fi_exit(&fr->index);
612
0
#endif
613
0
#ifdef OPT_DITHER
614
0
  if(fr->dithernoise != NULL)
615
0
  {
616
0
    free(fr->dithernoise);
617
0
    fr->dithernoise = NULL;
618
0
  }
619
0
#endif
620
0
  exit_id3(fr);
621
0
  clear_icy(&fr->icy);
622
  /* Clean up possible mess from LFS wrapper. */
623
0
  if(fr->wrapperclean != NULL)
624
0
  {
625
0
    fr->wrapperclean(fr->wrapperdata);
626
0
    fr->wrapperdata = NULL;
627
0
  }
628
0
#ifndef NO_FEEDER
629
0
  bc_cleanup(&fr->rdat.buffer);
630
0
#endif
631
0
}
632
633
int attribute_align_arg mpg123_framedata(mpg123_handle *mh, unsigned long *header, unsigned char **bodydata, size_t *bodybytes)
634
0
{
635
0
  if(mh == NULL)     return MPG123_BAD_HANDLE;
636
0
  if(!mh->to_decode) return MPG123_ERR;
637
638
0
  if(header    != NULL) *header    = mh->oldhead;
639
0
  if(bodydata  != NULL) *bodydata  = mh->bsbuf;
640
0
  if(bodybytes != NULL) *bodybytes = mh->framesize;
641
642
0
  return MPG123_OK;
643
0
}
644
645
int attribute_align_arg mpg123_set_moreinfo( mpg123_handle *mh
646
, struct mpg123_moreinfo *mi)
647
0
{
648
0
#ifndef NO_MOREINFO
649
0
  mh->pinfo = mi;
650
0
  return MPG123_OK;
651
#else
652
  mh->err = MPG123_MISSING_FEATURE;
653
  return MPG123_ERR;
654
#endif
655
0
}
656
657
/*
658
  Fuzzy frame offset searching (guessing).
659
  When we don't have an accurate position, we may use an inaccurate one.
660
  Possibilities:
661
    - use approximate positions from Xing TOC (not yet parsed)
662
    - guess wildly from mean framesize and offset of first frame / beginning of file.
663
*/
664
665
static off_t frame_fuzzy_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
666
0
{
667
  /* Default is to go to the beginning. */
668
0
  off_t ret = fr->audio_start;
669
0
  *get_frame = 0;
670
671
  /* But we try to find something better. */
672
  /* Xing VBR TOC works with relative positions, both in terms of audio frames and stream bytes.
673
     Thus, it only works when whe know the length of things.
674
     Oh... I assume the offsets are relative to the _total_ file length. */
675
0
  if(fr->xing_toc != NULL && fr->track_frames > 0 && fr->rdat.filelen > 0)
676
0
  {
677
    /* One could round... */
678
0
    int toc_entry = (int) ((double)want_frame*100./fr->track_frames);
679
    /* It is an index in the 100-entry table. */
680
0
    if(toc_entry < 0)  toc_entry = 0;
681
0
    if(toc_entry > 99) toc_entry = 99;
682
683
    /* Now estimate back what frame we get. */
684
0
    *get_frame = (off_t) ((double)toc_entry/100. * fr->track_frames);
685
0
    fr->state_flags &= ~FRAME_ACCURATE;
686
0
    fr->silent_resync = 1;
687
    /* Question: Is the TOC for whole file size (with/without ID3) or the "real" audio data only?
688
       ID3v1 info could also matter. */
689
0
    ret = (off_t) ((double)fr->xing_toc[toc_entry]/256.* fr->rdat.filelen);
690
0
  }
691
0
  else if(fr->mean_framesize > 0)
692
0
  { /* Just guess with mean framesize (may be exact with CBR files). */
693
    /* Query filelen here or not? */
694
0
    fr->state_flags &= ~FRAME_ACCURATE; /* Fuzzy! */
695
0
    fr->silent_resync = 1;
696
0
    *get_frame = want_frame;
697
0
    ret = (off_t) (fr->audio_start+fr->mean_framesize*want_frame);
698
0
  }
699
0
  debug5("fuzzy: want %li of %li, get %li at %li B of %li B",
700
0
    (long)want_frame, (long)fr->track_frames, (long)*get_frame, (long)ret, (long)(fr->rdat.filelen-fr->audio_start));
701
0
  return ret;
702
0
}
703
704
/*
705
  find the best frame in index just before the wanted one, seek to there
706
  then step to just before wanted one with read_frame
707
  do not care tabout the stuff that was in buffer but not played back
708
  everything that left the decoder is counted as played
709
  
710
  Decide if you want low latency reaction and accurate timing info or stable long-time playback with buffer!
711
*/
712
713
off_t frame_index_find(mpg123_handle *fr, off_t want_frame, off_t* get_frame)
714
0
{
715
  /* default is file start if no index position */
716
0
  off_t gopos = 0;
717
0
  *get_frame = 0;
718
0
#ifdef FRAME_INDEX
719
  /* Possibly use VBRI index, too? I'd need an example for this... */
720
0
  if(fr->index.fill)
721
0
  {
722
    /* find in index */
723
0
    size_t fi;
724
    /* at index fi there is frame step*fi... */
725
0
    fi = want_frame/fr->index.step;
726
0
    if(fi >= fr->index.fill) /* If we are beyond the end of frame index...*/
727
0
    {
728
      /* When fuzzy seek is allowed, we have some limited tolerance for the frames we want to read rather then jump over. */
729
0
      if(fr->p.flags & MPG123_FUZZY && want_frame - (fr->index.fill-1)*fr->index.step > 10)
730
0
      {
731
0
        gopos = frame_fuzzy_find(fr, want_frame, get_frame);
732
0
        if(gopos > fr->audio_start) return gopos; /* Only in that case, we have a useful guess. */
733
        /* Else... just continue, fuzzyness didn't help. */
734
0
      }
735
      /* Use the last available position, slowly advancing from that one. */
736
0
      fi = fr->index.fill - 1;
737
0
    }
738
    /* We have index position, that yields frame and byte offsets. */
739
0
    *get_frame = fi*fr->index.step;
740
0
    gopos = fr->index.data[fi];
741
0
    fr->state_flags |= FRAME_ACCURATE; /* When using the frame index, we are accurate. */
742
0
  }
743
0
  else
744
0
  {
745
0
#endif
746
0
    if(fr->p.flags & MPG123_FUZZY)
747
0
    return frame_fuzzy_find(fr, want_frame, get_frame);
748
    /* A bit hackish here... but we need to be fresh when looking for the first header again. */
749
0
    fr->firsthead = 0;
750
0
    fr->oldhead = 0;
751
0
#ifdef FRAME_INDEX
752
0
  }
753
0
#endif
754
0
  debug2("index: 0x%lx for frame %li", (unsigned long)gopos, (long) *get_frame);
755
0
  return gopos;
756
0
}
757
758
off_t frame_ins2outs(mpg123_handle *fr, off_t ins)
759
0
{ 
760
0
  off_t outs = 0;
761
0
  switch(fr->down_sample)
762
0
  {
763
0
    case 0:
764
0
#   ifndef NO_DOWNSAMPLE
765
0
    case 1:
766
0
    case 2:
767
0
#   endif
768
0
      outs = ins>>fr->down_sample;
769
0
    break;
770
0
#   ifndef NO_NTOM
771
0
    case 3: outs = ntom_ins2outs(fr, ins); break;
772
0
#   endif
773
0
    default: if(NOQUIET)
774
0
      merror( "Bad down_sample (%i) ... should not be possible!!"
775
0
      , fr->down_sample );
776
0
  }
777
0
  return outs;
778
0
}
779
780
off_t frame_outs(mpg123_handle *fr, off_t num)
781
0
{
782
0
  off_t outs = 0;
783
0
  switch(fr->down_sample)
784
0
  {
785
0
    case 0:
786
0
#   ifndef NO_DOWNSAMPLE
787
0
    case 1:
788
0
    case 2:
789
0
#   endif
790
0
      outs = (fr->spf>>fr->down_sample)*num;
791
0
    break;
792
0
#ifndef NO_NTOM
793
0
    case 3: outs = ntom_frmouts(fr, num); break;
794
0
#endif
795
0
    default: if(NOQUIET)
796
0
      merror( "Bad down_sample (%i) ... should not be possible!!"
797
0
      , fr->down_sample );
798
0
  }
799
0
  return outs;
800
0
}
801
802
/* Compute the number of output samples we expect from this frame.
803
   This is either simple spf() or a tad more elaborate for ntom. */
804
off_t frame_expect_outsamples(mpg123_handle *fr)
805
0
{
806
0
  off_t outs = 0;
807
0
  switch(fr->down_sample)
808
0
  {
809
0
    case 0:
810
0
#   ifndef NO_DOWNSAMPLE
811
0
    case 1:
812
0
    case 2:
813
0
#   endif
814
0
      outs = fr->spf>>fr->down_sample;
815
0
    break;
816
0
#ifndef NO_NTOM
817
0
    case 3: outs = ntom_frame_outsamples(fr); break;
818
0
#endif
819
0
    default: if(NOQUIET)
820
0
      merror( "Bad down_sample (%i) ... should not be possible!!"
821
0
      , fr->down_sample );
822
0
  }
823
0
  return outs;
824
0
}
825
826
off_t frame_offset(mpg123_handle *fr, off_t outs)
827
0
{
828
0
  off_t num = 0;
829
0
  switch(fr->down_sample)
830
0
  {
831
0
    case 0:
832
0
#   ifndef NO_DOWNSAMPLE
833
0
    case 1:
834
0
    case 2:
835
0
#   endif
836
0
      num = outs/(fr->spf>>fr->down_sample);
837
0
    break;
838
0
#ifndef NO_NTOM
839
0
    case 3: num = ntom_frameoff(fr, outs); break;
840
0
#endif
841
0
    default: if(NOQUIET)
842
0
      error("Bad down_sample ... should not be possible!!");
843
0
  }
844
0
  return num;
845
0
}
846
847
#ifdef GAPLESS
848
/* input in _input_ samples */
849
void frame_gapless_init(mpg123_handle *fr, off_t framecount, off_t bskip, off_t eskip)
850
0
{
851
0
  debug3("frame_gapless_init: given %"OFF_P" frames, skip %"OFF_P" and %"OFF_P, (off_p)framecount, (off_p)bskip, (off_p)eskip);
852
0
  fr->gapless_frames = framecount;
853
0
  if(fr->gapless_frames > 0 && bskip >=0 && eskip >= 0)
854
0
  {
855
0
    fr->begin_s = bskip+GAPLESS_DELAY;
856
0
    fr->end_s = framecount*fr->spf-eskip+GAPLESS_DELAY;
857
0
  }
858
0
  else fr->begin_s = fr->end_s = 0;
859
  /* These will get proper values later, from above plus resampling info. */
860
0
  fr->begin_os = 0;
861
0
  fr->end_os = 0;
862
0
  fr->fullend_os = 0;
863
0
  debug2("frame_gapless_init: from %"OFF_P" to %"OFF_P" samples", (off_p)fr->begin_s, (off_p)fr->end_s);
864
0
}
865
866
void frame_gapless_realinit(mpg123_handle *fr)
867
0
{
868
0
  fr->begin_os = frame_ins2outs(fr, fr->begin_s);
869
0
  fr->end_os   = frame_ins2outs(fr, fr->end_s);
870
0
  if(fr->gapless_frames > 0)
871
0
  fr->fullend_os = frame_ins2outs(fr, fr->gapless_frames*fr->spf);
872
0
  else fr->fullend_os = 0;
873
874
0
  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);
875
0
}
876
877
/* At least note when there is trouble... */
878
void frame_gapless_update(mpg123_handle *fr, off_t total_samples)
879
0
{
880
0
  off_t gapless_samples = fr->gapless_frames*fr->spf;
881
0
  if(fr->gapless_frames < 1) return;
882
883
0
  debug2("gapless update with new sample count %"OFF_P" as opposed to known %"OFF_P, (off_p)total_samples, (off_p)gapless_samples);
884
0
  if(NOQUIET && total_samples != gapless_samples)
885
0
  fprintf(stderr, "\nWarning: Real sample count %"OFF_P" differs from given gapless sample count %"OFF_P". Frankenstein stream?\n"
886
0
  , (off_p)total_samples, (off_p)gapless_samples);
887
888
0
  if(gapless_samples > total_samples)
889
0
  {
890
0
    if(NOQUIET)
891
0
      merror( "End sample count smaller than gapless end! (%"OFF_P
892
0
        " < %"OFF_P"). Disabling gapless mode from now on."
893
0
      , (off_p)total_samples, (off_p)fr->end_s );
894
    /* This invalidates the current position... but what should I do? */
895
0
    frame_gapless_init(fr, -1, 0, 0);
896
0
    frame_gapless_realinit(fr);
897
0
    fr->lastframe = -1;
898
0
    fr->lastoff = 0;
899
0
  }
900
0
}
901
902
#endif
903
904
/* Compute the needed frame to ignore from, for getting accurate/consistent output for intended firstframe. */
905
static off_t ignoreframe(mpg123_handle *fr)
906
0
{
907
0
  off_t preshift = fr->p.preframes;
908
  /* Layer 3 _really_ needs at least one frame before. */
909
0
  if(fr->lay==3 && preshift < 1) preshift = 1;
910
  /* Layer 1 & 2 reall do not need more than 2. */
911
0
  if(fr->lay!=3 && preshift > 2) preshift = 2;
912
913
0
  return fr->firstframe - preshift;
914
0
}
915
916
/* The frame seek... This is not simply the seek to fe*fr->spf samples in output because we think of _input_ frames here.
917
   Seek to frame offset 1 may be just seek to 200 samples offset in output since the beginning of first frame is delay/padding.
918
   Hm, is that right? OK for the padding stuff, but actually, should the decoder delay be better totally hidden or not?
919
   With gapless, even the whole frame position could be advanced further than requested (since Homey don't play dat). */
920
void frame_set_frameseek(mpg123_handle *fr, off_t fe)
921
0
{
922
0
  fr->firstframe = fe;
923
0
#ifdef GAPLESS
924
0
  if(fr->p.flags & MPG123_GAPLESS && fr->gapless_frames > 0)
925
0
  {
926
    /* Take care of the beginning... */
927
0
    off_t beg_f = frame_offset(fr, fr->begin_os);
928
0
    if(fe <= beg_f)
929
0
    {
930
0
      fr->firstframe = beg_f;
931
0
      fr->firstoff   = fr->begin_os - frame_outs(fr, beg_f);
932
0
    }
933
0
    else fr->firstoff = 0;
934
    /* The end is set once for a track at least, on the frame_set_frameseek called in get_next_frame() */
935
0
    if(fr->end_os > 0)
936
0
    {
937
0
      fr->lastframe  = frame_offset(fr,fr->end_os);
938
0
      fr->lastoff    = fr->end_os - frame_outs(fr, fr->lastframe);
939
0
    } else {fr->lastframe = -1; fr->lastoff = 0; }
940
0
  } else { fr->firstoff = fr->lastoff = 0; fr->lastframe = -1; }
941
0
#endif
942
0
  fr->ignoreframe = ignoreframe(fr);
943
0
#ifdef GAPLESS
944
0
  debug5("frame_set_frameseek: begin at %li frames and %li samples, end at %li and %li; ignore from %li",
945
0
         (long) fr->firstframe, (long) fr->firstoff,
946
0
         (long) fr->lastframe,  (long) fr->lastoff, (long) fr->ignoreframe);
947
#else
948
  debug3("frame_set_frameseek: begin at %li frames, end at %li; ignore from %li",
949
         (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);
950
#endif
951
0
}
952
953
void frame_skip(mpg123_handle *fr)
954
0
{
955
0
#ifndef NO_LAYER3
956
0
  if(fr->lay == 3) set_pointer(fr, 1, 512);
957
0
#endif
958
0
}
959
960
/* Sample accurate seek prepare for decoder. */
961
/* This gets unadjusted output samples and takes resampling into account */
962
void frame_set_seek(mpg123_handle *fr, off_t sp)
963
0
{
964
0
  fr->firstframe = frame_offset(fr, sp);
965
0
  debug1("frame_set_seek: from %"OFF_P, fr->num);
966
0
#ifndef NO_NTOM
967
0
  if(fr->down_sample == 3) ntom_set_ntom(fr, fr->firstframe);
968
0
#endif
969
0
  fr->ignoreframe = ignoreframe(fr);
970
0
#ifdef GAPLESS /* The sample offset is used for non-gapless mode, too! */
971
0
  fr->firstoff = sp - frame_outs(fr, fr->firstframe);
972
0
  debug5("frame_set_seek: begin at %li frames and %li samples, end at %li and %li; ignore from %li",
973
0
         (long) fr->firstframe, (long) fr->firstoff,
974
0
         (long) fr->lastframe,  (long) fr->lastoff, (long) fr->ignoreframe);
975
#else
976
  debug3("frame_set_seek: begin at %li frames, end at %li; ignore from %li",
977
         (long) fr->firstframe, (long) fr->lastframe, (long) fr->ignoreframe);
978
#endif
979
0
}
980
981
int attribute_align_arg mpg123_volume_change(mpg123_handle *mh, double change)
982
0
{
983
0
  if(mh == NULL) return MPG123_ERR;
984
0
  return mpg123_volume(mh, change + (double) mh->p.outscale);
985
0
}
986
987
int attribute_align_arg mpg123_volume_change_db(mpg123_handle *mh, double change)
988
0
{
989
0
  if(mh == NULL) return MPG123_ERR;
990
0
  return mpg123_volume(mh, dbchange(mh->p.outscale, change));
991
0
}
992
993
int attribute_align_arg mpg123_volume(mpg123_handle *mh, double vol)
994
0
{
995
0
  if(mh == NULL) return MPG123_ERR;
996
997
0
  if(vol >= 0) mh->p.outscale = vol;
998
0
  else mh->p.outscale = 0.;
999
1000
0
  do_rva(mh);
1001
0
  return MPG123_OK;
1002
0
}
1003
1004
static int get_rva(mpg123_handle *fr, double *peak, double *gain)
1005
0
{
1006
0
  double p = -1;
1007
0
  double g = 0;
1008
0
  int ret = 0;
1009
0
  if(fr->p.rva)
1010
0
  {
1011
0
    int rt = 0;
1012
    /* Should one assume a zero RVA as no RVA? */
1013
0
    if(fr->p.rva == 2 && fr->rva.level[1] != -1) rt = 1;
1014
0
    if(fr->rva.level[rt] != -1)
1015
0
    {
1016
0
      p = fr->rva.peak[rt];
1017
0
      g = fr->rva.gain[rt];
1018
0
      ret = 1; /* Success. */
1019
0
    }
1020
0
  }
1021
0
  if(peak != NULL) *peak = p;
1022
0
  if(gain != NULL) *gain = g;
1023
0
  return ret;
1024
0
}
1025
1026
/* adjust the volume, taking both fr->outscale and rva values into account */
1027
void do_rva(mpg123_handle *fr)
1028
0
{
1029
0
  double peak = 0;
1030
0
  double gain = 0;
1031
0
  double newscale;
1032
0
  double rvafact = 1;
1033
0
  if(get_rva(fr, &peak, &gain))
1034
0
  {
1035
0
    if(NOQUIET && fr->p.verbose > 1) fprintf(stderr, "Note: doing RVA with gain %f\n", gain);
1036
0
    rvafact = pow(10,gain/20);
1037
0
  }
1038
1039
0
  newscale = fr->p.outscale*rvafact;
1040
1041
  /* if peak is unknown (== 0) this check won't hurt */
1042
0
  if((peak*newscale) > 1.0)
1043
0
  {
1044
0
    newscale = 1.0/peak;
1045
0
    warning2("limiting scale value to %f to prevent clipping with indicated peak factor of %f", newscale, peak);
1046
0
  }
1047
  /* first rva setting is forced with fr->lastscale < 0 */
1048
0
  if(newscale != fr->lastscale || fr->decoder_change)
1049
0
  {
1050
0
    debug3("changing scale value from %f to %f (peak estimated to %f)", fr->lastscale != -1 ? fr->lastscale : fr->p.outscale, newscale, (double) (newscale*peak));
1051
0
    fr->lastscale = newscale;
1052
    /* It may be too early, actually. */
1053
0
    if(fr->make_decode_tables != NULL) fr->make_decode_tables(fr); /* the actual work */
1054
0
  }
1055
0
}
1056
1057
1058
int attribute_align_arg mpg123_getvolume(mpg123_handle *mh, double *base, double *really, double *rva_db)
1059
0
{
1060
0
  if(mh == NULL) return MPG123_ERR;
1061
0
  if(base)   *base   = mh->p.outscale;
1062
0
  if(really) *really = mh->lastscale;
1063
0
  get_rva(mh, NULL, rva_db);
1064
0
  return MPG123_OK;
1065
0
}
1066
1067
off_t attribute_align_arg mpg123_framepos(mpg123_handle *mh)
1068
0
{
1069
0
  if(mh == NULL) return MPG123_ERR;
1070
1071
0
  return mh->input_offset;
1072
0
}