diff options
Diffstat (limited to 'src/libapetag/info_mac.c')
-rwxr-xr-x | src/libapetag/info_mac.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/libapetag/info_mac.c b/src/libapetag/info_mac.c new file mode 100755 index 0000000..1b8b5e2 --- /dev/null +++ b/src/libapetag/info_mac.c @@ -0,0 +1,151 @@ +/******************************************************************** +* +* Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved. +* <artii@o2.pl> LGPL-2.1 +* $ArtId: info_mac.c,v 1.15 2003/04/13 11:24:10 art Exp $ +********************************************************************/ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "info_mac.h" +#include "is_tag.h" + +#define MAC_FORMAT_FLAG_8_BIT 1 // 8-bit wave +#define MAC_FORMAT_FLAG_CRC 2 // new CRC32 error detection +#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // u-long Peak_Level after the header +#define MAC_FORMAT_FLAG_24_BIT 8 // 24-bit wave +#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // number of seek elements after the peak level +#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // wave header not stored + +struct macHeader { + char id[4]; // should equal 'MAC ' + unsigned short ver; // version number * 1000 (3.81 = 3810) + unsigned short compLevel; // the compression level + unsigned short formatFlags; // any format flags (for future use) + unsigned short channels; // the number of channels (1 or 2) + unsigned long sampleRate; // the sample rate (typically 44100) + unsigned long headerBytesWAV; // the bytes after the MAC header that compose the WAV header + unsigned long terminatingBytesWAV; // the bytes after that raw data (for extended info) + unsigned long totalFrames; // the number of frames in the file + unsigned long finalFrameBlocks; // the number of samples in the final frame + unsigned long peakLevel; + unsigned short seekElements; +}; + + +// local prototypes +static int +monkey_samples_per_frame(unsigned int versionid, unsigned int compressionlevel); +static const char * +monkey_stringify(unsigned int profile); + +static const char * +monkey_stringify(unsigned int profile) +{ + static const char na[] = "unknown"; + static const char *Names[] = { + na, "Fast", "Normal", "High", "Extra-High", "Insane" + }; + unsigned int profile2 = profile/1000; + + return (profile2 >= sizeof (Names) / sizeof (*Names)) ? na : Names[(profile2)]; +} + + +static int +monkey_samples_per_frame(unsigned int versionid, unsigned int compressionlevel) +{ + if (versionid >= 3950) { + return 294912; // 73728 * 4 + } else if (versionid >= 3900) { + return 73728; + } else if ((versionid >= 3800) && (compressionlevel == COMPRESSION_LEVEL_EXTRA_HIGH)) { + return 73728; + } else { + return 9216; + } +} + +/* + return 0; Info has all info + return 1; File not found + return 2; no MAC file +*/ +int +info_mac_read(const char *fn, StreamInfoMac * Info) +{ + unsigned int HeaderData[32]; + FILE *tmpFile = NULL; + long SkipSizeID3; + struct macHeader * header; + + // load file + tmpFile = fopen(fn, "rb"); + + if (tmpFile == NULL) + return 1; // file not found or read-protected + + // skip id3v2 + SkipSizeID3 = is_id3v2(tmpFile); + fseek(tmpFile, SkipSizeID3, SEEK_SET); + fread((void *) HeaderData, sizeof (int), 16, tmpFile); + fseek(tmpFile, 0, SEEK_END); + Info->FileSize = ftell(tmpFile); + fclose(tmpFile); + + if (0 != memcmp(HeaderData, "MAC", 3)) + return 2; // no monkeyAudio file + + header= (struct macHeader *) HeaderData; + + Info->Version = Info->EncoderVersion = header->ver; + Info->Channels = header->channels; + Info->SampleFreq = header->sampleRate; + Info->Flags = header->formatFlags; + Info->SamplesPerFrame = monkey_samples_per_frame(header->ver, header->compLevel); + Info->BitsPerSample = (header->formatFlags & MAC_FORMAT_FLAG_8_BIT) + ? 8 : ((header->formatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16); + + Info->PeakLevel = header->peakLevel; +// Info->PeakRatio = Info->PakLevel / pow(2, Info->bitsPerSample - 1); + Info->Frames = header->totalFrames; + Info->Samples = (Info->Frames - 1) * Info->SamplesPerFrame + + header->finalFrameBlocks; + + Info->Duration = Info->SampleFreq > 0 ? + ((float)Info->Samples / Info->SampleFreq)*1000 : 0; + + Info->Compresion = header->compLevel; + Info->CompresionName = monkey_stringify(Info->Compresion); + + Info->UncompresedSize = Info->Samples * Info->Channels * + (Info->BitsPerSample / 8); + + Info->CompresionRatio = + (Info->UncompresedSize + header->headerBytesWAV) > 0 ? + Info->FileSize / (float) (Info->UncompresedSize + + header->headerBytesWAV) : 0. ; + + Info->Bitrate = Info->Duration > 0 ? (((Info->Samples * + Info->Channels * Info->BitsPerSample) / (float) Info->Duration) * + Info->CompresionRatio) * 1000 : 0; + + Info->PeakRatio=Info->ByteLength=0; + return 0; +} |