diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-24 01:25:21 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-03-18 12:00:39 +0100 |
commit | b5716df4cb2837bbbc42195cf1aefcf03e21d6a6 (patch) | |
tree | 130cd712e2e00893b6df9959a375a8d9523a1aca /apps/metadata/mpc.c | |
parent | 24bd9d5393dbe39a5c6194877bc00ede669b1d5d (diff) | |
download | rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.tar.gz rockbox-b5716df4cb2837bbbc42195cf1aefcf03e21d6a6.zip |
Build librbcodec with DSP and metadata.
All associated files are moved to /lib/rbcodec.
Change-Id: I572ddd2b8a996aae1e98c081d06b1ed356dce222
Diffstat (limited to 'apps/metadata/mpc.c')
-rw-r--r-- | apps/metadata/mpc.c | 220 |
1 files changed, 0 insertions, 220 deletions
diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c deleted file mode 100644 index 0b75ed04dd..0000000000 --- a/apps/metadata/mpc.c +++ /dev/null | |||
@@ -1,220 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Thom Johansen | ||
11 | * Copyright (C) 2010 Andree Buschmann | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | |||
23 | #include <string.h> | ||
24 | #include <stdio.h> | ||
25 | #include <inttypes.h> | ||
26 | #include "system.h" | ||
27 | #include "metadata.h" | ||
28 | #include "metadata_common.h" | ||
29 | #include "metadata_parsers.h" | ||
30 | #include "logf.h" | ||
31 | #include "replaygain.h" | ||
32 | #include "fixedpoint.h" | ||
33 | |||
34 | /* Needed for replay gain and clipping prevention of SV8 files. */ | ||
35 | #define SV8_TO_SV7_CONVERT_GAIN (6482) /* 64.82 * 100, MPC_OLD_GAIN_REF */ | ||
36 | #define SV8_TO_SV7_CONVERT_PEAK (23119) /* 256 * 20 * log10(32768) */ | ||
37 | |||
38 | static int set_replaygain_sv7(struct mp3entry* id3, | ||
39 | bool album, | ||
40 | long value, | ||
41 | long used) | ||
42 | { | ||
43 | long gain = (int16_t) ((value >> 16) & 0xffff); | ||
44 | long peak = (uint16_t) (value & 0xffff); | ||
45 | |||
46 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ | ||
47 | if (peak != 0) { | ||
48 | /* Save the ReplayGain data to id3-structure for further processing. */ | ||
49 | parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3); | ||
50 | } | ||
51 | |||
52 | return used; | ||
53 | } | ||
54 | |||
55 | static int set_replaygain_sv8(struct mp3entry* id3, | ||
56 | bool album, | ||
57 | long gain, | ||
58 | long peak, | ||
59 | long used) | ||
60 | { | ||
61 | gain = (long)(SV8_TO_SV7_CONVERT_GAIN - ((gain*100)/256)); | ||
62 | |||
63 | /* Transform SV8's logarithmic peak representation to the desired linear | ||
64 | * representation: linear = pow(10, peak/256/20). | ||
65 | * | ||
66 | * FP_BITS = 24 bits = desired fp representation for dsp routines | ||
67 | * FRAC_BITS = 12 bits = resolution used for fp_bits | ||
68 | * fp_factor(peak*(1<<FRAC_BITS)/256, FRAC_BITS) << (FP_BITS-FRAC_BITS) | ||
69 | **/ | ||
70 | peak = (fp_factor((peak-SV8_TO_SV7_CONVERT_PEAK)*16, 12) << 12); | ||
71 | |||
72 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ | ||
73 | if (peak != 0) { | ||
74 | /* Save the ReplayGain data to id3-structure for further processing. */ | ||
75 | parse_replaygain_int(album, gain * 512 / 100, peak, id3); | ||
76 | } | ||
77 | |||
78 | return used; | ||
79 | } | ||
80 | |||
81 | static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size) | ||
82 | { | ||
83 | unsigned char tmp; | ||
84 | uint64_t size = 0; | ||
85 | |||
86 | do { | ||
87 | tmp = buffer[index++]; | ||
88 | size = (size << 7) | (tmp & 0x7F); | ||
89 | } while((tmp & 0x80)); | ||
90 | |||
91 | *p_size = size; | ||
92 | return index; | ||
93 | } | ||
94 | |||
95 | bool get_musepack_metadata(int fd, struct mp3entry *id3) | ||
96 | { | ||
97 | static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 }; | ||
98 | uint32_t header[8]; | ||
99 | uint64_t samples = 0; | ||
100 | int i; | ||
101 | |||
102 | if (!skip_id3v2(fd, id3)) | ||
103 | return false; | ||
104 | if (read(fd, header, 4*8) != 4*8) return false; | ||
105 | /* Musepack files are little endian, might need swapping */ | ||
106 | for (i = 1; i < 8; i++) | ||
107 | header[i] = letoh32(header[i]); | ||
108 | if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */ | ||
109 | unsigned int streamversion; | ||
110 | header[0] = letoh32(header[0]); | ||
111 | streamversion = (header[0] >> 24) & 15; | ||
112 | if (streamversion == 7) { | ||
113 | unsigned int gapless = (header[5] >> 31) & 0x0001; | ||
114 | unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff; | ||
115 | unsigned int bufused = 0; | ||
116 | |||
117 | id3->frequency = sfreqs[(header[2] >> 16) & 0x0003]; | ||
118 | samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */ | ||
119 | if (gapless) | ||
120 | samples -= 1152 - last_frame_samples; | ||
121 | else | ||
122 | samples -= 481; /* Musepack subband synth filter delay */ | ||
123 | |||
124 | bufused = set_replaygain_sv7(id3, false, header[3], bufused); | ||
125 | bufused = set_replaygain_sv7(id3, true , header[4], bufused); | ||
126 | |||
127 | id3->codectype = AFMT_MPC_SV7; | ||
128 | } else { | ||
129 | return false; /* only SV7 is allowed within a "MP+" signature */ | ||
130 | } | ||
131 | } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */ | ||
132 | uint8_t sv8_header[32]; | ||
133 | /* 4 bytes 'MPCK' */ | ||
134 | lseek(fd, 4, SEEK_SET); | ||
135 | if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */ | ||
136 | if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */ | ||
137 | int32_t k = 0; | ||
138 | uint32_t streamversion; | ||
139 | uint64_t size = 0; /* tag size */ | ||
140 | uint64_t dummy = 0; /* used to dummy read data from header */ | ||
141 | |||
142 | /* 4 bytes 'MPCK' + 2 'SH' */ | ||
143 | lseek(fd, 6, SEEK_SET); | ||
144 | if (read(fd, sv8_header, 32) != 32) return false; | ||
145 | |||
146 | /* Read the size of 'SH'-tag */ | ||
147 | k = sv8_get_size(sv8_header, k, &size); | ||
148 | |||
149 | /* Skip crc32 */ | ||
150 | k += 4; | ||
151 | |||
152 | /* Read stream version */ | ||
153 | streamversion = sv8_header[k++]; | ||
154 | if (streamversion != 8) return false; /* Only SV8 is allowed. */ | ||
155 | |||
156 | /* Number of samples */ | ||
157 | k = sv8_get_size(sv8_header, k, &samples); | ||
158 | |||
159 | /* Number of leading zero-samples */ | ||
160 | k = sv8_get_size(sv8_header, k, &dummy); | ||
161 | |||
162 | /* Sampling frequency */ | ||
163 | id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003]; | ||
164 | |||
165 | /* Number of channels */ | ||
166 | id3->channels = (sv8_header[k++] >> 4) + 1; | ||
167 | |||
168 | /* Skip to next tag: k = size -2 */ | ||
169 | k = size - 2; | ||
170 | |||
171 | if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */ | ||
172 | long peak, gain; | ||
173 | int bufused = 0; | ||
174 | |||
175 | k += 2; /* 2 bytes 'RG' */ | ||
176 | |||
177 | /* sv8_get_size must be called to skip the right amount of | ||
178 | * bits within the header data. */ | ||
179 | k = sv8_get_size(sv8_header, k, &size); | ||
180 | |||
181 | /* Read and set replay gain */ | ||
182 | if (sv8_header[k++] == 1) { | ||
183 | /* Title's peak and gain */ | ||
184 | gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
185 | peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
186 | bufused += set_replaygain_sv8(id3, false, gain, peak, bufused); | ||
187 | |||
188 | /* Album's peak and gain */ | ||
189 | gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
190 | peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
191 | bufused += set_replaygain_sv8(id3, true , gain, peak, bufused); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | id3->codectype = AFMT_MPC_SV8; | ||
196 | } else { | ||
197 | /* No sv8 stream header found */ | ||
198 | return false; | ||
199 | } | ||
200 | } else { | ||
201 | return false; /* SV4-6 is not supported anymore */ | ||
202 | } | ||
203 | |||
204 | id3->vbr = true; | ||
205 | /* Estimate bitrate, we should probably subtract the various header sizes | ||
206 | here for super-accurate results */ | ||
207 | id3->length = ((int64_t) samples * 1000) / id3->frequency; | ||
208 | |||
209 | if (id3->length <= 0) | ||
210 | { | ||
211 | logf("mpc length invalid!"); | ||
212 | return false; | ||
213 | } | ||
214 | |||
215 | id3->filesize = filesize(fd); | ||
216 | id3->bitrate = id3->filesize * 8 / id3->length; | ||
217 | |||
218 | read_ape_tags(fd, id3); | ||
219 | return true; | ||
220 | } | ||