
// GKSound:  se the header file for info on it's use.

#import <gamekit/gamekit.h>
#import <daymisckit/daymisckit.h>
#import <sound/sound.h>

@implementation GKSound

- setPlayStream:aStream { streamGroup = aStream; return self; }
- _initGKSound
{
	if (!now) now = [[DAYTime alloc] init];
	if (!timeToPlay) timeToPlay = [[DAYTime alloc] init];
	if (!nextPlay) nextPlay = [[DAYTime alloc] initWithCurrentTime];
	return self;
}

// overridden init methods: (to assure that _initGKSound is called)
- initFromSoundfile:(const char *)filename
{
	id ret = [super initFromSoundfile:filename];
	[self _initGKSound];
	[self convert];
	return ret;
}

- initFromSection:(const char *)sectionName
{
	id ret = [super initFromSection:sectionName];
	[self _initGKSound];
	[self convert];
	return ret;
}

- initFromPasteboard:(Pasteboard *)thePboard
{
	id ret = [super initFromPasteboard:thePboard];
	[self _initGKSound];
	[self convert];
	return ret;
}

// the new methods:
- setPercentToPlay:(double)percent // how much to play before next play
{
	SNDSoundStruct *mySoundData = [self soundStruct];
	// assuming that we're 16bit 22.050kHz mono sound
	long timeOnStream = (mySoundData->dataSize / 2) * 45.3514739229;
	double usecToPlay = timeOnStream * percent;
	[[timeToPlay init] addMicroseconds:(timeOnStream - usecToPlay)];
#ifdef NOISYDEBUG
	fprintf(stderr, "GKSound:  Play %f percent out of %ld usec (%f usec).\n",
		percent, timeOnStream, usecToPlay);
	fprintf(stderr, "GKSound:  Play when %s (%d) left to go.\n\n",
		[timeToPlay stringValue], [timeToPlay microsecond]);
#endif
	return self;
}

- setTimeToPlay:aTime	// how long to play sound before next play
{	// aTime says how long after start of sound play we must wait.
	// we need to find how soon before the sound ends we can start:
	SNDSoundStruct *mySoundData = [self soundStruct];
	// assuming that we're 16bit 22.050kHz mono sound
	long timeOnStream = (mySoundData->dataSize / 2) * 45.3514739229;
	[[[timeToPlay init] addMicroseconds:timeOnStream] subtractTime:aTime];
#ifdef NOISYDEBUG
	fprintf(stderr, "GKSound:  Play after %s (%d).\n",
		[aTime stringValue], [aTime microsecond]);
	fprintf(stderr, "GKSound:  Play when %s (%d) left to go.\n\n",
		[timeToPlay stringValue], [timeToPlay microsecond]);
#endif
	return self;
}

- convert
{
	int err;
	if (err = [self convertToFormat:SND_FORMAT_LINEAR_16
			samplingRate:SND_RATE_LOW channelCount:1]) {
		fprintf(stderr, "%s:  GKSound convert error %s\n",
				[NXApp appName], SNDSoundError(err));
	}
	return self;
}

- (int)play // overridden playback method
{
	id temp; // a DAYTime that says when the sound will finish playing.
	
	// check to see if we can be played or not
	[now initWithCurrentTime];
#ifdef NOISYDEBUG
	fprintf(stderr, "GKSound:  Now is: %s (%d)\n", [now stringValue],
		[now microsecond]);
	fprintf(stderr, "GKSound:  Next play at: %s (%d) -- %s\n",
		[nextPlay stringValue], [nextPlay microsecond],
		([nextPlay isAfter:now] ? "Don't play it." : "Play it."));
#endif
	if ([nextPlay isAfter:now])
		return SND_ERR_NONE; // not time yet:  ignore the play
	
	// do the actual playback:
	if (delegate && [delegate respondsTo:@selector(willPlay:)])
		[delegate willPlay:self]; // we can do this one.
	temp = [streamGroup playSoundStruct:[self soundStruct]];
	// I suppose that if you _really_ need the didPlay, you could set a
	// timed entry to go off when the sound is supposed to finish. *****
	// or hack the GKSoundStream to return/forward the delegate method
	// -soundStream:didCompleteBuffer: which would do the trick (if you
	// have it track the tags; right now it forgets them)

	// Calculate when it will be OK to fire off a new sound:
	[nextPlay copyTimeFrom:temp];
	[nextPlay subtractTime:timeToPlay];
#ifdef NOISYDEBUG
	fprintf(stderr, "GKSound:  Sound should end at: %s (%d)\n",
		[temp stringValue], [temp microsecond]);
	fprintf(stderr,
		"GKSound:  Subtract %s (%d) and start next sound at %s (%d)\n\n",
		[timeToPlay stringValue], [timeToPlay microsecond],
		[nextPlay stringValue], [nextPlay microsecond]);
#endif
	return SND_ERR_NONE;
}

@end
