2007-10-12 01:03:12 +00:00
|
|
|
//
|
|
|
|
// DumbFile.m
|
|
|
|
// Cog
|
|
|
|
//
|
|
|
|
// Created by Vincent Spader on 5/29/06.
|
|
|
|
// Copyright 2006 Vincent Spader. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "DumbDecoder.h"
|
|
|
|
|
|
|
|
@implementation DumbDecoder
|
|
|
|
|
|
|
|
int skipCallback(void *f, long n)
|
|
|
|
{
|
|
|
|
DumbDecoder *decoder = (DumbDecoder *)f;
|
|
|
|
|
|
|
|
if (![[decoder source] seek:n whence: SEEK_CUR])
|
|
|
|
{
|
|
|
|
return 1; //Non-zero is error
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0; //Zero for success
|
|
|
|
}
|
|
|
|
|
|
|
|
int getCharCallback(void *f)
|
|
|
|
{
|
|
|
|
DumbDecoder *decoder = (DumbDecoder *)f;
|
|
|
|
|
2007-10-12 01:46:31 +00:00
|
|
|
unsigned char c;
|
2007-10-12 01:03:12 +00:00
|
|
|
|
|
|
|
if ([[decoder source] read:&c amount:1] < 1)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
long readCallback(char *ptr, long n, void *f)
|
|
|
|
{
|
|
|
|
DumbDecoder *decoder = (DumbDecoder *)f;
|
|
|
|
|
|
|
|
return [[decoder source] read:ptr amount:n];
|
|
|
|
}
|
|
|
|
|
|
|
|
void closeCallback(void *f)
|
|
|
|
{
|
|
|
|
// DumbDecoder *decoder = (DumbDecoder *)f;
|
|
|
|
NSLog(@"CLOSE"); //I DO NOTHING
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)open:(id<CogSource>)s
|
|
|
|
{
|
|
|
|
[self setSource:s];
|
|
|
|
|
|
|
|
dfs.open = NULL;
|
|
|
|
dfs.skip = skipCallback;
|
|
|
|
dfs.getc = getCharCallback;
|
|
|
|
dfs.getnc = readCallback;
|
|
|
|
dfs.close = closeCallback;
|
|
|
|
|
2007-10-13 02:20:51 +00:00
|
|
|
// dumb_register_stdfiles();
|
2007-10-12 01:03:12 +00:00
|
|
|
|
|
|
|
df = dumbfile_open_ex(self, &dfs);
|
|
|
|
if (!df)
|
|
|
|
{
|
|
|
|
NSLog(@"EX Failed");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *ext = [[[[s url] path] pathExtension] lowercaseString];
|
|
|
|
if ([ext isEqualToString:@"it"])
|
|
|
|
duh = dumb_read_it(df);
|
|
|
|
else if ([ext isEqualToString:@"xm"])
|
2007-10-12 01:46:31 +00:00
|
|
|
duh = dumb_read_xm(df);
|
2007-10-12 01:03:12 +00:00
|
|
|
else if ([ext isEqualToString:@"s3m"])
|
|
|
|
duh = dumb_read_s3m(df);
|
|
|
|
else if ([ext isEqualToString:@"mod"])
|
|
|
|
duh = dumb_read_mod(df);
|
|
|
|
else {
|
|
|
|
NSLog(@"DUH IS NUL!!!");
|
|
|
|
duh = NULL;
|
|
|
|
}
|
|
|
|
if (!duh)
|
|
|
|
{
|
|
|
|
NSLog(@"Failed to create duh");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = duh_get_length(duh);
|
|
|
|
|
|
|
|
|
|
|
|
dsr = duh_start_sigrenderer(duh, 0, 2 /* stereo */, 0 /* start from the beginning */);
|
|
|
|
if (!dsr)
|
|
|
|
{
|
|
|
|
NSLog(@"Failed to create dsr");
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
|
2007-10-12 02:55:59 +00:00
|
|
|
[self willChangeValueForKey:@"properties"];
|
|
|
|
[self didChangeValueForKey:@"properties"];
|
|
|
|
|
2007-10-12 01:03:12 +00:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary *)properties
|
|
|
|
{
|
|
|
|
return [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
[NSNumber numberWithInt:0], @"bitrate",
|
|
|
|
[NSNumber numberWithFloat:44100], @"sampleRate",
|
2008-02-10 15:56:18 +00:00
|
|
|
[NSNumber numberWithDouble:((length / 65.536f)*44.1000)], @"totalFrames",
|
2007-10-12 01:03:12 +00:00
|
|
|
[NSNumber numberWithInt:16], @"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 15:56:18 +00:00
|
|
|
- (int)readAudio:(void *)buf frames:(UInt32)frames
|
2007-10-12 01:03:12 +00:00
|
|
|
{
|
|
|
|
if (duh_sigrenderer_get_position(dsr) > length) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-10 15:56:18 +00:00
|
|
|
return duh_render(dsr, 16 /* shorts */, 0 /* not unsigned */, 1.0 /* volume */, 65536.0f / 44100.0f /* 65536 hz? */, frames, buf);
|
2007-10-12 01:03:12 +00:00
|
|
|
}
|
|
|
|
|
2008-02-10 15:56:18 +00:00
|
|
|
- (long)seek:(long)frame
|
2007-10-12 01:03:12 +00:00
|
|
|
{
|
|
|
|
double pos = (double)duh_sigrenderer_get_position(dsr) / 65.536f;
|
2008-02-10 15:56:18 +00:00
|
|
|
double seekPos = frame/44.100;
|
2007-10-12 01:03:12 +00:00
|
|
|
|
|
|
|
if (seekPos < pos) {
|
|
|
|
//Reset. Dumb cannot seek backwards. It's dumb.
|
|
|
|
[self cleanUp];
|
2007-10-12 01:49:36 +00:00
|
|
|
|
|
|
|
[source seek:0 whence:SEEK_SET];
|
2007-10-12 01:03:12 +00:00
|
|
|
[self open:source];
|
|
|
|
|
|
|
|
pos = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int numSamples = (seekPos - pos)/1000 * 44100;
|
|
|
|
|
|
|
|
duh_sigrenderer_generate_samples(dsr, 1.0f, 65536.0f / 44100.0f, numSamples, NULL);
|
|
|
|
|
2008-02-10 15:56:18 +00:00
|
|
|
return frame;
|
2007-10-12 01:03:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)cleanUp
|
|
|
|
{
|
|
|
|
if (dsr) {
|
|
|
|
duh_end_sigrenderer(dsr);
|
|
|
|
dsr = NULL;
|
|
|
|
}
|
|
|
|
if (duh) {
|
|
|
|
unload_duh(duh);
|
|
|
|
duh = NULL;
|
|
|
|
}
|
|
|
|
if (df) {
|
|
|
|
dumbfile_close(df);
|
|
|
|
df = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)close
|
|
|
|
{
|
|
|
|
[self cleanUp];
|
|
|
|
|
|
|
|
if (source) {
|
|
|
|
[source close];
|
|
|
|
[self setSource:nil];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setSource:(id<CogSource>)s
|
|
|
|
{
|
|
|
|
[s retain];
|
|
|
|
[source release];
|
|
|
|
source = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id<CogSource>)source
|
|
|
|
{
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
2007-10-14 18:39:58 +00:00
|
|
|
+ (NSArray *)fileTypes
|
|
|
|
{
|
|
|
|
return [NSArray arrayWithObjects:@"it", @"xm", @"s3m", @"mod", nil];
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (NSArray *)mimeTypes
|
|
|
|
{
|
|
|
|
return [NSArray arrayWithObjects:@"audio/x-it", @"audio/x-xm", @"audio/x-s3m", @"audio/x-mod", nil];
|
|
|
|
}
|
|
|
|
|
2007-10-12 01:03:12 +00:00
|
|
|
@end
|