PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/metadata/mpc.c

https://github.com/claymodel/rockbox
C | 220 lines | 132 code | 36 blank | 52 comment | 28 complexity | a1a1a406084019dd7854ed65a1828bd5 MD5 | raw file
  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. #include <string.h>
  23. #include <stdio.h>
  24. #include <inttypes.h>
  25. #include "system.h"
  26. #include "metadata.h"
  27. #include "metadata_common.h"
  28. #include "metadata_parsers.h"
  29. #include "logf.h"
  30. #include "replaygain.h"
  31. #include "fixedpoint.h"
  32. /* Needed for replay gain and clipping prevention of SV8 files. */
  33. #define SV8_TO_SV7_CONVERT_GAIN (6482) /* 64.82 * 100, MPC_OLD_GAIN_REF */
  34. #define SV8_TO_SV7_CONVERT_PEAK (23119) /* 256 * 20 * log10(32768) */
  35. static int set_replaygain_sv7(struct mp3entry* id3,
  36. bool album,
  37. long value,
  38. long used)
  39. {
  40. long gain = (int16_t) ((value >> 16) & 0xffff);
  41. long peak = (uint16_t) (value & 0xffff);
  42. /* We use a peak value of 0 to indicate a given gain type isn't used. */
  43. if (peak != 0) {
  44. /* Save the ReplayGain data to id3-structure for further processing. */
  45. parse_replaygain_int(album, gain * 512 / 100, peak << 9, id3);
  46. }
  47. return used;
  48. }
  49. static int set_replaygain_sv8(struct mp3entry* id3,
  50. bool album,
  51. long gain,
  52. long peak,
  53. long used)
  54. {
  55. gain = (long)(SV8_TO_SV7_CONVERT_GAIN - ((gain*100)/256));
  56. /* Transform SV8's logarithmic peak representation to the desired linear
  57. * representation: linear = pow(10, peak/256/20).
  58. *
  59. * FP_BITS = 24 bits = desired fp representation for dsp routines
  60. * FRAC_BITS = 12 bits = resolution used for fp_bits
  61. * fp_factor(peak*(1<<FRAC_BITS)/256, FRAC_BITS) << (FP_BITS-FRAC_BITS)
  62. **/
  63. peak = (fp_factor((peak-SV8_TO_SV7_CONVERT_PEAK)*16, 12) << 12);
  64. /* We use a peak value of 0 to indicate a given gain type isn't used. */
  65. if (peak != 0) {
  66. /* Save the ReplayGain data to id3-structure for further processing. */
  67. parse_replaygain_int(album, gain * 512 / 100, peak, id3);
  68. }
  69. return used;
  70. }
  71. static int sv8_get_size(uint8_t *buffer, int index, uint64_t *p_size)
  72. {
  73. unsigned char tmp;
  74. uint64_t size = 0;
  75. do {
  76. tmp = buffer[index++];
  77. size = (size << 7) | (tmp & 0x7F);
  78. } while((tmp & 0x80));
  79. *p_size = size;
  80. return index;
  81. }
  82. bool get_musepack_metadata(int fd, struct mp3entry *id3)
  83. {
  84. static const int32_t sfreqs[4] = { 44100, 48000, 37800, 32000 };
  85. uint32_t header[8];
  86. uint64_t samples = 0;
  87. int i;
  88. if (!skip_id3v2(fd, id3))
  89. return false;
  90. if (read(fd, header, 4*8) != 4*8) return false;
  91. /* Musepack files are little endian, might need swapping */
  92. for (i = 1; i < 8; i++)
  93. header[i] = letoh32(header[i]);
  94. if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */
  95. unsigned int streamversion;
  96. header[0] = letoh32(header[0]);
  97. streamversion = (header[0] >> 24) & 15;
  98. if (streamversion == 7) {
  99. unsigned int gapless = (header[5] >> 31) & 0x0001;
  100. unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff;
  101. unsigned int bufused = 0;
  102. id3->frequency = sfreqs[(header[2] >> 16) & 0x0003];
  103. samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */
  104. if (gapless)
  105. samples -= 1152 - last_frame_samples;
  106. else
  107. samples -= 481; /* Musepack subband synth filter delay */
  108. bufused = set_replaygain_sv7(id3, false, header[3], bufused);
  109. bufused = set_replaygain_sv7(id3, true , header[4], bufused);
  110. id3->codectype = AFMT_MPC_SV7;
  111. } else {
  112. return false; /* only SV7 is allowed within a "MP+" signature */
  113. }
  114. } else if (!memcmp(header, "MPCK", 4)) { /* Compare to sig "MPCK" */
  115. uint8_t sv8_header[32];
  116. /* 4 bytes 'MPCK' */
  117. lseek(fd, 4, SEEK_SET);
  118. if (read(fd, sv8_header, 2) != 2) return false; /* read frame ID */
  119. if (!memcmp(sv8_header, "SH", 2)) { /* Stream Header ID */
  120. int32_t k = 0;
  121. uint32_t streamversion;
  122. uint64_t size = 0; /* tag size */
  123. uint64_t dummy = 0; /* used to dummy read data from header */
  124. /* 4 bytes 'MPCK' + 2 'SH' */
  125. lseek(fd, 6, SEEK_SET);
  126. if (read(fd, sv8_header, 32) != 32) return false;
  127. /* Read the size of 'SH'-tag */
  128. k = sv8_get_size(sv8_header, k, &size);
  129. /* Skip crc32 */
  130. k += 4;
  131. /* Read stream version */
  132. streamversion = sv8_header[k++];
  133. if (streamversion != 8) return false; /* Only SV8 is allowed. */
  134. /* Number of samples */
  135. k = sv8_get_size(sv8_header, k, &samples);
  136. /* Number of leading zero-samples */
  137. k = sv8_get_size(sv8_header, k, &dummy);
  138. /* Sampling frequency */
  139. id3->frequency = sfreqs[(sv8_header[k++] >> 5) & 0x0003];
  140. /* Number of channels */
  141. id3->channels = (sv8_header[k++] >> 4) + 1;
  142. /* Skip to next tag: k = size -2 */
  143. k = size - 2;
  144. if (!memcmp(sv8_header+k, "RG", 2)) { /* Replay Gain ID */
  145. long peak, gain;
  146. int bufused = 0;
  147. k += 2; /* 2 bytes 'RG' */
  148. /* sv8_get_size must be called to skip the right amount of
  149. * bits within the header data. */
  150. k = sv8_get_size(sv8_header, k, &size);
  151. /* Read and set replay gain */
  152. if (sv8_header[k++] == 1) {
  153. /* Title's peak and gain */
  154. gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
  155. peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
  156. bufused += set_replaygain_sv8(id3, false, gain, peak, bufused);
  157. /* Album's peak and gain */
  158. gain = (int16_t) ((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
  159. peak = (uint16_t)((sv8_header[k]<<8) + sv8_header[k+1]); k += 2;
  160. bufused += set_replaygain_sv8(id3, true , gain, peak, bufused);
  161. }
  162. }
  163. id3->codectype = AFMT_MPC_SV8;
  164. } else {
  165. /* No sv8 stream header found */
  166. return false;
  167. }
  168. } else {
  169. return false; /* SV4-6 is not supported anymore */
  170. }
  171. id3->vbr = true;
  172. /* Estimate bitrate, we should probably subtract the various header sizes
  173. here for super-accurate results */
  174. id3->length = ((int64_t) samples * 1000) / id3->frequency;
  175. if (id3->length <= 0)
  176. {
  177. logf("mpc length invalid!");
  178. return false;
  179. }
  180. id3->filesize = filesize(fd);
  181. id3->bitrate = id3->filesize * 8 / id3->length;
  182. read_ape_tags(fd, id3);
  183. return true;
  184. }