/*
* XmNap A Motif napster client
*
* Copyright (C) 2000 Mats Peterson
*
* 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 2 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; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Please send any comments/bug reports to
*
[email protected] (Mats Peterson)
*/
#include <Xm/Xm.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "mp3info.h"
#include "msgbox.h"
#include "util.h"
static int bitrateTbl[2][3][16] = {
{
/* MPEG 2 & 2.5 */
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}, /* Layer III */
{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160,0}, /* Layer II */
{0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256,0} /* Layer I */
},
{
/* MPEG 1 */
{0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,0}, /* Layer III */
{0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384,0}, /* Layer II */
{0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448,0} /* Layer I */
}
};
static int freqTbl[4][3] = {
{32000, 16000, 8000}, /* MPEG 2.5 */
{ 0, 0, 0}, /* reserved */
{22050, 24000, 16000}, /* MPEG 2 */
{44100, 48000, 32000} /* MPEG 1 */
};
MP3INFO* MP3Info(String fileName)
{
static MP3INFO *info = NULL;
FILE *fd;
char tmp[128], hdrSize[4];
unsigned long bitHeader;
int tryCount = 0, skip, fileSize, hdrSkip;
float frameSize;
if (! (fd = fopen(fileName, "r"))) {
ErrMsg(strerror(errno));
return NULL;
}
if (info)
XtFree((char*)info);
info = XtNew(MP3INFO);
fseek(fd, 0, SEEK_END);
fileSize = ftell(fd);
fseek(fd, 0, SEEK_SET);
fread(&tmp[1], 1, 3, fd);
do {
tmp[0]=tmp[1];
tmp[1]=tmp[2];
tmp[2]=tmp[3];
fread(&tmp[3], 1, 1, fd);
/* check for ID3v2 tag */
if ((tryCount == 0) && (! strncmp(tmp, "ID3", 3))) {
/* skip id3v2 version and flags */
fread(tmp, 1, 2, fd);
/* read id3v2 header size */
fread(hdrSize, 1, 4, fd);
/* compute bytes to skip */
hdrSkip = ((int)hdrSize[3] |
((int)hdrSize[2] << (8 - 1)) |
((int)hdrSize[1] << (16 - 2)) |
((int)hdrSize[0] << (24 - 3))) + 10;
/* skip */
fseek(fd, hdrSkip, SEEK_SET);
/* and get (hopefully) the first frame header */
fread(tmp, 1, 4, fd);
}
bitHeader = (unsigned long)(
( (tmp[0] & 255) << 24) | ( (tmp[1] & 255) << 16) |
( (tmp[2] & 255) << 8) | ( (tmp[3] & 255) )
);
info->sync = (bitHeader >> 21)&0x7ff;
info->version = ((bitHeader >> 19)&0x3);
info->layer = ((bitHeader >> 17)&0x3);
info->bitrate = ((bitHeader >> 12)&0xf);
info->freq = ((bitHeader >> 10)&0x3);
tryCount++;
if (tryCount >= 500)
return NULL;
} while (info->sync!=0x7ff || info->version==1 ||
info->layer==0 || info->bitrate==0xf ||
info->freq==3);
info->protect = ((bitHeader >> 16)&0x1);
/* get index & calc brate from it */
info->bitrate =
bitrateTbl[info->version & 1][info->layer - 1][info->bitrate];
info->freq = freqTbl[info->version][info->freq];
info->padding = ((bitHeader >> 9)&0x1);
info->channels = ((bitHeader >> 6)&0x3);
info->ext = ((bitHeader >> 4)&0x3);
info->copyright = ((bitHeader >> 3)&0x1);
info->original = ((bitHeader >> 2)&0x1);
info->emphasis = (bitHeader & 0x3);
skip=0;
/* is there a variable bit rate bit */
if (info->version == 3 ) { /* mpeg version 1 */
if (info->channels == 3)
skip = 17; /* Single Channel */
else
skip = 32;
} else { /* mpeg version 2 or 2.5 */
if (info->channels==3 )
skip = 9; /* Single Channel */
else
skip = 17;
}
/* read next twelve bits in */
fread(tmp, 1, skip, fd);
fread(tmp, 1, 12, fd);
if (! strncmp("Xing", tmp, 4)) {
/* Got a varible bitrate */
bitHeader = (unsigned long) (
(tmp[4] << 24) |
(tmp[5] << 16) |
(tmp[6] << 8) |
(tmp[7] )
);
if (bitHeader & 1) { /* there is frame data */
/* get the num of frames */
bitHeader = (unsigned long)(
(tmp[8] << 24) |
(tmp[9] << 16) |
(tmp[10] << 8) |
(tmp[11] )
);
frameSize = (float)fileSize / (float)bitHeader;
info->bitrate =
(int)(( frameSize * (float)info->freq) /
( 1000.0 * ( (info->layer==3) ? 12.0 : 144.0)) );
}
}
info->seconds = (8 * fileSize) / 1000;
if (info->bitrate)
info->seconds = info->seconds/info->bitrate;
else
info->seconds=0;
fclose(fd);
return info;
}