Fixed shorten and cue sheet decoders so they conform with the updated protocols.
parent
7314c6cba1
commit
03ad906fb4
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */,
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
int channels;
|
int channels;
|
||||||
int bitsPerSample;
|
int bitsPerSample;
|
||||||
float frequency;
|
float frequency;
|
||||||
double length;
|
long totalFrames;
|
||||||
BOOL seekable;
|
BOOL seekable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue