Add support for APEv2 tags and detecting WavPack files

custom
ayumi 3 months ago
parent 52217b637d
commit a363986076
No known key found for this signature in database
  1. 2
      lib/libtags/CMakeLists.txt
  2. 233
      lib/libtags/ape.c
  3. 2
      lib/libtags/tags.c
  4. 1
      lib/libtags/tags.h

@ -1,5 +1,5 @@
idf_component_register( idf_component_register(
SRCS 437.c 8859.c flac.c id3genres.c id3v1.c id3v2.c it.c m4a.c mod.c opus.c SRCS 437.c 8859.c ape.c flac.c id3genres.c id3v1.c id3v2.c it.c m4a.c mod.c opus.c
s3m.c tags.c utf16.c vorbis.c wav.c xm.c s3m.c tags.c utf16.c vorbis.c wav.c xm.c
INCLUDE_DIRS . INCLUDE_DIRS .
) )

@ -0,0 +1,233 @@
#include <math.h>
#include "tagspriv.h"
#define leu16int(d) (u16int)(((uchar*)(d))[1]<<8 | ((uchar*)(d))[0]<<0)
enum
{
HeaderSize = 32,
FooterSize = HeaderSize,
MagicOffset = 0,
VersionOffset = 8,
SizeOffset = 12,
CountOffset = 16,
FlagsOffset = 20,
WvHeaderSize = 32,
WvMagicOffset = 0,
WvVersionOffset = 8,
WvSamplesHighOffset = 11,
WvSamplesLowOffset = 12,
WvFlagsOffset = 24,
WvSampleRateMask = 0xf << 23,
WvSampleRateShift = 23,
WvCustomSampleRate = 16,
WvMonoMask = 4,
};
typedef enum
{
TagUTF8,
TagBinary,
TagExternal,
TagReserved,
TagInvalid,
} TagType;
static int
isWavpack(Tagctx *ctx)
{
uchar header[WvHeaderSize];
int size;
u16int version;
u32int flags, samplerate;
uvlong samples;
if(ctx->seek(ctx, 0, 0) < 0)
return 0;
if(ctx->read(ctx, header, WvHeaderSize) != WvHeaderSize)
return 0;
if(memcmp(header+WvMagicOffset, "wvpk", 4))
return 0;
version = leu16int(header+WvVersionOffset);
if(version<0x402 || version>0x410)
return 0;
samples = (uvlong)(*(uchar*)(header+WvSamplesHighOffset))<<32 | leuint(header+WvSamplesLowOffset);
flags = leuint(header+WvFlagsOffset);
if((flags&WvSampleRateMask)>>WvSampleRateShift != WvCustomSampleRate){
const u32int samplerates[] = {6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000};
samplerate = samplerates[(flags&WvSampleRateMask)>>WvSampleRateShift];
ctx->samplerate = samplerate;
uvlong duration = round((double)samples/samplerate*1000);
ctx->duration = duration;
}
ctx->channels = flags&WvMonoMask ? 1 : 2;
if(ctx->seek(ctx, 0, 0) < 0)
return 0;
if(size = ctx->seek(ctx, 0, 2), size < 0)
return 0;
ctx->bitrate = (double)size*8.0/(samples/samplerate)/1000;
return 1;
}
static int
detectFormat(Tagctx *ctx)
{
if(isWavpack(ctx))
return Fwavpack;
return Funknown;
}
static int
tagHasHeader(u32int tags)
{
return (tags&(1<<31)) >> 31;
}
static int
tagIsHeader(u32int tags)
{
return (tags&(1<<29)) >> 29;
}
static TagType
tagGetType(u32int tags)
{
switch((tags&(1<<1))>>1 | (tags&(1<<2))>>1 | (tags&(1<<3))>>1 | (tags&(1<<4))>>1){
case 0:
return TagUTF8;
case 1:
return TagBinary;
case 2:
return TagExternal;
case 3:
return TagReserved;
default:
return TagInvalid;
}
}
static int
tagTagType(char *name)
{
if(!strcmp(name, "Album"))
return Talbum;
else if(!strcmp(name, "Album Artist"))
return Talbumartist;
else if(!strcmp(name, "Artist"))
return Tartist;
else if(!strcmp(name, "Comment"))
return Tcomment;
else if(!strcmp(name, "Composer"))
return Tcomposer;
else if(!strncmp(name, "Cover Art (", 11)){
if(name[strlen(name)-1] == ')')
return Timage;
}else if(!strcmp(name, "Genre"))
return Tgenre;
else if(!strcmp(name, "Replaygain_Album_Gain"))
return Talbumgain;
else if(!strcmp(name, "Replaygain_Album_Peak"))
return Talbumpeak;
else if(!strcmp(name, "Replaygain_Track_Gain"))
return Ttrackgain;
else if(!strcmp(name, "Replaygain_Track_Peak"))
return Ttrackpeak;
else if(!strcmp(name, "Title"))
return Ttitle;
else if(!strcmp(name, "Track"))
return Ttrack;
else if(!strcmp(name, "Year"))
return Tdate;
return Tunknown;
}
int
tagape(Tagctx *ctx)
{
uchar footer[FooterSize];
u32int i, count;
ctx->format = detectFormat(ctx);
if(ctx->seek(ctx, -FooterSize, 2) < 0)
return -1;
if(ctx->read(ctx, footer, FooterSize) != FooterSize)
return -1;
if(memcmp(footer+MagicOffset, "APETAGEX", 8))
return -1;
if(leuint(footer+VersionOffset) != 2000)
return -1;
if(tagIsHeader(leuint(footer+FlagsOffset)))
return -1;
if(ctx->seek(ctx, -FooterSize-leuint(footer+SizeOffset), 2) < 0)
return -1;
if(tagHasHeader(leuint(footer+FlagsOffset))){
uchar header[HeaderSize];
if(ctx->read(ctx, header, HeaderSize) != HeaderSize)
return -1;
if(memcmp(header, footer, 23))
return -1;
if(!tagHasHeader(leuint(header+FlagsOffset)))
return -1;
if(!tagIsHeader(leuint(header+FlagsOffset)))
return -1;
}else if(ctx->seek(ctx, HeaderSize, 1) < 0)
return -1;
for(i = 0, count = leuint(footer+CountOffset); i < count; i++){
int valueOffset = 0;
char c;
u32int d, length, flags;
if(ctx->read(ctx, &d, 4) != 4)
return -1;
length = leuint(&d);
if(ctx->read(ctx, &d, 4) != 4)
return -1;
flags = leuint(&d);
do{
if(valueOffset == ctx->bufsz)
return -1;
if(ctx->read(ctx, &c, 1) != 1)
return -1;
if(c<' ' || c>'~')
if(c != '\0')
return -1;
ctx->buf[valueOffset++] = c;
}while(c != '\0');
if(valueOffset+1+(int)length>ctx->bufsz && tagTagType(ctx->buf)!=Timage){
if(ctx->seek(ctx, length, 1) < 0)
return -1;
continue;
}
switch(tagGetType(flags)){
u32int keyOffset;
case TagUTF8:
if(ctx->read(ctx, ctx->buf+valueOffset, length) != (int)length)
return -1;
(ctx->buf+valueOffset)[length] = '\0';
for(keyOffset = 0; keyOffset != length;){
txtcb(ctx, tagTagType(ctx->buf), ctx->buf, ctx->buf+valueOffset+keyOffset);
if(keyOffset += strlen(ctx->buf+valueOffset+keyOffset), keyOffset != length)
keyOffset++;
}
break;
case TagBinary:
if(tagTagType(ctx->buf) == Timage)
tagscallcb(ctx, Timage, ctx->buf, ctx->buf, ctx->seek(ctx, 0, 1), length, NULL);
if(ctx->seek(ctx, length, 1) < 0)
return -1;
break;
default:
if(ctx->seek(ctx, length, 1) < 0)
return -1;
}
}
return 0;
}

@ -8,6 +8,7 @@ struct Getter
int format; int format;
}; };
extern int tagape(Tagctx *ctx);
extern int tagflac(Tagctx *ctx); extern int tagflac(Tagctx *ctx);
extern int tagid3v1(Tagctx *ctx); extern int tagid3v1(Tagctx *ctx);
extern int tagid3v2(Tagctx *ctx); extern int tagid3v2(Tagctx *ctx);
@ -22,6 +23,7 @@ extern int tagmod(Tagctx *ctx);
static const Getter g[] = static const Getter g[] =
{ {
{tagape, Funknown},
{tagid3v2, Fmp3}, {tagid3v2, Fmp3},
{tagid3v1, Fmp3}, {tagid3v1, Fmp3},
{tagvorbis, Fogg}, {tagvorbis, Fogg},

@ -37,6 +37,7 @@ enum
Fm4a, Fm4a,
Fopus, Fopus,
Fwav, Fwav,
Fwavpack,
Fit, Fit,
Fxm, Fxm,
Fs3m, Fs3m,

Loading…
Cancel
Save