Fixed shorten and cue sheet decoders so they conform with the updated protocols.

CQTexperiment
vspader 2008-03-30 15:43:28 +00:00
parent 7314c6cba1
commit 03ad906fb4
6 changed files with 53 additions and 81 deletions

View File

@ -18,11 +18,11 @@
id<CogDecoder> decoder; id<CogDecoder> decoder;
int bytesPerFrame; //Number of bytes per frame, ie channels * (bitsPerSample/8) int bytesPerFrame; //Number of bytes per frame, ie channels * (bitsPerSample/8)
int bytesPerSecond; //Number of bytes per second, ie bytesPerFrame * sampleRate
int bytePosition; //Current position in bytes. long framePosition; //Current position in frames.
double trackEnd; //Seconds until end of track. long trackStart; //Starting frame of track.
long trackEnd; //Frames until end of track.
CueSheet *cuesheet; CueSheet *cuesheet;
CueSheetTrack *track; CueSheetTrack *track;

View File

@ -29,7 +29,7 @@
NSMutableDictionary *properties = [[decoder properties] mutableCopy]; NSMutableDictionary *properties = [[decoder properties] mutableCopy];
//Need to alter length //Need to alter length
[properties setObject:[NSNumber numberWithDouble:((trackEnd - [track time]) * 1000)] forKey:@"totalFrames"]; [properties setObject:[NSNumber numberWithLong:(trackEnd - trackStart)] forKey:@"totalFrames"];
return [properties autorelease]; return [properties autorelease];
} }
@ -82,18 +82,19 @@
float sampleRate = [[properties objectForKey:@"sampleRate"] floatValue]; float sampleRate = [[properties objectForKey:@"sampleRate"] floatValue];
bytesPerFrame = (bitsPerSample/8) * channels; bytesPerFrame = (bitsPerSample/8) * channels;
bytesPerSecond = (int)(bytesPerFrame * sampleRate);
trackStart = [track time] * sampleRate;
if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) { if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) {
trackEnd = [nextTrack time]; trackEnd = [nextTrack time] * sampleRate;
} }
else { else {
trackEnd = [[properties objectForKey:@"length"] doubleValue]/1000.0; trackEnd = [[properties objectForKey:@"totalFrames"] doubleValue];
} }
[self seekToTime: 0.0]; [self seek: 0];
//Note: Should register for observations of the decoder, but laziness consumes all. //Note: Should register for observations of the decoder
[self willChangeValueForKey:@"properties"]; [self willChangeValueForKey:@"properties"];
[self didChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"];
@ -127,7 +128,8 @@
- (BOOL)setTrack:(NSURL *)url - (BOOL)setTrack:(NSURL *)url
{ {
if ([[url fragment] intValue] == [[track track] intValue] + 1) { //Same file, just next track...this may be unnecessary since frame-based decoding is done now...
if ([[[track url] path] isEqualToString:[url path]] && [[[track url] host] isEqualToString:[url host]] && [[url fragment] intValue] == [[track track] intValue] + 1) {
NSArray *tracks = [cuesheet tracks]; NSArray *tracks = [cuesheet tracks];
int i; int i;
@ -137,16 +139,20 @@
track = [tracks objectAtIndex:i]; track = [tracks objectAtIndex:i];
[track retain]; [track retain];
float sampleRate = [[[decoder properties] objectForKey:@"sampleRate"] floatValue];
trackStart = [track time] * sampleRate;
CueSheetTrack *nextTrack = nil; CueSheetTrack *nextTrack = nil;
if (i + 1 < [tracks count]) { if (i + 1 < [tracks count]) {
nextTrack = [tracks objectAtIndex:i + 1]; nextTrack = [tracks objectAtIndex:i + 1];
} }
if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) { if (nextTrack && [[[nextTrack url] absoluteString] isEqualToString:[[track url] absoluteString]]) {
trackEnd = [nextTrack time]; trackEnd = [nextTrack time] * sampleRate;
} }
else { else {
trackEnd = [[[decoder properties] objectForKey:@"length"] doubleValue]/1000.0; trackEnd = [[[decoder properties] objectForKey:@"totalFrames"] longValue];
} }
NSLog(@"CHANGING TRACK!"); NSLog(@"CHANGING TRACK!");
@ -158,50 +164,35 @@
return NO; return NO;
} }
- (double)seekToTime:(double)time //milliseconds - (long)seek:(long)frame
{ {
double trackStartMs = [track time] * 1000.0; if (frame > trackEnd - trackStart) {
double trackEndMs = trackEnd * 1000.0;
if (time > trackEndMs - trackStartMs) {
//need a better way of returning fail. //need a better way of returning fail.
return -1.0; return -1;
} }
time += trackStartMs; frame += trackStart;
bytePosition = (time/1000.0) * bytesPerSecond; framePosition = [decoder seek:frame];
NSLog(@"Before: %li", bytePosition); return framePosition;
bytePosition -= bytePosition % bytesPerFrame;
NSLog(@"After: %li", bytePosition);
return [decoder seekToTime:time];
} }
- (int)fillBuffer:(void *)buf ofSize:(UInt32)size - (int)readAudio:(void *)buf frames:(UInt32)frames
{ {
long trackByteEnd = trackEnd * bytesPerSecond; if (framePosition + frames > trackEnd) {
trackByteEnd -= trackByteEnd % (bytesPerFrame); frames = trackEnd - framePosition;
// NSLog(@"Position: %i/%i", bytePosition, trackByteEnd);
// NSLog(@"Requested: %i", size);
if (bytePosition + size > trackByteEnd) {
size = trackByteEnd - bytePosition;
} }
// NSLog(@"Revised size: %i", size); if (!frames)
{
if (!size) { NSLog(@"Returning 0");
NSLog(@"Returning 0");
return 0; return 0;
} }
int n = [decoder fillBuffer:buf ofSize:size]; int n = [decoder readAudio:buf frames:frames];
// NSLog(@"Received: %i", n); framePosition += n;
bytePosition += n;
return n; return n;
} }

View File

@ -19,7 +19,7 @@
NSString *genre; NSString *genre;
NSString *year; NSString *year;
double time; double time; //Starting time for the track
} }
+ (id)trackWithURL:(NSURL *)u track:(NSString *)t time:(double)s artist:(NSString *)a album:(NSString *)b title:(NSString *)l genre:(NSString *)g year:(NSString *)y; + (id)trackWithURL:(NSURL *)u track:(NSString *)t time:(double)s artist:(NSString *)a album:(NSString *)b title:(NSString *)l genre:(NSString *)g year:(NSString *)y;

