Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 2 | * __________ __ ___. |
| 3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ |
| 4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / |
| 5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < |
| 6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ |
| 7 | * \/ \/ \/ \/ \/ |
| 8 | * $Id$ |
| 9 | * |
Thom Johansen | 1a24595 | 2007-08-24 11:11:06 +0000 | [diff] [blame] | 10 | * Copyright (C) 2005 Thom Johansen |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 11 | * |
Daniel Stenberg | 2acc0ac | 2008-06-28 18:10:04 +0000 | [diff] [blame^] | 12 | * This program is free software; you can redistribute it and/or |
| 13 | * modify it under the terms of the GNU General Public License |
| 14 | * as published by the Free Software Foundation; either version 2 |
| 15 | * of the License, or (at your option) any later version. |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 16 | * |
| 17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 18 | * KIND, either express or implied. |
| 19 | * |
| 20 | ****************************************************************************/ |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 21 | |
Thom Johansen | 5915736 | 2007-12-04 20:48:40 +0000 | [diff] [blame] | 22 | #include <string.h> |
| 23 | #include <inttypes.h> |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 24 | #include "system.h" |
| 25 | #include "id3.h" |
| 26 | #include "metadata_common.h" |
Bertrik Sikken | 1273f95 | 2008-05-03 07:03:59 +0000 | [diff] [blame] | 27 | #include "metadata_parsers.h" |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 28 | #include "logf.h" |
| 29 | #include "replaygain.h" |
| 30 | |
Magnus Holmgren | aee243e | 2007-12-01 11:55:19 +0000 | [diff] [blame] | 31 | static int set_replaygain(struct mp3entry* id3, bool album, long value, |
| 32 | long used) |
| 33 | { |
| 34 | long gain = (int16_t) ((value >> 16) & 0xffff); |
| 35 | long peak = (uint16_t) (value & 0xffff); |
| 36 | |
| 37 | /* We use a peak value of 0 to indicate a given gain type isn't used. */ |
| 38 | if (peak != 0) |
| 39 | { |
| 40 | /* 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 |
| 42 | * other way. |
| 43 | */ |
| 44 | used += parse_replaygain_int(album, gain * 512 / 100, peak << 9, |
| 45 | id3, id3->toc + used, sizeof(id3->toc) - used); |
| 46 | } |
| 47 | |
| 48 | return used; |
| 49 | } |
| 50 | |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 51 | bool get_musepack_metadata(int fd, struct mp3entry *id3) |
| 52 | { |
| 53 | const int32_t sfreqs_sv7[4] = { 44100, 48000, 37800, 32000 }; |
| 54 | uint32_t header[8]; |
| 55 | uint64_t samples = 0; |
| 56 | int i; |
| 57 | |
| 58 | if (!skip_id3v2(fd, id3)) |
| 59 | return false; |
| 60 | if (read(fd, header, 4*8) != 4*8) return false; |
| 61 | /* Musepack files are little endian, might need swapping */ |
| 62 | for (i = 1; i < 8; i++) |
| 63 | header[i] = letoh32(header[i]); |
| 64 | if (!memcmp(header, "MP+", 3)) { /* Compare to sig "MP+" */ |
| 65 | unsigned int streamversion; |
| 66 | |
| 67 | header[0] = letoh32(header[0]); |
| 68 | streamversion = (header[0] >> 24) & 15; |
| 69 | if (streamversion >= 8) { |
| 70 | return false; /* SV8 or higher don't exist yet, so no support */ |
| 71 | } else if (streamversion == 7) { |
| 72 | unsigned int gapless = (header[5] >> 31) & 0x0001; |
| 73 | unsigned int last_frame_samples = (header[5] >> 20) & 0x07ff; |
Thom Johansen | 655fa16 | 2007-11-30 01:10:28 +0000 | [diff] [blame] | 74 | unsigned int bufused = 0; |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 75 | |
| 76 | id3->frequency = sfreqs_sv7[(header[2] >> 16) & 0x0003]; |
| 77 | samples = (uint64_t)header[1]*1152; /* 1152 is mpc frame size */ |
| 78 | if (gapless) |
| 79 | samples -= 1152 - last_frame_samples; |
| 80 | else |
| 81 | samples -= 481; /* Musepack subband synth filter delay */ |
| 82 | |
Magnus Holmgren | aee243e | 2007-12-01 11:55:19 +0000 | [diff] [blame] | 83 | bufused = set_replaygain(id3, false, header[3], bufused); |
| 84 | bufused = set_replaygain(id3, true, header[4], bufused); |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 85 | } |
| 86 | } else { |
Andree Buschmann | e1e0bc2 | 2008-05-22 10:08:24 +0000 | [diff] [blame] | 87 | return false; /* SV4-6 is not supported anymore */ |
Marcoen Hirschberg | 2175d1e | 2007-06-16 18:19:51 +0000 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | id3->vbr = true; |
| 91 | /* Estimate bitrate, we should probably subtract the various header sizes |
| 92 | here for super-accurate results */ |
| 93 | id3->length = ((int64_t) samples * 1000) / id3->frequency; |
| 94 | |
| 95 | if (id3->length <= 0) |
| 96 | { |
| 97 | logf("mpc length invalid!"); |
| 98 | return false; |
| 99 | } |
| 100 | |
| 101 | id3->filesize = filesize(fd); |
| 102 | id3->bitrate = id3->filesize * 8 / id3->length; |
| 103 | return true; |
| 104 | } |