cog/Plugins/Dumb/DumbDecoder.m

271 lines
5.5 KiB
Matlab
Raw Normal View History

//
// 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)
{
id source = (id)f;
if (![source seek:n whence: SEEK_CUR])
{
return 1; //Non-zero is error
}
return 0; //Zero for success
}
int getCharCallback(void *f)
{
id source = (id)f;
2007-10-12 01:46:31 +00:00
unsigned char c;
if ([source read:&c amount:1] < 1)
{
return -1;
}
return c;
}
long readCallback(char *ptr, long n, void *f)
{
id source = (id)f;
return [source read:ptr amount:n];
}
2013-09-28 03:24:23 +00:00
int seekCallback(void *f, long n)
{
id source = (id)f;
2013-09-28 03:24:23 +00:00
if (![source seekable]) return -1;
2013-09-28 03:24:23 +00:00
if ([source seek:n whence:SEEK_SET]) return 0;
2013-09-28 03:24:23 +00:00
else return -1;
}
long getsizeCallback(void *f)
{
id source = (id)f;
2013-09-28 03:24:23 +00:00
if (![source seekable]) return 0;
2013-09-28 03:24:23 +00:00
long current_offset = [source tell];
2013-09-28 03:24:23 +00:00
[source seek:0 whence:SEEK_END];
2013-09-28 03:24:23 +00:00
long size = [source tell];
2013-09-28 03:24:23 +00:00
[source seek:current_offset whence:SEEK_SET];
2013-09-28 03:24:23 +00:00
return size;
}
void oneTimeInit()
{
static bool initialized = false;
if (!initialized)
{
}
}
DUMBFILE_SYSTEM dfs = {
.open = NULL,
.skip = skipCallback,
.getc = getCharCallback,
.getnc = readCallback,
.close = NULL,
.seek = seekCallback,
.get_size = getsizeCallback
};
int callbackLoop(void *data)
{
long * loops = (long *) data;
++ *loops;
return 0;
}
- (BOOL)open:(id<CogSource>)s
{
[self setSource:s];
DUMBFILE *df;
// dumb_register_stdfiles();
df = dumbfile_open_ex(s, &dfs);
if (!df)
{
NSLog(@"EX Failed");
return NO;
}
2013-10-04 23:34:29 +00:00
int subsong = 0;
int startOrder = 0;
NSURL * url = [s url];
int track_num;
if ([[url fragment] length] == 0)
track_num = 0;
else
track_num = [[url fragment] intValue];
if ( dumb_get_psm_subsong_count( df ) )
subsong = track_num;
else
startOrder = track_num;
dumbfile_seek( df, 0, SEEK_SET );
NSString *ext = [[[[s url] path] pathExtension] lowercaseString];
2013-10-04 23:34:29 +00:00
duh = dumb_read_any(df, [ext isEqualToString:@"mod"] ? 0 : 1, subsong);
if (!duh)
{
NSLog(@"Failed to create duh");
dumbfile_close(df);
return NO;
}
dumbfile_close(df);
2013-10-04 23:34:29 +00:00
length = dumb_it_build_checkpoints( duh_get_it_sigdata( duh ), startOrder );
2013-10-04 23:34:29 +00:00
dsr = duh_start_sigrenderer(duh, 0, 2 /* stereo */, startOrder);
if (!dsr)
{
NSLog(@"Failed to create dsr");
return NO;
}
2013-09-28 03:24:23 +00:00
DUMB_IT_SIGRENDERER * itsr = duh_get_it_sigrenderer( dsr );
dumb_it_set_ramp_style( itsr, 2 );
dumb_it_set_loop_callback( itsr, callbackLoop, &loops);
dumb_it_set_xm_speed_zero_callback( itsr, dumb_it_callback_terminate, 0);
dumb_it_set_global_volume_zero_callback( itsr, dumb_it_callback_terminate, 0);
loops = 0;
fadeTotal = fadeRemain = 44100 * 8;
2013-09-28 03:24:23 +00:00
[self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"];
return YES;
}
- (NSDictionary *)properties
{
return [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:0], @"bitrate",
[NSNumber numberWithFloat:44100], @"sampleRate",
[NSNumber numberWithDouble:((length / 65.536f)*44.1000)], @"totalFrames",
[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];
}
- (int)readAudio:(void *)buf frames:(UInt32)frames
{
int rendered = duh_render(dsr, 16 /* shorts */, 0 /* not unsigned */, 1.0 /* volume */, 65536.0f / 44100.0f /* 65536 hz? */, frames, buf);
if ( loops >= 2 ) {
int16_t * sampleBuf = ( int16_t * ) buf;
long fadeEnd = fadeRemain - rendered;
if ( fadeEnd < 0 )
fadeEnd = 0;
for ( long fadePos = fadeRemain; fadePos > fadeEnd; --fadePos ) {
long offset = (fadeRemain - fadePos) * 2;
int64_t sampleLeft = sampleBuf[ offset + 0 ];
int64_t sampleRight = sampleBuf[ offset + 1 ];
sampleLeft = (sampleLeft * fadePos) / fadeTotal;
sampleRight = (sampleRight * fadePos) / fadeTotal;
sampleBuf[ offset + 0 ] = sampleLeft;
sampleBuf[ offset + 1 ] = sampleRight;
}
rendered = fadeRemain - fadeEnd;
fadeRemain = fadeEnd;
}
return rendered;
}
- (long)seek:(long)frame
{
double pos = (double)duh_sigrenderer_get_position(dsr) / 65.536f;
double seekPos = frame/44.100;
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];
[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);
return frame;
}
- (void)cleanUp
{
if (dsr) {
duh_end_sigrenderer(dsr);
dsr = NULL;
}
if (duh) {
unload_duh(duh);
duh = 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
{
2013-10-04 23:34:29 +00:00
return [NSArray arrayWithObjects:@"it", @"itz", @"xm", @"xmz", @"s3m", @"s3z", @"mod", @"mdz", @"stm", @"stz", @"ptm", @"mtm", @"669", @"psm", @"am", @"dsm", @"amf", @"okt", @"okta", nil];
2007-10-14 18:39:58 +00:00
}
+ (NSArray *)mimeTypes
{
return [NSArray arrayWithObjects:@"audio/x-it", @"audio/x-xm", @"audio/x-s3m", @"audio/x-mod", nil];
}
@end