fmod音频bank打包加载以及热更方案

https://blog.csdn.net/UWA4D/article/details/106091666

fmod的音频有两种引入的模式,一个是streaming的方式,另外一个是assetbundle的方式。
第一种方式:Streaming Assets形式
我们将制作好的bank,导入到unity之后,在设置中:
fmod音频bank打包加载以及热更方案_第1张图片
选择:streaming assets
这是最通常的做法,fmod在运行的时候或者是Refresh bank的时候,会将bank拷贝到streaming文件夹下:
fmod音频bank打包加载以及热更方案_第2张图片
fmod音频bank打包加载以及热更方案_第3张图片

那么unity在何时加载呢?
fmod音频bank打包加载以及热更方案_第4张图片
代码在:
RuntimeManager——>FMOD.RESULT Initialize()——>LoadBanks
fmod音频bank打包加载以及热更方案_第5张图片
这样就将所有的bank加载到内存了。

第二种方式:Asset Bundle
在这里插入图片描述
当选择Asset Bundle的时候,fmod会自动将我们的Build Path下的bank,重新拷贝一份到当前的项目中,但是每个bank的后缀都更改为.bytes了。
这是因为unity打包的时候,对unity之外的一些文件后缀是不识别的,比如这里.bank。我记得lua也是要改为.txt才能进行打包。

ok,我们有了bytes文件,就好打包了。我们准备将其中的一个bytes文件,进行打包:
fmod音频bank打包加载以及热更方案_第6张图片
打包代码:

public class BuildBundle
{

    [MenuItem("ArtTool/Build Single Bank")]
    public static void BuildSingleBank()
    {
        AssetBundleBuild[] abs = new AssetBundleBuild[1];
        abs[0].assetBundleName = "Tone.bundle";
        abs[0].assetNames = new string[1];
        abs[0].assetNames[0] = @"Assets/Desktop/bytes/Tone.bytes";
        string outpath = Application.streamingAssetsPath + "/Desktop/bytes";
        if(!Directory.Exists(outpath))
        {
            Directory.CreateDirectory(outpath);
        }
        BuildPipeline.BuildAssetBundles(outpath, abs, BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.Android);
        AssetDatabase.Refresh();
    }
}

打包之后的位置:
fmod音频bank打包加载以及热更方案_第7张图片

我们将其拷贝到persistentDataPath路径下:
fmod音频bank打包加载以及热更方案_第8张图片

下面就是加载:

public void LoadBank()
{
    //RuntimeManager.LoadBank();
    AssetBundle ab = AssetBundle.LoadFromFile(Application.persistentDataPath + "/tone.bundle");
    UnityEngine.Object obj = ab.LoadAsset("Tone"); // 无类型&无后缀加载,能加载到
    UnityEngine.Object[] objs = ab.LoadAllAssets(); // 加载所有资源,能加载到
    TextAsset txtAsset = ab.LoadAsset<TextAsset>("Tone"); // 有类型&无后缀,能加载到
    TextAsset txtAsset2 = ab.LoadAsset<TextAsset>("Tone.bytes"); //有类型&有后缀,能加载到

    RuntimeManager.LoadBank(txtAsset);
    string[] names = ab.GetAllAssetNames();
    for (int i = 0; i < names.Length; ++i)
    {
        Debug.LogError("name = " + names[i]);
    }

    TextAsset txtAsset3 = ab.LoadAsset<TextAsset>(names[0]); //这个names[0]=Assets/Desktop/bytes/Tone.bytes,其在tone.bundle.manifest中能找到
    if (txtAsset3 != null) //经实验,能加载到
    {
        Debug.LogError("well done!");
    }
}

其中:LoadBank(TextAsset asset, bool loadSamples = false)在RuntimeManager中:

public static void LoadBank(TextAsset asset, bool loadSamples = false)
{
	……
}

ok,在pc上测试成功;如果是手机上,我们如果不是下载的bundle文件的话,也好模拟(android手机),只要打包之后,找到包路径,将其bundle文件拷贝到持久化目录下,然后加载,经过测试也是成功的。成功的判断标准是,在未加载之前,播放Tone包里面的一个音频,是听不到声音的,并且报错事件找不到;但是在加载Tone之后,再次进行播放,则播放出声音了。

这是我拷贝手动拷贝到手机安装包里的bundle文件:
fmod音频bank打包加载以及热更方案_第9张图片
pc上和手机上加载的代码是不变的,路径都是Application.persistentDataPath。

第三种,如果是以原生的bank的方式,直接拷贝到Application.persistentDataPath,下如何加载呢?
就是我们不打包,直接进行bank的加载,只是此时bank在持久化的目录下而已。
我同样做了实验,将一个原始Tone.bank直接拷贝到Application.persistentDataPath下,然后用下面的函数加载:

public static void LoadBank()
{
    LoadedBank loadedBank = new LoadedBank();
    string bankPath = Application.persistentDataPath + "/Tone.bank";
    FMOD.RESULT loadResult = Instance.studioSystem.loadBankFile(bankPath, FMOD.Studio.LOAD_BANK_FLAGS.NORMAL, out loadedBank.Bank);
}

经过测试,加载争取。

综上,无论是Streaming Assets还是Asset Bundle,还是原生的bank只是拷贝到Application.persistentDataPath之后,都是可以正常加载的。

如果是考虑热更新的话,我是这样想的:
1、同名的bank,优先加载Application.persistentDataPath下的bank
2、音频制作方面,需要制作两份Master Bank,一个是在Streaming下的,一个是在Application.persistentDataPath下,如果是同名的bank,遵循规则1,这样就只加载一份的bank了。
3、也可是Streaming的不改,如果是新添加的音频,那么则直接在新的bank中,此bank热更到Application.persistentDataPath下。程序一运行,就直接读取两个目录下的所有的bank即可。
4、如果bank过大,考虑使用loadSampleData?这个没怎么研究,后面再补充下。结合profie分析下fmod的内存占用情况。还可以进一步的优化,进行bank的卸载:UnloadBank方法。

public static void UnloadBank(string bankName)
  {
      LoadedBank loadedBank;
      if (Instance.loadedBanks.TryGetValue(bankName, out loadedBank))
      {
          loadedBank.RefCount--;
          if (loadedBank.RefCount == 0)
          {
              loadedBank.Bank.unload();
              Instance.loadedBanks.Remove(bankName);
              return;
          }
          Instance.loadedBanks[bankName] = loadedBank;
      }
  }

5、判断以事件是否在bank中:


public static bool CheckEventInBank(string bankName, string eventName)
{
	  if (Instance.loadedBanks.ContainsKey(bankName))
	  {
	      LoadedBank bank = Instance.loadedBanks[bankName];
	      FMOD.Studio.EventDescription[] eventList;
	      var result = bank.Bank.getEventList(out eventList);
	      if (result == FMOD.RESULT.OK)
	      {
	          foreach (var eventDesc in eventList)
	          {
	              string path;
	              eventDesc.getPath(out path);
	              if (path.Equals(eventName)) return true;
	          }
	      }
	  }
	  return false;
}

ok,至此,fmod的音频打包,加载介绍完毕,后续在补充实际项目中遇到的问题。

你可能感兴趣的:(fmod)