2
0

WavParser.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AudioInput/WavParser.h>
  9. namespace Audio
  10. {
  11. ///////////////////////////////////////////////////////////////////////////////////////////////
  12. /*static*/ const AZ::u8 WavFileParser::riff_tag[4] = { 'R', 'I', 'F', 'F' };
  13. /*static*/ const AZ::u8 WavFileParser::wave_tag[4] = { 'W', 'A', 'V', 'E' };
  14. /*static*/ const AZ::u8 WavFileParser::fmt__tag[4] = { 'f', 'm', 't', ' ' };
  15. /*static*/ const AZ::u8 WavFileParser::data_tag[4] = { 'd', 'a', 't', 'a' };
  16. ///////////////////////////////////////////////////////////////////////////////////////////////
  17. WavFileParser::WavFileParser()
  18. {
  19. ::memset(&m_header, 0, sizeof(m_header));
  20. }
  21. ///////////////////////////////////////////////////////////////////////////////////////////////
  22. WavFileParser::~WavFileParser()
  23. {
  24. }
  25. ///////////////////////////////////////////////////////////////////////////////////////////////
  26. size_t WavFileParser::ParseHeader(AZ::IO::FileIOStream& fileStream)
  27. {
  28. if (IsHeaderValid())
  29. {
  30. // Header was already parsed then, no work needed.
  31. return 0;
  32. }
  33. AZ_Assert(fileStream.IsOpen(), "WavFileParser::ParseHeader - FileIOStream is not open!\n");
  34. // Parsers are allowed to seek into the stream if they want in order to perform their task
  35. // of gathering file information. Will return the byte-offset into the file where the
  36. // data starts.
  37. fileStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
  38. // Begin parsing, start with the RIFF + WAVE tags...
  39. AZ::u8* writePtr = reinterpret_cast<AZ::u8*>(&m_header);
  40. size_t copySize = sizeof(m_header.riff) + sizeof(m_header.wave);
  41. fileStream.Read(copySize, writePtr);
  42. if (!ValidTag(m_header.riff.tag, WavFileParser::riff_tag))
  43. {
  44. AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Not a 'RIFF'!\n");
  45. return 0;
  46. }
  47. if (!ValidTag(m_header.wave, WavFileParser::wave_tag))
  48. {
  49. AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Not a 'RIFF / WAVE'!\n");
  50. return 0;
  51. }
  52. writePtr += copySize;
  53. bool formatTagFound = false;
  54. bool dataTagFound = false;
  55. while (!dataTagFound)
  56. {
  57. // read the next tag, check what it is...
  58. ChunkHeader header;
  59. copySize = sizeof(header);
  60. fileStream.Read(copySize, &header);
  61. if (ValidTag(header.tag, WavFileParser::fmt__tag))
  62. {
  63. m_header.fmt.header = header;
  64. writePtr = reinterpret_cast<AZ::u8*>(&m_header.fmt);
  65. writePtr += sizeof(m_header.fmt.header); // skip forward because it was already read into the temp chunkheader.
  66. copySize = sizeof(m_header.fmt) - sizeof(m_header.fmt.header);
  67. fileStream.Read(copySize, writePtr);
  68. formatTagFound = true;
  69. }
  70. else if (ValidTag(header.tag, WavFileParser::data_tag))
  71. {
  72. m_header.data = header;
  73. dataTagFound = true;
  74. }
  75. else
  76. {
  77. // Unknown tag, skip by the size specified
  78. // It is possible that we want to read certain tag data in the future.
  79. // Tools/encoders may embed extra data in various sections.
  80. fileStream.Seek(header.size, AZ::IO::GenericStream::ST_SEEK_CUR);
  81. }
  82. // Check for Eof (premature)...
  83. if (fileStream.GetCurPos() == fileStream.GetLength())
  84. {
  85. AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Got to end of file and did not locate a 'data' chunk!\n");
  86. return 0;
  87. }
  88. }
  89. if (!ValidTag(m_header.fmt.header.tag, WavFileParser::fmt__tag))
  90. {
  91. AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Did not find a 'fmt' tag!\n");
  92. }
  93. if (!ValidTag(m_header.data.tag, WavFileParser::data_tag))
  94. {
  95. AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Did not find a 'data' tag!\n");
  96. }
  97. #ifdef AZ_DEBUG_BUILD
  98. if (formatTagFound)
  99. {
  100. AZ_TracePrintf("WavFileParser", "Format: %u\n", static_cast<AZ::u32>(GetSampleType()));
  101. AZ_TracePrintf("WavFileParser", "Channels: %u\n", GetNumChannels());
  102. AZ_TracePrintf("WavFileParser", "SampleRate: %u\n", GetSampleRate());
  103. AZ_TracePrintf("WavFileParser", "ByteRate: %u\n", GetByteRate());
  104. AZ_TracePrintf("WavFileParser", "BitsPerSample: %u\n", GetBitsPerSample());
  105. AZ_TracePrintf("WavFileParser", "DataSize: %u\n", GetDataSize());
  106. }
  107. #endif // AZ_DEBUG_BUILD
  108. if (dataTagFound && formatTagFound)
  109. {
  110. m_headerIsValid = true;
  111. return fileStream.GetCurPos();
  112. }
  113. else
  114. {
  115. return 0;
  116. }
  117. }
  118. ///////////////////////////////////////////////////////////////////////////////////////////////
  119. AudioInputSampleType WavFileParser::GetSampleType() const
  120. {
  121. switch (m_header.fmt.audioFormat)
  122. {
  123. case 1:
  124. return AudioInputSampleType::Int;
  125. case 3:
  126. return AudioInputSampleType::Float;
  127. default:
  128. return AudioInputSampleType::Unsupported;
  129. }
  130. }
  131. ///////////////////////////////////////////////////////////////////////////////////////////////
  132. // static
  133. AZ_FORCE_INLINE bool WavFileParser::ValidTag(const AZ::u8 tag[4], const AZ::u8 name[4])
  134. {
  135. return (tag[0] == name[0] && tag[1] == name[1] && tag[2] == name[2] && tag[3] == name[3]);
  136. }
  137. } // namespace Audio