2007-10-20 16:15:02 +00:00
|
|
|
#import "APLDecoder.h"
|
|
|
|
#import "APLFile.h"
|
|
|
|
|
2013-10-11 12:03:55 +00:00
|
|
|
#import "Logging.h"
|
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
@implementation APLDecoder
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)fileTypes {
|
|
|
|
return @[@"apl"];
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)mimeTypes {
|
|
|
|
return @[@"application/x-apl"];
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
|
|
|
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
+ (float)priority {
|
2022-02-07 05:49:27 +00:00
|
|
|
return 1.0;
|
Implemented support for multiple decoders per file name extension, with a floating point priority control per interface. In the event that more than one input is registered to a given extension, and we match that extension, it will be passed off to an instance of the multi-decoder wrapper, which will try opening the file with all of the decoders in order of priority, until either one of them accepts it, or all of them have failed. This paves the way for adding a VGMSTREAM input, so I can give it a very low priority, since it has several formats that are verified by file name extension only. All current inputs have been given a priority of 1.0, except for CoreAudio, which was given a priority of 0.5, because it contains an MP3 and AC3 decoders that I'd rather not use if I don't have to.
2013-10-21 17:54:11 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
+ (NSArray *)fileTypeAssociations {
|
|
|
|
return @[
|
|
|
|
@[@"APL Link File", @"song.icns", @"apl"]
|
|
|
|
];
|
2022-01-18 11:06:03 +00:00
|
|
|
}
|
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
- (NSDictionary *)properties {
|
|
|
|
NSMutableDictionary *properties = [[decoder properties] mutableCopy];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
// Need to alter length
|
2022-06-17 13:39:02 +00:00
|
|
|
[properties setObject:@(trackLength) forKey:@"totalFrames"];
|
2022-02-09 03:56:39 +00:00
|
|
|
return [NSDictionary dictionaryWithDictionary:properties];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)metadata {
|
|
|
|
return @{};
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (BOOL)open:(id<CogSource>)s {
|
|
|
|
// DLog(@"Loading apl...");
|
|
|
|
if(![[s url] isFileURL])
|
2007-10-20 16:15:02 +00:00
|
|
|
return NO;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
NSURL *url = [s url];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
apl = [APLFile createWithFile:[url path]];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
// Kind of a hackish way of accessing outside classes.
|
2007-10-20 16:15:02 +00:00
|
|
|
source = [NSClassFromString(@"AudioSource") audioSourceForURL:[apl file]];
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
if(![source open:[apl file]]) {
|
2013-10-11 12:03:55 +00:00
|
|
|
ALog(@"Could not open source for file '%@' referenced in apl", [apl file]);
|
2007-10-20 16:15:02 +00:00
|
|
|
return NO;
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
decoder = [NSClassFromString(@"AudioDecoder") audioDecoderForSource:source skipCue:YES];
|
|
|
|
|
|
|
|
if(![decoder open:source]) {
|
2013-10-11 12:03:55 +00:00
|
|
|
ALog(@"Could not open decoder for source for apl");
|
2007-10-20 16:15:02 +00:00
|
|
|
return NO;
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
NSDictionary *properties = [decoder properties];
|
|
|
|
int bitsPerSample = [[properties objectForKey:@"bitsPerSample"] intValue];
|
|
|
|
int channels = [[properties objectForKey:@"channels"] intValue];
|
2022-02-07 05:49:27 +00:00
|
|
|
// float sampleRate = [[properties objectForKey:@"sampleRate"] floatValue];
|
|
|
|
|
|
|
|
bytesPerFrame = (bitsPerSample / 8) * channels;
|
|
|
|
|
|
|
|
if([apl endBlock] > [apl startBlock])
|
2008-05-09 21:24:49 +00:00
|
|
|
trackEnd = [apl endBlock]; //([apl endBlock] / sampleRate) * 1000.0;
|
2022-02-07 05:49:27 +00:00
|
|
|
else
|
2008-05-09 21:24:49 +00:00
|
|
|
trackEnd = [[properties objectForKey:@"totalFrames"] doubleValue]; //!!? double?
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-05-09 21:24:49 +00:00
|
|
|
trackStart = [apl startBlock];
|
2007-10-20 16:15:02 +00:00
|
|
|
trackLength = trackEnd - trackStart;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
[self seek:0];
|
|
|
|
|
|
|
|
// Note: Should register for observations of the decoder, but laziness consumes all.
|
2007-10-20 16:15:02 +00:00
|
|
|
[self willChangeValueForKey:@"properties"];
|
|
|
|
[self didChangeValueForKey:@"properties"];
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)close {
|
2022-02-07 05:49:27 +00:00
|
|
|
if(decoder) {
|
2007-10-20 16:15:02 +00:00
|
|
|
[decoder close];
|
|
|
|
decoder = nil;
|
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
|
|
|
source = nil;
|
|
|
|
apl = nil;
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
|
|
|
|
2016-06-19 19:57:18 +00:00
|
|
|
- (void)dealloc {
|
2022-02-07 05:49:27 +00:00
|
|
|
[self close];
|
2016-06-19 19:57:18 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (long)seek:(long)frame {
|
|
|
|
if(frame > trackEnd - trackStart) {
|
|
|
|
// need a better way of returning fail.
|
2008-05-09 21:24:49 +00:00
|
|
|
return -1;
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-05-09 21:24:49 +00:00
|
|
|
frame += trackStart;
|
2022-02-07 05:49:27 +00:00
|
|
|
|
2008-05-09 21:24:49 +00:00
|
|
|
framePosition = [decoder seek:frame];
|
|
|
|
|
|
|
|
return framePosition;
|
2007-10-20 16:15:02 +00:00
|
|
|
}
|
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
- (int)readAudio:(void *)buf frames:(UInt32)frames {
|
|
|
|
if(framePosition + frames > trackEnd)
|
2021-04-30 01:16:24 +00:00
|
|
|
frames = (UInt32)(trackEnd - framePosition);
|
2008-05-09 21:24:49 +00:00
|
|
|
|
2022-02-07 05:49:27 +00:00
|
|
|
if(!frames) {
|
2013-10-11 12:03:55 +00:00
|
|
|
DLog(@"APL readAudio Returning 0");
|
2007-10-20 16:15:02 +00:00
|
|
|
return 0;
|
2008-05-09 21:24:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int n = [decoder readAudio:buf frames:frames];
|
|
|
|
framePosition += n;
|
2007-10-20 16:15:02 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2022-02-10 10:15:48 +00:00
|
|
|
- (BOOL)isSilence {
|
|
|
|
if([decoder respondsToSelector:@selector(isSilence)])
|
|
|
|
return [decoder isSilence];
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2007-10-20 16:15:02 +00:00
|
|
|
@end
|