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 *
_mpc_profile_string(uint32_t profile)46 _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 return profile >= sizeof(names) / sizeof(*names) ? na : names[profile];
69 }
70
71 unsigned int
_mpc_bits_get_size(Buffer * buf,uint64_t * p_size)72 _mpc_bits_get_size(Buffer *buf, uint64_t *p_size)
73 {
74 unsigned char tmp;
75 uint64_t size = 0;
76 unsigned int ret = 0;
77
78 do {
79 tmp = buffer_get_char(buf);
80 size = (size << 7) | (tmp & 0x7F);
81 ret++;
82 } while((tmp & 0x80));
83
84 *p_size = size;
85 return ret;
86 }
87
88 static void
_mpc_get_encoder_string(mpc_streaminfo * si)89 _mpc_get_encoder_string(mpc_streaminfo* si)
90 {
91 int ver = si->encoder_version;
92 if (si->stream_version >= 8)
93 ver = (si->encoder_version >> 24) * 100 + ((si->encoder_version >> 16) & 0xFF);
94 if (ver <= 116) {
95 if (ver == 0) {
96 sprintf(si->encoder, "Buschmann 1.7.0...9, Klemm 0.90...1.05");
97 } else {
98 switch (ver % 10) {
99 case 0:
100 sprintf(si->encoder, "Release %u.%u", ver / 100,
101 ver / 10 % 10);
102 break;
103 case 2: case 4: case 6: case 8:
104 sprintf(si->encoder, "Beta %u.%02u", ver / 100,
105 ver % 100);
106 break;
107 default:
108 sprintf(si->encoder, "--Alpha-- %u.%02u",
109 ver / 100, ver % 100);
110 break;
111 }
112 }
113 } else {
114 int major = si->encoder_version >> 24;
115 int minor = (si->encoder_version >> 16) & 0xFF;
116 int build = (si->encoder_version >> 8) & 0xFF;
117 char * tmp = "--Stable--";
118
119 if (minor & 1)
120 tmp = "--Unstable--";
121
122 sprintf(si->encoder, "%s %u.%u.%u", tmp, major, minor, build);
123 }
124 }
125
126 static int32_t
_mpc_read_header_sv8(mpc_streaminfo * si)127 _mpc_read_header_sv8(mpc_streaminfo *si)
128 {
129 unsigned char blocktype[2];
130 unsigned char *bptr = buffer_ptr(si->buf);
131 uint64_t size;
132
133 while ( memcmp(bptr, "AP", 2) != 0 ) { // scan all blocks until audio
134 memcpy(blocktype, bptr, 2);
135 buffer_consume(si->buf, 2);
136
137 _mpc_bits_get_size(si->buf, &size);
138 size -= 3;
139
140 DEBUG_TRACE("%c%c block, size %llu\n", blocktype[0], blocktype[1], size);
141
142 if ( !_check_buf(si->infile, si->buf, size, MPC_BLOCK_SIZE) ) {
143 return -1;
144 }
145
146 if (memcmp(blocktype, "SH", 2) == 0) {
147 // Skip CRC
148 buffer_consume(si->buf, 4);
149
150 si->stream_version = buffer_get_char(si->buf);
151 _mpc_bits_get_size(si->buf, &si->pcm_samples);
152 _mpc_bits_get_size(si->buf, &si->beg_silence);
153
154 si->is_true_gapless = 1;
155
156 bptr = buffer_ptr(si->buf);
157 si->sample_freq = samplefreqs[ (bptr[0] & 0xE0) >> 5 ];
158 si->max_band = (bptr[0] & 0x1F) + 1;
159 si->channels = ( (bptr[1] & 0xF0) >> 4 ) + 1;
160 si->ms = (bptr[1] & 0x8) >> 3;
161 si->block_pwr = (bptr[1] & 0x7) * 2;
162 buffer_consume(si->buf, 2);
163 }
164 else if (memcmp(blocktype, "RG", 2) == 0) {
165 // Check version
166 if ( buffer_get_char(si->buf) != 1 ) {
167 // Skip
168 buffer_consume(si->buf, size - 1);
169 }
170 else {
171 si->gain_title = buffer_get_short(si->buf);
172 si->peak_title = buffer_get_short(si->buf);
173 si->gain_album = buffer_get_short(si->buf);
174 si->peak_album = buffer_get_short(si->buf);
175 }
176 }
177 else if (memcmp(blocktype, "EI", 2) == 0) {
178 bptr = buffer_ptr(si->buf);
179
180 si->fprofile = ((bptr[0] & 0xFE) >> 1) / 8.;
181 si->profile_name = _mpc_profile_string((uint32_t)si->fprofile);
182 buffer_consume(si->buf, 1);
183
184 si->encoder_version = buffer_get_char(si->buf) << 24; // major
185 si->encoder_version |= buffer_get_char(si->buf) << 16; // minor
186 si->encoder_version |= buffer_get_char(si->buf) << 8; // build
187 DEBUG_TRACE("ver: %d\n", si->encoder_version);
188
189 _mpc_get_encoder_string(si);
190 }
191 else {
192 break;
193 }
194
195 bptr = buffer_ptr(si->buf);
196 }
197
198 return 0;
199 }
200
201 static int32_t
_mpc_read_header_sv7(mpc_streaminfo * si)202 _mpc_read_header_sv7(mpc_streaminfo *si)
203 {
204 unsigned char *bptr;
205
206 // Update (si->stream_version);
207 if (si->stream_version > 0x71) {
208 return 0;
209 }
210
211 si->bitrate = 0;
212 si->frames = buffer_get_int_le(si->buf);
213
214 bptr = buffer_ptr(si->buf);
215 si->is = (bptr[3] >> 7) & 0x1;
216 si->ms = (bptr[3] >> 6) & 0x1;
217 si->max_band = bptr[3] & 0x3F;
218
219 si->block_size = 1;
220 si->profile = (bptr[2] >> 4) & 0xF;
221 si->profile_name = _mpc_profile_string(si->profile);
222 // skip Link
223 si->sample_freq = samplefreqs[bptr[2] & 0x3];
224 // skip MaxLevel
225 buffer_consume(si->buf, 4);
226
227 si->peak_title = buffer_get_short_le(si->buf);
228 si->gain_title = buffer_get_short_le(si->buf);
229
230 si->peak_album = buffer_get_short_le(si->buf);
231 si->gain_album = buffer_get_short_le(si->buf);
232
233 // convert gain info
234 if (si->gain_title != 0) {
235 int tmp = (int)((MPC_OLD_GAIN_REF - (int16_t)si->gain_title / 100.) * 256. + .5);
236 if (tmp >= (1 << 16) || tmp < 0) tmp = 0;
237 si->gain_title = (int16_t)tmp;
238 }
239
240 if (si->gain_album != 0) {
241 int tmp = (int)((MPC_OLD_GAIN_REF - (int16_t)si->gain_album / 100.) * 256. + .5);
242 if (tmp >= (1 << 16) || tmp < 0) tmp = 0;
243 si->gain_album = (int16_t)tmp;
244 }
245
246 if (si->peak_title != 0)
247 si->peak_title = (uint16_t) (log10(si->peak_title) * 20 * 256 + .5);
248
249 if (si->peak_album != 0)
250 si->peak_album = (uint16_t) (log10(si->peak_album) * 20 * 256 + .5);
251
252 bptr = buffer_ptr(si->buf);
253 si->is_true_gapless = (bptr[3] >> 7) & 0x1;
254 si->last_frame_samples = ((bptr[3] >> 1) & 0x7F) | ((bptr[2] >> 4) & 0xF); // true gapless: valid samples for last frame
255 buffer_consume(si->buf, 4);
256
257 bptr = buffer_ptr(si->buf);
258 si->encoder_version = bptr[3];
259 si->channels = 2;
260
261 _mpc_get_encoder_string(si);
262
263 return 0;
264 }
265
266 static int
get_mpcfileinfo(PerlIO * infile,char * file,HV * info)267 get_mpcfileinfo(PerlIO *infile, char *file, HV *info)
268 {
269 Buffer buf;
270 int32_t ret = 0;
271 unsigned char *bptr;
272
273 mpc_streaminfo *si;
274
275 Newz(0, si, sizeof(mpc_streaminfo), mpc_streaminfo);
276 buffer_init(&buf, MPC_BLOCK_SIZE);
277
278 si->buf = &buf;
279 si->infile = infile;
280
281 // get header position
282 if ((si->header_position = skip_id3v2(infile)) < 0) {
283 PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't skip ID3v2]: %s\n", file);
284 goto out;
285 }
286
287 // seek to first byte of mpc data
288 if (PerlIO_seek(infile, si->header_position, SEEK_SET) < 0) {
289 PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't seek to offset %d]: %s\n", si->header_position, file);
290 goto out;
291 }
292
293 if ( !_check_buf(infile, &buf, 128, MPC_BLOCK_SIZE) ) {
294 goto out;
295 }
296
297 if (PerlIO_seek(infile, si->header_position + 6 * 4, SEEK_SET) < 0) {
298 PerlIO_printf(PerlIO_stderr(), "Musepack: [Couldn't seek to offset %d + (6*4)]: %s\n", si->header_position, file);
299 goto out;
300 }
301
302 si->tag_offset = PerlIO_tell(infile);
303
304 si->total_file_length = _file_size(infile);
305
306 bptr = buffer_ptr(&buf);
307
308 if (memcmp(bptr, "MP+", 3) == 0) {
309 buffer_consume(&buf, 3);
310 si->stream_version = buffer_get_char(&buf);
311
312 if ((si->stream_version & 15) == 7) {
313 DEBUG_TRACE("parsing MPC SV7 header\n");
314 ret = _mpc_read_header_sv7(si);
315 }
316
317 }
318 else if (memcmp(bptr, "MPCK", 4) == 0) {
319 buffer_consume(&buf, 4);
320
321 DEBUG_TRACE("parsing MPC SV8 header\n");
322 ret = _mpc_read_header_sv8(si);
323 }
324 else {
325 PerlIO_printf(PerlIO_stderr(), "Not a Musepack SV7 or SV8 file: %s\n", file);
326 goto out;
327 }
328
329 // estimation, exact value needs too much time
330 if ( !si->pcm_samples )
331 si->pcm_samples = 1152 * si->frames - 576;
332
333 if (ret == 0) {
334 double total_seconds = (double)( (si->pcm_samples * 1.0) / si->sample_freq);
335
336 my_hv_store(info, "stream_version", newSVuv(si->stream_version));
337 my_hv_store(info, "samplerate", newSViv(si->sample_freq));
338 my_hv_store(info, "channels", newSViv(si->channels));
339 my_hv_store(info, "song_length_ms", newSVuv(total_seconds * 1000));
340 my_hv_store(info, "bitrate", newSVuv(8 * (double)(si->total_file_length - si->tag_offset) / total_seconds));
341
342 my_hv_store(info, "audio_offset", newSVuv(si->tag_offset));
343 my_hv_store(info, "audio_size", newSVuv(si->total_file_length - si->tag_offset));
344 my_hv_store(info, "file_size", newSVuv(si->total_file_length));
345 my_hv_store(info, "encoder", newSVpv(si->encoder, 0));
346
347 if (si->profile_name)
348 my_hv_store(info, "profile", newSVpv(si->profile_name, 0));
349
350 my_hv_store(info, "gapless", newSViv(si->is_true_gapless));
351 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 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 Safefree(si);
357 buffer_free(&buf);
358
359 return ret;
360 }
361