/*
 * EKSoundManager
 * description: a generic object for loading and playing threaded sounds
 * history:
 *	5/15/93 [Erik Kay] - created
 *	5/22/93 [Erik Kay] - preloading sounds
 *	6/12/93	[Erik Kay] - uncompressing sounds at load time
 */

#import "EKSoundManager.h"

@implementation EKSoundManager

- init
{
    int i;

    [super init];
    
    /* initialize the streams */
    device = [[NXSoundOut alloc] init];
    for (i = 0; i < MAX_STREAMS; i++) {
    	streamList[i] = [[NXPlayStream alloc] initOnDevice:device];
	if (streamList[i] == nil) {
	    fprintf(stderr,"Splat: error allocating playstreams\n");
	    return nil;
	}
    }
    currentStream = 0;
    maxSound = 0;
    playSounds = NO;
    return self;
}

- (int)addSound:(const char *)name
{
    char path[MAXPATHLEN+1];
    
    // whoops!  no more slots in the sound list available
    // this is why this stuff should be dynamic
    if (maxSound >= MAX_SOUNDS)
	return -1;
	
    // perhaps we should do this by specifying a different bundle dir
    // such as a 'sounds' directory in the app wrapper
    [[NXBundle mainBundle] getPath:path forResource:name ofType:"snd"];
    soundList[maxSound] = [[Sound allocFromZone:[self zone]]
    					initFromSoundfile:path];

/*
    >>>>>>>>>Warning: READ THIS<<<<<<<<<
    This line of code converts all sounds it reads in into
    uncompressed, 16 bit linear, 22kHz format.  If you store your sound
    in any other format than this, loading the sounds could be slow.
    However, it must be done, since compressed sounds do not work at all with
    NXPlayStreams.  They must be uncompressed otherwise garbage will come out.
    WARNING: (here's the important part of all of this :-) in 3.1 there is a
    bug in convertToFormat:.... If the source is compressed and the destination
    is uncompressed, the output may have some annoying pops and hisses in it.
    This bug has been fixed for 3.2, and didn't exist in 3.0, so unless you
    are running 3.1, feel free to use compressed sounds.  This is a very useful
    feature, since it slims down the size of your app wrapper, while still
    giving you the ability to use this object.  If you have 3.1, you should
    only use uncompressed sounds.
 */
	
    // do the conversion... may take some time
    //! (perhaps this conversion should be optional?)
    [soundList[maxSound] convertToFormat:SND_FORMAT_LINEAR_16
    			samplingRate:SND_RATE_LOW
			channelCount:1];
    maxSound++;
    return maxSound - 1;
}

// effectively turn this object on and off.
// if playSounds is NO, then the playSound:... methods won't do anything
- setPlaySounds:(BOOL)flag
{
    int i;
    if (flag == playSounds)
	return self;
    playSounds = flag;
    if (playSounds) {
	for (i = 0; i < MAX_STREAMS; i++)
	    if ([streamList[i] activate] != NX_SoundDeviceErrorNone)
		return self;
	SNDReserve(SND_ACCESS_OUT,0);
    } else {
	for (i = 0; i < MAX_STREAMS; i++)
	    [streamList[i] deactivate];
	SNDUnreserve(SND_ACCESS_OUT);
    }
    return self;
}


// play a sound with full left and right gain
- playSound:(int)whichSound
{
    [self playSound:whichSound withGainLeft:1.0 right:1.0];
    return self;
}


// play a sound with specified left and right gain
- playSound:(int)whichSound withGainLeft:(float)l right:(float)r
{
    NXPlayStream *stream;
    Sound *sound;

    // not a sound in our list...
    if ((whichSound > maxSound) || (whichSound < 0))
	return nil;
    
    // find an available NXPlayStream
    stream = streamList[currentStream++];
    if (currentStream == MAX_STREAMS)
	currentStream = 0;
    sound = soundList[whichSound];

    // make sure that nothing is playing on it
    [stream abort:self];

    // set the gain appropriately
    [stream setGainLeft:l right:r];

    // play the sound through the stream...
    [stream playBuffer:[sound data]
	    size:[sound dataSize]
	    tag:0
	    channelCount:[sound channelCount]
	    samplingRate:[sound samplingRate]];

    return self;
}

@end
