home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / AppKit / BreakApp / SoundEffect.m < prev    next >
Text File  |  1992-04-29  |  4KB  |  180 lines

  1. /*
  2.  * SoundEffect.m, class to play sounds
  3.  * Originally by Terry Donahue, modified by Ali Ozer
  4.  *
  5.  * SoundEffect is a class which conveniently groups the 3.0
  6.  * sound stream functionality with sound data using the Sound
  7.  * class.
  8.  *
  9.  *  You may freely copy, distribute and reuse the code in this example.
  10.  *  NeXT disclaims any warranty of any kind, expressed or implied,
  11.  *  as to its fitness for any particular use.
  12.  */
  13.  
  14. #import "SoundEffect.h"
  15. #import <soundkit/NXSoundOut.h>
  16. #import <appkit/nextstd.h>
  17. #import <objc/List.h>
  18.  
  19. @implementation SoundEffect
  20.  
  21. static BOOL soundEnabled = YES;
  22.  
  23. + (void)setSoundEnabled:(BOOL)flag
  24. {
  25.     soundEnabled = flag;
  26. }
  27.  
  28. + (BOOL)soundEnabled
  29. {
  30.     return soundEnabled;
  31. }
  32.  
  33. #define DEFAULTMAXSOUNDSTREAMS 20
  34.  
  35. static List *soundStreams = nil;
  36. static unsigned int soundStreamsAllocated = 0;
  37. static unsigned int maxSoundStreams = DEFAULTMAXSOUNDSTREAMS;
  38.  
  39. // These two methods let the client set/get the maximum number of
  40. // sound streams to allocate. If this number is excee@ sound requests
  41. // are simply not honored until sound streams are freed up.
  42.  
  43. + (void)setMaxSoundStreams:(unsigned int)max
  44. {
  45.     maxSoundStreams = max;
  46. }
  47.  
  48. + (unsigned int)maxSoundStreams
  49. {
  50.     return maxSoundStreams;
  51. }
  52.  
  53. // This method returns a sound stream to be used in playing a sound.
  54. // Sound streams allocated through this method should be given back
  55. // via releaseSoundStream:. Note that this is for internal use only;
  56. // it however might be overridden if necessary.
  57.  
  58. - (NXPlayStream *)soundStream
  59. {
  60.     static NXSoundOut *dev = nil;            // We only have one instance of this...
  61.     NXPlayStream *newStream = nil;
  62.     
  63.     if (!dev && !(dev = [[NXSoundOut alloc] init])) {    // We allocate this from the default zone so that
  64.     NXLogError ("Couldn't create NXSoundOut");    //  freeing this zone won't accidentally blast it
  65.         return nil;
  66.     }
  67.  
  68.     if (!soundStreams) {
  69.     soundStreams = [[List alloc] init];
  70.     }
  71.  
  72.     if (![soundStreams count]) {
  73.     if (soundStreamsAllocated < maxSoundStreams) {
  74.         newStream = [[NXPlayStream allocFromZone:[self zone]] initOnDevice:dev];
  75.         soundStreamsAllocated++;
  76.     }
  77.     } else {
  78.         newStream = [soundStreams removeLastObject];
  79.     }
  80.     
  81.     if (newStream) {
  82.         [newStream setDelegate:self];
  83.     if (![newStream isActive]) {
  84.         [newStream activate];
  85.     }
  86.     }
  87.  
  88.     return newStream;
  89. }
  90.  
  91. - (void)releaseSoundStream:(NXPlayStream *)soundStream
  92. {
  93.     [soundStreams addObject:soundStream];
  94. }
  95.  
  96. // This method lets you create new instances of SoundEffect. If the specified
  97. // sound file does not exist, the allocated instance is freed and nil is returned.
  98.  
  99. - initFromSection:(const char *)path
  100. {
  101.     [super init];
  102.  
  103.     if (!(sound = [[Sound allocFromZone:[self zone]] initFromSection:path])) {
  104.     NXLogError ("Couldn't load sound from %s", path);
  105.     [self free];
  106.     return nil;
  107.     }
  108.  
  109.     return self;
  110. }
  111.  
  112. // Free frees the SoundEffect. If this sound effect is being played at the time,
  113. // the free is delayed and happens as soon as all pending sounds are finished.
  114.  
  115. - free
  116. {
  117.     if (flags.refCount) {
  118.     flags.freeWhenDone = YES;
  119.     return nil;
  120.     } else {
  121.     if (sound) [sound free];
  122.     return [super free];
  123.     }
  124. }
  125.  
  126. // These two methods play the sound effect.
  127.  
  128. - play
  129. {
  130.     return [self play:1.0 pan:0.0];
  131. }
  132.  
  133. - play:(float)volume pan:(float)pan
  134. {
  135.     float left, right;
  136.     NXPlayStream *soundStream;
  137.     
  138.     if (![@f class] soundEnabled]) {
  139.         return self;
  140.     }
  141.  
  142.     if (!(soundStream = [self soundStream])) {
  143.         NXLogError ("No sound stream to play sound %x", self);
  144.     return self;
  145.     }
  146.     
  147.     left = right = volume;
  148.     if (pan > 0.0) left  *= 1.0 - pan;
  149.     else if (pan < 0.0) right *= 1.0 + pan;
  150.     [soundStream setGainLeft:left right:right];
  151.     [soundStream playBuffer:(void *)[sound data]
  152.                size:(unsigned int)[sound dataSize]
  153.                 tag:0
  154.                channelCount:(unsigned int)[sound channelCount]
  155.            samplingRate:[sound samplingRate]];
  156.  
  157.     flags.refCount++;
  158.  
  159.     return self;
  160. }
  161.  
  162. // Delegate methods for internal use only.
  163.  
  164. - soundStream:sender didCompleteBuffer:(int)tag
  165. {
  166.     flags.refCount--;
  167.     [self releaseSoundStream:sender];
  168.     if (flags.freeWhenDone && flags.refCount == 0) {
  169.     [self free];
  170.     }
  171.     return sender;
  172. }
  173.  
  174. - soundStreamDidAbort:sender deviceReserved:(BOOL)flag
  175. {
  176.     return [self soundStream:sender didCompleteBuffer:0];
  177. }
  178.  
  179. @end
  180.