/******************************************************************** * * Copyright (c) 2002 Artur Polaczynski (Ar't) All rights reserved. * 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 #include #include #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; }