2007-10-11 23:11:58 +00:00
|
|
|
//
|
|
|
|
// GameFile.m
|
|
|
|
// Cog
|
|
|
|
//
|
|
|
|
// Created by Vincent Spader on 5/29/06.
|
|
|
|
// Copyright 2006 Vincent Spader. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "GameDecoder.h"
|
|
|
|
|
|
|
|
@implementation GameDecoder
|
|
|
|
|
|
|
|
gme_err_t readCallback( void* data, void* out, long count )
|
|
|
|
{
|
|
|
|
GameDecoder *decoder = (GameDecoder *)data;
|
|
|
|
NSLog(@"Amount: %li", count);
|
|
|
|
int n = [[decoder source] read:out amount:count];
|
|
|
|
NSLog(@"Read: %i", n);
|
|
|
|
if (n <= 0) {
|
|
|
|
|
|
|
|
NSLog(@"ERROR!");
|
|
|
|
return (gme_err_t)1; //Return non-zero for error
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; //Return 0 for no error
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)open:(id<CogSource>)s
|
|
|
|
{
|
|
|
|
[self setSource:s];
|
|
|
|
|
|
|
|
//We need file-size to use GME
|
|
|
|
if (![source seekable]) {
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
gme_err_t error;
|
|
|
|
|
|
|
|
NSString *ext = [[[[source url] path] pathExtension] lowercaseString];
|
|
|
|
|
|
|
|
gme_type_t type = gme_identify_extension([ext UTF8String]);
|
|
|
|
if (!type)
|
|
|
|
{
|
|
|
|
NSLog(@"No type!");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
emu = gme_new_emu(type, 44100);
|
|
|
|
if (!emu)
|
|
|
|
{
|
|
|
|
NSLog(@"No new emu!");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
[source seek:0 whence:SEEK_END];
|
|
|
|
long size = [source tell];
|
|
|
|
[source seek:0 whence:SEEK_SET];
|
|
|
|
|
|
|
|
NSLog(@"Size: %li", size);
|
|
|
|
|
|
|
|
error = gme_load_custom(emu, readCallback, size, self);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
NSLog(@"ERROR Loding custom!");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
int track_num = [[[source url] fragment] intValue]; //What if theres no fragment? Assuming we get 0.
|
|
|
|
|
|
|
|
track_info_t info;
|
|
|
|
error = gme_track_info( emu, &info, track_num );
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
NSLog(@"Unable to get track info");
|
|
|
|
}
|
|
|
|
|
|
|
|
//As recommended
|
|
|
|
if (info.length > 0) {
|
|
|
|
NSLog(@"Using length: %li", info.length);
|
|
|
|
length = info.length;
|
|
|
|
}
|
|
|
|
else if (info.loop_length > 0) {
|
|
|
|
NSLog(@"Using loop length: %li", info.loop_length);
|
|
|
|
length = info.intro_length + 2*info.loop_length;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
length = 150000;
|
|
|
|
NSLog(@"Setting default: %li", length);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSLog(@"Length: %li", length);
|
|
|
|
|
|
|
|
NSLog(@"Track num: %i", track_num);
|
|
|
|
error = gme_start_track(emu, track_num);
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
NSLog(@"Error starting track");
|
|
|
|
return NO;
|
|
|
|
}
|
2007-10-12 02:55:59 +00:00
|
|
|
|
|
|
|
[self willChangeValueForKey:@"properties"];
|
|
|
|
[self didChangeValueForKey:@"properties"];
|
2007-10-11 23:11:58 +00:00
|
|
|
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)properties
|
|
|
|
{
|
|
|
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithInt:0], @"bitrate",
|
|
|
|
[NSNumber numberWithFloat:44100], @"sampleRate",
|
2008-02-10 16:04:28 +00:00
|
|
|
[NSNumber numberWithLong:length*44.1], @"totalFrames",
|
2007-10-11 23:11:58 +00:00
|
|
|
[NSNumber numberWithInt:sizeof(short)*8], @"bitsPerSample", //Samples are short
|
|
|
|
[NSNumber numberWithInt:2], @"channels", //output from gme_play is in stereo
|
|
|
|
[NSNumber numberWithBool:[source seekable]], @"seekable",
|
|
|
|
@"host", @"endian",
|
|
|
|
nil];
|
|
|
|
}
|
|
|
|
|
2008-02-10 16:04:28 +00:00
|
|
|
- (int)readAudio:(void *)buf frames:(UInt32)frames
|
2007-10-11 23:11:58 +00:00
|
|
|
{
|
2008-02-10 16:04:28 +00:00
|
|
|
int numSamples = frames * 2; //channels = 2
|
2007-10-11 23:11:58 +00:00
|
|
|
|
|
|
|
if (gme_track_ended(emu) || length < gme_tell(emu)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
gme_play(emu, numSamples, (short int *)buf);
|
|
|
|
|
|
|
|
//Some formats support length, but we'll add that in the future.
|
|
|
|
//(From gme.txt) If track length, then use it. If loop length, play for intro + loop * 2. Otherwise, default to 2.5 minutes
|
2008-02-10 16:04:28 +00:00
|
|
|
return frames; //GME will always generate samples. There's no real EOS.
|
2007-10-11 23:11:58 +00:00
|
|
|
}
|
|
|
|
|
2008-02-10 16:04:28 +00:00
|
|
|
- (long)seek:(long)frame
|
2007-10-11 23:11:58 +00:00
|
|
|
{
|
|
|
|
gme_err_t error;
|
2008-02-10 16:04:28 +00:00
|
|
|
error = gme_seek(emu, frame/44.1);
|
2007-10-11 23:11:58 +00:00
|
|
|
if (error) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-02-10 16:04:28 +00:00
|
|
|
return frame;
|
2007-10-11 23:11:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)close
|
|
|
|
{
|
|
|
|
if (emu) {
|
|
|
|
gme_delete(emu);
|
|
|
|
emu = NULL;
|
|
|
|
}
|
|
|
|
if (source) {
|
|
|
|
[source close];
|
|
|
|
[self setSource:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *)fileTypes
|
|
|
|
{
|
2007-10-20 03:17:43 +00:00
|
|
|
NSMutableArray *types = [NSMutableArray array];
|
|
|
|
gme_type_t const* type = gme_type_list();
|
|
|
|
while(*type)
|
|
|
|
{
|
|
|
|
//We're digging a little deep here, but there seems to be no other choice.
|
|
|
|
[types addObject:[NSString stringWithCString:(*type)->extension_ encoding: NSASCIIStringEncoding]];
|
|
|
|
|
|
|
|
type++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [[types copy] autorelease];
|
2007-10-11 23:11:58 +00:00
|
|
|
}
|
|
|
|
|
2007-10-14 18:39:58 +00:00
|
|
|
+ (NSArray *)mimeTypes
|
|
|
|
{
|
2007-10-20 03:17:43 +00:00
|
|
|
return nil;
|
2007-10-14 18:39:58 +00:00
|
|
|
}
|
|
|
|
|
2007-10-11 23:11:58 +00:00
|
|
|
- (void)setSource:(id<CogSource>)s
|
|
|
|
{
|
|
|
|
[s retain];
|
|
|
|
[source release];
|
|
|
|
source = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id<CogSource>)source
|
|
|
|
{
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
|
|
|
@end
|