2 Copyright (c) 2005, The Musepack Development Team
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
17 * Neither the name of the The Musepack Development Team nor the
18 names of its contributors may be used to endorse or promote
19 products derived from this software without specific prior
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /// \file streaminfo.c
36 /// Implementation of streaminfo reading functions.
42 Stringify(mpc_uint32_t profile
) // profile is 0...15, where 7...13 is used
44 static const char na
[] = "n.a.";
45 static const char *Names
[] = {
46 na
, "'Unstable/Experimental'", na
, na
,
47 na
, "'quality 0'", "'quality 1'", "'Telephone'",
48 "'Thumb'", "'Radio'", "'Standard'", "'Xtreme'",
49 "'Insane'", "'BrainDead'", "'quality 9'", "'quality 10'"
52 return profile
>= sizeof(Names
) / sizeof(*Names
) ? na
: Names
[profile
];
56 mpc_streaminfo_init(mpc_streaminfo
* si
)
58 memset(si
, 0, sizeof(mpc_streaminfo
));
61 /// Reads streaminfo from SV7 header.
63 streaminfo_read_header_sv7(mpc_streaminfo
* si
, mpc_uint32_t HeaderData
[8])
65 const mpc_int32_t samplefreqs
[4] = { 44100, 48000, 37800, 32000 };
67 //mpc_uint32_t HeaderData [8];
68 mpc_uint16_t Estimatedpeak_title
= 0;
70 if (si
->stream_version
> 0x71) {
71 // Update (si->stream_version);
76 if ( !fp->seek ( si->header_position ) ) // seek to header start
77 return ERROR_CODE_FILE;
78 if ( fp->read ( HeaderData, sizeof HeaderData) != sizeof HeaderData )
79 return ERROR_CODE_FILE;
83 si
->frames
= HeaderData
[1];
85 si
->ms
= (HeaderData
[2] >> 30) & 0x0001;
86 si
->max_band
= (HeaderData
[2] >> 24) & 0x003F;
88 si
->profile
= (HeaderData
[2] << 8) >> 28;
89 si
->profile_name
= Stringify(si
->profile
);
90 si
->sample_freq
= samplefreqs
[(HeaderData
[2] >> 16) & 0x0003];
91 Estimatedpeak_title
= (mpc_uint16_t
) (HeaderData
[2] & 0xFFFF); // read the ReplayGain data
92 si
->gain_title
= (mpc_uint16_t
) ((HeaderData
[3] >> 16) & 0xFFFF);
93 si
->peak_title
= (mpc_uint16_t
) (HeaderData
[3] & 0xFFFF);
94 si
->gain_album
= (mpc_uint16_t
) ((HeaderData
[4] >> 16) & 0xFFFF);
95 si
->peak_album
= (mpc_uint16_t
) (HeaderData
[4] & 0xFFFF);
96 si
->is_true_gapless
= (HeaderData
[5] >> 31) & 0x0001; // true gapless: used?
97 si
->last_frame_samples
= (HeaderData
[5] >> 20) & 0x07FF; // true gapless: valid samples for last frame
98 si
->encoder_version
= (HeaderData
[6] >> 24) & 0x00FF;
100 if (si
->encoder_version
== 0) {
101 //sprintf(si->encoder, "Buschmann 1.7.0...9, Klemm 0.90...1.05");
104 switch (si
->encoder_version
% 10) {
106 //sprintf(si->encoder, "Release %u.%u", si->encoder_version / 100,
107 // si->encoder_version / 10 % 10);
113 //sprintf(si->encoder, "Beta %u.%02u", si->encoder_version / 100,
114 // si->encoder_version % 100);
117 //sprintf(si->encoder, "--Alpha-- %u.%02u",
118 // si->encoder_version / 100, si->encoder_version % 100);
123 // if ( si->peak_title == 0 ) // there is no correct peak_title contained within header
124 // si->peak_title = (mpc_uint16_t)(Estimatedpeak_title * 1.18);
125 // if ( si->peak_album == 0 )
126 // si->peak_album = si->peak_title; // no correct peak_album, use peak_title
128 //si->sample_freq = 44100; // AB: used by all files up to SV7
131 return ERROR_CODE_OK
;
134 // read information from SV4-SV6 header
135 #ifdef MPC_SUPPORT_SV456
137 streaminfo_read_header_sv6(mpc_streaminfo
* si
, mpc_uint32_t HeaderData
[8])
139 //mpc_uint32_t HeaderData [8];
142 if ( !fp->seek ( si->header_position ) ) // seek to header start
143 return ERROR_CODE_FILE;
144 if ( fp->read ( HeaderData, sizeof HeaderData ) != sizeof HeaderData )
145 return ERROR_CODE_FILE;
148 si
->bitrate
= (HeaderData
[0] >> 23) & 0x01FF; // read the file-header (SV6 and below)
149 si
->is
= (HeaderData
[0] >> 22) & 0x0001;
150 si
->ms
= (HeaderData
[0] >> 21) & 0x0001;
151 si
->stream_version
= (HeaderData
[0] >> 11) & 0x03FF;
152 si
->max_band
= (HeaderData
[0] >> 6) & 0x001F;
153 si
->block_size
= (HeaderData
[0]) & 0x003F;
155 si
->profile_name
= Stringify((mpc_uint32_t
) (-1));
156 if (si
->stream_version
>= 5)
157 si
->frames
= HeaderData
[1]; // 32 bit
159 si
->frames
= (HeaderData
[1] >> 16); // 16 bit
161 si
->gain_title
= 0; // not supported
166 si
->last_frame_samples
= 0;
167 si
->is_true_gapless
= 0;
169 si
->encoder_version
= 0;
170 si
->encoder
[0] = '\0';
172 if (si
->stream_version
== 7)
173 return ERROR_CODE_SV7BETA
; // are there any unsupported parameters used?
174 if (si
->bitrate
!= 0)
175 return ERROR_CODE_CBR
;
177 return ERROR_CODE_IS
;
178 if (si
->block_size
!= 1)
179 return ERROR_CODE_BLOCKSIZE
;
181 if (si
->stream_version
< 6) // Bugfix: last frame was invalid for up to SV5
184 si
->sample_freq
= 44100; // AB: used by all files up to SV7
187 if (si
->stream_version
< 4 || si
->stream_version
> 7)
188 return ERROR_CODE_INVALIDSV
;
190 return ERROR_CODE_OK
;
193 // reads file header and tags
195 mpc_streaminfo_read(mpc_streaminfo
* si
, mpc_reader
* r
)
197 mpc_uint32_t HeaderData
[8];
198 mpc_int32_t Error
= 0;
200 // get header position
201 if ((si
->header_position
= JumpID3v2(r
)) < 0) {
202 return ERROR_CODE_FILE
;
204 // seek to first byte of mpc data
205 if (!r
->seek(r
->data
, si
->header_position
)) {
206 return ERROR_CODE_FILE
;
208 if (r
->read(r
->data
, HeaderData
, 8 * 4) != 8 * 4) {
209 return ERROR_CODE_FILE
;
211 if (!r
->seek(r
->data
, si
->header_position
+ 6 * 4)) {
212 return ERROR_CODE_FILE
;
215 si
->total_file_length
= r
->get_size(r
->data
);
216 si
->tag_offset
= si
->total_file_length
;
217 if (memcmp(HeaderData
, "MP+", 3) == 0) {
218 #ifndef MPC_LITTLE_ENDIAN
220 for (ptr
= 0; ptr
< 8; ptr
++) {
221 HeaderData
[ptr
] = mpc_swap32(HeaderData
[ptr
]);
224 si
->stream_version
= HeaderData
[0] >> 24;
227 if ((si
->stream_version
& 15) >= 8) {
228 return ERROR_CODE_INVALIDSV
;
231 else if ((si
->stream_version
& 15) == 7) {
232 Error
= streaminfo_read_header_sv7(si
, HeaderData
);
233 if (Error
!= ERROR_CODE_OK
) return Error
;
236 #ifdef MPC_SUPPORT_SV456
237 #ifndef MPC_LITTLE_ENDIAN
239 for (ptr
= 0; ptr
< 8; ptr
++) {
240 HeaderData
[ptr
] = mpc_swap32(HeaderData
[ptr
]);
243 // stream version 4-6
244 Error
= streaminfo_read_header_sv6(si
, HeaderData
);
245 if (Error
!= ERROR_CODE_OK
) return Error
;
247 return ERROR_CODE_INVALIDSV
;
251 // estimation, exact value needs too much time
252 si
->pcm_samples
= 1152 * si
->frames
- 576;
254 if (si
->pcm_samples
> 0) {
255 si
->average_bitrate
=
257 si
->header_position
) * 8.0 * si
->sample_freq
/ si
->pcm_samples
;
260 si
->average_bitrate
= 0;
263 return ERROR_CODE_OK
;
267 mpc_streaminfo_get_length(mpc_streaminfo
* si
)
269 return (double)mpc_streaminfo_get_length_samples(si
) /
270 (double)si
->sample_freq
;
274 mpc_streaminfo_get_length_samples(mpc_streaminfo
* si
)
276 mpc_int64_t samples
= (mpc_int64_t
) si
->frames
* MPC_FRAME_LENGTH
;
277 if (si
->is_true_gapless
) {
278 samples
-= (MPC_FRAME_LENGTH
- si
->last_frame_samples
);
281 samples
-= MPC_DECODER_SYNTH_DELAY
;