/* $Id$ */ /* * Cantus Tag Editor * Copyright © 2002-2004 by Samuel Abels * Copyright © 2007 by Tim Huetz * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see **/ #ifdef HAVE_CONFIG_H # include #endif #include #if defined( __cplusplus ) extern "C" { #endif int get_mpgheader(MpgHeader *header, const char *filename) { /* * 16 possibile bitrates, and: * 2 MPEG Versions * 3 possible layers = 6 columns * Columns are: * 0=Version 1, Layer 1 * 1=Version 1, Layer 2 * 2=Version 1, Layer 3 * 3=Version 2, Layer 1 * 4=Version 2, Layer 2 * 5=Version 2, Layer 3 */ int bitrates[16][6] = { {0, 0, 0, 0, 0, 0}, /* VBR. */ {32, 32, 32, 32, 32, 8}, {64, 48, 40, 64, 48, 16}, {96, 56, 48, 96, 56, 24}, {128, 64, 56, 128, 64, 32}, {160, 80, 64, 160, 80, 64}, {192, 96, 80, 192, 96, 80}, {224, 112, 96, 224, 112, 56}, {256, 128, 112, 256, 128, 64}, {288, 160, 128, 288, 160, 128}, {320, 192, 160, 320, 192, 160}, {352, 224, 192, 352, 224, 112}, {384, 256, 224, 384, 256, 128}, {416, 320, 256, 416, 320, 256}, {448, 384, 320, 448, 384, 320}, {-1, -1, -1, -1, -1, -1} /* Forbidden. */ }; FILE *mp3file; long len = 0; unsigned char buf[20]; int i = 0, start = -1; memset(header, 0, sizeof(MpgHeader)); #ifdef _DEBUG_ fprintf(stderr, "get_mpgheader(): Opening %s... ", filename); fflush(stderr); #endif mp3file = fopen(filename, "rb"); if (!mp3file) return 1; #ifdef _DEBUG_ fprintf(stderr, "done.\n"); #endif // Save the file length without its tag in len. fseek(mp3file, -128, SEEK_END); len = ftell(mp3file); if( fgetc(mp3file) != 'T' || fgetc(mp3file) != 'A' || fgetc(mp3file) != 'G' ) len = len + 128; fseek(mp3file, 0, SEEK_SET); if (!fread(buf, 1, 4, mp3file)) { fclose(mp3file); return 2; } #ifdef _DEBUG_ fprintf(stderr, "get_mpgheader(): File length excl. V1 tag determined.\n"); #endif // Find the first valid frameheader. i = -1; while (++i <= (int)len) { if (buf[0] == 255 && (buf[1] & (32 + 64 + 128)) == (32 + 64 + 128) && (buf[1] & 24) != 8 && (buf[1] & 6) != 0 && (buf[2] & 240) != 240 && (buf[2] & 12) != 12 && (buf[3] & 3) != 2) { start = i; if( ((buf[2] & 240) >> 4) != 0 ) break; } buf[0] = buf[1]; buf[1] = buf[2]; buf[2] = buf[3]; buf[3] = fgetc(mp3file); } fclose(mp3file); #ifdef _DEBUG_ fprintf(stderr, "get_mpgheader(): First MPEG header search finished, "); fprintf(stderr, start == -1 ? "no valid header found." : "a valid header has been found.\n"); #endif if (start == -1) return(-1); switch (buf[1] & 24) { case 0: sprintf(header->version, "2.5"); break; case 8: sprintf(header->version, "invalid"); break; case 16: sprintf(header->version, "2"); break; case 24: sprintf(header->version, "1"); break; } header->layer = -1; switch (buf[1] & 6) { case 0: header->layer = 0; break; case 2: header->layer = 3; break; case 4: header->layer = 2; break; case 6: header->layer = 1; break; } if( buf[1] & 1 ) header->protection = TRUE; else header->protection = FALSE; // get bitrate out of a table. if (*header->version == '1') header->bitrate = bitrates[(buf[2] & 240) >> 4][header->layer - 1] * 1000; if (*header->version == '2') header->bitrate = bitrates[(buf[2] & 240) >> 4][header->layer + 2] * 1000; switch (buf[2] & 12) { case 0: header->frequency = 11025; break; case 4: header->frequency = 12000; break; case 8: header->frequency = 8000; break; } if( *header->version == '2' && *(header->version + 1) == '\0' ) header->frequency *= 2; if( *header->version == '1' ) header->frequency *= 4; // padding bit header->padding = FALSE; if( buf[2] & 2 ) header->padding = TRUE; // private bit header->is_private = FALSE; if( buf[2] & 1 ) header->is_private = TRUE; // next byte ++i; // stereo mode switch (buf[3] & 192) { case 0: header->mode = 0; break; case 64: header->mode = 1; break; case 128: header->mode = 2; break; case 192: header->mode = 3; break; } // mode extension (for joint stereo) switch (buf[3] & 48) { case 0: header->intensity_stereo = FALSE; header->ms_stereo = FALSE; break; case 16: header->intensity_stereo = TRUE; header->ms_stereo = FALSE; break; case 32: header->intensity_stereo = FALSE; header->ms_stereo = TRUE; break; case 48: header->intensity_stereo = TRUE; header->ms_stereo = TRUE; break; } // copyright bit header->copyright = FALSE; if (buf[3] & 8) header->copyright = TRUE; // original bit header->original = FALSE; if (buf[3] & 4) header->original = TRUE; // emphasis bits switch (buf[3] & 3) { case 0: header->emphasis = 0; break; case 1: header->emphasis = 1; break; case 2: header->emphasis = 2; break; case 3: header->emphasis = 3; break; } // Frames count header->frames = (len - start) / (144 * header->bitrate / header->frequency + header->padding); // lenght calculate if (header->bitrate > 0) header->seconds = ((len-start) * 8) / (header->bitrate); else header->seconds = 0; return(0); } #if defined( __cplusplus ) } #endif