home *** CD-ROM | disk | FTP | other *** search
- /*
- * SoundEffect.m, class to play sounds
- * Originally by Terry Donahue, modified by Ali Ozer
- *
- * SoundEffect is a class which conveniently groups the 3.0
- * sound stream functionality with sound data using the Sound
- * class.
- *
- * You may freely copy, distribute and reuse the code in this example.
- * NeXT disclaims any warranty of any kind, expressed or implied,
- * as to its fitness for any particular use.
- */
-
- #import "SoundEffect.h"
- #import <soundkit/NXSoundOut.h>
- #import <appkit/nextstd.h>
- #import <objc/List.h>
-
- @implementation SoundEffect
-
- static BOOL soundEnabled = YES;
-
- + (void)setSoundEnabled:(BOOL)flag
- {
- soundEnabled = flag;
- }
-
- + (BOOL)soundEnabled
- {
- return soundEnabled;
- }
-
- #define DEFAULTMAXSOUNDSTREAMS 20
-
- static List *soundStreams = nil;
- static unsigned int soundStreamsAllocated = 0;
- static unsigned int maxSoundStreams = DEFAULTMAXSOUNDSTREAMS;
-
- // These two methods let the client set/get the maximum number of
- // sound streams to allocate. If this number is excee@ sound requests
- // are simply not honored until sound streams are freed up.
-
- + (void)setMaxSoundStreams:(unsigned int)max
- {
- maxSoundStreams = max;
- }
-
- + (unsigned int)maxSoundStreams
- {
- return maxSoundStreams;
- }
-
- // This method returns a sound stream to be used in playing a sound.
- // Sound streams allocated through this method should be given back
- // via releaseSoundStream:. Note that this is for internal use only;
- // it however might be overridden if necessary.
-
- - (NXPlayStream *)soundStream
- {
- static NXSoundOut *dev = nil; // We only have one instance of this...
- NXPlayStream *newStream = nil;
-
- if (!dev && !(dev = [[NXSoundOut alloc] init])) { // We allocate this from the default zone so that
- NXLogError ("Couldn't create NXSoundOut"); // freeing this zone won't accidentally blast it
- return nil;
- }
-
- if (!soundStreams) {
- soundStreams = [[List alloc] init];
- }
-
- if (![soundStreams count]) {
- if (soundStreamsAllocated < maxSoundStreams) {
- newStream = [[NXPlayStream allocFromZone:[self zone]] initOnDevice:dev];
- soundStreamsAllocated++;
- }
- } else {
- newStream = [soundStreams removeLastObject];
- }
-
- if (newStream) {
- [newStream setDelegate:self];
- if (![newStream isActive]) {
- [newStream activate];
- }
- }
-
- return newStream;
- }
-
- - (void)releaseSoundStream:(NXPlayStream *)soundStream
- {
- [soundStreams addObject:soundStream];
- }
-
- // This method lets you create new instances of SoundEffect. If the specified
- // sound file does not exist, the allocated instance is freed and nil is returned.
-
- - initFromSection:(const char *)path
- {
- [super init];
-
- if (!(sound = [[Sound allocFromZone:[self zone]] initFromSection:path])) {
- NXLogError ("Couldn't load sound from %s", path);
- [self free];
- return nil;
- }
-
- return self;
- }
-
- // Free frees the SoundEffect. If this sound effect is being played at the time,
- // the free is delayed and happens as soon as all pending sounds are finished.
-
- - free
- {
- if (flags.refCount) {
- flags.freeWhenDone = YES;
- return nil;
- } else {
- if (sound) [sound free];
- return [super free];
- }
- }
-
- // These two methods play the sound effect.
-
- - play
- {
- return [self play:1.0 pan:0.0];
- }
-
- - play:(float)volume pan:(float)pan
- {
- float left, right;
- NXPlayStream *soundStream;
-
- if (![@f class] soundEnabled]) {
- return self;
- }
-
- if (!(soundStream = [self soundStream])) {
- NXLogError ("No sound stream to play sound %x", self);
- return self;
- }
-
- left = right = volume;
- if (pan > 0.0) left *= 1.0 - pan;
- else if (pan < 0.0) right *= 1.0 + pan;
- [soundStream setGainLeft:left right:right];
- [soundStream playBuffer:(void *)[sound data]
- size:(unsigned int)[sound dataSize]
- tag:0
- channelCount:(unsigned int)[sound channelCount]
- samplingRate:[sound samplingRate]];
-
- flags.refCount++;
-
- return self;
- }
-
- // Delegate methods for internal use only.
-
- - soundStream:sender didCompleteBuffer:(int)tag
- {
- flags.refCount--;
- [self releaseSoundStream:sender];
- if (flags.freeWhenDone && flags.refCount == 0) {
- [self free];
- }
- return sender;
- }
-
- - soundStreamDidAbort:sender deviceReserved:(BOOL)flag
- {
- return [self soundStream:sender didCompleteBuffer:0];
- }
-
- @end
-