/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 | } |