Search code examples
objective-caudiococos2d-iphonesimpleaudioengine

How to wait finish current audio for playing next audio?


I'm working with cocos2d. How to wait finish current audio for playing next audio? I can't make it with SimpleAudioEngine.


Solution

  • http://www.cocos2d-iphone.org/api-ref/0.99.0/interface_c_d_sound_engine.html

    use CDAudioEngine. It have the method you want. By the way SimpleAudioEngine is using CDAudioEngine to play sounds.

    EDIT

    When your button is clicked first time - play the sound and save the sound's interval to some of your lass variable. Then in next click use this variable to determine the "enough interval". Or just use some maximum.

    EDIT 2 If you'll take a look at SimpleAudioEngine implementation you will notice that it's using CDSoundEngine to play sounds. Here is the init method of SimpleAudioEngine:

    static SimpleAudioEngine *sharedEngine = nil;
    static CDSoundEngine* soundEngine = nil;
    static CDAudioManager *am = nil;
    static CDBufferManager *bufferManager = nil;
    
    
    -(id) init
    {
        if((self=[super init])) {
            am = [CDAudioManager sharedManager];
            soundEngine = am.soundEngine;
            bufferManager = [[CDBufferManager alloc] initWithEngine:soundEngine];
            mute_ = NO;
            enabled_ = YES;
        }
        return self;
    }
    

    So we can also access to CDSoundEngine:

    CDSoundEngine *engine = [CDAudioManager sharedManager].soundEngine;
    

    When calling playEffect method on SimpleAudioEngine (when your button is clicked) save the returned sound id.

    ALuint soundId = [[SimpleAudioEngine sharedEngine] playEffect:...];
    

    Now we can get the interval using our CDSoundEngine:

    float seconds = [engine bufferDurationInSeconds:soundId];
    

    That's the answer!

    By the way you can also stop a sound with CDSoundEngine if you know the sound id.

    From CocosDenshion.h

    @class CDSoundSource;
    @interface CDSoundEngine : NSObject <CDAudioInterruptProtocol> {
    
        bufferInfo      *_buffers;
        sourceInfo      *_sources;
        sourceGroup     *_sourceGroups;
        ALCcontext      *context;
        int             _sourceGroupTotal;
        UInt32          _audioSessionCategory;
        BOOL            _handleAudioSession;
        BOOL            mute_;
        BOOL            enabled_;
        ALfloat         _preMuteGain;
    
        ALenum          lastErrorCode_;
        BOOL            functioning_;
        float           asynchLoadProgress_;
        BOOL            getGainWorks_;
    
        //For managing dynamic allocation of sources and buffers
        int sourceTotal_;
        int bufferTotal;
    
    }
    
    @property (readwrite, nonatomic) ALfloat masterGain;
    @property (readonly)  ALenum lastErrorCode;//Last OpenAL error code that was generated
    @property (readonly)  BOOL functioning;//Is the sound engine functioning
    @property (readwrite) float asynchLoadProgress;
    @property (readonly)  BOOL getGainWorks;//Does getting the gain for a source work
    /** Total number of sources available */
    @property (readonly) int sourceTotal;
    /** Total number of source groups that have been defined */
    @property (readonly) int sourceGroupTotal;
    
    /** Sets the sample rate for the audio mixer. For best performance this should match the sample rate of your audio content */
    +(void) setMixerSampleRate:(Float32) sampleRate;
    
    /** Initializes the engine with a group definition and a total number of groups */
    -(id)init;
    
    /** Plays a sound in a channel group with a pitch, pan and gain. The sound could played looped or not */
    -(ALuint) playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop;
    
    /** Creates and returns a sound source object for the specified sound within the specified source group.
     */
    -(CDSoundSource *) soundSourceForSound:(int) soundId sourceGroupId:(int) sourceGroupId;
    
    /** Stops playing a sound */
    - (void) stopSound:(ALuint) sourceId;
    /** Stops playing a source group */
    - (void) stopSourceGroup:(int) sourceGroupId;
    /** Stops all playing sounds */
    -(void) stopAllSounds;
    -(void) defineSourceGroups:(NSArray*) sourceGroupDefinitions;
    -(void) defineSourceGroups:(int[]) sourceGroupDefinitions total:(int) total;
    -(void) setSourceGroupNonInterruptible:(int) sourceGroupId isNonInterruptible:(BOOL) isNonInterruptible;
    -(void) setSourceGroupEnabled:(int) sourceGroupId enabled:(BOOL) enabled;
    -(BOOL) sourceGroupEnabled:(int) sourceGroupId;
    -(BOOL) loadBufferFromData:(int) soundId soundData:(ALvoid*) soundData format:(ALenum) format size:(ALsizei) size freq:(ALsizei) freq;
    -(BOOL) loadBuffer:(int) soundId filePath:(NSString*) filePath;
    -(void) loadBuffersAsynchronously:(NSArray *) loadRequests;
    -(BOOL) unloadBuffer:(int) soundId;
    -(ALCcontext *) openALContext;
    
    /** Returns the duration of the buffer in seconds or a negative value if the buffer id is invalid */
    -(float) bufferDurationInSeconds:(int) soundId;
    /** Returns the size of the buffer in bytes or a negative value if the buffer id is invalid */
    -(ALsizei) bufferSizeInBytes:(int) soundId;
    /** Returns the sampling frequency of the buffer in hertz or a negative value if the buffer id is invalid */
    -(ALsizei) bufferFrequencyInHertz:(int) soundId;
    
    /** Used internally, never call unless you know what you are doing */
    -(void) _soundSourcePreRelease:(CDSoundSource *) soundSource;
    
    @end
    

    I'm using cocos2D 0.99.5

    implementation:

    -(float) bufferDurationInSeconds:(int) soundId {
        if ([self validateBufferId:soundId]) {
            float factor = 0.0f;
            switch (_buffers[soundId].format) {
                case AL_FORMAT_MONO8:
                    factor = 1.0f;
                    break;
                case AL_FORMAT_MONO16:
                    factor = 0.5f;
                    break;
                case AL_FORMAT_STEREO8:
                    factor = 0.5f;
                    break;
                case AL_FORMAT_STEREO16:
                    factor = 0.25f;
                    break;
            }   
            return (float)_buffers[soundId].sizeInBytes/(float)_buffers[soundId].frequencyInHertz * factor;
        } else {
            return -1.0f;
        }   
    }