[{"data":1,"prerenderedAt":159},["ShallowReactive",2],{"\u002F2015-05-21-ue4-fmod-visulization":3},{"id":4,"title":5,"body":6,"date":135,"description":12,"extension":136,"meta":137,"navigation":140,"path":152,"seo":153,"stem":154,"tags":155,"__hash__":158},"blogs\u002F_legacy\u002F2015\u002F2015-05-21-ue4-fmod-visulization.md","UE4与FMod音乐可视化验证",{"type":7,"value":8,"toc":131},"minimark",[9,13,16,19,30,33,36,39,45,48,54,57,60,66,69,75,80,83,89,92,98,101,107,110,116,119,122,128],[10,11,12],"p",{},"制作音游的一个重要步骤，就是验证引擎的相关技术特性，以此来决定是否更换引擎或者更改设计。",[10,14,15],{},"当前UE版本4.7.6；FMod版本1.06.02；",[10,17,18],{},"由于需要播放用户提供的音乐文件，所以需要读取用户设备上的文件。在翻阅文档之后，发现可以使用PlatformFileManager读取外部文件相关信息，同时也有获取目录信息的相关接口。",[20,21,26],"pre",{"className":22,"code":24,"language":25},[23],"language-text","FString CompleteFilePath = \"H:\u002Fmusic\u002Ftest.mp3\";\nif (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*CompleteFilePath))\n{\nOutputDebugStringA(\"Error\");\nreturn 0;\n}\n\nconst int32 FileSize = FPlatformFileManager::Get().GetPlatformFile().FileSize(*CompleteFilePath);\n","text",[27,28,24],"code",{"__ignoreMap":29},"",[10,31,32],{},"通过上面的代码，成功获得文件大小。外部文件相关验证完成。",[10,34,35],{},"接下来就是音乐播放相关的实现了，FMod在UE4上有插件实现。基本可以满足使用需求。",[10,37,38],{},"下载并将FMod插件解压到UE4目录之后，首先在项目的*.Build.cs中添加下面的代码",[20,40,43],{"className":41,"code":42,"language":25},[23],"public class mpop : ModuleRules\n{\npublic mpop(TargetInfo Target)\n{\nPublicDependencyModuleNames.AddRange(new string[] { \"Core\", \"CoreUObject\", \"Engine\", \"InputCore\" });\n\nPrivateDependencyModuleNames.AddRange(new string[] { \"FMODStudio\" });\n}\n}\n",[27,44,42],{"__ignoreMap":29},[10,46,47],{},"这样一来在需要使用到FMod地方进行文件包含就不会遇到报错了",[20,49,52],{"className":50,"code":51,"language":25},[23],"#include \"fmod_studio.hpp\"\n",[27,53,51],{"__ignoreMap":29},[10,55,56],{},"如果在编译时遇到LNK1181之类的编译错误，建议按照提示查找FMod插件中是否提供了对应的Lib文件。如果没有的话可能需要重新编译插件或者使用更早期有提供的版本。",[10,58,59],{},"使用FMod底层API的第一步是得到一个底层的API System，根据使用方式的不同有两条路径。",[10,61,62],{},[63,64,65],"strong",{},"获取插件系统",[10,67,68],{},"适合与EndPlay和BeginPlay之类的事件挂钩进行使用。不需要自主使用update，插件内部已经有更新机制了。",[20,70,73],{"className":71,"code":72,"language":25},[23],"result = IFMODStudioModule::Get().GetStudioSystem(EFMODSystemContext::Runtime)->getLowLevelSystem(&system);\n\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = system->getVersion(&version);\n\nif (result != FMOD_RESULT::FMOD_OK) break;\n",[27,74,72],{"__ignoreMap":29},[10,76,77],{},[63,78,79],{},"自主创建系统",[10,81,82],{},"适合配合单例模式使用，和插件建立的系统相对独立。不过依然不需要自己进行update操作。与直接获取不同的是，需要自己进行初始化操作。",[20,84,87],{"className":85,"code":86,"language":25},[23],"result = FMOD::System_Create(&system);\n\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = system->getVersion(&version);\n\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = system->init(32, FMOD_INIT_NORMAL, extradriverdata);    \u002F\u002F \u003C进行初始化\n\nif (result != FMOD_RESULT::FMOD_OK) break;\n",[27,88,86],{"__ignoreMap":29},[10,90,91],{},"系统创建之后，音乐播放使用createsound即可",[20,93,96],{"className":94,"code":95,"language":25},[23],"result = system->createSound(\"H:\u002Fmusic\u002Ftest.mp3\", FMOD_LOOP_NORMAL | FMOD_2D, 0, &sound);\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = sound->getNumSubSounds(&numsubsounds);\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nif (numsubsounds)\n{\nsound->getSubSound(0, &sound_to_play);\nif (result != FMOD_RESULT::FMOD_OK) break;\n}\nelse\n{\nsound_to_play = sound;\n}\n\nresult = system->playSound(sound_to_play, 0, false, &channel);\nif (result != FMOD_RESULT::FMOD_OK) break;\n",[27,97,95],{"__ignoreMap":29},[10,99,100],{},"要对音乐进行可视化，最基础的数据获取方式是对音乐进行快速傅里叶变换（FFT）。FMod本身有提供FFT的功能，因此直接使用即可，无需再造车轮。FMod提供的FFT是DSP的一种，可以加载在Channel、ChannelGroup、ChannelControl上。这里，我们选择在系统创建并初始化之后直接加载到ChannelGroup上。",[20,102,105],{"className":103,"code":104,"language":25},[23],"FMOD::ChannelGroup *mastergroup;\n\nresult = system->createDSPByType(FMOD_DSP_TYPE_FFT, &fftdsp);\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = system->getMasterChannelGroup(&mastergroup);\nif (result != FMOD_RESULT::FMOD_OK) break;\n\nresult = mastergroup->addDSP(0, fftdsp);\nif (result != FMOD_RESULT::FMOD_OK) break;\n",[27,106,104],{"__ignoreMap":29},[10,108,109],{},"在每一次Ontick时进行FFT数据的获取：",[20,111,114],{"className":112,"code":113,"language":25},[23],"FMOD_DSP_PARAMETER_FFT *fft;\n\nchar* ts = new char[40];\nfftdsp->getParameterData(FMOD_DSP_FFT_SPECTRUMDATA, (void **)&fft, 0, 0, 0);\nOutputDebugStringA(\"\u003CFMODHolders> - Update Begin -\\n\");\nfor (int channel = 0; channel \u003C fft->numchannels; channel++){\nOutputDebugStringA(\"> -c-\");\nfor (int bin = 0; bin \u003C fft->length; bin++)\n{\nfloat val = fft->spectrum[channel][bin];\nsprintf(ts, \"> spec: %f \\n\", val);\nOutputDebugStringA(ts);\n}\n}\nOutputDebugStringA(\"\u003CFMODHolders> - Update End -\\n\");\ndelete ts;\n",[27,115,113],{"__ignoreMap":29},[10,117,118],{},"开始播放之后就可以看到fft数据已经正常输出了。",[10,120,121],{},"为了方便对fft的数据进行解析，需要获得采样率。",[20,123,126],{"className":124,"code":125,"language":25},[23],"system->getSoftwareFormat(&tnp, NULL, NULL);\n",[27,127,125],{"__ignoreMap":29},[10,129,130],{},"这样基本上音乐数据一块的验证就完成了。",{"title":29,"searchDepth":132,"depth":133,"links":134},2,3,[],"2015-05-21","md",{"layout":138,"status":139,"published":140,"author":141,"author_login":142,"author_email":143,"author_url":144,"wordpress_id":145,"wordpress_url":146,"date_gmt":147,"excerpt":148},"post","publish",true,{"display_name":142,"login":142,"email":143,"url":144},"chaoshikari","chaoshikari@gmail.com","\u002F",1272,"\u002F\u002F?p=1272","2015-05-21 04:09:36 +0000",{"type":7,"value":149},[150],[10,151,12],{},"\u002F2015-05-21-ue4-fmod-visulization",{"title":5,"description":12},"_legacy\u002F2015\u002F2015-05-21-ue4-fmod-visulization",[156,157],"UE4","FMod","53jn81bS0zOR_BQlQpG7tZSyEzEGNvhY4okZF-i8EkU",1788763180879]