This is SoundEffect.m in view mode; [Download] [Up]
//
/* SoundEffect.m, class to play sounds
* Originally by Terry Donahue, modified by Ali Ozer and Katzlberger Thomas (cat)
*
* 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 <appkit/Application.h>
#import <objc/List.h>
// 8/28/93 reference limiting by cat for MissileCommand
@implementation SoundEffect
static BOOL soundEnabled = YES;
+ (void)setSoundEnabled:(BOOL)flag
{
soundEnabled = flag;
}
+ (BOOL)soundEnabled
{
return soundEnabled;
}
#define DEFAULTMAXSOUNDSTREAMS 40
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 exceeded, 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.
// aha ! soundStreams is a list of available (unused,not playing) streams
- (NXPlayStream *)soundStream
{
static NXSoundOut *dev = nil; // We only have one instance of this...
NXPlayStream *newStream = nil;
if (!dev && !(dev = [[NXSoundOut alloc] init]))
{ // We allocate from the default zone so
NXLogError ("Couldn't create NXSoundOut"); // freeing this zone won't 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 withLimit:(unsigned int)n
{
flags.limit = n;
return [self initFromSection:path];
}
- initFromSection:(const char *)path
{
[super init];
if(flags.limit == 0) flags.limit = 255;
if (!(sound = [[Sound alloc] initFromSection:path]))
{ NXLogError ("Couldn't load sound from %s", path);
[self free];
return nil;
}
if([sound samplingRate]<22000.0)
[sound convertToFormat:SND_FORMAT_LINEAR_16 samplingRate:SND_RATE_LOW channelCount:2];
return self;
}
- (int)soundsPlaying
{
return flags.refCount;
}
// 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 3 methods play the sound effect.
// This function ensures that soundstreams will be reactivated (by calling:
// soundStream:didCompleteBuffer:) if lots of (>20) short sounds are played within
// one function without invoking the eventloop
- playEvent
{
[NXApp getNextEvent:NX_NULLEVENTMASK waitFor:0.0 threshold:NX_BASETHRESHOLD];
return [self play:1.0 pan:0.0];
}
- play
{
return [self play:1.0 pan:0.0];
}
- play:(float)volume pan:(float)pan
{
float left,right;
NXPlayStream *soundStream;
if((flags.refCount>=flags.limit) || (!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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.