2006-06-03 20:26:19 +00:00
//
// ShnFile.mm
// Cog
//
// Created by Vincent Spader on 6/6/05.
// Copyright 2005 Vincent Spader All rights reserved.
//
2007-02-24 20:36:27 +00:00
#import "ShortenDecoder.h"
2006-06-03 20:26:19 +00:00
2007-02-24 20:36:27 +00:00
@implementation ShortenDecoder
2006-06-03 20:26:19 +00:00
2022-02-07 05:49:27 +00:00
- (BOOL)open:(id<CogSource>)source {
2007-03-04 18:46:44 +00:00
NSURL *url = [source url];
2007-10-13 07:51:42 +00:00
2022-02-07 05:49:27 +00:00
if(![[url scheme] isEqualToString:@"file"])
2007-03-04 18:46:44 +00:00
return NO;
2022-02-07 05:49:27 +00:00
decoder = new shn_reader;
if(!decoder) {
2006-06-03 20:26:19 +00:00
return NO;
}
2022-02-07 05:49:27 +00:00
2007-02-24 20:36:27 +00:00
decoder->open([[url path] UTF8String], true);
2022-02-07 05:49:27 +00:00
2007-05-16 22:56:54 +00:00
bufferSize = decoder->shn_get_buffer_block_size(NUM_DEFAULT_BUFFER_BLOCKS);
2022-02-07 05:49:27 +00:00
2007-05-27 15:11:30 +00:00
bool seekTable;
2007-05-27 14:48:01 +00:00
decoder->file_info(NULL, &channels, &frequency, NULL, &bitsPerSample, &seekTable);
2007-05-27 15:11:30 +00:00
seekable = seekTable == true ? YES : NO;
2022-02-07 05:49:27 +00:00
totalFrames = (decoder->shn_get_song_length() * frequency) / 1000.0;
2006-06-03 20:26:19 +00:00
decoder->go();
2007-05-11 01:33:05 +00:00
[self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"];
2022-02-07 05:49:27 +00:00
2006-06-03 20:26:19 +00:00
return YES;
}
2022-07-10 22:14:47 +00:00
- (AudioChunk *)readAudio {
long frames = 1024;
2022-02-07 05:49:27 +00:00
long bytesPerFrame = channels * (bitsPerSample / 8);
2021-04-30 01:16:24 +00:00
long amountRead;
2007-05-16 01:30:28 +00:00
2022-07-10 22:14:47 +00:00
id audioChunkClass = NSClassFromString(@"AudioChunk");
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]];
uint8_t buffer[bytesPerFrame * 1024];
void *buf = (void *)buffer;
2022-02-07 05:49:27 +00:00
// For some reason a busy loop is causing pops when output is set to 48000. Probably CPU starvation, since the SHN decoder seems to use a multithreaded nonblocking approach.
do {
2008-03-30 15:43:28 +00:00
amountRead = decoder->read(buf, frames * bytesPerFrame);
} while(amountRead == -1);
2007-05-11 01:33:05 +00:00
2022-07-10 22:14:47 +00:00
[chunk assignSamples:buf frameCount:amountRead / bytesPerFrame];
return chunk;
2006-06-03 20:26:19 +00:00
}
2022-02-07 05:49:27 +00:00
- (long)seek:(long)sample {
unsigned int sec = sample / frequency;
2006-06-03 20:26:19 +00:00
decoder->seek(sec);
2022-02-07 05:49:27 +00:00
2008-03-30 15:43:28 +00:00
return sample;
2006-06-03 20:26:19 +00:00
}
2022-02-07 05:49:27 +00:00
- (void)close {
if(decoder) {
2006-06-03 20:26:19 +00:00
decoder->exit();
delete decoder;
2022-02-07 05:49:27 +00:00
decoder = NULL;
2006-06-03 20:26:19 +00:00
}
/*if (shn_cleanup_decoder(handle))
2022-02-07 05:49:27 +00:00
shn_unload(handle);*/
2006-06-03 20:26:19 +00:00
}
2022-02-07 05:49:27 +00:00
- (void)dealloc {
[self close];
2016-06-19 19:57:18 +00:00
}
2022-02-07 05:49:27 +00:00
- (NSDictionary *)properties {
2022-06-17 13:39:02 +00:00
return @{ @"channels": @(channels),
@"bitsPerSample": @(bitsPerSample),
@"sampleRate": @(frequency),
@"totalFrames": @(totalFrames),
@"seekable": @(seekable),
@"codec": @"Shorten",
@"endian": @"little",
@"encoding": @"lossless" };
2007-02-24 20:36:27 +00:00
}
2022-02-09 03:56:39 +00:00
- (NSDictionary *)metadata {
return @{};
}
2022-02-07 05:49:27 +00:00
+ (NSArray *)fileTypes {
2022-01-19 02:12:57 +00:00
return @[@"shn"];
2007-02-24 20:36:27 +00:00
}
2022-02-07 05:49:27 +00:00
+ (NSArray *)mimeTypes {
return @[@"application/x-shorten"]; // This is basically useless, since we cant stream shorten yet
2007-10-14 18:39:58 +00:00
}
2022-02-07 05:49:27 +00:00
+ (float)priority {
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 @[
@[@"Shorten File", @"shn.icns", @"shn"]
];
2022-01-18 11:06:03 +00:00
}
2006-06-03 20:26:19 +00:00
@end