Annotation of Examples/AppKit/BreakApp/SoundEffect.m, revision 1.1.1.1

1.1       root        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 = NO;
                     22: 
                     23: #define DEFAULTMAXSOUNDSTREAMS 20
                     24: 
                     25: static List *soundStreams = nil;               // List of currently idle sound streams
                     26: static unsigned int soundStreamsAllocated = 0; // Total number of sound streams allocated
                     27: static unsigned int maxSoundStreams = DEFAULTMAXSOUNDSTREAMS;  // Max allowed
                     28: 
                     29: // After calling this, you may call soundEnabled to check to see if it was successful.
                     30: 
                     31: + (void)setSoundEnabled:(BOOL)flag
                     32: {
                     33:     if (flag && !soundEnabled) {
                     34:        NXPlayStream *testStream = [self soundStream];
                     35:        if (testStream) {
                     36:            soundEnabled = YES;     
                     37:            [self releaseSoundStream:testStream];
                     38:        } else {
                     39:            NXLogError ("Can't enable sounds.");
                     40:        }
                     41:     } else if (!flag && soundEnabled) {
                     42:        soundEnabled = flag;
                     43:        soundStreamsAllocated -= [soundStreams count];
                     44:        [soundStreams freeObjects];
                     45:     }
                     46: }
                     47: 
                     48: + (BOOL)soundEnabled
                     49: {
                     50:     return soundEnabled;
                     51: }
                     52: 
                     53: // These two methods let the client set/get the maximum number of
                     54: // sound streams to allocate. If this number is exceeded, sound requests
                     55: // are simply not honored until sound streams are freed up.
                     56: 
                     57: + (void)setMaxSoundStreams:(unsigned int)max
                     58: {
                     59:     maxSoundStreams = max;
                     60: }
                     61: 
                     62: + (unsigned int)maxSoundStreams
                     63: {
                     64:     return maxSoundStreams;
                     65: }
                     66: 
                     67: // This method returns a sound stream to be used in playing a sound.
                     68: // Sound streams allocated through this method should be given back
                     69: // via releaseSoundStream:. Note that this is for internal use only;
                     70: // it however might be overridden if necessary.
                     71: 
                     72: + (NXPlayStream *)soundStream
                     73: {
                     74:     static BOOL cantPlaySounds = NO;
                     75:     static NXSoundOut *dev = nil;                      // We only have one instance of this...
                     76:     NXPlayStream *newStream = nil;
                     77: 
                     78:     if (cantPlaySounds) return nil;    // If we've tried before and failed, just give up.
                     79:     
                     80:     if (!dev && !(dev = [[NXSoundOut alloc] init])) {  // We allocate this from the default zone so that
                     81:        NXLogError ("Couldn't create NXSoundOut");      //  freeing this zone won't accidentally blast it
                     82:        cantPlaySounds = YES;
                     83:         return nil;
                     84:     }
                     85: 
                     86:     if (!soundStreams) {
                     87:        soundStreams = [[List alloc] init];
                     88:     }
                     89: 
                     90:     if (![soundStreams count]) {
                     91:        if (soundStreamsAllocated < maxSoundStreams) {
                     92:            newStream = [[NXPlayStream alloc] initOnDevice:dev];
                     93:            soundStreamsAllocated++;
                     94:        }
                     95:     } else {
                     96:         newStream = [soundStreams removeLastObject];
                     97:     }
                     98:     
                     99:     if (newStream) {
                    100:        if (![newStream isActive] && ([newStream activate] != NX_SoundDeviceErrorNone)) {
                    101:            [newStream free];
                    102:            newStream = nil;
                    103:            soundStreamsAllocated--;
                    104:        }
                    105:     }
                    106: 
                    107:     return newStream;
                    108: }
                    109: 
                    110: // When a sound stream is released, put it on the idle list unless sounds were disabled;
                    111: // then just free it.
                    112: 
                    113: + (void)releaseSoundStream:(NXPlayStream *)soundStream
                    114: {
                    115:     if ([self soundEnabled]) {
                    116:        [soundStreams addObject:soundStream];
                    117:     } else {
                    118:        [soundStream free];     // This also deactivates.
                    119:        soundStreamsAllocated--;
                    120:     }
                    121: }
                    122: 
                    123: // This method lets you create new instances of SoundEffect. If the specified
                    124: // sound file does not exist, the allocated instance is freed and nil is returned.
                    125: 
                    126: - initFromSection:(const char *)path
                    127: {
                    128:     [super init];
                    129: 
                    130:     if (!(sound = [[Sound allocFromZone:[self zone]] initFromSection:path])) {
                    131:        NXLogError ("Couldn't load sound from %s", path);
                    132:        [self free];
                    133:        return nil;
                    134:     }
                    135: 
                    136:     return self;
                    137: }
                    138: 
                    139: // Free frees the SoundEffect. If this sound effect is being played at the time,
                    140: // the free is delayed and happens as soon as all pending sounds are finished.
                    141: 
                    142: - free
                    143: {
                    144:     if (flags.refCount) {
                    145:        flags.freeWhenDone = YES;
                    146:        return nil;
                    147:     } else {
                    148:        if (sound) [sound free];
                    149:        return [super free];
                    150:     }
                    151: }
                    152: 
                    153: // These two methods play the sound effect.
                    154: 
                    155: - play
                    156: {
                    157:     return [self play:1.0 pan:0.0];
                    158: }
                    159: 
                    160: - play:(float)volume pan:(float)pan
                    161: {
                    162:     float left, right;
                    163:     NXPlayStream *soundStream;
                    164:     
                    165:     if (![[self class] soundEnabled]) {
                    166:        return self;
                    167:     }
                    168: 
                    169:     if (!(soundStream = [[self class] soundStream])) {
                    170:        return self;
                    171:     }
                    172:     
                    173:     [soundStream setDelegate:self];
                    174: 
                    175:     left = right = volume;
                    176:     if (pan > 0.0) left  *= 1.0 - pan;
                    177:     else if (pan < 0.0) right *= 1.0 + pan;
                    178:     [soundStream setGainLeft:left right:right];
                    179:     if ([soundStream playBuffer:(void *)[sound data]
                    180:                            size:(unsigned int)[sound dataSize]
                    181:                            tag:0
                    182:                    channelCount:(unsigned int)[sound channelCount]
                    183:                    samplingRate:[sound samplingRate]] == NX_SoundDeviceErrorNone) {
                    184:        flags.refCount++;
                    185:     } else {
                    186:        [[self class] releaseSoundStream:soundStream];
                    187:     }
                    188: 
                    189:     return self;
                    190: }
                    191: 
                    192: // Delegate methods for internal use only.
                    193: 
                    194: - soundStream:sender didCompleteBuffer:(int)tag
                    195: {
                    196:     flags.refCount--;
                    197:     [[self class] releaseSoundStream:sender];
                    198:     if (flags.freeWhenDone && flags.refCount == 0) {
                    199:        [self free];
                    200:     }
                    201:     return sender;
                    202: }
                    203: 
                    204: - soundStreamDidAbort:sender deviceReserved:(BOOL)flag
                    205: {
                    206:     return [self soundStream:sender didCompleteBuffer:0];
                    207: }
                    208: 
                    209: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.