line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* |
2
|
|
|
|
|
|
|
* Original Copyright: |
3
|
|
|
|
|
|
|
* |
4
|
|
|
|
|
|
|
Copyright (c) 2005, The Musepack Development Team |
5
|
|
|
|
|
|
|
All rights reserved. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without |
8
|
|
|
|
|
|
|
modification, are permitted provided that the following conditions are |
9
|
|
|
|
|
|
|
met: |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright |
12
|
|
|
|
|
|
|
notice, this list of conditions and the following disclaimer. |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
* Redistributions in binary form must reproduce the above |
15
|
|
|
|
|
|
|
copyright notice, this list of conditions and the following |
16
|
|
|
|
|
|
|
disclaimer in the documentation and/or other materials provided |
17
|
|
|
|
|
|
|
with the distribution. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
* Neither the name of the The Musepack Development Team nor the |
20
|
|
|
|
|
|
|
names of its contributors may be used to endorse or promote |
21
|
|
|
|
|
|
|
products derived from this software without specific prior |
22
|
|
|
|
|
|
|
written permission. |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
25
|
|
|
|
|
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
26
|
|
|
|
|
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
27
|
|
|
|
|
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
28
|
|
|
|
|
|
|
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
29
|
|
|
|
|
|
|
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
30
|
|
|
|
|
|
|
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
31
|
|
|
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
32
|
|
|
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
33
|
|
|
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
34
|
|
|
|
|
|
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
35
|
|
|
|
|
|
|
*/ |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#include "mpc.h" |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
#define MPC_BLOCK_SIZE 1024 |
40
|
|
|
|
|
|
|
#define MPC_OLD_GAIN_REF 64.82 |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
const int32_t samplefreqs[4] = { 44100, 48000, 37800, 32000 }; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
// profile is 0...15, where 7...13 is used |
45
|
|
|
|
|
|
|
static const char * |
46
|
4
|
|
|
|
|
|
_mpc_profile_string(uint32_t profile) |
47
|
|
|
|
|
|
|
{ |
48
|
|
|
|
|
|
|
static const char na[] = "n.a."; |
49
|
|
|
|
|
|
|
static const char *names[] = { |
50
|
|
|
|
|
|
|
na, |
51
|
|
|
|
|
|
|
"Unstable/Experimental", |
52
|
|
|
|
|
|
|
na, |
53
|
|
|
|
|
|
|
na, |
54
|
|
|
|
|
|
|
na, |
55
|
|
|
|
|
|
|
"below Telephone (q=0)", |
56
|
|
|
|
|
|
|
"below Telephone (q=1)", |
57
|
|
|
|
|
|
|
"Telephone (q=2)", |
58
|
|
|
|
|
|
|
"Thumb (q=3)", |
59
|
|
|
|
|
|
|
"Radio (q=4)", |
60
|
|
|
|
|
|
|
"Standard (q=5)", |
61
|
|
|
|
|
|
|
"Extreme (q=6)", |
62
|
|
|
|
|
|
|
"Insane (q=7)", |
63
|
|
|
|
|
|
|
"BrainDead (q=8)", |
64
|
|
|
|
|
|
|
"above BrainDead (q=9)", |
65
|
|
|
|
|
|
|
"above BrainDead (q=10)" |
66
|
|
|
|
|
|
|
}; |
67
|
|
|
|
|
|
|
|
68
|
4
|
50
|
|
|
|
|
return profile >= sizeof(names) / sizeof(*names) ? na : names[profile]; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
unsigned int |
72
|
6
|
|
|
|
|
|
_mpc_bits_get_size(Buffer *buf, uint64_t *p_size) |
73
|
|
|
|
|
|
|
{ |
74
|
|
|
|
|
|
|
unsigned char tmp; |
75
|
6
|
|
|
|
|
|
uint64_t size = 0; |
76
|
6
|
|
|
|
|
|
unsigned int ret = 0; |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
do { |
79
|
9
|
|
|
|
|
|
tmp = buffer_get_char(buf); |
80
|
9
|
|
|
|
|
|
size = (size << 7) | (tmp & 0x7F); |
81
|
9
|
|
|
|
|
|
ret++; |
82
|
9
|
100
|
|
|
|
|
} while((tmp & 0x80)); |
83
|
|
|
|
|
|
|
|
84
|
6
|
|
|
|
|
|
*p_size = size; |
85
|
6
|
|
|
|
|
|
return ret; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
static void |
89
|
4
|
|
|
|
|
|
_mpc_get_encoder_string(mpc_streaminfo* si) |
90
|
|
|
|
|
|
|
{ |
91
|
4
|
|
|
|
|
|
int ver = si->encoder_version; |
92
|
4
|
100
|
|
|
|
|
if (si->stream_version >= 8) |
93
|
1
|
|
|
|
|
|
ver = (si->encoder_version >> 24) * 100 + ((si->encoder_version >> 16) & 0xFF); |
94
|
4
|
100
|
|
|
|
|
if (ver <= 116) { |
95
|
3
|
100
|
|
|
|
|
if (ver == 0) { |
96
|
1
|
|
|
|
|
|
sprintf(si->encoder, "Buschmann 1.7.0...9, Klemm 0.90...1.05"); |
97
|
|
|
|
|
|
|
} else { |
98
|
2
|
|
|
|
|
|
switch (ver % 10) { |
99
|
|
|
|
|
|
|
case 0: |
100
|
0
|
|
|
|
|
|
sprintf(si->encoder, "Release %u.%u", ver / 100, |
101
|
0
|
|
|
|
|
|
ver / 10 % 10); |
102
|
0
|
|
|
|
|
|
break; |
103
|
|
|
|
|
|
|
case 2: case 4: case 6: case 8: |
104
|
0
|
|
|
|
|
|
sprintf(si->encoder, "Beta %u.%02u", ver / 100, |
105
|
|
|
|
|
|
|
ver % 100); |
106
|
0
|
|
|
|
|
|
break; |
107
|
|
|
|
|
|
|
default: |
108
|
2
|
|
|
|
|
|
sprintf(si->encoder, "--Alpha-- %u.%02u", |
109
|
|
|
|
|
|
|
ver / 100, ver % 100); |
110
|
3
|
|
|
|
|
|
break; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
} else { |
114
|
1
|
|
|
|
|
|
int major = si->encoder_version >> 24; |
115
|
1
|
|
|
|
|
|
int minor = (si->encoder_version >> 16) & 0xFF; |
116
|
1
|
|
|
|
|
|
int build = (si->encoder_version >> 8) & 0xFF; |
117
|
1
|
|
|
|
|
|
char * tmp = "--Stable--"; |
118
|
|
|
|
|
|
|
|
119
|
1
|
50
|
|
|
|
|
if (minor & 1) |
120
|
0
|
|
|
|
|
|
tmp = "--Unstable--"; |
121
|
|
|
|
|
|
|
|
122
|
1
|
|
|
|
|
|
sprintf(si->encoder, "%s %u.%u.%u", tmp, major, minor, build); |
123
|
|
|
|
|
|
|
} |
124
|
4
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
static int32_t |
127
|
1
|
|
|
|
|
|
_mpc_read_header_sv8(mpc_streaminfo *si) |
128
|
|
|
|
|
|
|
{ |
129
|
|
|
|
|
|
|
unsigned char blocktype[2]; |
130
|
1
|
|
|
|
|
|
unsigned char *bptr = buffer_ptr(si->buf); |
131
|
|
|
|
|
|
|
uint64_t size; |
132
|
|
|
|
|
|
|
|
133
|
4
|
50
|
|
|
|
|
while ( memcmp(bptr, "AP", 2) != 0 ) { // scan all blocks until audio |
134
|
4
|
|
|
|
|
|
memcpy(blocktype, bptr, 2); |
135
|
4
|
|
|
|
|
|
buffer_consume(si->buf, 2); |
136
|
|
|
|
|
|
|
|
137
|
4
|
|
|
|
|
|
_mpc_bits_get_size(si->buf, &size); |
138
|
4
|
|
|
|
|
|
size -= 3; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
DEBUG_TRACE("%c%c block, size %llu\n", blocktype[0], blocktype[1], size); |
141
|
|
|
|
|
|
|
|
142
|
4
|
50
|
|
|
|
|
if ( !_check_buf(si->infile, si->buf, size, MPC_BLOCK_SIZE) ) { |
143
|
0
|
|
|
|
|
|
return -1; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
4
|
100
|
|
|
|
|
if (memcmp(blocktype, "SH", 2) == 0) { |
147
|
|
|
|
|
|
|
// Skip CRC |
148
|
1
|
|
|
|
|
|
buffer_consume(si->buf, 4); |
149
|
|
|
|
|
|
|
|
150
|
1
|
|
|
|
|
|
si->stream_version = buffer_get_char(si->buf); |
151
|
1
|
|
|
|
|
|
_mpc_bits_get_size(si->buf, &si->pcm_samples); |
152
|
1
|
|
|
|
|
|
_mpc_bits_get_size(si->buf, &si->beg_silence); |
153
|
|
|
|
|
|
|
|
154
|
1
|
|
|
|
|
|
si->is_true_gapless = 1; |
155
|
|
|
|
|
|
|
|
156
|
1
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
157
|
1
|
|
|
|
|
|
si->sample_freq = samplefreqs[ (bptr[0] & 0xE0) >> 5 ]; |
158
|
1
|
|
|
|
|
|
si->max_band = (bptr[0] & 0x1F) + 1; |
159
|
1
|
|
|
|
|
|
si->channels = ( (bptr[1] & 0xF0) >> 4 ) + 1; |
160
|
1
|
|
|
|
|
|
si->ms = (bptr[1] & 0x8) >> 3; |
161
|
1
|
|
|
|
|
|
si->block_pwr = (bptr[1] & 0x7) * 2; |
162
|
1
|
|
|
|
|
|
buffer_consume(si->buf, 2); |
163
|
|
|
|
|
|
|
} |
164
|
3
|
100
|
|
|
|
|
else if (memcmp(blocktype, "RG", 2) == 0) { |
165
|
|
|
|
|
|
|
// Check version |
166
|
1
|
50
|
|
|
|
|
if ( buffer_get_char(si->buf) != 1 ) { |
167
|
|
|
|
|
|
|
// Skip |
168
|
0
|
|
|
|
|
|
buffer_consume(si->buf, size - 1); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
else { |
171
|
1
|
|
|
|
|
|
si->gain_title = buffer_get_short(si->buf); |
172
|
1
|
|
|
|
|
|
si->peak_title = buffer_get_short(si->buf); |
173
|
1
|
|
|
|
|
|
si->gain_album = buffer_get_short(si->buf); |
174
|
1
|
|
|
|
|
|
si->peak_album = buffer_get_short(si->buf); |
175
|
|
|
|
|
|
|
} |
176
|
|
|
|
|
|
|
} |
177
|
2
|
100
|
|
|
|
|
else if (memcmp(blocktype, "EI", 2) == 0) { |
178
|
1
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
179
|
|
|
|
|
|
|
|
180
|
1
|
|
|
|
|
|
si->fprofile = ((bptr[0] & 0xFE) >> 1) / 8.; |
181
|
1
|
|
|
|
|
|
si->profile_name = _mpc_profile_string((uint32_t)si->fprofile); |
182
|
1
|
|
|
|
|
|
buffer_consume(si->buf, 1); |
183
|
|
|
|
|
|
|
|
184
|
1
|
|
|
|
|
|
si->encoder_version = buffer_get_char(si->buf) << 24; // major |
185
|
1
|
|
|
|
|
|
si->encoder_version |= buffer_get_char(si->buf) << 16; // minor |
186
|
1
|
|
|
|
|
|
si->encoder_version |= buffer_get_char(si->buf) << 8; // build |
187
|
|
|
|
|
|
|
DEBUG_TRACE("ver: %d\n", si->encoder_version); |
188
|
|
|
|
|
|
|
|
189
|
1
|
|
|
|
|
|
_mpc_get_encoder_string(si); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
else { |
192
|
1
|
|
|
|
|
|
break; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
3
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
1
|
|
|
|
|
|
return 0; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
static int32_t |
202
|
3
|
|
|
|
|
|
_mpc_read_header_sv7(mpc_streaminfo *si) |
203
|
|
|
|
|
|
|
{ |
204
|
|
|
|
|
|
|
unsigned char *bptr; |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
// Update (si->stream_version); |
207
|
3
|
50
|
|
|
|
|
if (si->stream_version > 0x71) { |
208
|
0
|
|
|
|
|
|
return 0; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
3
|
|
|
|
|
|
si->bitrate = 0; |
212
|
3
|
|
|
|
|
|
si->frames = buffer_get_int_le(si->buf); |
213
|
|
|
|
|
|
|
|
214
|
3
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
215
|
3
|
|
|
|
|
|
si->is = (bptr[3] >> 7) & 0x1; |
216
|
3
|
|
|
|
|
|
si->ms = (bptr[3] >> 6) & 0x1; |
217
|
3
|
|
|
|
|
|
si->max_band = bptr[3] & 0x3F; |
218
|
|
|
|
|
|
|
|
219
|
3
|
|
|
|
|
|
si->block_size = 1; |
220
|
3
|
|
|
|
|
|
si->profile = (bptr[2] >> 4) & 0xF; |
221
|
3
|
|
|
|
|
|
si->profile_name = _mpc_profile_string(si->profile); |
222
|
|
|
|
|
|
|
// skip Link |
223
|
3
|
|
|
|
|
|
si->sample_freq = samplefreqs[bptr[2] & 0x3]; |
224
|
|
|
|
|
|
|
// skip MaxLevel |
225
|
3
|
|
|
|
|
|
buffer_consume(si->buf, 4); |
226
|
|
|
|
|
|
|
|
227
|
3
|
|
|
|
|
|
si->peak_title = buffer_get_short_le(si->buf); |
228
|
3
|
|
|
|
|
|
si->gain_title = buffer_get_short_le(si->buf); |
229
|
|
|
|
|
|
|
|
230
|
3
|
|
|
|
|
|
si->peak_album = buffer_get_short_le(si->buf); |
231
|
3
|
|
|
|
|
|
si->gain_album = buffer_get_short_le(si->buf); |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
// convert gain info |
234
|
3
|
100
|
|
|
|
|
if (si->gain_title != 0) { |
235
|
1
|
|
|
|
|
|
int tmp = (int)((MPC_OLD_GAIN_REF - (int16_t)si->gain_title / 100.) * 256. + .5); |
236
|
1
|
50
|
|
|
|
|
if (tmp >= (1 << 16) || tmp < 0) tmp = 0; |
|
|
50
|
|
|
|
|
|
237
|
1
|
|
|
|
|
|
si->gain_title = (int16_t)tmp; |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
|
240
|
3
|
100
|
|
|
|
|
if (si->gain_album != 0) { |
241
|
1
|
|
|
|
|
|
int tmp = (int)((MPC_OLD_GAIN_REF - (int16_t)si->gain_album / 100.) * 256. + .5); |
242
|
1
|
50
|
|
|
|
|
if (tmp >= (1 << 16) || tmp < 0) tmp = 0; |
|
|
50
|
|
|
|
|
|
243
|
1
|
|
|
|
|
|
si->gain_album = (int16_t)tmp; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
3
|
100
|
|
|
|
|
if (si->peak_title != 0) |
247
|
1
|
|
|
|
|
|
si->peak_title = (uint16_t) (log10(si->peak_title) * 20 * 256 + .5); |
248
|
|
|
|
|
|
|
|
249
|
3
|
100
|
|
|
|
|
if (si->peak_album != 0) |
250
|
1
|
|
|
|
|
|
si->peak_album = (uint16_t) (log10(si->peak_album) * 20 * 256 + .5); |
251
|
|
|
|
|
|
|
|
252
|
3
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
253
|
3
|
|
|
|
|
|
si->is_true_gapless = (bptr[3] >> 7) & 0x1; |
254
|
3
|
|
|
|
|
|
si->last_frame_samples = ((bptr[3] >> 1) & 0x7F) | ((bptr[2] >> 4) & 0xF); // true gapless: valid samples for last frame |
255
|
3
|
|
|
|
|
|
buffer_consume(si->buf, 4); |
256
|
|
|
|
|
|
|
|
257
|
3
|
|
|
|
|
|
bptr = buffer_ptr(si->buf); |
258
|
3
|
|
|
|
|
|
si->encoder_version = bptr[3]; |
259
|
3
|
|
|
|
|
|
si->channels = 2; |
260
|
|
|
|
|
|
|
|
261
|
3
|
|
|
|
|
|
_mpc_get_encoder_string(si); |
262
|
|
|
|
|
|
|
|
263
|
3
|
|
|
|
|
|
return 0; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
static int |
267
|
4
|
|
|
|
|
|
get_mpcfileinfo(PerlIO *infile, char *file, HV *info) |
268
|
|
|
|
|
|
|
{ |
269
|
|
|
|
|
|
|
Buffer buf; |
270
|
4
|
|
|
|
|
|
int32_t ret = 0; |
271
|
|
|
|
|
|
|
unsigned char *bptr; |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
mpc_streaminfo *si; |
274
|
|
|
|
|
|
|
|
275
|
4
|
|
|
|
|
|
Newz(0, si, sizeof(mpc_streaminfo), mpc_streaminfo); |
276
|
4
|
|
|
|
|
|
buffer_init(&buf, MPC_BLOCK_SIZE); |
277
|
|
|
|
|
|
|
|
278
|
4
|
|
|
|
|
|
si->buf = &buf; |
279
|
4
|
|
|
|
|
|
si->infile = infile; |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
// get header position |
282
|
4
|
50
|
|
|
|
|
if ((si->header_position = skip_id3v2(infile)) < 0) { |
283
|
0
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't skip ID3v2]: %s\n", file); |
284
|
0
|
|
|
|
|
|
goto out; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
// seek to first byte of mpc data |
288
|
4
|
50
|
|
|
|
|
if (PerlIO_seek(infile, si->header_position, SEEK_SET) < 0) { |
289
|
0
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't seek to offset %d]: %s\n", si->header_position, file); |
290
|
0
|
|
|
|
|
|
goto out; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
4
|
50
|
|
|
|
|
if ( !_check_buf(infile, &buf, 128, MPC_BLOCK_SIZE) ) { |
294
|
0
|
|
|
|
|
|
goto out; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
4
|
50
|
|
|
|
|
if (PerlIO_seek(infile, si->header_position + 6 * 4, SEEK_SET) < 0) { |
298
|
0
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't seek to offset %d + (6*4)]: %s\n", si->header_position, file); |
299
|
0
|
|
|
|
|
|
goto out; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
4
|
|
|
|
|
|
si->tag_offset = PerlIO_tell(infile); |
303
|
|
|
|
|
|
|
|
304
|
4
|
|
|
|
|
|
si->total_file_length = _file_size(infile); |
305
|
|
|
|
|
|
|
|
306
|
4
|
|
|
|
|
|
bptr = buffer_ptr(&buf); |
307
|
|
|
|
|
|
|
|
308
|
4
|
100
|
|
|
|
|
if (memcmp(bptr, "MP+", 3) == 0) { |
309
|
3
|
|
|
|
|
|
buffer_consume(&buf, 3); |
310
|
3
|
|
|
|
|
|
si->stream_version = buffer_get_char(&buf); |
311
|
|
|
|
|
|
|
|
312
|
3
|
50
|
|
|
|
|
if ((si->stream_version & 15) == 7) { |
313
|
|
|
|
|
|
|
DEBUG_TRACE("parsing MPC SV7 header\n"); |
314
|
3
|
|
|
|
|
|
ret = _mpc_read_header_sv7(si); |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
} |
318
|
1
|
50
|
|
|
|
|
else if (memcmp(bptr, "MPCK", 4) == 0) { |
319
|
1
|
|
|
|
|
|
buffer_consume(&buf, 4); |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
DEBUG_TRACE("parsing MPC SV8 header\n"); |
322
|
1
|
|
|
|
|
|
ret = _mpc_read_header_sv8(si); |
323
|
|
|
|
|
|
|
} |
324
|
|
|
|
|
|
|
else { |
325
|
0
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Not a Musepack SV7 or SV8 file: %s\n", file); |
326
|
0
|
|
|
|
|
|
goto out; |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
// estimation, exact value needs too much time |
330
|
4
|
100
|
|
|
|
|
if ( !si->pcm_samples ) |
331
|
3
|
|
|
|
|
|
si->pcm_samples = 1152 * si->frames - 576; |
332
|
|
|
|
|
|
|
|
333
|
4
|
50
|
|
|
|
|
if (ret == 0) { |
334
|
4
|
|
|
|
|
|
double total_seconds = (double)( (si->pcm_samples * 1.0) / si->sample_freq); |
335
|
|
|
|
|
|
|
|
336
|
4
|
|
|
|
|
|
my_hv_store(info, "stream_version", newSVuv(si->stream_version)); |
337
|
4
|
|
|
|
|
|
my_hv_store(info, "samplerate", newSViv(si->sample_freq)); |
338
|
4
|
|
|
|
|
|
my_hv_store(info, "channels", newSViv(si->channels)); |
339
|
4
|
|
|
|
|
|
my_hv_store(info, "song_length_ms", newSVuv(total_seconds * 1000)); |
340
|
4
|
|
|
|
|
|
my_hv_store(info, "bitrate", newSVuv(8 * (double)(si->total_file_length - si->tag_offset) / total_seconds)); |
341
|
|
|
|
|
|
|
|
342
|
4
|
|
|
|
|
|
my_hv_store(info, "audio_offset", newSVuv(si->tag_offset)); |
343
|
4
|
|
|
|
|
|
my_hv_store(info, "audio_size", newSVuv(si->total_file_length - si->tag_offset)); |
344
|
4
|
|
|
|
|
|
my_hv_store(info, "file_size", newSVuv(si->total_file_length)); |
345
|
4
|
|
|
|
|
|
my_hv_store(info, "encoder", newSVpv(si->encoder, 0)); |
346
|
|
|
|
|
|
|
|
347
|
4
|
50
|
|
|
|
|
if (si->profile_name) |
348
|
4
|
|
|
|
|
|
my_hv_store(info, "profile", newSVpv(si->profile_name, 0)); |
349
|
|
|
|
|
|
|
|
350
|
4
|
|
|
|
|
|
my_hv_store(info, "gapless", newSViv(si->is_true_gapless)); |
351
|
4
|
100
|
|
|
|
|
my_hv_store(info, "track_gain", newSVpvf("%2.2f dB", si->gain_title == 0 ? 0 : MPC_OLD_GAIN_REF - si->gain_title / 256.0)); |
352
|
4
|
100
|
|
|
|
|
my_hv_store(info, "album_gain", newSVpvf("%2.2f dB", si->gain_album == 0 ? 0 : MPC_OLD_GAIN_REF - si->gain_album / 256.0)); |
353
|
|
|
|
|
|
|
} |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
out: |
356
|
4
|
|
|
|
|
|
Safefree(si); |
357
|
4
|
|
|
|
|
|
buffer_free(&buf); |
358
|
|
|
|
|
|
|
|
359
|
4
|
|
|
|
|
|
return ret; |
360
|
|
|
|
|
|
|
} |