cocos2dx 音频模块分析(5): 音效部分

我们上一篇中分析的音效部分的预加载和播放函数,这一篇来分析下其他函数:
1、
暂停某个播放中的音效
//注意这里的nSoundId不是java端的soundID,而是streamID
//不要被参数的名字迷惑了。
void SimpleAudioEngine::pauseEffect(unsigned int nSoundId)
{
    pauseEffectJNI(nSoundId);
}
-->>
 void pauseEffectJNI(unsigned int nSoundId)
    {
        // void pauseEffect(int)

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "pauseEffect", "(I)V"))
        {
            return ;
        }

        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, (int)nSoundId);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
---->>//java端方法:
//pStreamID 这个参数,是调用unsigned int SimpleAudioEngine::playEffect()放回的StreamID
public void pauseEffect(final int pStreamID) {
	     /**
	     * Pause a playback stream. 暂停一个播放流
	     *
	     * Pause the stream specified by the streamID. This is the
	     * value returned by the play() function. (这个值是play函数的返回值)If the stream is
	     * playing, it will be paused. If the stream is not playing
	     * (e.g. is stopped or was previously paused), calling this
	     * function will have no effect.(如果处于播放状态则暂停,如果不处于播放状态,则无效)
	     *
	     * @param streamID a streamID returned by the play() function
	     */
		this.mSoundPool.pause(pStreamID);
	}
2、
 暂停所有音效
 void pauseAllEffectsJNI()
    {
        // void pauseAllEffects()

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "pauseAllEffects", "()V"))
        {
            return ;
        }

        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
 --->>java端

 public void pauseAllEffects() {
	  /**
	     * Pause all active streams. //暂停所有正在播放的音效
	     *
	     * Pause all streams that are currently playing. This function
	     * iterates through all the active streams and pauses any that
	     * are playing. It also sets a flag so that any streams that
	     * are playing can be resumed by calling autoResume().
	     */
	      this.mSoundPool.autoPause();
	}

3、
 恢复播放某个音效
 void resumeEffectJNI(unsigned int nSoundId)
    {
        // void resumeEffect(int)

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "resumeEffect", "(I)V"))
        {
            return ;
        }

        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, (int)nSoundId);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
    --->>
    public void resumeEffect(final int pStreamID) {
	    /**
	     * Resume a playback stream.
	     * 只有处于暂停状态的stream,才可以恢复播放。
	     * Resume the stream specified by the streamID. This
	     * is the value returned by the play() function. If the stream
	     * is paused, this will resume playback. If the stream was not
	     * previously paused, calling this function will have no effect.
	     *
	     * @param streamID a streamID returned by the play() function
	     */
		this.mSoundPool.resume(pStreamID);
	}
4、
void resumeAllEffectsJNI()
    {
        // void resumeAllEffects()

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "resumeAllEffects", "()V"))
        {
            return ;
        }

        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
---->>>java端函数:
	public void resumeAllEffects() {
		// can not only invoke SoundPool.autoResume() here, because
		// it only resumes all effects paused by pauseAllEffects()
		// 这里注释的很清楚
		if (!this.mPathStreamIDsMap.isEmpty()) {
			final Iterator<Entry<String, ArrayList<Integer>>> iter = this.mPathStreamIDsMap.entrySet().iterator();
			while (iter.hasNext()) {
				final Entry<String, ArrayList<Integer>> entry = iter.next();
				for (final int pStreamID : entry.getValue()) {
					this.mSoundPool.resume(pStreamID);
				}
			}
		}
	}
5、
停止播放某个音效,这里的nSoundId同样是pStreamID,停止播放的音效是不能
通过resume恢复播放的。
void SimpleAudioEngine::stopEffect(unsigned int nSoundId)
{
    stopEffectJNI(nSoundId);
}
--->>java端:
public void stopEffect(final int pStreamID) {
                  /**
		     * Stop a playback stream.
		     *
		     * Stop the stream specified by the streamID. This
		     * is the value returned by the play() function. If the stream
		     * is playing, it will be stopped. It also releases any native
		     * resources associated with this stream. (会释放对应的资源)If the stream is not
		     * playing, it will have no effect.
		     *
		     * @param streamID a streamID returned by the play() function
		     */
		this.mSoundPool.stop(pStreamID);

		// remove record
		// 从记录列表中移除
		for (final String pPath : this.mPathStreamIDsMap.keySet()) {
			if (this.mPathStreamIDsMap.get(pPath).contains(pStreamID)) {
				this.mPathStreamIDsMap.get(pPath).remove(this.mPathStreamIDsMap.get(pPath).indexOf(pStreamID));
				break;
			}
		}
	}
6、
void stopAllEffectsJNI()
    {
        // void stopAllEffects()

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "stopAllEffects", "()V"))
        {
            return ;
        }

        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
--->>>java端
	@SuppressWarnings("unchecked")
	public void stopAllEffects() {
		// stop effects,停止所有音效的播放
		if (!this.mPathStreamIDsMap.isEmpty()) {
			final Iterator<?> iter = this.mPathStreamIDsMap.entrySet().iterator();
			while (iter.hasNext()) {
				final Map.Entry<String, ArrayList<Integer>> entry = (Map.Entry<String, ArrayList<Integer>>) iter.next();
				for (final int pStreamID : entry.getValue()) {
					this.mSoundPool.stop(pStreamID);
				}
			}
		}

		// remove records,清空播放记录
		this.mPathStreamIDsMap.clear();
	}

7、
卸载加载的音效(重要)
//pszFilePath:音效文件名
void SimpleAudioEngine::unloadEffect(const char* pszFilePath)
{
    std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);
    unloadEffectJNI(fullPath.c_str());
}
--->>
 void unloadEffectJNI(const char* path)
    {
        // void unloadEffect(String)

        JniMethodInfo methodInfo;

        if (! getStaticMethodInfo(methodInfo, "unloadEffect", "(Ljava/lang/String;)V"))
        {
            return ;
        }

        jstring stringArg = methodInfo.env->NewStringUTF(path);
        methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg);
        methodInfo.env->DeleteLocalRef(stringArg);
        methodInfo.env->DeleteLocalRef(methodInfo.classID);
    }
--->>>
public void unloadEffect(final String pPath) {
		// stop effects
		// 先停止
		final ArrayList<Integer> streamIDs = this.mPathStreamIDsMap.get(pPath);
		if (streamIDs != null) {
			for (final Integer pStreamID : streamIDs) {
				this.mSoundPool.stop(pStreamID);
			}
		}
		this.mPathStreamIDsMap.remove(pPath);

		// unload effect
		final Integer soundID = this.mPathSoundIDMap.get(pPath);
		if(soundID != null){

			    /**
			     * Unload a sound from a sound ID.
			     *
			     * Unloads the sound specified by the soundID. This is the value
			     * returned by the load() function. Returns true if the sound is
			     * successfully unloaded, false if the sound was already unloaded.
			     *
			     * @param soundID a soundID returned by the load() function
			     * @return true if just unloaded, false if previously unloaded
			     */
			// 卸载音效
			this.mSoundPool.unload(soundID);
			// 从mPathSoundIDMap中移除
			this.mPathSoundIDMap.remove(pPath);
		}
	}

/************************************************
总结:
音效部分最重要的函数是preloadEffect,unloadEffect,playEffect,stopAllEffects
其他的感觉不是很常用,java有两个比较重要的map,一个是:
private final HashMap<String, Integer> mPathSoundIDMap = new HashMap<String, Integer>();
这个是用来存放所有加载的音效文件路径和SoundID的map。
一个是:
	// sound path and stream ids map cocos2dx原本注释
	// a file may be played many times at the same time
	// so there is an array map to a file path
private final HashMap<String, ArrayList<Integer>> mPathStreamIDsMap = new HashMap<String, ArrayList<Integer>>();
用来存放所有播放的音效文件路径和StreamIDs的map。
注意:这里的SoundID和StreamID不是一个概念,一个音效文件只对应一个SoundID,而却可以对应多个StreamID,因为一个
音效文件可以播放多次(StreamID),但是只需要加载一次(SoundID).

************************************************/
时间: 2024-08-28 01:52:27

cocos2dx 音频模块分析(5): 音效部分的相关文章

cocos2dx 音频模块分析(4): 音效部分

我们上面几篇分析了cocos2dx音频模块的音乐部分,从这篇开始, 我们分析下音效部分: 1. //预加载音效文件:pszFilePath 音效文件名 void SimpleAudioEngine::preloadEffect(const char* pszFilePath) { //获取音效文件的全路径,如果是apk包里的路径,则不包含assets/ std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath); prel

cocos2dx 音频模块分析(3): 背景音乐部分

cocos2dx 音频模块分析(3):背景音乐部分 我在(2)已经分析了背景音乐文件的预加载preloadBackgroundMusic和播放playBackgroundMusic两个函数, 这里接着分析,还是基于android平台: 1. //暂停函数,用于音乐的暂停 void SimpleAudioEngine::pauseBackgroundMusic() { //在SimpleAudioEngineJni.cpp源文件中定义 pauseBackgroundMusicJNI(); } //

cocos2dx 音频模块分析(2):背景音乐

cocos2dx 音频模块分析(2): 背景音乐部分 我在(1)已经分析了一些东西,这里接着分析,这一篇我们主要分析背景音乐文件的播放, 还是基于android平台: 1. 这里只是背景音乐的预加载,为什么要进行预加载呢? 主要是加载音乐文件是比较耗时的,如果我们没有预加载就直接播放也是可以的, 但是会有一定的延时,因为如果没有预加载,就直接播放,也是会先进行加载音乐文件, 然后进行播放. void SimpleAudioEngine::preloadBackgroundMusic(const

WebRTC源码分析:音频模块结构分析

一.概要介绍WebRTC的音频处理流程,见下图: webRTC将音频会话抽象为一个通道Channel,譬如A与B进行音频通话,则A需要建立一个Channel与B进行音频数据传输.上图中有三个Channel,每个Channel包含编解码和RTP/RTCP发送功能. 以一个Channel而言,应用程序中将包含三个活动线程,录音线程,音频接收线程和播放线程. 1)录音线程:负责麦克风音频的采集,见图中红色路径,采集到音频后,缓存到一定长度,进行音频处理,主要包括EC,AGC和NS等.然后送到Chann

cocos2dx基础篇(19)——音乐音效SimpleAudioEngine

[唠叨] 本节比较简单,主要讲讲cocos2dx引擎中的音乐音效. [致谢] http://gl.paea.cn/contents/f86d1f6e2a52e7ea.html [术语] 单例类:说的通俗一点,它就是一个全局静态类.第一次调用时会创建一个全局静态对象,整个游戏的运行过程中会一直存在,全局都可以访问. [SimpleAudioEngine] 音乐音效是每个游戏中不可或缺的部分,一个好的声音会给玩家留下深刻的印象,当一听到游戏的声音,就会不自觉得说出游戏的名称来.就像<中国好声音>一

css扁平化博客学习总结(一)模块分析

一.模块分析 1.每开发一个项目之前,首先要对项目进行一个大致规划,它到底要做什么功能,它有什么具体需求. 2.所以需要进行模块化分析,把这些东西具象化,把一个问题模块化,对需求有一个宏观的了解. 3.有一个模块的概念后,把模块进行细分,细分成更小的模块,然后逐一击破. 不进行模块分析的恶劣影响: 不做模块分析,一上手就想到哪儿做到哪儿,很容易一叶障目,不能看到全貌,你会发现做着做着就失控了.因为有些地方出现了矛盾,你会发现要修改的成本很高,还不如推倒重写. 新手很容易着眼于细节,首先不应该从细

学生信息管理系统(四)——模块分析

学生信息管理系统已经敲完了,也进行了第一次验收,结果不是太理想.之前的总结也没有及时发表.现在重新复习一遍,把它发表. 从今天开始,我们就进入了代码分析阶段.现在我们就来分析一下模块中的几个函数. Public Function ExecuteSQL(ByVal SQL As String, MsgString As String) As ADODB.Recordset 'executes SQL and returns Recordset Dim cnn As ADODB.Connection

cocos2d-x 源码分析 : control 源码分析 ( 控制类组件 controlButton)

源码版本来自3.1rc 转载请注明 cocos2d-x源码分析总目录 http://blog.csdn.net/u011225840/article/details/31743129 1.继承结构 control的设计整体感觉挺美的,在父类control定义了整个控制事件的基础以及管理,虽然其继承了Layer,但其本身和UI组件的实现并没有关联.在子类(controlButton,controlSwitch,controlStepper等中实现不同的UI组件).下面通过源码来分析control与

ABP之模块分析

ABP之模块分析 本篇作为我ABP介绍的第三篇文章,这次想讲下模块的,ABP文档已经有模块这方面的介绍,但是它只讲到如何使用模块,我想详细讲解下它模块的设计思路. ABP 框架提供了创建和组装模块的基础,一个模块能够依赖于另一个模块.在通常情况 下,一个程序集就可以看成是一个模块.在 ABP 框架中,一个模块通过一个类来定义,而这 个类要继承自 AbpModule. 其实它的设计思路很简单: 1.加载bin目录下的所有dll 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15