View File

@ -183,6 +183,7 @@
089C1669FE841209C02AAC07 /* Project object */ = { 089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "Shorten" */; buildConfigurationList = 1DEB913E08733D840010E9CD /* Build configuration list for PBXProject "Shorten" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1; hasScannedForEncodings = 1;
mainGroup = 089C166AFE841209C02AAC07 /* Shorten */; mainGroup = 089C166AFE841209C02AAC07 /* Shorten */;
projectDirPath = ""; projectDirPath = "";
@ -192,6 +193,7 @@
ProjectRef = 17F563DD0C3BDBF10019975C /* Shorten.xcodeproj */; ProjectRef = 17F563DD0C3BDBF10019975C /* Shorten.xcodeproj */;
}, },
); );
projectRoot = "";
targets = ( targets = (
8D5B49AC048680CD000E48DA /* Shorten Plugin */, 8D5B49AC048680CD000E48DA /* Shorten Plugin */,
); );

View File

@ -21,7 +21,7 @@
int channels; int channels;
int bitsPerSample; int bitsPerSample;
float frequency; float frequency;
double length; long totalFrames;
BOOL seekable; BOOL seekable;
} }

View File

@ -34,7 +34,7 @@
seekable = seekTable == true ? YES : NO; seekable = seekTable == true ? YES : NO;
length = decoder->shn_get_song_length(); totalFrames = (decoder->shn_get_song_length() * frequency)/1000.0;
decoder->go(); decoder->go();
@ -44,49 +44,28 @@
return YES; return YES;
} }
- (int)fillBuffer:(void *)buf ofSize:(UInt32)size - (int)readAudio:(void *)buf frames:(UInt32)frames
{ {
long totalRead, amountRead, amountToRead; int bytesPerFrame = channels * (bitsPerSample/8);
int amountRead;
totalRead = 0; //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
{
amountRead = decoder->read(buf, frames * bytesPerFrame);
} while(amountRead == -1);
//For some reason the 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.
// while (totalRead < size) {
amountToRead = size - totalRead;
if (amountToRead > bufferSize) {
amountToRead = bufferSize;
}
do return amountRead/bytesPerFrame;
{
amountRead = decoder->read(buf, amountToRead);
} while(amountRead == -1 && totalRead == 0);
// if (amountRead <= 0) {
// return totalRead;
// }
totalRead += amountRead;
// buf = (void *)((char *)buf + amountRead);
// }
return totalRead;
} }
- (double)seekToTime:(double)milliseconds - (long)seek:(long)sample
{ {
unsigned int sec; unsigned int sec = sample/frequency;
/*if (!shn_seekable(handle))
return -1.0;*/
sec = (int)(milliseconds/1000.0);
//shn_seek(handle, sec);
decoder->seek(sec); decoder->seek(sec);
return (sec * 1000.0); return sample;
} }
- (void)close - (void)close
@ -108,7 +87,7 @@
[NSNumber numberWithInt:channels],@"channels", [NSNumber numberWithInt:channels],@"channels",
[NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", [NSNumber numberWithInt:bitsPerSample],@"bitsPerSample",
[NSNumber numberWithFloat:frequency],@"sampleRate", [NSNumber numberWithFloat:frequency],@"sampleRate",
[NSNumber numberWithDouble:length],@"length", [NSNumber numberWithDouble:totalFrames],@"totalFrames",
[NSNumber numberWithBool:seekable ],@"seekable", [NSNumber numberWithBool:seekable ],@"seekable",
@"little",@"endian", @"little",@"endian",
nil]; nil];
@ -121,7 +100,7 @@
+ (NSArray *)mimeTypes + (NSArray *)mimeTypes
{ {
return [NSArray arrayWithObjects:@"application/x-shorten", nil]; //This is basically useless return [NSArray arrayWithObjects:@"application/x-shorten", nil]; //This is basically useless, since we cant stream shorten yet
} }