diff options
Diffstat (limited to 'apps/metadata/mpc.c')
-rw-r--r-- | apps/metadata/mpc.c | 126 |
1 files changed, 115 insertions, 11 deletions
diff --git a/apps/metadata/mpc.c b/apps/metadata/mpc.c index 3f8907a934..9894bb8b54 100644 --- a/apps/metadata/mpc.c +++ b/apps/metadata/mpc.c | |||
@@ -28,15 +28,48 @@ | |||
28 | #include "logf.h" | 28 | #include "logf.h" |
29 | #include "replaygain.h" | 29 | #include "replaygain.h" |
30 | 30 | ||
31 | static int set_replaygain(struct mp3entry* id3, bool album, long value, | 31 | #include "fixedpoint.h" |
32 | long used) | 32 | #include <stdlib.h> |
33 | #include <stdbool.h> | ||
34 | #include <inttypes.h> | ||
35 | |||
36 | /* Needed for replay gain in sv8, please search MPC_OLD_GAIN_REF in libmusepack */ | ||
37 | #define SV8_TO_SV7_CONVERT_GAIN (64.82*100) | ||
38 | |||
39 | static int set_replaygain_sv7(struct mp3entry* id3, | ||
40 | bool album, | ||
41 | long value, | ||
42 | long used) | ||
33 | { | 43 | { |
34 | long gain = (int16_t) ((value >> 16) & 0xffff); | 44 | long gain = (int16_t) ((value >> 16) & 0xffff); |
35 | long peak = (uint16_t) (value & 0xffff); | 45 | long peak = (uint16_t) (value & 0xffff); |
36 | 46 | ||
47 | /* Remark: mpc sv7 outputs peak as amplitude, not as dB. The following | ||
48 | * useage of peak is not correct and needs to be fixed. */ | ||
49 | |||
37 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ | 50 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ |
38 | if (peak != 0) | 51 | if (peak != 0) { |
39 | { | 52 | /* Use the Xing TOC field to store ReplayGain strings for use in the |
53 | * ID3 screen, since Musepack files shouldn't need to use it in any | ||
54 | * other way. | ||
55 | */ | ||
56 | used += parse_replaygain_int(album, gain * 512 / 100, peak << 9, | ||
57 | id3, id3->toc + used, sizeof(id3->toc) - used); | ||
58 | } | ||
59 | |||
60 | return used; | ||
61 | } | ||
62 | |||
63 | static int set_replaygain_sv8(struct mp3entry* id3, | ||
64 | bool album, | ||
65 | long gain, | ||
66 | long peak, | ||
67 | long used) | ||
68 | { | ||
69 | gain = (long)(SV8_TO_SV7_CONVERT_GAIN - (gain*100./256.)); | ||
70 | |||
71 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ | ||
72 | if (peak != 0) { | ||
40 | /* Use the Xing TOC field to store ReplayGain strings for use in the | 73 | /* Use the Xing TOC field to store ReplayGain strings for use in the |
41 | * ID3 screen, since Musepack files shouldn't need to use it in any | 74 | * ID3 screen, since Musepack files shouldn't need to use it in any |
42 | * other way. | 75 | * other way. |
@@ -48,9 +81,23 @@ static int set_replaygain(struct mp3entry* id3, bool album, long value, | |||
48 | return used; | 81 | return used; |
49 | } | 82 | } |
50 | 83 | ||
84 | static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size) | ||
85 | { | ||
86 | unsigned char tmp; | ||
87 | uint64_t size = 0; | ||
88 | |||
89 | do { | ||
90 | tmp = buffer[index++]; | ||
91 | size = (size << 7) | (tmp & 0x7F); | ||
92 | } while((tmp & 0x80)); | ||
93 | |||
94 | *p_size = size; | ||
95 | return index; | ||
96 | } | ||
97 | |||
51 | bool get_musepack_metadata(int fd, struct mp3entry *id3) | 98 | bool get_musepack_metadata(int fd, struct mp3entry *id3) |
52 | { | 99 | { |
53 | static const int32_t sfreqs_sv7[4] = { 44100, 48000, 37800, 32000 }; | 100 | static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 }; |
54 | uint32_t header[8]; | 101 | uint32_t header[8]; |
55 | uint64_t samples = 0; | 102 | uint64_t samples = 0; |
56 | int i; | 103 | int i; |
@@ -63,7 +110,6 @@ bool get_musepack_metadata(int fd, struct mp3entry *id3) | |||
63 | header[i] = letoh32(header[i]); | 110 | header[i] = letoh32(header[i]); |
64 | if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */ | 111 | if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */ |
65 | unsigned int streamversion; | 112 | unsigned int streamversion; |
66 | |||
67 | header[0] = letoh32(header[0]); | 113 | header[0] = letoh32(header[0]); |
68 | streamversion = (header[0] >> 24) & 15; | 114 | streamversion = (header[0] >> 24) & 15; |
69 | if (streamversion == 7) { | 115 | if (streamversion == 7) { |
@@ -71,20 +117,78 @@ bool get_musepack_metadata(int fd, struct mp3entry *id3) | |||
71 | unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff; | 117 | unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff; |
72 | unsigned int bufused = 0; | 118 | unsigned int bufused = 0; |
73 | 119 | ||
74 | id3->frequency = sfreqs_sv7[(header[2] >> 16) & 0x0003]; | 120 | id3->frequency = sfreqs[(header[2] >> 16) & 0x0003]; |
75 | samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */ | 121 | samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */ |
76 | if (gapless) | 122 | if (gapless) |
77 | samples -= 1152 - last_frame_samples; | 123 | samples -= 1152 - last_frame_samples; |
78 | else | 124 | else |
79 | samples -= 481; /* Musepack subband synth filter delay */ | 125 | samples -= 481; /* Musepack subband synth filter delay */ |
80 | 126 | ||
81 | bufused = set_replaygain(id3, false, header[3], bufused); | 127 | bufused = set_replaygain_sv7(id3, false, header[3], bufused); |
82 | bufused = set_replaygain(id3, true, header[4], bufused); | 128 | bufused = set_replaygain_sv7(id3, true , header[4], bufused); |
83 | } else { | 129 | } else { |
84 | return false; /* only SV7 is allowed within a "MP+" signature */ | 130 | return false; /* only SV7 is allowed within a "MP+" signature */ |
85 | } | 131 | } |
86 | } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */ | 132 | } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */ |
87 | return false; /* SV8 is not supported yet */ | 133 | uint8_t sv8_header[32]; |
134 | /* 4 bytes 'MPCK' */ | ||
135 | lseek(fd, 4, SEEK_SET); | ||
136 | if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */ | ||
137 | if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */ | ||
138 | int32_t k = 0; | ||
139 | uint32_t streamversion; | ||
140 | uint64_t size = 0; | ||
141 | |||
142 | /* 4 bytes 'MPCK' + 4 bytes crc + 2 'SH' */ | ||
143 | lseek(fd, 10, SEEK_SET); | ||
144 | if (read(fd, sv8_header, 32) != 32) return false; | ||
145 | |||
146 | /* dummy read the correct amount of bits within the header data. */ | ||
147 | size = sv8_header[k++]; | ||
148 | |||
149 | /* Read stream version */ | ||
150 | streamversion = sv8_header[k++]; | ||
151 | if (streamversion != 8) return false; /* Only SV8 is allowed. */ | ||
152 | |||
153 | /* Number of samples */ | ||
154 | k = sv8_get_size(sv8_header, k, &samples); | ||
155 | |||
156 | /* Number of leading zero-samples */ | ||
157 | k = sv8_get_size(sv8_header, k, &size); | ||
158 | |||
159 | /* Sampling frequency */ | ||
160 | id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003]; | ||
161 | |||
162 | /* Number of channels */ | ||
163 | id3->channels = (sv8_header[k++] >> 4) + 1; | ||
164 | |||
165 | if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */ | ||
166 | long peak, gain; | ||
167 | int bufused = 0; | ||
168 | |||
169 | k += 2; /* 2 bytes 'RG' */ | ||
170 | |||
171 | /* sv8_get_size must be called to skip the right amount of | ||
172 | * bits within the header data. */ | ||
173 | k = sv8_get_size(sv8_header, k, &size); | ||
174 | |||
175 | /* Read and set replay gain */ | ||
176 | if (sv8_header[k++] == 1) { | ||
177 | /* Title's peak and gain */ | ||
178 | gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
179 | peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
180 | bufused += set_replaygain_sv8(id3, false, gain, peak, bufused); | ||
181 | |||
182 | /* Album's peak and gain */ | ||
183 | gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
184 | peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2; | ||
185 | bufused += set_replaygain_sv8(id3, true , gain, peak, bufused); | ||
186 | } | ||
187 | } | ||
188 | } else { | ||
189 | /* No sv8 stream header found */ | ||
190 | return false; | ||
191 | } | ||
88 | } else { | 192 | } else { |
89 | return false; /* SV4-6 is not supported anymore */ | 193 | return false; /* SV4-6 is not supported anymore */ |
90 | } | 194 | } |