Implemented basic embedded CueSheet support
parent
6315377eaf
commit
d24a01a637
|
@ -14,5 +14,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id<CogDecoder>)audioDecoderForSource:(id <CogSource>)source;
|
+ (id<CogDecoder>)audioDecoderForSource:(id <CogSource>)source;
|
||||||
|
+ (id<CogDecoder>)audioDecoderForSource:(id <CogSource>)source skipCue:(BOOL)skip;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,7 +14,12 @@
|
||||||
|
|
||||||
+ (id<CogDecoder>) audioDecoderForSource:(id <CogSource>)source
|
+ (id<CogDecoder>) audioDecoderForSource:(id <CogSource>)source
|
||||||
{
|
{
|
||||||
return [[PluginController sharedPluginController] audioDecoderForSource:source];
|
return [[PluginController sharedPluginController] audioDecoderForSource:source skipCue:NO];
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (id<CogDecoder>) audioDecoderForSource:(id <CogSource>)source skipCue:(BOOL)skip
|
||||||
|
{
|
||||||
|
return [[PluginController sharedPluginController] audioDecoderForSource:source skipCue:skip];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,5 +14,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)metadataForURL:(NSURL *)url;
|
+ (NSDictionary *)metadataForURL:(NSURL *)url;
|
||||||
|
+ (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -14,7 +14,14 @@
|
||||||
+ (NSDictionary *)metadataForURL:(NSURL *)url
|
+ (NSDictionary *)metadataForURL:(NSURL *)url
|
||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
return [[PluginController sharedPluginController] metadataForURL:url];
|
return [[PluginController sharedPluginController] metadataForURL:url skipCue:NO];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
return [[PluginController sharedPluginController] metadataForURL:url skipCue:skip];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -347,11 +347,49 @@
|
||||||
lastChain = bufferChain;
|
lastChain = bufferChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([[nextStream scheme] isEqualToString:[[lastChain streamURL] scheme]]
|
BOOL pathsEqual = NO;
|
||||||
|
|
||||||
|
if ([nextStream isFileURL] && [[lastChain streamURL] isFileURL])
|
||||||
|
{
|
||||||
|
NSMutableString *unixPathNext = [[nextStream path] mutableCopy];
|
||||||
|
NSMutableString *unixPathPrev = [[[lastChain streamURL] path] mutableCopy];
|
||||||
|
|
||||||
|
//Get the fragment
|
||||||
|
NSString *fragmentNext = @"";
|
||||||
|
NSScanner *scanner = [NSScanner scannerWithString:unixPathNext];
|
||||||
|
NSCharacterSet *characterSet = [NSCharacterSet characterSetWithCharactersInString:@"#1234567890"];
|
||||||
|
while (![scanner isAtEnd]) {
|
||||||
|
NSString *possibleFragment;
|
||||||
|
[scanner scanUpToString:@"#" intoString:nil];
|
||||||
|
|
||||||
|
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd]) {
|
||||||
|
fragmentNext = possibleFragment;
|
||||||
|
[unixPathNext deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *fragmentPrev = @"";
|
||||||
|
scanner = [NSScanner scannerWithString:unixPathPrev];
|
||||||
|
while (![scanner isAtEnd]) {
|
||||||
|
NSString *possibleFragment;
|
||||||
|
[scanner scanUpToString:@"#" intoString:nil];
|
||||||
|
|
||||||
|
if ([scanner scanCharactersFromSet:characterSet intoString:&possibleFragment] && [scanner isAtEnd]) {
|
||||||
|
fragmentPrev = possibleFragment;
|
||||||
|
[unixPathPrev deleteCharactersInRange:NSMakeRange([scanner scanLocation] - [possibleFragment length], [possibleFragment length])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ([unixPathNext isEqualToString:unixPathPrev])
|
||||||
|
pathsEqual = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathsEqual || ([[nextStream scheme] isEqualToString:[[lastChain streamURL] scheme]]
|
||||||
&& (([nextStream host] == nil &&
|
&& (([nextStream host] == nil &&
|
||||||
[[lastChain streamURL] host] == nil)
|
[[lastChain streamURL] host] == nil)
|
||||||
|| [[nextStream host] isEqualToString:[[lastChain streamURL] host]])
|
|| [[nextStream host] isEqualToString:[[lastChain streamURL] host]])
|
||||||
&& [[nextStream path] isEqualToString:[[lastChain streamURL] path]])
|
&& [[nextStream path] isEqualToString:[[lastChain streamURL] path]]))
|
||||||
{
|
{
|
||||||
if ([lastChain setTrack:nextStream]
|
if ([lastChain setTrack:nextStream]
|
||||||
&& [newChain openWithInput:[lastChain inputNode] withOutputFormat:[output format] withRGInfo:nextStreamRGInfo])
|
&& [newChain openWithInput:[lastChain inputNode] withOutputFormat:[output format] withRGInfo:nextStreamRGInfo])
|
||||||
|
|
|
@ -88,9 +88,9 @@
|
||||||
|
|
||||||
- (id<CogSource>) audioSourceForURL:(NSURL *)url;
|
- (id<CogSource>) audioSourceForURL:(NSURL *)url;
|
||||||
- (NSArray *) urlsForContainerURL:(NSURL *)url;
|
- (NSArray *) urlsForContainerURL:(NSURL *)url;
|
||||||
- (NSDictionary *) metadataForURL:(NSURL *)url;
|
- (NSDictionary *) metadataForURL:(NSURL *)url skipCue:(BOOL)skip;
|
||||||
- (NSDictionary *) propertiesForURL:(NSURL *)url;
|
- (NSDictionary *) propertiesForURL:(NSURL *)url;
|
||||||
- (id<CogDecoder>) audioDecoderForSource:(id<CogSource>)source;
|
- (id<CogDecoder>) audioDecoderForSource:(id<CogSource>)source skipCue:(BOOL)skip;
|
||||||
|
|
||||||
- (int) putMetadataInURL:(NSURL *)url;
|
- (int) putMetadataInURL:(NSURL *)url;
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -296,13 +296,25 @@ static PluginController *sharedPluginController = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Note: Source is assumed to already be opened.
|
//Note: Source is assumed to already be opened.
|
||||||
- (id<CogDecoder>) audioDecoderForSource:(id <CogSource>)source
|
- (id<CogDecoder>) audioDecoderForSource:(id <CogSource>)source skipCue:(BOOL)skip
|
||||||
{
|
{
|
||||||
NSString *ext = [[source url] pathExtension];
|
NSString *ext = [[source url] pathExtension];
|
||||||
NSArray *decoders = [decodersByExtension objectForKey:[ext lowercaseString]];
|
NSArray *decoders = [decodersByExtension objectForKey:[ext lowercaseString]];
|
||||||
NSString *classString;
|
NSString *classString;
|
||||||
if (decoders) {
|
if (decoders) {
|
||||||
if ( [decoders count] > 1 ) {
|
if ( [decoders count] > 1 ) {
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
NSMutableArray * _decoders = [decoders mutableCopy];
|
||||||
|
for (int i = 0; i < [_decoders count];)
|
||||||
|
{
|
||||||
|
if ([[_decoders objectAtIndex:i] isEqualToString:@"CueSheetDecoder"])
|
||||||
|
[_decoders removeObjectAtIndex:i];
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return [[CogDecoderMulti alloc] initWithDecoders:_decoders];
|
||||||
|
}
|
||||||
return [[CogDecoderMulti alloc] initWithDecoders:decoders];
|
return [[CogDecoderMulti alloc] initWithDecoders:decoders];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -329,7 +341,7 @@ static PluginController *sharedPluginController = nil;
|
||||||
return [[decoder alloc] init];
|
return [[decoder alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSDictionary *)metadataForURL:(NSURL *)url
|
- (NSDictionary *)metadataForURL:(NSURL *)url skipCue:(BOOL)skip
|
||||||
{
|
{
|
||||||
NSString * urlScheme = [url scheme];
|
NSString * urlScheme = [url scheme];
|
||||||
if ([urlScheme isEqualToString:@"http"] ||
|
if ([urlScheme isEqualToString:@"http"] ||
|
||||||
|
@ -341,6 +353,18 @@ static PluginController *sharedPluginController = nil;
|
||||||
NSString *classString;
|
NSString *classString;
|
||||||
if (readers) {
|
if (readers) {
|
||||||
if ( [readers count] > 1 ) {
|
if ( [readers count] > 1 ) {
|
||||||
|
if (skip)
|
||||||
|
{
|
||||||
|
NSMutableArray *_readers = [readers mutableCopy];
|
||||||
|
for (int i = 0; i < [_readers count];)
|
||||||
|
{
|
||||||
|
if ([[_readers objectAtIndex:i] isEqualToString:@"CueSheetMetadataReader"])
|
||||||
|
[_readers removeObjectAtIndex:i];
|
||||||
|
else
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return [CogMetadataReaderMulti metadataForURL:url readers:_readers];
|
||||||
|
}
|
||||||
return [CogMetadataReaderMulti metadataForURL:url readers:readers];
|
return [CogMetadataReaderMulti metadataForURL:url readers:readers];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -410,7 +434,7 @@ static PluginController *sharedPluginController = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
id<CogDecoder> decoder = [self audioDecoderForSource:source];
|
id<CogDecoder> decoder = [self audioDecoderForSource:source skipCue:NO];
|
||||||
if (![decoder open:source])
|
if (![decoder open:source])
|
||||||
{
|
{
|
||||||
return nil;
|
return nil;
|
||||||
|
|
|
@ -174,6 +174,13 @@ unsigned int APE::Tag::track() const
|
||||||
return d->itemListMap["TRACK"].toString().toInt();
|
return d->itemListMap["TRACK"].toString().toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String APE::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
if(d->itemListMap["CUESHEET"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->itemListMap["CUESHEET"].toString();
|
||||||
|
}
|
||||||
|
|
||||||
float APE::Tag::rgAlbumGain() const
|
float APE::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
if (d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
if (d->itemListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||||
|
@ -248,6 +255,10 @@ void APE::Tag::setTrack(unsigned int i)
|
||||||
addValue("TRACK", String::number(i), true);
|
addValue("TRACK", String::number(i), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void APE::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void APE::Tag::setRGAlbumGain(float f)
|
void APE::Tag::setRGAlbumGain(float f)
|
||||||
{
|
{
|
||||||
if (f == 0)
|
if (f == 0)
|
||||||
|
|
|
@ -95,6 +95,7 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
virtual String cuesheet() const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -108,6 +109,7 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &s);
|
virtual void setGenre(const String &s);
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -115,6 +115,11 @@ String ASF::Tag::genre() const
|
||||||
return String();
|
return String();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ASF::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float ASF::Tag::rgAlbumGain() const
|
float ASF::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -184,6 +189,10 @@ void ASF::Tag::setTrack(unsigned int value)
|
||||||
setAttribute("WM/TrackNumber", String::number(value));
|
setAttribute("WM/TrackNumber", String::number(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ASF::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ASF::Tag::setRGAlbumGain(float)
|
void ASF::Tag::setRGAlbumGain(float)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,8 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
virtual String cuesheet() const;
|
||||||
|
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -159,6 +161,8 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
|
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -94,6 +94,11 @@ unsigned int Mod::Tag::track() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Mod::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float Mod::Tag::rgAlbumGain() const
|
float Mod::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -153,6 +158,10 @@ void Mod::Tag::setTrack(unsigned int)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mod::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void Mod::Tag::setRGAlbumGain(float)
|
void Mod::Tag::setRGAlbumGain(float)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,11 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files. Therefore always returns empty.
|
||||||
|
*/
|
||||||
|
virtual String cuesheet() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Not supported by module files. Therefore always returns 0.
|
* Not supported by module files. Therefore always returns 0.
|
||||||
*/
|
*/
|
||||||
|
@ -182,6 +187,11 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual void setTrack(unsigned int track);
|
virtual void setTrack(unsigned int track);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Not supported by module files and therefore ignored.
|
||||||
|
*/
|
||||||
|
virtual void setCuesheet(const String &);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Not supported by module files and therefore ignored.
|
* Not supported by module files and therefore ignored.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -780,6 +780,12 @@ MP4::Tag::track() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
MP4::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
MP4::Tag::rgAlbumGain() const
|
MP4::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
|
@ -872,6 +878,11 @@ MP4::Tag::setTrack(unsigned int value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MP4::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MP4::Tag::setRGAlbumGain(float f)
|
MP4::Tag::setRGAlbumGain(float f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,10 +61,11 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
float rgAlbumGain() const;
|
virtual String cuesheet() const;
|
||||||
float rgAlbumPeak() const;
|
virtual float rgAlbumGain() const;
|
||||||
float rgTrackGain() const;
|
virtual float rgAlbumPeak() const;
|
||||||
float rgTrackPeak() const;
|
virtual float rgTrackGain() const;
|
||||||
|
virtual float rgTrackPeak() const;
|
||||||
|
|
||||||
virtual void setTitle(const String &value);
|
virtual void setTitle(const String &value);
|
||||||
virtual void setAlbumArtist(const String &value);
|
virtual void setAlbumArtist(const String &value);
|
||||||
|
@ -74,10 +75,11 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &value);
|
virtual void setGenre(const String &value);
|
||||||
virtual void setYear(unsigned int value);
|
virtual void setYear(unsigned int value);
|
||||||
virtual void setTrack(unsigned int value);
|
virtual void setTrack(unsigned int value);
|
||||||
void setRGAlbumGain(float);
|
virtual void setCuesheet(const String &value);
|
||||||
void setRGAlbumPeak(float);
|
virtual void setRGAlbumGain(float);
|
||||||
void setRGTrackGain(float);
|
virtual void setRGAlbumPeak(float);
|
||||||
void setRGTrackPeak(float);
|
virtual void setRGTrackGain(float);
|
||||||
|
virtual void setRGTrackPeak(float);
|
||||||
|
|
||||||
virtual bool isEmpty() const;
|
virtual bool isEmpty() const;
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,11 @@ unsigned int ID3v1::Tag::track() const
|
||||||
return d->track;
|
return d->track;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ID3v1::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float ID3v1::Tag::rgAlbumGain() const
|
float ID3v1::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -226,6 +231,10 @@ void ID3v1::Tag::setTrack(unsigned int i)
|
||||||
d->track = i < 256 ? i : 0;
|
d->track = i < 256 ? i : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ID3v1::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void ID3v1::Tag::setRGAlbumGain(float)
|
void ID3v1::Tag::setRGAlbumGain(float)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,6 +143,7 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
virtual String cuesheet() const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -156,6 +157,7 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &s);
|
virtual void setGenre(const String &s);
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -245,6 +245,26 @@ unsigned int ID3v2::Tag::track() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String ID3v2::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
const FrameList &list = d->frameListMap["TXXX"];
|
||||||
|
if (!list.isEmpty()) {
|
||||||
|
for (FrameList::ConstIterator it = list.begin(); it != list.end(); ++it) {
|
||||||
|
UserTextIdentificationFrame const* frame = static_cast<UserTextIdentificationFrame *>(*it);
|
||||||
|
if (!frame->description().isNull() && frame->description() == "cuesheet") {
|
||||||
|
// Remove description
|
||||||
|
StringList l = frame->fieldList();
|
||||||
|
for(StringList::Iterator it = l.begin(); it != l.end(); ++it) {
|
||||||
|
l.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return l.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float ID3v2::Tag::rg(const String &type) const
|
float ID3v2::Tag::rg(const String &type) const
|
||||||
{
|
{
|
||||||
const FrameList &list = d->frameListMap["TXXX"];
|
const FrameList &list = d->frameListMap["TXXX"];
|
||||||
|
@ -376,6 +396,32 @@ void ID3v2::Tag::setTrack(unsigned int i)
|
||||||
setTextFrame("TRCK", String::number(i));
|
setTextFrame("TRCK", String::number(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ID3v2::Tag::setCuesheet(const String &s)
|
||||||
|
{
|
||||||
|
bool createdFrame = false;
|
||||||
|
UserTextIdentificationFrame * frame = NULL;
|
||||||
|
FrameList &list = d->frameListMap["TXXX"];
|
||||||
|
for (FrameList::Iterator it = list.begin(); it != list.end(); ++it) {
|
||||||
|
if (static_cast<UserTextIdentificationFrame *>(*it)->description() == "cuesheet") {
|
||||||
|
frame = static_cast<UserTextIdentificationFrame*>(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s.isEmpty()) {
|
||||||
|
if (frame)
|
||||||
|
removeFrame(frame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (frame == NULL) {
|
||||||
|
frame = new UserTextIdentificationFrame;
|
||||||
|
frame->setDescription("cuesheet");
|
||||||
|
createdFrame = true;
|
||||||
|
}
|
||||||
|
frame->setText(s);
|
||||||
|
if (createdFrame)
|
||||||
|
addFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
void ID3v2::Tag::setRG(const String &type, float f, bool peak)
|
void ID3v2::Tag::setRG(const String &type, float f, bool peak)
|
||||||
{
|
{
|
||||||
bool createdFrame = false;
|
bool createdFrame = false;
|
||||||
|
|
|
@ -165,6 +165,8 @@ namespace TagLib {
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
|
||||||
|
virtual String cuesheet() const;
|
||||||
|
|
||||||
float rg(const String &type) const;
|
float rg(const String &type) const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
|
@ -180,6 +182,8 @@ namespace TagLib {
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
|
|
||||||
void setRG(const String &type, float f, bool peak);
|
void setRG(const String &type, float f, bool peak);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
|
|
|
@ -148,6 +148,13 @@ unsigned int Ogg::XiphComment::track() const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String Ogg::XiphComment::cuesheet() const
|
||||||
|
{
|
||||||
|
if(d->fieldListMap["CUESHEET"].isEmpty())
|
||||||
|
return String();
|
||||||
|
return d->fieldListMap["CUESHEET"].front();
|
||||||
|
}
|
||||||
|
|
||||||
float Ogg::XiphComment::rgAlbumGain() const
|
float Ogg::XiphComment::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
if(d->fieldListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
if(d->fieldListMap["REPLAYGAIN_ALBUM_GAIN"].isEmpty())
|
||||||
|
@ -231,6 +238,14 @@ void Ogg::XiphComment::setTrack(unsigned int i)
|
||||||
addField("TRACKNUMBER", String::number(i));
|
addField("TRACKNUMBER", String::number(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Ogg::XiphComment::setCuesheet(const String &s)
|
||||||
|
{
|
||||||
|
if (s.isEmpty())
|
||||||
|
removeField("CUESHEET");
|
||||||
|
else
|
||||||
|
addField("CUESHEET", s);
|
||||||
|
}
|
||||||
|
|
||||||
void Ogg::XiphComment::setRGAlbumGain(float f)
|
void Ogg::XiphComment::setRGAlbumGain(float f)
|
||||||
{
|
{
|
||||||
if (f == 0)
|
if (f == 0)
|
||||||
|
|
|
@ -88,6 +88,7 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
virtual String cuesheet() const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -101,6 +102,7 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &s);
|
virtual void setGenre(const String &s);
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -128,6 +128,11 @@ unsigned int RIFF::Info::Tag::track() const
|
||||||
return fieldText("IPRT").toInt();
|
return fieldText("IPRT").toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String RIFF::Info::Tag::cuesheet() const
|
||||||
|
{
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
float RIFF::Info::Tag::rgAlbumGain() const
|
float RIFF::Info::Tag::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -193,6 +198,10 @@ void RIFF::Info::Tag::setTrack(unsigned int i)
|
||||||
d->fieldListMap.erase("IPRT");
|
d->fieldListMap.erase("IPRT");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RIFF::Info::Tag::setCuesheet(const String &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void RIFF::Info::Tag::setRGAlbumGain(float)
|
void RIFF::Info::Tag::setRGAlbumGain(float)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,7 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
virtual String cuesheet() const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -123,6 +124,7 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &s);
|
virtual void setGenre(const String &s);
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -125,6 +125,12 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual unsigned int track() const = 0;
|
virtual unsigned int track() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Returns the embedded cuesheet; if there is no cuesheet set, this
|
||||||
|
* will return an empty string.
|
||||||
|
*/
|
||||||
|
virtual String cuesheet() const = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Returns the ReplayGain album gain; if there is no gain level set, this
|
* Returns the ReplayGain album gain; if there is no gain level set, this
|
||||||
* will return 0.
|
* will return 0.
|
||||||
|
@ -198,6 +204,12 @@ namespace TagLib {
|
||||||
*/
|
*/
|
||||||
virtual void setTrack(unsigned int i) = 0;
|
virtual void setTrack(unsigned int i) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the embedded cuesheet to \a s. If \a s is empty then this
|
||||||
|
* value will be cleared.
|
||||||
|
*/
|
||||||
|
virtual void setCuesheet(const String &s) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sets the ReplayGain album gain to \a f. If \a f is 0 then this value will
|
* Sets the ReplayGain album gain to \a f. If \a f is 0 then this value will
|
||||||
* be cleared.
|
* be cleared.
|
||||||
|
|
|
@ -213,6 +213,11 @@ unsigned int TagUnion::track() const
|
||||||
numberUnion(track);
|
numberUnion(track);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String TagUnion::cuesheet() const
|
||||||
|
{
|
||||||
|
stringUnion(cuesheet);
|
||||||
|
}
|
||||||
|
|
||||||
float TagUnion::rgAlbumGain() const
|
float TagUnion::rgAlbumGain() const
|
||||||
{
|
{
|
||||||
floatUnion(rgAlbumGain);
|
floatUnion(rgAlbumGain);
|
||||||
|
@ -273,6 +278,11 @@ void TagUnion::setTrack(unsigned int i)
|
||||||
setUnion(Track, i);
|
setUnion(Track, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagUnion::setCuesheet(const String &s)
|
||||||
|
{
|
||||||
|
setUnion(Cuesheet, s);
|
||||||
|
}
|
||||||
|
|
||||||
void TagUnion::setRGAlbumGain(float f)
|
void TagUnion::setRGAlbumGain(float f)
|
||||||
{
|
{
|
||||||
setUnion(RGAlbumGain, f);
|
setUnion(RGAlbumGain, f);
|
||||||
|
|
|
@ -67,6 +67,7 @@ namespace TagLib {
|
||||||
virtual String genre() const;
|
virtual String genre() const;
|
||||||
virtual unsigned int year() const;
|
virtual unsigned int year() const;
|
||||||
virtual unsigned int track() const;
|
virtual unsigned int track() const;
|
||||||
|
virtual String cuesheet() const;
|
||||||
virtual float rgAlbumGain() const;
|
virtual float rgAlbumGain() const;
|
||||||
virtual float rgAlbumPeak() const;
|
virtual float rgAlbumPeak() const;
|
||||||
virtual float rgTrackGain() const;
|
virtual float rgTrackGain() const;
|
||||||
|
@ -80,6 +81,7 @@ namespace TagLib {
|
||||||
virtual void setGenre(const String &s);
|
virtual void setGenre(const String &s);
|
||||||
virtual void setYear(unsigned int i);
|
virtual void setYear(unsigned int i);
|
||||||
virtual void setTrack(unsigned int i);
|
virtual void setTrack(unsigned int i);
|
||||||
|
virtual void setCuesheet(const String &s);
|
||||||
virtual void setRGAlbumGain(float f);
|
virtual void setRGAlbumGain(float f);
|
||||||
virtual void setRGAlbumPeak(float f);
|
virtual void setRGAlbumPeak(float f);
|
||||||
virtual void setRGTrackGain(float f);
|
virtual void setRGTrackGain(float f);
|
||||||
|
|
|
@ -34,6 +34,8 @@
|
||||||
NSNumber *year;
|
NSNumber *year;
|
||||||
NSNumber *track;
|
NSNumber *track;
|
||||||
|
|
||||||
|
NSString *cuesheet;
|
||||||
|
|
||||||
NSData *albumArtInternal;
|
NSData *albumArtInternal;
|
||||||
|
|
||||||
float replayGainAlbumGain;
|
float replayGainAlbumGain;
|
||||||
|
@ -109,6 +111,8 @@
|
||||||
@property(retain) NSNumber *year;
|
@property(retain) NSNumber *year;
|
||||||
@property(retain) NSNumber *track;
|
@property(retain) NSNumber *track;
|
||||||
|
|
||||||
|
@property(retain) NSString *cuesheet;
|
||||||
|
|
||||||
@property(retain, readonly) NSImage *albumArt;
|
@property(retain, readonly) NSImage *albumArt;
|
||||||
@property(retain) NSData *albumArtInternal;
|
@property(retain) NSData *albumArtInternal;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@
|
||||||
@synthesize year;
|
@synthesize year;
|
||||||
@synthesize track;
|
@synthesize track;
|
||||||
|
|
||||||
|
@synthesize cuesheet;
|
||||||
|
|
||||||
@synthesize totalFrames;
|
@synthesize totalFrames;
|
||||||
@synthesize bitrate;
|
@synthesize bitrate;
|
||||||
@synthesize channels;
|
@synthesize channels;
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
ALog(@"Could not open source for file '%@' referenced in apl", [apl file]);
|
ALog(@"Could not open source for file '%@' referenced in apl", [apl file]);
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source];
|
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source skipCue:YES];
|
||||||
|
|
||||||
if (![decoder open:source]) {
|
if (![decoder open:source]) {
|
||||||
ALog(@"Could not open decoder for source for apl");
|
ALog(@"Could not open decoder for source for apl");
|
||||||
|
|
|
@ -15,10 +15,13 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)cueSheetWithFile: (NSString *)filename;
|
+ (id)cueSheetWithFile: (NSString *)filename;
|
||||||
|
+ (id)cueSheetWithString: (NSString *)cuesheet withFilename:(NSString *)filename;
|
||||||
|
|
||||||
- (id)initWithFile:(NSString *)filename;
|
- (id)initWithFile:(NSString *)filename;
|
||||||
|
- (id)initWithString:(NSString *)cuesheet withFilename:(NSString *)filename;
|
||||||
|
|
||||||
- (void)parseFile:(NSString *)filename;
|
- (void)parseFile:(NSString *)filename;
|
||||||
|
- (void)parseString:(NSString *)contents withFilename:(NSString *)filename;
|
||||||
|
|
||||||
- (NSArray *)tracks;
|
- (NSArray *)tracks;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
return [[CueSheet alloc] initWithFile:filename];
|
return [[CueSheet alloc] initWithFile:filename];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (id)cueSheetWithString:(NSString *)cuesheet withFilename:(NSString *)filename
|
||||||
|
{
|
||||||
|
return [[CueSheet alloc] initWithString:cuesheet withFilename:filename];
|
||||||
|
}
|
||||||
|
|
||||||
- (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename
|
- (NSURL *)urlForPath:(NSString *)path relativeTo:(NSString *)baseFilename
|
||||||
{
|
{
|
||||||
NSRange protocolRange = [path rangeOfString:@"://"];
|
NSRange protocolRange = [path rangeOfString:@"://"];
|
||||||
|
@ -60,9 +65,6 @@
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- (void)parseFile:(NSString *)filename
|
- (void)parseFile:(NSString *)filename
|
||||||
{
|
{
|
||||||
NSStringEncoding encoding;
|
NSStringEncoding encoding;
|
||||||
|
@ -89,6 +91,11 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[self parseString:contents withFilename:filename];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)parseString:(NSString *)contents withFilename:(NSString *)filename
|
||||||
|
{
|
||||||
NSMutableArray *entries = [[NSMutableArray alloc] init];
|
NSMutableArray *entries = [[NSMutableArray alloc] init];
|
||||||
|
|
||||||
NSString *track = nil;
|
NSString *track = nil;
|
||||||
|
@ -262,6 +269,16 @@
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (id)initWithString:(NSString *)cuesheet withFilename:(NSString *)filename
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
[self parseString:cuesheet withFilename:filename];
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray *)tracks
|
- (NSArray *)tracks
|
||||||
{
|
{
|
||||||
return tracks;
|
return tracks;
|
||||||
|
|
|
@ -11,11 +11,13 @@
|
||||||
#import "CueSheet.h"
|
#import "CueSheet.h"
|
||||||
#import "CueSheetTrack.h"
|
#import "CueSheetTrack.h"
|
||||||
|
|
||||||
|
#import "AudioMetadataReader.h"
|
||||||
|
|
||||||
@implementation CueSheetContainer
|
@implementation CueSheetContainer
|
||||||
|
|
||||||
+ (NSArray *)fileTypes
|
+ (NSArray *)fileTypes
|
||||||
{
|
{
|
||||||
return [NSArray arrayWithObject:@"cue"];
|
return [NSArray arrayWithObjects:@"cue", @"ogg", @"opus", @"flac", @"wv", @"mp3", nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)mimeTypes
|
+ (NSArray *)mimeTypes
|
||||||
|
@ -25,7 +27,7 @@
|
||||||
|
|
||||||
+ (float)priority
|
+ (float)priority
|
||||||
{
|
{
|
||||||
return 1.0f;
|
return 16.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)urlsForContainerURL:(NSURL *)url
|
+ (NSArray *)urlsForContainerURL:(NSURL *)url
|
||||||
|
@ -41,7 +43,27 @@
|
||||||
|
|
||||||
NSMutableArray *tracks = [NSMutableArray array];
|
NSMutableArray *tracks = [NSMutableArray array];
|
||||||
|
|
||||||
CueSheet *cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
BOOL embedded = NO;
|
||||||
|
CueSheet *cuesheet = nil;
|
||||||
|
NSDictionary * fileMetadata;
|
||||||
|
|
||||||
|
NSString *ext = [url pathExtension];
|
||||||
|
if ([ext caseInsensitiveCompare:@"cue"] != NSOrderedSame)
|
||||||
|
{
|
||||||
|
// Embedded cuesheet check
|
||||||
|
fileMetadata = [NSClassFromString(@"AudioMetadataReader") metadataForURL:url skipCue:YES];
|
||||||
|
NSString * sheet = [fileMetadata objectForKey:@"cuesheet"];
|
||||||
|
if ([sheet length])
|
||||||
|
{
|
||||||
|
cuesheet = [CueSheet cueSheetWithString:sheet withFilename:[url path]];
|
||||||
|
}
|
||||||
|
embedded = YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
||||||
|
|
||||||
|
if (!cuesheet)
|
||||||
|
return embedded ? [NSMutableArray arrayWithObject:url] : tracks;
|
||||||
|
|
||||||
for (CueSheetTrack *track in [cuesheet tracks]) {
|
for (CueSheetTrack *track in [cuesheet tracks]) {
|
||||||
[tracks addObject:[NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:@"#%@", [track track]]]];
|
[tracks addObject:[NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:@"#%@", [track track]]]];
|
||||||
|
|
|
@ -24,6 +24,10 @@
|
||||||
long trackStart; //Starting frame of track.
|
long trackStart; //Starting frame of track.
|
||||||
long trackEnd; //Frames until end of track.
|
long trackEnd; //Frames until end of track.
|
||||||
|
|
||||||
|
BOOL embedded;
|
||||||
|
BOOL noFragment;
|
||||||
|
NSURL *baseURL;
|
||||||
|
|
||||||
CueSheet *cuesheet;
|
CueSheet *cuesheet;
|
||||||
CueSheetTrack *track;
|
CueSheetTrack *track;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,8 +49,35 @@
|
||||||
|
|
||||||
NSURL *url = [s url];
|
NSURL *url = [s url];
|
||||||
|
|
||||||
|
embedded = NO;
|
||||||
|
cuesheet = nil;
|
||||||
|
NSDictionary * fileMetadata;
|
||||||
|
|
||||||
|
noFragment = NO;
|
||||||
|
|
||||||
|
NSString *ext = [url pathExtension];
|
||||||
|
if ([ext caseInsensitiveCompare:@"cue"] != NSOrderedSame)
|
||||||
|
{
|
||||||
|
// Embedded cuesheet check
|
||||||
|
fileMetadata = [NSClassFromString(@"AudioMetadataReader") metadataForURL:url skipCue:YES];
|
||||||
|
NSString * sheet = [fileMetadata objectForKey:@"cuesheet"];
|
||||||
|
if ([sheet length])
|
||||||
|
{
|
||||||
|
cuesheet = [CueSheet cueSheetWithString:sheet withFilename:[url path]];
|
||||||
|
embedded = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL = url;
|
||||||
|
|
||||||
|
NSString *fragment = [url fragment];
|
||||||
|
if (!fragment || [fragment isEqualToString:@""])
|
||||||
|
noFragment = YES;
|
||||||
|
}
|
||||||
|
else
|
||||||
cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
||||||
|
|
||||||
|
if (!noFragment)
|
||||||
|
{
|
||||||
NSArray *tracks = [cuesheet tracks];
|
NSArray *tracks = [cuesheet tracks];
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < [tracks count]; i++)
|
for (i = 0; i < [tracks count]; i++)
|
||||||
|
@ -58,15 +85,17 @@
|
||||||
if ([[[tracks objectAtIndex:i] track] isEqualToString:[url fragment]]){
|
if ([[[tracks objectAtIndex:i] track] isEqualToString:[url fragment]]){
|
||||||
track = [tracks objectAtIndex:i];
|
track = [tracks objectAtIndex:i];
|
||||||
|
|
||||||
//Kind of a hackish way of accessing outside classes.
|
NSURL *trackUrl = (embedded) ? baseURL : [track url];
|
||||||
source = [NSClassFromString(@"AudioSource") audioSourceForURL:[track url]];
|
|
||||||
|
|
||||||
if (![source open:[track url]]) {
|
//Kind of a hackish way of accessing outside classes.
|
||||||
|
source = [NSClassFromString(@"AudioSource") audioSourceForURL:trackUrl];
|
||||||
|
|
||||||
|
if (![source open:url]) {
|
||||||
ALog(@"Could not open cuesheet source");
|
ALog(@"Could not open cuesheet source");
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source];
|
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source skipCue:YES];
|
||||||
|
|
||||||
if (![decoder open:source]) {
|
if (![decoder open:source]) {
|
||||||
ALog(@"Could not open cuesheet decoder");
|
ALog(@"Could not open cuesheet decoder");
|
||||||
|
@ -87,7 +116,7 @@
|
||||||
|
|
||||||
trackStart = [track time] * sampleRate;
|
trackStart = [track time] * sampleRate;
|
||||||
|
|
||||||
if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) {
|
if (nextTrack && (embedded || ([[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]))) {
|
||||||
trackEnd = [nextTrack time] * sampleRate;
|
trackEnd = [nextTrack time] * sampleRate;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -103,6 +132,39 @@
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
NSURL *trackUrl = (embedded) ? baseURL : [track url];
|
||||||
|
|
||||||
|
//Kind of a hackish way of accessing outside classes.
|
||||||
|
source = [NSClassFromString(@"AudioSource") audioSourceForURL:trackUrl];
|
||||||
|
|
||||||
|
if (![source open:url]) {
|
||||||
|
ALog(@"Could not open cuesheet source");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source skipCue:YES];
|
||||||
|
|
||||||
|
if (![decoder open:source]) {
|
||||||
|
ALog(@"Could not open cuesheet decoder");
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *properties = [decoder properties];
|
||||||
|
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
|
||||||
|
int channels = [[properties objectForKey:@"channels"] intValue];
|
||||||
|
|
||||||
|
bytesPerFrame = (bitsPerSample/8) * channels;
|
||||||
|
|
||||||
|
trackStart = 0;
|
||||||
|
|
||||||
|
trackEnd = [[properties objectForKey:@"totalFrames"] doubleValue];
|
||||||
|
|
||||||
|
[self seek: 0];
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
@ -124,8 +186,12 @@
|
||||||
|
|
||||||
- (BOOL)setTrack:(NSURL *)url
|
- (BOOL)setTrack:(NSURL *)url
|
||||||
{
|
{
|
||||||
|
// handling the file directly
|
||||||
|
if (noFragment)
|
||||||
|
return NO;
|
||||||
|
|
||||||
//Same file, just next track...this may be unnecessary since frame-based decoding is done now...
|
//Same file, just next track...this may be unnecessary since frame-based decoding is done now...
|
||||||
if ([[[track url] path] isEqualToString:[url path]] && [[[track url] host] isEqualToString:[url host]] && [[url fragment] intValue] == [[track track] intValue] + 1) {
|
if (embedded || ([[[track url] path] isEqualToString:[url path]] && [[[track url] host] isEqualToString:[url host]] && [[url fragment] intValue] == [[track track] intValue] + 1)) {
|
||||||
NSArray *tracks = [cuesheet tracks];
|
NSArray *tracks = [cuesheet tracks];
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
@ -142,13 +208,16 @@
|
||||||
nextTrack = [tracks objectAtIndex:i + 1];
|
nextTrack = [tracks objectAtIndex:i + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) {
|
if (nextTrack && (embedded || [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]])) {
|
||||||
trackEnd = [nextTrack time] * sampleRate;
|
trackEnd = [nextTrack time] * sampleRate;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
trackEnd = [[[decoder properties] objectForKey:@"totalFrames"] longValue];
|
trackEnd = [[[decoder properties] objectForKey:@"totalFrames"] longValue];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (embedded)
|
||||||
|
[self seek:0];
|
||||||
|
|
||||||
DLog(@"CHANGING TRACK!");
|
DLog(@"CHANGING TRACK!");
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
|
|
||||||
+ (float)priority
|
+ (float)priority
|
||||||
{
|
{
|
||||||
return 1.0f;
|
return 16.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSDictionary *)metadataForURL:(NSURL *)url
|
+ (NSDictionary *)metadataForURL:(NSURL *)url
|
||||||
|
@ -38,7 +38,29 @@
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
CueSheet *cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
BOOL embedded = NO;
|
||||||
|
CueSheet *cuesheet = nil;
|
||||||
|
NSDictionary * fileMetadata;
|
||||||
|
|
||||||
|
Class audioMetadataReader = NSClassFromString(@"AudioMetadataReader");
|
||||||
|
|
||||||
|
NSString *ext = [url pathExtension];
|
||||||
|
if ([ext caseInsensitiveCompare:@"cue"] != NSOrderedSame)
|
||||||
|
{
|
||||||
|
// Embedded cuesheet check
|
||||||
|
fileMetadata = [audioMetadataReader metadataForURL:url skipCue:YES];
|
||||||
|
NSString * sheet = [fileMetadata objectForKey:@"cuesheet"];
|
||||||
|
if ([sheet length])
|
||||||
|
{
|
||||||
|
cuesheet = [CueSheet cueSheetWithString:sheet withFilename:[url path]];
|
||||||
|
embedded = YES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cuesheet = [CueSheet cueSheetWithFile:[url path]];
|
||||||
|
|
||||||
|
if (!cuesheet)
|
||||||
|
return nil;
|
||||||
|
|
||||||
NSArray *tracks = [cuesheet tracks];
|
NSArray *tracks = [cuesheet tracks];
|
||||||
for (CueSheetTrack *track in tracks)
|
for (CueSheetTrack *track in tracks)
|
||||||
|
@ -46,7 +68,8 @@
|
||||||
if ([[url fragment] isEqualToString:[track track]])
|
if ([[url fragment] isEqualToString:[track track]])
|
||||||
{
|
{
|
||||||
// Class supplied by CogAudio, which is guaranteed to be present
|
// Class supplied by CogAudio, which is guaranteed to be present
|
||||||
NSDictionary * fileMetadata = [NSClassFromString(@"AudioMetadataReader") metadataForURL:[track url]];
|
if (!embedded)
|
||||||
|
fileMetadata = [audioMetadataReader metadataForURL:[track url] skipCue:YES];
|
||||||
NSDictionary * cuesheetMetadata = [NSDictionary dictionaryWithObjectsAndKeys:
|
NSDictionary * cuesheetMetadata = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[track artist], @"artist",
|
[track artist], @"artist",
|
||||||
[track album], @"album",
|
[track album], @"album",
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
TagLib::String artist, albumartist, title, album, genre, comment;
|
TagLib::String artist, albumartist, title, album, genre, comment;
|
||||||
int year, track;
|
int year, track;
|
||||||
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
float rgAlbumGain, rgAlbumPeak, rgTrackGain, rgTrackPeak;
|
||||||
|
TagLib::String cuesheet;
|
||||||
|
|
||||||
artist = tag->artist();
|
artist = tag->artist();
|
||||||
albumartist = tag->albumartist();
|
albumartist = tag->albumartist();
|
||||||
|
@ -81,6 +82,7 @@
|
||||||
album = tag->album();
|
album = tag->album();
|
||||||
genre = tag->genre();
|
genre = tag->genre();
|
||||||
comment = tag->comment();
|
comment = tag->comment();
|
||||||
|
cuesheet = tag->cuesheet();
|
||||||
|
|
||||||
year = tag->year();
|
year = tag->year();
|
||||||
[dict setObject:[NSNumber numberWithInt:year] forKey:@"year"];
|
[dict setObject:[NSNumber numberWithInt:year] forKey:@"year"];
|
||||||
|
@ -111,6 +113,9 @@
|
||||||
|
|
||||||
if (!genre.isEmpty())
|
if (!genre.isEmpty())
|
||||||
[dict setObject:[NSString stringWithUTF8String:genre.toCString(true)] forKey:@"genre"];
|
[dict setObject:[NSString stringWithUTF8String:genre.toCString(true)] forKey:@"genre"];
|
||||||
|
|
||||||
|
if (!cuesheet.isEmpty())
|
||||||
|
[dict setObject:[NSString stringWithUTF8String:cuesheet.toCString(true)] forKey:@"cuesheet"];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to load the image.
|
// Try to load the image.
|
||||||
|
|
Loading…
Reference in New Issue