Removed APE tag reader from APL plugin and enabled stub APE tag reading of APE tags from APL files in the TagLib plugin

CQTexperiment
Chris Moeller 2013-10-10 21:49:16 -07:00
parent a9982e9c80
commit 4aab503658
9 changed files with 4 additions and 341 deletions

View File

@ -139,6 +139,7 @@ StringList FileRef::defaultFileExtensions()
l.append("ape");
l.append("opus");
l.append("tak");
l.append("apl");
return l;
}
@ -234,7 +235,7 @@ File *FileRef::create(FileName fileName, bool readAudioProperties,
return new ASF::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "APE")
return new APE::File(fileName, readAudioProperties, audioPropertiesStyle);
if(ext == "TAK")
if(ext == "TAK" || ext == "APL")
return new APE::File(fileName, false, audioPropertiesStyle);
}

View File

@ -7,10 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
99B98A1E0CC7E1CA00C256E9 /* ApeTag.mm in Sources */ = {isa = PBXBuildFile; fileRef = 99B9865F0CC7A20800C256E9 /* ApeTag.mm */; };
99B98A1F0CC7E1CD00C256E9 /* APLDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E8D42360CBB0F9800135C1B /* APLDecoder.m */; };
99B98A200CC7E1CE00C256E9 /* APLFile.m in Sources */ = {isa = PBXBuildFile; fileRef = 99B9863F0CC7A08600C256E9 /* APLFile.m */; };
99B98A210CC7E1D100C256E9 /* APLMetadataReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 17DA346D0CC04FCD0003F6B2 /* APLMetadataReader.m */; };
99B98A260CC7E22500C256E9 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
@ -18,8 +16,6 @@
089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
17DA346C0CC04FCD0003F6B2 /* APLMetadataReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APLMetadataReader.h; sourceTree = "<group>"; };
17DA346D0CC04FCD0003F6B2 /* APLMetadataReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APLMetadataReader.m; sourceTree = "<group>"; };
32DBCF630370AF2F00C91783 /* APL_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APL_Prefix.pch; sourceTree = "<group>"; };
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8E8D42350CBB0F9800135C1B /* APLDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APLDecoder.h; sourceTree = "<group>"; };
@ -27,8 +23,6 @@
8E8D423C0CBB0FF600135C1B /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; };
99B9863E0CC7A08600C256E9 /* APLFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = APLFile.h; sourceTree = "<group>"; };
99B9863F0CC7A08600C256E9 /* APLFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = APLFile.m; sourceTree = "<group>"; };
99B9865E0CC7A20800C256E9 /* ApeTag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApeTag.h; sourceTree = "<group>"; };
99B9865F0CC7A20800C256E9 /* ApeTag.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ApeTag.mm; sourceTree = "<group>"; };
99B989F40CC7E10400C256E9 /* APL.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = APL.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
/* End PBXFileReference section */
@ -80,12 +74,8 @@
8E8D423C0CBB0FF600135C1B /* Plugin.h */,
8E8D42350CBB0F9800135C1B /* APLDecoder.h */,
8E8D42360CBB0F9800135C1B /* APLDecoder.m */,
17DA346C0CC04FCD0003F6B2 /* APLMetadataReader.h */,
17DA346D0CC04FCD0003F6B2 /* APLMetadataReader.m */,
99B9863E0CC7A08600C256E9 /* APLFile.h */,
99B9863F0CC7A08600C256E9 /* APLFile.m */,
99B9865E0CC7A20800C256E9 /* ApeTag.h */,
99B9865F0CC7A20800C256E9 /* ApeTag.mm */,
);
name = Classes;
sourceTree = "<group>";
@ -183,10 +173,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
99B98A1E0CC7E1CA00C256E9 /* ApeTag.mm in Sources */,
99B98A1F0CC7E1CD00C256E9 /* APLDecoder.m in Sources */,
99B98A200CC7E1CE00C256E9 /* APLFile.m in Sources */,
99B98A210CC7E1D100C256E9 /* APLMetadataReader.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -1,12 +1,9 @@
#import <Cocoa/Cocoa.h>
@class ApeTag;
@interface APLFile : NSObject {
long startBlock;
long endBlock;
ApeTag* tag;
NSURL* file;
}
+createWithFile:(NSString*)f;
@ -14,7 +11,6 @@
-(long)startBlock; // always return 0 or greater!
-(long)endBlock;
-(ApeTag*) tag;
-(NSURL*) file;
//writing support to be added in far future

View File

@ -1,7 +1,6 @@
#import "APLFile.h"
#import "ApeTag.h"
@implementation APLFile
+createWithFile:(NSString*)f { return [[APLFile alloc] initWithFile:f]; }
@ -98,7 +97,6 @@
}
[scanner release];
//check here for EOF? cocoa does not have this functionality :(
tag = [ApeTag createFromFileRead:f];
[f closeFile];
}
return self;
@ -106,7 +104,6 @@
-(long)startBlock { return startBlock; }
-(long)endBlock { return endBlock; }
-(ApeTag*) tag { return tag; }
-(NSURL*) file { return file; }

View File

@ -1,10 +0,0 @@
#import <Cocoa/Cocoa.h>
#import "Plugin.h"
@interface APLMetadataReader : NSObject <CogMetadataReader> {
}
@end

View File

@ -1,26 +0,0 @@
//
// APLMetadataReader.m
#import "APLMetadataReader.h"
#import "APLDecoder.h"
#import "APLFile.h"
#import "ApeTag.h"
@implementation APLMetadataReader
+ (NSArray *)fileTypes { return [APLDecoder fileTypes]; }
+ (NSArray *)mimeTypes { return [APLDecoder mimeTypes]; }
+ (NSDictionary *)metadataForURL:(NSURL *)url {
if (![url isFileURL]) return nil;
APLFile *apl = [APLFile createWithFile:[url path]];
ApeTag* tag = [apl tag];
NSDictionary* res =[tag convertToCogTag];
return res;
}
@end

View File

@ -1,46 +0,0 @@
#import <Cocoa/Cocoa.h>
//not full support!! and even may have not enougth checks to find a non-supported data!
@interface ApeTagItem: NSObject {
UInt32 flags;
NSString* tag;
NSData* data;
}
+createTag:(NSString*)t flags:(SInt32)f data:(NSData*)d;
-initTag:(NSString*)t flags:(SInt32)f data:(NSData*)d;
//for writing:
-(NSData*) pack;
//for reading:
-(NSString*) tag;
-(bool) isString; //returns whether data is UTF-8 string(or implicitly can be converted to)
-(NSString*) getString; //returns string, if is not string - this is error, check isString before
@end
@interface ApeTag : NSObject {
NSMutableArray* fields;
}
+(id)create;
+(id)createFromFileRead:(NSFileHandle*)f;
-(id)init;
-(id)initFromFileRead:(NSFileHandle*)f;
-(NSArray*) fields; // returns fields array
-(void) addField:(NSString*)f text:(NSString*)t;
-(NSData*) pack; //returns comoplete tag, ready for writing to file/transmitting smwhere
-(void) write:(NSFileHandle*)f; //writes to file output of -pack
-(bool) read:(NSFileHandle*)f; //reads from file, returns true on success
-(NSDictionary*) convertToCogTag;
@end

View File

@ -1,237 +0,0 @@
// as simple as it can be - just write a readable tag, no options etc.
#import "ApeTag.h"
#define CURRENT_APE_TAG_VERSION 2000
/*****************************************************************************************
"Standard" APE tag fields
*****************************************************************************************/
#define APE_TAG_FIELD_TITLE @"Title"
#define APE_TAG_FIELD_ARTIST @"Artist"
#define APE_TAG_FIELD_ALBUM @"Album"
#define APE_TAG_FIELD_COMMENT @"Comment"
#define APE_TAG_FIELD_YEAR @"Year"
#define APE_TAG_FIELD_TRACK @"Track"
#define APE_TAG_FIELD_GENRE @"Genre"
#define APE_TAG_FIELD_COVER_ART_FRONT @"Cover Art (front)"
#define APE_TAG_FIELD_NOTES @"Notes"
#define APE_TAG_FIELD_LYRICS @"Lyrics"
#define APE_TAG_FIELD_COPYRIGHT @"Copyright"
#define APE_TAG_FIELD_BUY_URL @"Buy URL"
#define APE_TAG_FIELD_ARTIST_URL @"Artist URL"
#define APE_TAG_FIELD_PUBLISHER_URL @"Publisher URL"
#define APE_TAG_FIELD_FILE_URL @"File URL"
#define APE_TAG_FIELD_COPYRIGHT_URL @"Copyright URL"
#define APE_TAG_FIELD_MJ_METADATA @"Media Jukebox Metadata"
#define APE_TAG_FIELD_TOOL_NAME @"Tool Name"
#define APE_TAG_FIELD_TOOL_VERSION @"Tool Version"
#define APE_TAG_FIELD_PEAK_LEVEL @"Peak Level"
#define APE_TAG_FIELD_REPLAY_GAIN_RADIO @"Replay Gain (radio)"
#define APE_TAG_FIELD_REPLAY_GAIN_ALBUM @"Replay Gain (album)"
#define APE_TAG_FIELD_COMPOSER @"Composer"
#define APE_TAG_FIELD_KEYWORDS @"Keywords"
/*****************************************************************************************
Standard APE tag field values
*****************************************************************************************/
#define APE_TAG_GENRE_UNDEFINED @"Undefined"
/*****************************************************************************************
Footer (and header) flags
*****************************************************************************************/
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
#define APE_TAG_FLAGS_DEFAULT (APE_TAG_FLAG_CONTAINS_FOOTER)
/*****************************************************************************************
Tag field flags
*****************************************************************************************/
#define TAG_FIELD_FLAG_READ_ONLY (1 << 0)
#define TAG_FIELD_FLAG_DATA_TYPE_MASK (6)
#define TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8 (0 << 1)
#define TAG_FIELD_FLAG_DATA_TYPE_BINARY (1 << 1)
#define TAG_FIELD_FLAG_DATA_TYPE_EXTERNAL_INFO (2 << 1)
#define TAG_FIELD_FLAG_DATA_TYPE_RESERVED (3 << 1)
/*****************************************************************************************
The footer at the end of APE tagged files (can also optionally be at the front of the tag)
*****************************************************************************************/
#define APE_TAG_FOOTER_BYTES 32
//------------------------
@implementation ApeTagItem
+createTag:(NSString*)t flags:(SInt32)f data:(NSData*)d{
return [[ApeTagItem alloc] initTag:t flags:f data:d];
}
-initTag:(NSString*)t flags:(SInt32)f data:(NSData*)d{
self = [super init];
if (self)
{
tag = [t copy];
data = [d copy];
flags = f;
}
return self;
}
-(NSData*) pack {
//item header:
NSMutableData* d = [NSMutableData dataWithCapacity:8];
UInt32 len = CFSwapInt32HostToLittle([data length]);
UInt32 flags1 = CFSwapInt32HostToLittle(flags); // ApeTagv1 does not use this, 0 for v2 means only footer and all fields text in utf8 - just right what we want
[d appendBytes:&len length:4]; // lenth of value
[d appendBytes:&flags1 length:4]; // 32 bits of flags
[d appendData:[tag dataUsingEncoding: NSUTF8StringEncoding]]; // item tag
char c = 0; [d appendBytes:&c length:1]; // 0x00 separator after tag
[d appendData:data]; // item value
return d;
}
-(bool) isString { //returns whether data is UTF-8 string(or implicitly can be converted to)
return (flags & TAG_FIELD_FLAG_DATA_TYPE_MASK) == TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8;
}
-(NSString*) getString { //returns string, if is not string - this is error, check isString before
if ([self isString]) return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return nil;
}
-(NSString*) tag { return tag; }
@end
@implementation ApeTag
+(id)create { return [[ApeTag alloc] init];}
+(id)createFromFileRead:(NSFileHandle*)f { return [[ApeTag alloc] initFromFileRead:f]; }
-(id)init {
self = [super init];
if (self)
{
fields = [NSMutableArray array];
}
return self;
}
-(id)initFromFileRead:(NSFileHandle*)f {
self = [super init];
if(self)
{
fields = [NSMutableArray array];
if (![self read:f])
return nil;
}
return self;
}
-(void) addField:(NSString*)f text:(NSString*)t {
[fields addObject:[ApeTagItem createTag:f flags:(TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8) data:[t dataUsingEncoding: NSUTF8StringEncoding]]];
}
-(NSArray*) fields { return fields; }
-(NSDictionary*) convertToCogTag {
//NSLog(@"Converting ape tag to cog tag");
NSMutableDictionary* d = [NSMutableDictionary dictionaryWithCapacity:6];
ApeTagItem* item;
int n = 0;
for (item in fields) {
if (![[item tag] compare:APE_TAG_FIELD_ARTIST]) { [d setObject:[item getString] forKey:@"artist"]; n++;}
if (![[item tag] compare:APE_TAG_FIELD_ALBUM]) {[d setObject:[item getString] forKey:@"album"]; n++;}
if (![[item tag] compare:APE_TAG_FIELD_TITLE]) {[d setObject:[item getString] forKey:@"title"]; n++;}
if (![[item tag] compare:APE_TAG_FIELD_TRACK]) {[d setObject:[NSNumber numberWithInt:[[item getString] intValue]] forKey:@"track"]; n++;}
if (![[item tag] compare:APE_TAG_FIELD_GENRE]) {[d setObject:[item getString] forKey:@"genre"]; n++;}
if (![[item tag] compare:APE_TAG_FIELD_YEAR]) {[d setObject:[item getString] forKey:@"year"]; n++;}
}
if (n)
return d;
[d release]; d = nil;
return nil;
}
-(NSData*) pack {
int len = 0, num = 0;
NSMutableData* d = [NSMutableData dataWithCapacity:8];
id item;
for (item in fields)
{
NSData* i = [item pack];
[d appendData:i];
len += [i length];
num++;
}
UInt32 version = CFSwapInt32HostToLittle(CURRENT_APE_TAG_VERSION);
UInt32 size = CFSwapInt32HostToLittle(len + APE_TAG_FOOTER_BYTES);
UInt32 count = CFSwapInt32HostToLittle(num);
UInt32 flags = CFSwapInt32HostToLittle(APE_TAG_FLAGS_DEFAULT);
[d appendBytes:"APETAGEX" length:8];
[d appendBytes:&version length:4];
[d appendBytes:&size length:4];
[d appendBytes:&count length:4];
[d appendBytes:&flags length:4];
[d appendBytes:"\0\0\0\0\0\0\0\0" length:8]; //reserved
return d;
}
-(void) write:(NSFileHandle*)file {
[file writeData:[self pack]];
}
-(NSString*) readToNull:(NSFileHandle*)f { //!!!
NSMutableData* d = [NSMutableData dataWithCapacity:100]; //it will grow, here should be most expected value (may gain few nanosecond from it =) )
while(true) {
NSData* byte = [f readDataOfLength:1];
if (!byte)
{
[f seekToFileOffset:0-[d length]];
return nil;
}
if (*((const char*)[byte bytes]) == 0) break;
[d appendData:byte];
}
NSString* s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding]; //!handle encoding error (in case binary data starts not from newline, impossible on real apl, but who knows...)
return s;
}
-(bool) read:(NSFileHandle*)f { //reads from file, returns true on success
//reading from file erases previous data:
[fields removeAllObjects];
//!! prefix header may be present and we should read it but lazyness...
NSString* header = @"APETAGEX";
NSData* check = [f readDataOfLength:[header length]];
[f seekToFileOffset:([f offsetInFile]-[check length])];
if (check && [[[NSString alloc] initWithData:check encoding:NSASCIIStringEncoding] isEqualToString:header]) {
NSLog(@"Reading of prefix header not implemented");
return false;
}
//read fields and store 'em
while(true) {
NSData* check = [f readDataOfLength:[header length]];
[f seekToFileOffset:([f offsetInFile]-[check length])];
if (check && [[[NSString alloc] initWithData:check encoding:NSASCIIStringEncoding] isEqualToString:header]) break; // reached footer
NSData* f_len = [f readDataOfLength:4];
NSData* f_flag = [f readDataOfLength:4];
NSString* f_name = [self readToNull:f];
UInt32 len = CFSwapInt32LittleToHost(*(uint32_t*)[f_len bytes]);
UInt32 flags = CFSwapInt32LittleToHost(*(uint32_t*)[f_flag bytes]);
NSData* data = [f readDataOfLength:len];
ApeTagItem* item = [ApeTagItem createTag:f_name flags:flags data:data];
//NSLog(@"Read tag '%@'='%@'", [item tag], [item getString]);
[fields addObject:item];
}
//here we should read footer and check number of fields etc. - but who cares? =)
// just clean up file pointer:
[f readDataOfLength:APE_TAG_FOOTER_BYTES];
return true;
}
@end

View File

@ -130,12 +130,12 @@
+ (NSArray *)fileTypes
{
//May be a way to get a list of supported formats
return [NSArray arrayWithObjects:@"ape", @"asf", @"wma", @"ogg", @"opus", @"mpc", @"flac", @"m4a", @"mp3", @"tak", nil];
return [NSArray arrayWithObjects:@"ape", @"asf", @"wma", @"ogg", @"opus", @"mpc", @"flac", @"m4a", @"mp3", @"tak", @"apl", nil];
}
+ (NSArray *)mimeTypes
{
return [NSArray arrayWithObjects:@"audio/x-ape", @"audio/x-ms-wma", @"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg", @"audio/x-musepack", @"audio/x-flac", @"audio/x-m4a", @"audio/mpeg", @"audio/x-mp3", @"audio/x-tak", nil];
return [NSArray arrayWithObjects:@"audio/x-ape", @"audio/x-ms-wma", @"application/ogg", @"application/x-ogg", @"audio/x-vorbis+ogg", @"audio/x-musepack", @"audio/x-flac", @"audio/x-m4a", @"audio/mpeg", @"audio/x-mp3", @"audio/x-tak", @"audio/x-apl", nil];
}
@end