BsOAImporter.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsOAImporter.h"
  4. #include "FileSystem/BsDataStream.h"
  5. #include "FileSystem/BsFileSystem.h"
  6. #include "BsWaveDecoder.h"
  7. #include "BsFLACDecoder.h"
  8. #include "BsOggVorbisDecoder.h"
  9. #include "BsOggVorbisEncoder.h"
  10. #include "Audio/BsAudioClipImportOptions.h"
  11. #include "Audio/BsAudioUtility.h"
  12. namespace bs
  13. {
  14. OAImporter::OAImporter()
  15. :SpecificImporter()
  16. {
  17. }
  18. OAImporter::~OAImporter()
  19. {
  20. }
  21. bool OAImporter::isExtensionSupported(const WString& ext) const
  22. {
  23. WString lowerCaseExt = ext;
  24. StringUtil::toLowerCase(lowerCaseExt);
  25. return lowerCaseExt == L"wav" || lowerCaseExt == L"flac" || lowerCaseExt == L"ogg";
  26. }
  27. bool OAImporter::isMagicNumberSupported(const UINT8* magicNumPtr, UINT32 numBytes) const
  28. {
  29. // Don't check for magic number, rely on extension
  30. return true;
  31. }
  32. SPtr<ImportOptions> OAImporter::createImportOptions() const
  33. {
  34. return bs_shared_ptr_new<AudioClipImportOptions>();
  35. }
  36. SPtr<Resource> OAImporter::import(const Path& filePath, SPtr<const ImportOptions> importOptions)
  37. {
  38. SPtr<DataStream> stream = FileSystem::openFile(filePath);
  39. WString extension = filePath.getWExtension();
  40. StringUtil::toLowerCase(extension);
  41. UPtr<AudioDecoder> reader(nullptr, nullptr);
  42. if(extension == L".wav")
  43. reader = bs_unique_ptr<AudioDecoder>(bs_new<WaveDecoder>());
  44. else if(extension == L".flac")
  45. reader = bs_unique_ptr<AudioDecoder>(bs_new<FLACDecoder>());
  46. else if(extension == L".ogg")
  47. reader = bs_unique_ptr<AudioDecoder>(bs_new<OggVorbisDecoder>());
  48. if (reader == nullptr)
  49. return nullptr;
  50. AudioDataInfo info;
  51. if (!reader->isValid(stream))
  52. return nullptr;
  53. if (!reader->open(stream, info))
  54. return nullptr;
  55. UINT32 bytesPerSample = info.bitDepth / 8;
  56. UINT32 bufferSize = info.numSamples * bytesPerSample;
  57. UINT8* sampleBuffer = (UINT8*)bs_alloc(bufferSize);
  58. reader->read(sampleBuffer, info.numSamples);
  59. SPtr<const AudioClipImportOptions> clipIO = std::static_pointer_cast<const AudioClipImportOptions>(importOptions);
  60. // If 3D, convert to mono
  61. if(clipIO->getIs3D() && info.numChannels > 1)
  62. {
  63. UINT32 numSamplesPerChannel = info.numSamples / info.numChannels;
  64. UINT32 monoBufferSize = numSamplesPerChannel * bytesPerSample;
  65. UINT8* monoBuffer = (UINT8*)bs_alloc(monoBufferSize);
  66. AudioUtility::convertToMono(sampleBuffer, monoBuffer, info.bitDepth, numSamplesPerChannel, info.numChannels);
  67. info.numSamples = numSamplesPerChannel;
  68. info.numChannels = 1;
  69. bs_free(sampleBuffer);
  70. sampleBuffer = monoBuffer;
  71. bufferSize = monoBufferSize;
  72. }
  73. // Convert bit depth if needed
  74. if(clipIO->getBitDepth() != info.bitDepth)
  75. {
  76. UINT32 outBufferSize = info.numSamples * (clipIO->getBitDepth() / 8);
  77. UINT8* outBuffer = (UINT8*)bs_alloc(outBufferSize);
  78. AudioUtility::convertBitDepth(sampleBuffer, info.bitDepth, outBuffer, clipIO->getBitDepth(), info.numSamples);
  79. info.bitDepth = clipIO->getBitDepth();
  80. bs_free(sampleBuffer);
  81. sampleBuffer = outBuffer;
  82. bufferSize = outBufferSize;
  83. }
  84. // Encode to Ogg Vorbis if needed
  85. if(clipIO->getFormat() == AudioFormat::VORBIS)
  86. {
  87. // Note: If the original source was in Ogg Vorbis we could just copy it here, but instead we decode to PCM and
  88. // then re-encode which is redundant. If later we decide to copy be aware that the engine encodes Ogg in a
  89. // specific quality, and the the import source might have lower or higher bitrate/quality.
  90. UINT8* encodedSamples = OggVorbisEncoder::PCMToOggVorbis(sampleBuffer, info, bufferSize);
  91. bs_free(sampleBuffer);
  92. sampleBuffer = encodedSamples;
  93. }
  94. SPtr<MemoryDataStream> sampleStream = bs_shared_ptr_new<MemoryDataStream>(sampleBuffer, bufferSize);
  95. AUDIO_CLIP_DESC clipDesc;
  96. clipDesc.bitDepth = info.bitDepth;
  97. clipDesc.format = clipIO->getFormat();
  98. clipDesc.frequency = info.sampleRate;
  99. clipDesc.numChannels = info.numChannels;
  100. clipDesc.readMode = clipIO->getReadMode();
  101. clipDesc.is3D = clipIO->getIs3D();
  102. SPtr<AudioClip> clip = AudioClip::_createPtr(sampleStream, bufferSize, info.numSamples, clipDesc);
  103. WString fileName = filePath.getWFilename(false);
  104. clip->setName(fileName);
  105. return clip;
  106. }
  107. }