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