BsFMODImporter.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsFMODImporter.h"
  4. #include "FileSystem/BsDataStream.h"
  5. #include "FileSystem/BsFileSystem.h"
  6. #include "Audio/BsAudioClipImportOptions.h"
  7. #include "Audio/BsAudioUtility.h"
  8. #include "BsFMODAudio.h"
  9. #include "BsOggVorbisEncoder.h"
  10. #include <fmod.hpp>
  11. namespace bs
  12. {
  13. FMODImporter::FMODImporter()
  14. :SpecificImporter()
  15. {
  16. }
  17. FMODImporter::~FMODImporter()
  18. {
  19. }
  20. bool FMODImporter::isExtensionSupported(const WString& ext) const
  21. {
  22. WString lowerCaseExt = ext;
  23. StringUtil::toLowerCase(lowerCaseExt);
  24. return lowerCaseExt == L"wav" || lowerCaseExt == L"flac" || lowerCaseExt == L"ogg" || lowerCaseExt == L"mp3" ||
  25. lowerCaseExt == L"wma" || lowerCaseExt == L"asf" || lowerCaseExt == L"wmv" || lowerCaseExt == L"midi" ||
  26. lowerCaseExt == L"fsb" || lowerCaseExt == L"aif" || lowerCaseExt == L"aiff";
  27. }
  28. bool FMODImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
  29. {
  30. // Don't check for magic number, rely on extension
  31. return true;
  32. }
  33. SPtr<ImportOptions> FMODImporter::createImportOptions() const
  34. {
  35. return bs_shared_ptr_new<AudioClipImportOptions>();
  36. }
  37. SPtr<Resource> FMODImporter::import(const Path& filePath, SPtr<const ImportOptions> importOptions)
  38. {
  39. WString extension = filePath.getWExtension();
  40. StringUtil::toLowerCase(extension);
  41. AudioDataInfo info;
  42. FMOD::Sound* sound;
  43. String pathStr = filePath.toString();
  44. if(gFMODAudio()._getFMOD()->createSound(pathStr.c_str(), FMOD_CREATESAMPLE, nullptr, &sound) != FMOD_OK)
  45. {
  46. LOGERR("Failed importing audio file: " + pathStr);
  47. return nullptr;
  48. }
  49. FMOD_SOUND_FORMAT format;
  50. INT32 numChannels = 0;
  51. INT32 numBits = 0;
  52. sound->getFormat(nullptr, &format, &numChannels, &numBits);
  53. if(format != FMOD_SOUND_FORMAT_PCM8 && format != FMOD_SOUND_FORMAT_PCM16 && format != FMOD_SOUND_FORMAT_PCM24
  54. && format != FMOD_SOUND_FORMAT_PCM32 && format != FMOD_SOUND_FORMAT_PCMFLOAT)
  55. {
  56. LOGERR("Failed importing audio file, invalid imported format: " + pathStr);
  57. return nullptr;
  58. }
  59. float frequency = 0.0f;
  60. sound->getDefaults(&frequency, nullptr);
  61. UINT32 size;
  62. sound->getLength(&size, FMOD_TIMEUNIT_PCMBYTES);
  63. info.bitDepth = numBits;
  64. info.numChannels = numChannels;
  65. info.sampleRate = (UINT32)frequency;
  66. info.numSamples = size / (info.bitDepth / 8);
  67. UINT32 bytesPerSample = info.bitDepth / 8;
  68. UINT32 bufferSize = info.numSamples * bytesPerSample;
  69. UINT8* sampleBuffer = (UINT8*)bs_alloc(bufferSize);
  70. assert(bufferSize == size);
  71. UINT8* startData = nullptr;
  72. UINT8* endData = nullptr;
  73. UINT32 startSize = 0;
  74. UINT32 endSize = 0;
  75. sound->lock(0, size, (void**)&startData, (void**)&endData, &startSize, &endSize);
  76. if(format == FMOD_SOUND_FORMAT_PCMFLOAT)
  77. {
  78. assert(info.bitDepth == 32);
  79. UINT32* output = (UINT32*)sampleBuffer;
  80. for(UINT32 i = 0; i < info.numSamples; i++)
  81. {
  82. float value = *(((float*)startData) + i);
  83. *output = (UINT32)(value * 2147483647.0f);
  84. output++;
  85. }
  86. }
  87. else
  88. {
  89. memcpy(sampleBuffer, startData, bufferSize);
  90. }
  91. sound->unlock((void**)&startData, (void**)&endData, startSize, endSize);
  92. sound->release();
  93. SPtr<const AudioClipImportOptions> clipIO = std::static_pointer_cast<const AudioClipImportOptions>(importOptions);
  94. // If 3D, convert to mono
  95. if (clipIO->getIs3D() && info.numChannels > 1)
  96. {
  97. UINT32 numSamplesPerChannel = info.numSamples / info.numChannels;
  98. UINT32 monoBufferSize = numSamplesPerChannel * bytesPerSample;
  99. UINT8* monoBuffer = (UINT8*)bs_alloc(monoBufferSize);
  100. AudioUtility::convertToMono(sampleBuffer, monoBuffer, info.bitDepth, numSamplesPerChannel, info.numChannels);
  101. info.numSamples = numSamplesPerChannel;
  102. info.numChannels = 1;
  103. bs_free(sampleBuffer);
  104. sampleBuffer = monoBuffer;
  105. bufferSize = monoBufferSize;
  106. }
  107. // Convert bit depth if needed
  108. if (clipIO->getBitDepth() != info.bitDepth)
  109. {
  110. UINT32 outBufferSize = info.numSamples * (clipIO->getBitDepth() / 8);
  111. UINT8* outBuffer = (UINT8*)bs_alloc(outBufferSize);
  112. AudioUtility::convertBitDepth(sampleBuffer, info.bitDepth, outBuffer, clipIO->getBitDepth(), info.numSamples);
  113. info.bitDepth = clipIO->getBitDepth();
  114. bs_free(sampleBuffer);
  115. sampleBuffer = outBuffer;
  116. bufferSize = outBufferSize;
  117. }
  118. // Encode to Ogg Vorbis if needed
  119. if (clipIO->getFormat() == AudioFormat::VORBIS)
  120. {
  121. // Note: If the original source was in Ogg Vorbis we could just copy it here, but instead we decode to PCM and
  122. // then re-encode which is redundant. If later we decide to copy be aware that the engine encodes Ogg in a
  123. // specific quality, and the the import source might have lower or higher bitrate/quality.
  124. UINT8* encodedSamples = OggVorbisEncoder::PCMToOggVorbis(sampleBuffer, info, bufferSize);
  125. bs_free(sampleBuffer);
  126. sampleBuffer = encodedSamples;
  127. }
  128. SPtr<MemoryDataStream> sampleStream = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, bufferSize);
  129. AUDIO_CLIP_DESC clipDesc;
  130. clipDesc.bitDepth = info.bitDepth;
  131. clipDesc.format = clipIO->getFormat();
  132. clipDesc.frequency = info.sampleRate;
  133. clipDesc.numChannels = info.numChannels;
  134. clipDesc.readMode = clipIO->getReadMode();
  135. clipDesc.is3D = clipIO->getIs3D();
  136. SPtr<AudioClip> clip = AudioClip::_createPtr(sampleStream, bufferSize, info.numSamples, clipDesc);
  137. WString fileName = filePath.getWFilename(false);
  138. clip->setName(fileName);
  139. return clip;
  140. }
  141. }