SID: Add exception handling
Exception handling was quite missing from this code as well. Let's fix that too. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
8eddb7bf40
commit
034b0d20b8
3 changed files with 177 additions and 117 deletions
|
@ -35,31 +35,44 @@
|
||||||
id<CogSource> source = [audioSourceClass audioSourceForURL:url];
|
id<CogSource> source = [audioSourceClass audioSourceForURL:url];
|
||||||
|
|
||||||
if(![source open:url])
|
if(![source open:url])
|
||||||
return 0;
|
return @[];
|
||||||
|
|
||||||
if(![source seekable])
|
if(![source seekable])
|
||||||
return 0;
|
return @[];
|
||||||
|
|
||||||
[source seek:0 whence:SEEK_END];
|
[source seek:0 whence:SEEK_END];
|
||||||
long size = [source tell];
|
long size = [source tell];
|
||||||
[source seek:0 whence:SEEK_SET];
|
[source seek:0 whence:SEEK_SET];
|
||||||
|
|
||||||
|
if(!size)
|
||||||
|
return @[];
|
||||||
|
|
||||||
void *data = malloc(size);
|
void *data = malloc(size);
|
||||||
|
if(!data)
|
||||||
|
return @[];
|
||||||
|
|
||||||
[source read:data amount:size];
|
[source read:data amount:size];
|
||||||
|
|
||||||
SidTune *tune = new SidTune((const uint_least8_t *)data, (uint_least32_t)size);
|
unsigned int subsongs = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
SidTune *tune = new SidTune((const uint_least8_t *)data, (uint_least32_t)size);
|
||||||
|
|
||||||
|
if(!tune->getStatus()) {
|
||||||
|
delete tune;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidTuneInfo *info = tune->getInfo();
|
||||||
|
|
||||||
|
subsongs = info->songs();
|
||||||
|
|
||||||
if(!tune->getStatus()) {
|
|
||||||
delete tune;
|
delete tune;
|
||||||
return 0;
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught processing SID file for song count: %s", e.what());
|
||||||
|
return @[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const SidTuneInfo *info = tune->getInfo();
|
|
||||||
|
|
||||||
unsigned int subsongs = info->songs();
|
|
||||||
|
|
||||||
delete tune;
|
|
||||||
|
|
||||||
NSMutableArray *tracks = [NSMutableArray array];
|
NSMutableArray *tracks = [NSMutableArray array];
|
||||||
|
|
||||||
for(unsigned int i = 1; i <= subsongs; ++i) {
|
for(unsigned int i = 1; i <= subsongs; ++i) {
|
||||||
|
|
|
@ -85,6 +85,8 @@ static const char *extListStr[] = { ".str", NULL };
|
||||||
|
|
||||||
[source seek:0 whence:SEEK_END];
|
[source seek:0 whence:SEEK_END];
|
||||||
size_t fileSize = [source tell];
|
size_t fileSize = [source tell];
|
||||||
|
if(!fileSize)
|
||||||
|
return;
|
||||||
|
|
||||||
void *dataBytes = malloc(fileSize);
|
void *dataBytes = malloc(fileSize);
|
||||||
if(!dataBytes)
|
if(!dataBytes)
|
||||||
|
@ -162,17 +164,21 @@ static void sidTuneLoader(const char *fileName, std::vector<uint8_t> &bufferRef)
|
||||||
|
|
||||||
// Need this static initializer to create the static global tables that sidplayfp doesn't really lock access to
|
// Need this static initializer to create the static global tables that sidplayfp doesn't really lock access to
|
||||||
+ (void)initialize {
|
+ (void)initialize {
|
||||||
ReSIDfpBuilder *builder = new ReSIDfpBuilder("ReSIDfp");
|
try {
|
||||||
|
ReSIDfpBuilder *builder = new ReSIDfpBuilder("ReSIDfp");
|
||||||
|
|
||||||
if(builder) {
|
if(builder) {
|
||||||
builder->create(1);
|
builder->create(1);
|
||||||
if(builder->getStatus()) {
|
if(builder->getStatus()) {
|
||||||
builder->filter(true);
|
builder->filter(true);
|
||||||
builder->filter6581Curve(0.5);
|
builder->filter6581Curve(0.5);
|
||||||
builder->filter8580Curve(0.5);
|
builder->filter8580Curve(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete builder;
|
||||||
}
|
}
|
||||||
|
} catch (std::exception &e) {
|
||||||
delete builder;
|
ALog(@"Exception caught while doing one-time initialization of SID player: %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,61 +210,66 @@ static void sidTuneLoader(const char *fileName, std::vector<uint8_t> &bufferRef)
|
||||||
|
|
||||||
const char **extList = [extension isEqualToString:@"mus"] ? extListStr : extListEmpty;
|
const char **extList = [extension isEqualToString:@"mus"] ? extListStr : extListEmpty;
|
||||||
|
|
||||||
tune = new SidTune(sidTuneLoader, [currentUrl UTF8String], extList, true);
|
try {
|
||||||
|
tune = new SidTune(sidTuneLoader, [currentUrl UTF8String], extList, true);
|
||||||
|
|
||||||
if(!tune->getStatus())
|
if(!tune->getStatus())
|
||||||
return NO;
|
|
||||||
|
|
||||||
NSURL *url = [s url];
|
|
||||||
int track_num;
|
|
||||||
if([[url fragment] length] == 0)
|
|
||||||
track_num = 1;
|
|
||||||
else
|
|
||||||
track_num = [[url fragment] intValue];
|
|
||||||
|
|
||||||
n_channels = 1;
|
|
||||||
|
|
||||||
double defaultLength = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultSeconds"] doubleValue];
|
|
||||||
|
|
||||||
length = (int)ceil(sampleRate * defaultLength);
|
|
||||||
|
|
||||||
tune->selectSong(track_num);
|
|
||||||
|
|
||||||
engine = new sidplayfp;
|
|
||||||
|
|
||||||
engine->setRoms(kernel, basic, chargen);
|
|
||||||
|
|
||||||
if(!engine->load(tune))
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
ReSIDfpBuilder *_builder = new ReSIDfpBuilder("ReSIDfp");
|
|
||||||
builder = _builder;
|
|
||||||
|
|
||||||
if(_builder) {
|
|
||||||
_builder->create((engine->info()).maxsids());
|
|
||||||
if(_builder->getStatus()) {
|
|
||||||
_builder->filter(true);
|
|
||||||
_builder->filter6581Curve(0.5);
|
|
||||||
_builder->filter8580Curve(0.5);
|
|
||||||
}
|
|
||||||
if(!_builder->getStatus())
|
|
||||||
return NO;
|
return NO;
|
||||||
} else
|
|
||||||
|
NSURL *url = [s url];
|
||||||
|
int track_num;
|
||||||
|
if([[url fragment] length] == 0)
|
||||||
|
track_num = 1;
|
||||||
|
else
|
||||||
|
track_num = [[url fragment] intValue];
|
||||||
|
|
||||||
|
n_channels = 1;
|
||||||
|
|
||||||
|
double defaultLength = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultSeconds"] doubleValue];
|
||||||
|
|
||||||
|
length = (int)ceil(sampleRate * defaultLength);
|
||||||
|
|
||||||
|
tune->selectSong(track_num);
|
||||||
|
|
||||||
|
engine = new sidplayfp;
|
||||||
|
|
||||||
|
engine->setRoms(kernel, basic, chargen);
|
||||||
|
|
||||||
|
if(!engine->load(tune))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
ReSIDfpBuilder *_builder = new ReSIDfpBuilder("ReSIDfp");
|
||||||
|
builder = _builder;
|
||||||
|
|
||||||
|
if(_builder) {
|
||||||
|
_builder->create((engine->info()).maxsids());
|
||||||
|
if(_builder->getStatus()) {
|
||||||
|
_builder->filter(true);
|
||||||
|
_builder->filter6581Curve(0.5);
|
||||||
|
_builder->filter8580Curve(0.5);
|
||||||
|
}
|
||||||
|
if(!_builder->getStatus())
|
||||||
|
return NO;
|
||||||
|
} else
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
const SidTuneInfo *tuneInfo = tune->getInfo();
|
||||||
|
|
||||||
|
SidConfig conf = engine->config();
|
||||||
|
conf.frequency = (int)ceil(sampleRate);
|
||||||
|
conf.sidEmulation = builder;
|
||||||
|
conf.playback = SidConfig::MONO;
|
||||||
|
if(tuneInfo && (tuneInfo->sidChips() > 1))
|
||||||
|
conf.playback = SidConfig::STEREO;
|
||||||
|
if(!engine->config(conf))
|
||||||
|
return NO;
|
||||||
|
|
||||||
|
if(conf.playback == SidConfig::STEREO) {
|
||||||
|
n_channels = 2;
|
||||||
|
}
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught loading SID file: %s", e.what());
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
const SidTuneInfo *tuneInfo = tune->getInfo();
|
|
||||||
|
|
||||||
SidConfig conf = engine->config();
|
|
||||||
conf.frequency = (int)ceil(sampleRate);
|
|
||||||
conf.sidEmulation = builder;
|
|
||||||
conf.playback = SidConfig::MONO;
|
|
||||||
if(tuneInfo && (tuneInfo->sidChips() > 1))
|
|
||||||
conf.playback = SidConfig::STEREO;
|
|
||||||
if(!engine->config(conf))
|
|
||||||
return NO;
|
|
||||||
|
|
||||||
if(conf.playback == SidConfig::STEREO) {
|
|
||||||
n_channels = 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue];
|
double defaultFade = [[[[NSUserDefaultsController sharedUserDefaultsController] defaults] valueForKey:@"synthDefaultFadeSeconds"] doubleValue];
|
||||||
|
@ -299,7 +310,13 @@ static void sidTuneLoader(const char *fileName, std::vector<uint8_t> &bufferRef)
|
||||||
int16_t buffer[1024 * n_channels];
|
int16_t buffer[1024 * n_channels];
|
||||||
|
|
||||||
int framesToRender = 1024;
|
int framesToRender = 1024;
|
||||||
int rendered = engine->play(buffer, framesToRender * n_channels) / n_channels;
|
int rendered = 0;
|
||||||
|
try {
|
||||||
|
rendered = engine->play(buffer, framesToRender * n_channels) / n_channels;
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught while playing SID file: %s", e.what());
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
if(rendered <= 0)
|
if(rendered <= 0)
|
||||||
return nil;
|
return nil;
|
||||||
|
@ -343,8 +360,13 @@ static void sidTuneLoader(const char *fileName, std::vector<uint8_t> &bufferRef)
|
||||||
|
|
||||||
- (long)seek:(long)frame {
|
- (long)seek:(long)frame {
|
||||||
if(frame < renderedTotal) {
|
if(frame < renderedTotal) {
|
||||||
engine->load(tune);
|
|
||||||
renderedTotal = 0;
|
renderedTotal = 0;
|
||||||
|
try {
|
||||||
|
engine->load(tune);
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught reloading SID tune for seeking: %s", e.what());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t sampleBuffer[1024 * 2];
|
int16_t sampleBuffer[1024 * 2];
|
||||||
|
@ -352,48 +374,58 @@ static void sidTuneLoader(const char *fileName, std::vector<uint8_t> &bufferRef)
|
||||||
long remain = (frame - renderedTotal) % 32;
|
long remain = (frame - renderedTotal) % 32;
|
||||||
frame /= 32;
|
frame /= 32;
|
||||||
renderedTotal /= 32;
|
renderedTotal /= 32;
|
||||||
engine->fastForward(100 * 32);
|
|
||||||
|
|
||||||
while(renderedTotal < frame) {
|
try {
|
||||||
long todo = frame - renderedTotal;
|
engine->fastForward(100 * 32);
|
||||||
if(todo > 1024)
|
|
||||||
todo = 1024;
|
|
||||||
int done = engine->play(sampleBuffer, (uint_least32_t)(todo * n_channels)) / n_channels;
|
|
||||||
|
|
||||||
if(done < todo) {
|
while(renderedTotal < frame) {
|
||||||
if(engine->error())
|
long todo = frame - renderedTotal;
|
||||||
return -1;
|
if(todo > 1024)
|
||||||
|
todo = 1024;
|
||||||
|
int done = engine->play(sampleBuffer, (uint_least32_t)(todo * n_channels)) / n_channels;
|
||||||
|
|
||||||
renderedTotal = length;
|
if(done < todo) {
|
||||||
break;
|
if(engine->error())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
renderedTotal = length;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderedTotal += todo;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderedTotal += todo;
|
renderedTotal *= 32;
|
||||||
|
engine->fastForward(100);
|
||||||
|
|
||||||
|
if(remain)
|
||||||
|
renderedTotal += engine->play(sampleBuffer, (uint_least32_t)(remain * n_channels)) / n_channels;
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught while brute force seeking SID file: %s", e.what());
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderedTotal *= 32;
|
|
||||||
engine->fastForward(100);
|
|
||||||
|
|
||||||
if(remain)
|
|
||||||
renderedTotal += engine->play(sampleBuffer, (uint_least32_t)(remain * n_channels)) / n_channels;
|
|
||||||
|
|
||||||
return renderedTotal;
|
return renderedTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cleanUp {
|
- (void)cleanUp {
|
||||||
if(builder) {
|
try {
|
||||||
delete builder;
|
if(builder) {
|
||||||
builder = NULL;
|
delete builder;
|
||||||
}
|
builder = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if(engine) {
|
if(engine) {
|
||||||
delete engine;
|
delete engine;
|
||||||
engine = NULL;
|
engine = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tune) {
|
if(tune) {
|
||||||
delete tune;
|
delete tune;
|
||||||
tune = NULL;
|
tune = NULL;
|
||||||
|
}
|
||||||
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught while deleting SID player instances: %s", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
source = nil;
|
source = nil;
|
||||||
|
|
|
@ -30,34 +30,49 @@
|
||||||
id<CogSource> source = [audioSourceClass audioSourceForURL:url];
|
id<CogSource> source = [audioSourceClass audioSourceForURL:url];
|
||||||
|
|
||||||
if(![source open:url])
|
if(![source open:url])
|
||||||
return 0;
|
return @{};
|
||||||
|
|
||||||
if(![source seekable])
|
if(![source seekable])
|
||||||
return 0;
|
return @{};
|
||||||
|
|
||||||
[source seek:0 whence:SEEK_END];
|
[source seek:0 whence:SEEK_END];
|
||||||
long size = [source tell];
|
long size = [source tell];
|
||||||
[source seek:0 whence:SEEK_SET];
|
[source seek:0 whence:SEEK_SET];
|
||||||
|
|
||||||
|
if(!size)
|
||||||
|
return @{};
|
||||||
|
|
||||||
void *data = malloc(size);
|
void *data = malloc(size);
|
||||||
|
if(!data)
|
||||||
|
return @{};
|
||||||
|
|
||||||
[source read:data amount:size];
|
[source read:data amount:size];
|
||||||
|
|
||||||
SidTune *tune = new SidTune((const uint_least8_t *)data, (uint_least32_t)size);
|
NSString *title = @"";
|
||||||
|
NSString *titletag = @"title";
|
||||||
|
NSString *artist = @"";
|
||||||
|
|
||||||
|
try {
|
||||||
|
SidTune *tune = new SidTune((const uint_least8_t *)data, (uint_least32_t)size);
|
||||||
|
|
||||||
|
if(!tune->getStatus()) {
|
||||||
|
delete tune;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidTuneInfo *info = tune->getInfo();
|
||||||
|
|
||||||
|
unsigned int count = info->numberOfInfoStrings();
|
||||||
|
title = count >= 1 ? [guess_encoding_of_string(info->infoString(0)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
|
||||||
|
titletag = info->songs() > 1 ? @"album" : @"title";
|
||||||
|
artist = count >= 2 ? [guess_encoding_of_string(info->infoString(1)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
|
||||||
|
|
||||||
if(!tune->getStatus()) {
|
|
||||||
delete tune;
|
delete tune;
|
||||||
return 0;
|
} catch (std::exception &e) {
|
||||||
|
ALog(@"Exception caught while reading SID tags: %s", e.what());
|
||||||
|
return @{};
|
||||||
}
|
}
|
||||||
|
|
||||||
const SidTuneInfo *info = tune->getInfo();
|
|
||||||
|
|
||||||
unsigned int count = info->numberOfInfoStrings();
|
|
||||||
NSString *title = count >= 1 ? [guess_encoding_of_string(info->infoString(0)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
|
|
||||||
NSString *titletag = info->songs() > 1 ? @"album" : @"title";
|
|
||||||
NSString *artist = count >= 2 ? [guess_encoding_of_string(info->infoString(1)) stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] : @"";
|
|
||||||
|
|
||||||
delete tune;
|
|
||||||
|
|
||||||
return @{titletag: title, @"artist": artist};
|
return @{titletag: title, @"artist": artist};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue