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

发表于2015-12-02
评论0 3k浏览

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

  1. 我们上面几篇分析了cocos2dx音频模块的音乐部分,从这篇开始,  
  2. 我们分析下音效部分:  
  3. 1、  
  4. //预加载音效文件:pszFilePath 音效文件名  
  5. void SimpleAudioEngine::preloadEffect(const char* pszFilePath)  
  6. {  
  7.     //获取音效文件的全路径,如果是apk包里的路径,则不包含assets/  
  8.     std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);  
  9.     preloadEffectJNI(fullPath.c_str());  
  10. }  
  11.   
  12. --->>>// 这里通过jni调用java端的方法  
  13. void preloadEffectJNI(const char *path)  
  14.     {  
  15.         // void preloadEffect(String)  
  16.           
  17.         JniMethodInfo methodInfo;  
  18.           
  19.         if (! getStaticMethodInfo(methodInfo, "preloadEffect""(Ljava/lang/String;)V"))  
  20.         {  
  21.             return ;  
  22.         }  
  23.           
  24.         jstring stringArg = methodInfo.env->NewStringUTF(path);  
  25.         methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg);  
  26.         methodInfo.env->DeleteLocalRef(stringArg);  
  27.         methodInfo.env->DeleteLocalRef(methodInfo.classID);  
  28.     }  
  29. ----->>>//Cocos2dxHelper类中的方法:  
  30. public static void preloadEffect(final String path) {  
  31.                 //Cocos2dxSound类是专门处理音效的类  
  32.         Cocos2dxHelper.sCocos2dSound.preloadEffect(path);  
  33.     }  
  34. --->>>//Cocos2dxSound类的方法:  
  35. public int preloadEffect(final String pPath) {  
  36.                 //private final HashMap mPathSoundIDMap = new HashMap();  
  37.         //这个是音效路径对应音效ID的map  
  38.         Integer soundID = this.mPathSoundIDMap.get(pPath);  
  39.   
  40.         if (soundID == null) {  
  41.                 //  
  42.             soundID = this.createSoundIDFromAsset(pPath);  
  43.             // save value just in case if file is really loaded  
  44.             // 如果createSoundIDFromAsset函数调用成功,则添加到mPathSoundIDMap中。  
  45.             if (soundID != Cocos2dxSound.INVALID_SOUND_ID) {  
  46.                 this.mPathSoundIDMap.put(pPath, soundID);  
  47.             }  
  48.         }  
  49.   
  50.         return soundID;  
  51.     }  
  52.   
  53. ----->>>>根据我们传入的音效文件路径,加载音效  
  54.     public int createSoundIDFromAsset(final String pPath) {  
  55.         int soundID = Cocos2dxSound.INVALID_SOUND_ID;  
  56.   
  57.         try {  
  58.                 //根据传入的路径不同,做不同处理,一个是绝对路径一个是包里的路径,加载音效文件  
  59.             //The SoundPool class manages and plays audio resources for applications.  
  60.             //private SoundPool mSoundPool;音效缓存池  
  61.             if (pPath.startsWith("/")) {  
  62.                 soundID = this.mSoundPool.load(pPath, 0);  
  63.             } else {  
  64.                 soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);  
  65.             }  
  66.         } catch (final Exception e) {  
  67.             soundID = Cocos2dxSound.INVALID_SOUND_ID;  
  68.             Log.e(Cocos2dxSound.TAG, "error: "   e.getMessage(), e);  
  69.         }  
  70.   
  71.         // mSoundPool.load returns 0 if something goes wrong, for example a file does not exist  
  72.         if (soundID == 0) {  
  73.             soundID = Cocos2dxSound.INVALID_SOUND_ID;  
  74.         }  
  75.   
  76.         return soundID;  
  77.     }  
  78.   
  79. 2、  
  80. 播放音效文件。  
  81. pszFilePath:音效文件名;bLoop 是否循环播放  
  82. unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop)  
  83. {  
  84.     std::string fullPath = getFullPathWithoutAssetsPrefix(pszFilePath);  
  85.     return playEffectJNI(fullPath.c_str(), bLoop);  
  86. }  
  87. ----->>>playEffectJNI:  
  88.    unsigned int playEffectJNI(const char* path, bool bLoop)  
  89.     {  
  90.         // int playEffect(String)  
  91.           
  92.         JniMethodInfo methodInfo;  
  93.         int ret = 0;  
  94.           
  95.         if (! getStaticMethodInfo(methodInfo, "playEffect""(Ljava/lang/String;Z)I"))  
  96.         {  
  97.             return ret;  
  98.         }  
  99.           
  100.         jstring stringArg = methodInfo.env->NewStringUTF(path);  
  101.         ret = methodInfo.env->CallStaticIntMethod(methodInfo.classID, methodInfo.methodID, stringArg, bLoop);  
  102.         methodInfo.env->DeleteLocalRef(stringArg);  
  103.         methodInfo.env->DeleteLocalRef(methodInfo.classID);  
  104.           
  105.         return (unsigned int)ret;  
  106.     }  
  107. ------>>>>playEffect:  
  108. public int playEffect(final String pPath, final boolean pLoop) {  
  109.                 //从mPathSoundIDMap中,根据音效path得到音效ID  
  110.         Integer soundID = this.mPathSoundIDMap.get(pPath);  
  111.         int streamID = Cocos2dxSound.INVALID_STREAM_ID;  
  112.   
  113.         if (soundID != null) {  
  114.             // play sound  
  115.             // 如果音效ID存在,则表明我们已经预先加载过这个音效文件,则调用mSoundPool.play直接播放  
  116.             /* 
  117.             private int doPlayEffect(final String pPath, final int soundId, final boolean pLoop) { 
  118.                 // play sound 
  119.                 // Play a sound from a sound ID. 
  120.                 // return non-zero streamID if successful, zero if failed如果成功会返回一个streamID 
  121.                 int streamID = this.mSoundPool.play(soundId, this.mLeftVolume, this.mRightVolume, Cocos2dxSound.SOUND_PRIORITY, pLoop ? -1 : 0, Cocos2dxSound.SOUND_RATE); 
  122.  
  123.                 // record stream id 
  124.                 // 记录上面调用mSoundPool.play返回的streamID,至于为什么需要这样,看下面源码的说明: 
  125.                 // sound path and stream ids map 
  126.                 // a file may be played many times at the same time 
  127.                 // so there is an array map to a file path 
  128.                 // private final HashMap<string, arraylist> mPathStreamIDsMap = new HashMap<string, arraylist>();</string, arraylist</string, arraylist 
  129.                 ArrayList streamIDs = this.mPathStreamIDsMap.get(pPath); 
  130.                 if (streamIDs == null) { 
  131.                     streamIDs = new ArrayList(); 
  132.                     this.mPathStreamIDsMap.put(pPath, streamIDs); 
  133.                 } 
  134.                 streamIDs.add(streamID); 
  135.                  
  136.                 return streamID; 
  137.             } 
  138.             */  
  139.             streamID = this.doPlayEffect(pPath, soundID.intValue(), pLoop);  
  140.         } else {  
  141.             // the effect is not prepared,如果音效没有预先加载,则需要先加载  
  142.             soundID = this.preloadEffect(pPath); //加载音效文件  
  143.             if (soundID == Cocos2dxSound.INVALID_SOUND_ID) {  
  144.                 // can not preload effect  
  145.                 return Cocos2dxSound.INVALID_SOUND_ID;  
  146.             }  
  147.               
  148.             // only allow one playEffect at a time, or the semaphore will not work correctly  
  149.             synchronized(this.mSoundPool) {  
  150.                 // add this effect into mEffecToPlayWhenLoadedArray, and it will be played when loaded completely  
  151.                 // 这个应该和mSoundPool加载音效文件有关,我也不是很明白  
  152.                 /* 
  153.                 不过在初始化时设置了一个:this.mSoundPool.setOnLoadCompleteListener(new OnLoadCompletedListener()); 
  154.                 //加载完成回调函数,应该和这个有关,这里我们就不关心了。 只需要知道如果我们提前加载音效文件 
  155.                 //也可以直接调用play函数,在调用play函数时会调用加载函数,并放入加载队列中,加载完成后进行播放。 
  156.                 //这样做会有一些延时,所以我们还是最好先加载,然后在播放。这个延时只在第一次播放时有,以后就不会了, 
  157.                 //不过最好还是先加载。 
  158.                 */  
  159.                 /* 
  160.                     @Override 
  161.                     //加载完成回调函数。 
  162.                     public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 
  163.                         if (status == 0) 
  164.                         { 
  165.                             // only play effect that are in mEffecToPlayWhenLoadedArray 
  166.                             for ( SoundInfoForLoadedCompleted info : mEffecToPlayWhenLoadedArray) { 
  167.                                 if (sampleId == info.soundID) { 
  168.                                     // set the stream id which will be returned by playEffect() 
  169.                                     // 加载完成后调用doPlayEffect进行播放,并从mEffecToPlayWhenLoadedArray加载列表中 
  170.                                     // 移除。 
  171.                                     mStreamIdSyn = doPlayEffect(info.path, info.soundID, info.isLoop); 
  172.                                      
  173.                                     // remove it from array, because we will break here 
  174.                                     // so it is safe to do 
  175.                                     mEffecToPlayWhenLoadedArray.remove(info); 
  176.  
  177.                                     break; 
  178.                                 } 
  179.                             } 
  180.                         } else { 
  181.                             mStreamIdSyn = Cocos2dxSound.INVALID_SOUND_ID; 
  182.                         } 
  183.                          
  184.                         mSemaphore.release(); 
  185.                     } 
  186.                 } 
  187.                 */  
  188.                 mEffecToPlayWhenLoadedArray.add(new SoundInfoForLoadedCompleted(pPath, soundID.intValue(), pLoop));  
  189.                   
  190.                 try {  
  191.                     // wait OnloadedCompleteListener to set streamID  
  192.                     this.mSemaphore.acquire();  
  193.                       
  194.                     streamID = this.mStreamIdSyn;  
  195.                 } catch(Exception e) {  
  196.                     return Cocos2dxSound.INVALID_SOUND_ID;  
  197.                 }  
  198.             }  
  199.         }  
  200.   
  201.         return streamID;  
  202.     }  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: