Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3960 | Serge | 1 | /* |
2 | sampleadjust: gapless sample offset math |
||
3 | |||
4 | copyright 1995-2012 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 | |||
7 | This is no stand-alone header, precisely to be able to fool it into using fake handle types for testing the math. |
||
8 | */ |
||
9 | |||
10 | #include "debug.h" |
||
11 | |||
12 | #ifdef GAPLESS |
||
13 | /* From internal sample number to external. */ |
||
14 | static off_t sample_adjust(mpg123_handle *mh, off_t x) |
||
15 | { |
||
16 | off_t s; |
||
17 | if(mh->p.flags & MPG123_GAPLESS) |
||
18 | { |
||
19 | /* It's a bit tricky to do this computation for the padding samples. |
||
20 | They are not there on the outside. */ |
||
21 | if(x > mh->end_os) |
||
22 | { |
||
23 | if(x < mh->fullend_os) |
||
24 | s = mh->end_os - mh->begin_os; |
||
25 | else |
||
26 | s = x - (mh->fullend_os - mh->end_os + mh->begin_os); |
||
27 | } |
||
28 | else |
||
29 | s = x - mh->begin_os; |
||
30 | } |
||
31 | else |
||
32 | s = x; |
||
33 | |||
34 | return s; |
||
35 | } |
||
36 | |||
37 | /* from external samples to internal */ |
||
38 | static off_t sample_unadjust(mpg123_handle *mh, off_t x) |
||
39 | { |
||
40 | off_t s; |
||
41 | if(mh->p.flags & MPG123_GAPLESS) |
||
42 | { |
||
43 | s = x + mh->begin_os; |
||
44 | /* There is a hole; we don't create sample positions in there. |
||
45 | Jump from the end of the gapless track directly to after the padding. */ |
||
46 | if(s >= mh->end_os) |
||
47 | s += mh->fullend_os - mh->end_os; |
||
48 | } |
||
49 | else s = x; |
||
50 | |||
51 | return s; |
||
52 | } |
||
53 | |||
54 | /* |
||
55 | Take the buffer after a frame decode (strictly: it is the data from frame fr->num!) and cut samples out. |
||
56 | fr->buffer.fill may then be smaller than before... |
||
57 | */ |
||
58 | static void frame_buffercheck(mpg123_handle *fr) |
||
59 | { |
||
60 | /* When we have no accurate position, gapless code does not make sense. */ |
||
61 | if(!(fr->state_flags & FRAME_ACCURATE)) return; |
||
62 | |||
63 | /* Get a grip on dirty streams that start with a gapless header. |
||
64 | Simply accept all data from frames that are too much, |
||
65 | they are supposedly attached to the stream after the fact. */ |
||
66 | if(fr->gapless_frames > 0 && fr->num >= fr->gapless_frames) return; |
||
67 | |||
68 | /* Important: We first cut samples from the end, then cut from beginning (including left-shift of the buffer). |
||
69 | This order works also for the case where firstframe == lastframe. */ |
||
70 | |||
71 | /* The last interesting (planned) frame: Only use some leading samples. |
||
72 | Note a difference from the below: The last frame and offset are unchanges by seeks. |
||
73 | The lastoff keeps being valid. */ |
||
74 | if(fr->lastframe > -1 && fr->num >= fr->lastframe) |
||
75 | { |
||
76 | /* There can be more than one frame of padding at the end, so we ignore the whole frame if we are beyond lastframe. */ |
||
77 | off_t byteoff = (fr->num == fr->lastframe) ? samples_to_bytes(fr, fr->lastoff) : 0; |
||
78 | if((off_t)fr->buffer.fill > byteoff) |
||
79 | { |
||
80 | fr->buffer.fill = byteoff; |
||
81 | } |
||
82 | if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on end of stream to %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)(fr->num == fr->lastframe ? fr->lastoff : 0), (size_p)fr->buffer.fill); |
||
83 | } |
||
84 | |||
85 | /* The first interesting frame: Skip some leading samples. */ |
||
86 | if(fr->firstoff && fr->num == fr->firstframe) |
||
87 | { |
||
88 | off_t byteoff = samples_to_bytes(fr, fr->firstoff); |
||
89 | if((off_t)fr->buffer.fill > byteoff) |
||
90 | { |
||
91 | fr->buffer.fill -= byteoff; |
||
92 | /* buffer.p != buffer.data only for own buffer */ |
||
93 | debug6("cutting %li samples/%li bytes on begin, own_buffer=%i at %p=%p, buf[1]=%i", |
||
94 | (long)fr->firstoff, (long)byteoff, fr->own_buffer, (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
||
95 | if(fr->own_buffer) fr->buffer.p = fr->buffer.data + byteoff; |
||
96 | else memmove(fr->buffer.data, fr->buffer.data + byteoff, fr->buffer.fill); |
||
97 | debug3("done cutting, buffer at %p =? %p, buf[1]=%i", |
||
98 | (void*)fr->buffer.p, (void*)fr->buffer.data, ((short*)fr->buffer.p)[2]); |
||
99 | } |
||
100 | else fr->buffer.fill = 0; |
||
101 | |||
102 | if(VERBOSE3) fprintf(stderr, "\nNote: Cut frame %"OFF_P" buffer on beginning of stream by %"OFF_P" samples, fill now %"SIZE_P" bytes.\n", (off_p)fr->num, (off_p)fr->firstoff, (size_p)fr->buffer.fill); |
||
103 | /* We can only reach this frame again by seeking. And on seeking, firstoff will be recomputed. |
||
104 | So it is safe to null it here (and it makes the if() decision abort earlier). */ |
||
105 | fr->firstoff = 0; |
||
106 | } |
||
107 | } |
||
108 | |||
109 | #define SAMPLE_ADJUST(mh,x) sample_adjust(mh,x) |
||
110 | #define SAMPLE_UNADJUST(mh,x) sample_unadjust(mh,x) |
||
111 | #define FRAME_BUFFERCHECK(mh) frame_buffercheck(mh) |
||
112 | |||
113 | #else /* no gapless code included */ |
||
114 | |||
115 | #define SAMPLE_ADJUST(mh,x) (x) |
||
116 | #define SAMPLE_UNADJUST(mh,x) (x) |
||
117 | #define FRAME_BUFFERCHECK(mh) |
||
118 | |||
119 | #endif> |