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