Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,224 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AudioInput/AudioInputFile.h>
#include <AudioInput/WavParser.h>
#include <Common_wwise.h>
#include <AzCore/IO/FileIO.h>
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Audio Input File
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputFile::AudioInputFile(const SAudioInputConfig& sourceConfig)
{
m_config = sourceConfig;
switch (sourceConfig.m_sourceType)
{
case AudioInputSourceType::WavFile:
m_parser.reset(aznew WavFileParser());
break;
case AudioInputSourceType::PcmFile:
break;
default:
return;
}
LoadFile();
}
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputFile::~AudioInputFile()
{
UnloadFile();
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputFile::LoadFile()
{
bool result = false;
// Filename should be relative to the project assets root e.g.: 'sounds/files/my_sound.wav'
AZ::IO::FileIOStream fileStream(m_config.m_sourceFilename.c_str(), AZ::IO::OpenMode::ModeRead | AZ::IO::OpenMode::ModeBinary);
if (fileStream.IsOpen())
{
m_dataSize = fileStream.GetLength();
if (m_dataSize > 0)
{
// Here if a parser is available, can pass the file stream forward
// so it can parse header information.
// It will return the number of header bytes read, that is an offset to
// the beginning of the real signal data.
if (m_parser)
{
size_t headerBytesRead = m_parser->ParseHeader(fileStream);
if (headerBytesRead > 0 && m_parser->IsHeaderValid())
{
// Update the size...
m_dataSize = m_parser->GetDataSize();
// Set the format configuration obtained from the file...
m_config.m_bitsPerSample = m_parser->GetBitsPerSample();
m_config.m_numChannels = m_parser->GetNumChannels();
m_config.m_sampleRate = m_parser->GetSampleRate();
m_config.m_sampleType = m_parser->GetSampleType();
}
}
if (IsOk())
{
// Allocate a new buffer to hold the data...
m_dataPtr = new AZ::u8[m_dataSize];
// Read file into internal buffer...
size_t bytesRead = fileStream.Read(m_dataSize, m_dataPtr);
ResetBookmarks();
// Verify we read the full amount...
result = (bytesRead == m_dataSize);
}
}
fileStream.Close();
}
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputFile::UnloadFile()
{
if (m_dataPtr)
{
delete [] m_dataPtr;
m_dataPtr = nullptr;
}
m_dataSize = 0;
m_dataCurrentPtr = nullptr;
m_dataCurrentReadSize = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputFile::ReadInput([[maybe_unused]] const AudioStreamData& data)
{
// Don't really need this for File-based sources, the whole file is read in the constructor.
// However, we may need to implement this for asynchronous loading of the file (streaming).
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputFile::WriteOutput(AkAudioBuffer* akBuffer)
{
AZ::u16 numSampleFramesRequested = (akBuffer->MaxFrames() - akBuffer->uValidFrames);
if (m_config.m_sampleType == AudioInputSampleType::Int)
{
void* outBuffer = akBuffer->GetInterleavedData();
AZ::u16 numSampleFramesCopied = static_cast<AZ::u16>(CopyData(numSampleFramesRequested, outBuffer));
akBuffer->uValidFrames += numSampleFramesCopied;
akBuffer->eState = (numSampleFramesCopied > 0) ? AK_DataReady
: (IsEof() ? AK_NoMoreData : AK_NoDataReady);
}
else if (m_config.m_sampleType == AudioInputSampleType::Float)
{
// Not Implemented yet!
akBuffer->eState = AK_NoMoreData;
// Implementing this for files will likely involve de-interleaving the samples.
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputFile::IsOk() const
{
bool ok = (m_dataSize > 0);
ok &= IsFormatValid();
if (m_parser)
{
ok &= m_parser->IsHeaderValid();
ok &= (m_dataSize == m_parser->GetDataSize());
}
return ok;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputFile::OnDeactivated()
{
if (m_config.m_autoUnloadFile)
{
UnloadFile();
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
size_t AudioInputFile::CopyData(size_t numSampleFrames, void* toBuffer)
{
// Copies data to an output buffer.
// Size requested is in sample frames, not bytes!
// Number of frames actually copied is returned. This is useful if more
// frames were requested than can be copied.
if (!toBuffer || !numSampleFrames)
{
return 0;
}
const size_t frameBytes = (m_config.m_numChannels * m_config.m_bitsPerSample) >> 3; // bits --> bytes
size_t copySize = numSampleFrames * frameBytes;
// Check if request is larger than remaining, trim off excess.
if (m_dataCurrentReadSize + copySize > m_dataSize)
{
size_t excess = (m_dataCurrentReadSize + copySize) - m_dataSize;
copySize -= excess;
numSampleFrames = (copySize / frameBytes);
}
if (copySize > 0)
{
::memcpy(toBuffer, m_dataCurrentPtr, copySize);
m_dataCurrentReadSize += copySize;
m_dataCurrentPtr += copySize;
}
return numSampleFrames;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputFile::ResetBookmarks()
{
m_dataCurrentPtr = m_dataPtr;
m_dataCurrentReadSize = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputFile::IsEof() const
{
return (m_dataCurrentReadSize == m_dataSize);
}
} // namespace Audio
@@ -0,0 +1,127 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AudioSourceManager.h>
namespace Audio
{
/**
* Base class for audio file parser.
* Any supported audio file types will have a parser implementation
* that will parse header information to extract the audio format.
*/
class AudioFileParser
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(AudioFileParser)
AudioFileParser() = default;
virtual ~AudioFileParser() = default;
AudioFileParser(const AudioFileParser&) = delete;
AudioFileParser& operator=(const AudioFileParser&) = delete;
/**
* Parse header from a file stream.
* Parses header of an audio file and returns the byte-offset into the file where the audio data begins.
* @param fileStream An opened file stream on the audio file.
* @return Byte-offset into the file where audio data begins.
*/
virtual size_t ParseHeader(AZ::IO::FileIOStream& fileStream) = 0;
/**
* Check validity of the header info.
* This should only return true if the header was parsed and user can expect to see valid format data.
* @return True if the header was parsed without error.
*/
virtual bool IsHeaderValid() const = 0;
virtual AudioInputSampleType GetSampleType() const = 0;
virtual AZ::u32 GetNumChannels() const = 0;
virtual AZ::u32 GetSampleRate() const = 0;
virtual AZ::u32 GetByteRate() const = 0;
virtual AZ::u32 GetBitsPerSample() const = 0;
virtual AZ::u32 GetDataSize() const = 0;
};
/**
* A type of AudioInputSource representing an audio file.
* Contains audio file data, holds a pointer to the raw data and provides methods to read chunks of data at a time
* to an output (AkAudioBuffer).
*/
class AudioInputFile
: public AudioInputSource
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(AudioInputFile)
AudioInputFile(const SAudioInputConfig& sourceConfig);
~AudioInputFile() override;
/**
* Load file into buffer.
* Use an AudioFileParser if needed to parse header information, then proceed to load the audio data
* to the internal buffer.
* @return True upon successful load, false otherwise.
*/
bool LoadFile();
/**
* Unload the file data.
* Release the internal buffer of file data.
*/
void UnloadFile();
void ReadInput(const AudioStreamData& data) override;
void WriteOutput(AkAudioBuffer* akBuffer) override;
bool IsOk() const override;
void OnDeactivated() override;
/**
* Copy data from the internal buffer to an output buffer.
* Copies a specified number of sample frames to an output buffer. If more frames are requested
* than can be copied, only allowable frames are copied and number of frames that were copied is returned.
* @param numSampleFrames Number of sample frames requested for copy.
* @param toBuffer Output buffer to copy to.
* @return Number of sample frames actually copied.
*/
size_t CopyData(size_t numSampleFrames, void* toBuffer); // frames, not bytes!
private:
/**
* Resets internal bookmarking.
* Bookmarks are used internally to keep track of where we are in the buffer during
* chunk-copying to output.
*/
void ResetBookmarks();
/**
* Checks whether data copying has reached the end of the file data.
* @return True if end of file has been reached, false otherwise.
*/
bool IsEof() const;
AZStd::unique_ptr<AudioFileParser> m_parser = nullptr;
AZ::u8* m_dataPtr = nullptr; ///< The internal data buffer.
size_t m_dataSize = 0; ///< The internal data size.
// Bookmarks
AZ::u8* m_dataCurrentPtr = nullptr; ///< The internal bookmark pointer.
size_t m_dataCurrentReadSize = 0; ///< The internal bookmark indicating how much data has been read so far.
};
} // namespace Audio
@@ -0,0 +1,81 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AudioInput/AudioInputMicrophone.h>
#include <AzCore/Casting/numeric_cast.h>
#include <MicrophoneBus.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Audio Input Source : Microphone
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputMicrophone::AudioInputMicrophone(const SAudioInputConfig& sourceConfig)
{
m_config = sourceConfig;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputMicrophone::~AudioInputMicrophone()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputMicrophone::ReadInput([[maybe_unused]] const AudioStreamData& data)
{
// ReadInput only used when PUSHing source data in, and would need an internal buffer to store
// the data temporarily. For Microphone, the microphone impl has its own internal buffer, so
// we only need to PULL data in WriteOutput.
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputMicrophone::WriteOutput(AkAudioBuffer* akBuffer)
{
AZ::u32 numSampleFramesRequested = (akBuffer->MaxFrames() - akBuffer->uValidFrames);
AkSampleType* channelData[2] = { nullptr, nullptr };
for (AZ::u32 channel = 0; channel < akBuffer->NumChannels(); ++channel)
{
channelData[channel] = akBuffer->GetChannel(channel);
}
size_t numSampleFramesCopied = 0;
MicrophoneRequestBus::BroadcastResult(numSampleFramesCopied, &MicrophoneRequestBus::Events::GetData, reinterpret_cast<void**>(channelData), numSampleFramesRequested, m_config, true);
akBuffer->uValidFrames += aznumeric_cast<AkUInt16>(numSampleFramesCopied);
akBuffer->eState = (numSampleFramesCopied > 0) ? AK_DataReady : AK_NoDataReady;
// handle the AK_NoMoreData condition?
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputMicrophone::OnDeactivated()
{
m_config.m_numChannels = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputMicrophone::IsOk() const
{
// Mono and Stereo only
bool ok = (m_config.m_numChannels == 1 || m_config.m_numChannels == 2);
// 32-bit float or 16-bit int only
ok &= (m_config.m_sampleType == AudioInputSampleType::Float && m_config.m_bitsPerSample == 32)
|| (m_config.m_sampleType == AudioInputSampleType::Int && m_config.m_bitsPerSample == 16);
return ok;
}
} // namespace Audio
@@ -0,0 +1,34 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AudioSourceManager.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
class AudioInputMicrophone
: public AudioInputSource
{
public:
AudioInputMicrophone(const SAudioInputConfig& sourceConfig);
~AudioInputMicrophone() override;
void ReadInput(const AudioStreamData& data) override;
void WriteOutput(AkAudioBuffer* akBuffer) override;
bool IsOk() const override;
void OnDeactivated() override;
};
} // namespace Audio
@@ -0,0 +1,131 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AudioInput/AudioInputStream.h>
#include <Common_wwise.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Audio Streaming Input
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputStreaming::AudioInputStreaming(const SAudioInputConfig& sourceConfig)
: m_framesReady(0)
{
m_config = sourceConfig;
size_t bytesPerSample = (m_config.m_bitsPerSample >> 3);
size_t numSamples = m_config.m_sampleRate * m_config.m_numChannels; // <-- This gives a 1 second buffer based on the configuration.
m_config.m_bufferSize = static_cast<AZ::u32>(numSamples * bytesPerSample);
if (m_config.m_sampleType == AudioInputSampleType::Float && m_config.m_bitsPerSample == 32)
{
m_buffer.reset(new RingBuffer<float>(numSamples));
}
else if (m_config.m_sampleType == AudioInputSampleType::Int && m_config.m_bitsPerSample == 16)
{
m_buffer.reset(new RingBuffer<AZ::s16>(numSamples));
}
else
{
AZ_Error("AudioInputStreaming", false, "Audio Stream Format Unsupported! Bits Per Sample = %d, Sample Type = %d",
m_config.m_bitsPerSample, static_cast<int>(m_config.m_sampleType));
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputStreaming::~AudioInputStreaming()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
size_t AudioInputStreaming::ReadStreamingInput(const AudioStreamData& data)
{
size_t numFrames = data.m_sizeBytes / (m_config.m_bitsPerSample >> 3) / m_config.m_numChannels;
size_t framesAdded = m_buffer->AddData(data.m_data, numFrames, m_config.m_numChannels);
m_framesReady += framesAdded;
return framesAdded;
}
///////////////////////////////////////////////////////////////////////////////////////////////
size_t AudioInputStreaming::ReadStreamingMultiTrackInput(AudioStreamMultiTrackData& data)
{
size_t numFrames = data.m_sizeBytes / (m_config.m_bitsPerSample >> 3);
size_t framesAdded = m_buffer->AddMultiTrackDataInterleaved(data.m_data, numFrames, m_config.m_numChannels);
m_framesReady += framesAdded;
return framesAdded;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputStreaming::FlushStreamingInput()
{
m_buffer->ResetBuffer();
m_framesReady = 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////
size_t AudioInputStreaming::GetStreamingInputNumFramesReady() const
{
return m_framesReady;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputStreaming::ReadInput([[maybe_unused]] const AudioStreamData& data)
{
// Intentionally left as an empty implementation.
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputStreaming::WriteOutput(AkAudioBuffer* akBuffer)
{
AZ::u16 numSampleFramesRequested = (akBuffer->MaxFrames() - akBuffer->uValidFrames);
AkSampleType* channelData[6] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr };
for (AZ::u32 channel = 0; channel < akBuffer->NumChannels(); ++channel)
{
channelData[channel] = akBuffer->GetChannel(channel);
}
bool deinterleave = (m_config.m_sampleType == AudioInputSampleType::Float);
size_t numSampleFramesCopied = m_buffer->ConsumeData(reinterpret_cast<void**>(channelData), numSampleFramesRequested, akBuffer->NumChannels(), deinterleave);
akBuffer->uValidFrames += aznumeric_cast<AkUInt16>(numSampleFramesCopied);
m_framesReady -= numSampleFramesCopied;
akBuffer->eState = (numSampleFramesCopied > 0) ? AK_DataReady : AK_NoDataReady;
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputStreaming::IsOk() const
{
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputStreaming::OnActivated()
{
AZ_Assert(m_config.m_sourceId != INVALID_AUDIO_SOURCE_ID, "AudioInputStreaming - Being activated but no valid Source Id!\n");
AudioStreamingRequestBus::Handler::BusConnect(m_config.m_sourceId);
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputStreaming::OnDeactivated()
{
AudioStreamingRequestBus::Handler::BusDisconnect();
}
} // namespace Audio
@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "AudioSourceManager.h"
#include <IAudioSystem.h>
#include <AudioRingBuffer.h>
namespace Audio
{
/**
* A type of AudioInputSource representing an audio stream.
* holds a buffer of the raw data and provides methods to read chunks of data at a time
* to an output (AkAudioBuffer).
*/
class AudioInputStreaming
: public AudioInputSource
, public AudioStreamingRequestBus::Handler
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(AudioInputStreaming)
AudioInputStreaming(const SAudioInputConfig& sourceConfig);
~AudioInputStreaming() override;
// AudioInputSource Interface
void ReadInput(const AudioStreamData& data) override;
void WriteOutput(AkAudioBuffer* akBuffer) override;
bool IsOk() const override;
void OnDeactivated() override;
void OnActivated() override;
// AudioStreamingRequestBus::Handler Interface
size_t ReadStreamingInput(const AudioStreamData& data) override;
size_t ReadStreamingMultiTrackInput(AudioStreamMultiTrackData& data) override;
void FlushStreamingInput();
size_t GetStreamingInputNumFramesReady() const;
private:
AZStd::unique_ptr<RingBufferBase> m_buffer = nullptr;
size_t m_framesReady;
};
} // namespace Audio
@@ -0,0 +1,165 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <AudioInput/WavParser.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
/*static*/ const AZ::u8 WavFileParser::riff_tag[4] = { 'R', 'I', 'F', 'F' };
/*static*/ const AZ::u8 WavFileParser::wave_tag[4] = { 'W', 'A', 'V', 'E' };
/*static*/ const AZ::u8 WavFileParser::fmt__tag[4] = { 'f', 'm', 't', ' ' };
/*static*/ const AZ::u8 WavFileParser::data_tag[4] = { 'd', 'a', 't', 'a' };
///////////////////////////////////////////////////////////////////////////////////////////////
WavFileParser::WavFileParser()
{
::memset(&m_header, 0, sizeof(m_header));
}
///////////////////////////////////////////////////////////////////////////////////////////////
WavFileParser::~WavFileParser()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
size_t WavFileParser::ParseHeader(AZ::IO::FileIOStream& fileStream)
{
if (IsHeaderValid())
{
// Header was already parsed then, no work needed.
return 0;
}
AZ_Assert(fileStream.IsOpen(), "WavFileParser::ParseHeader - FileIOStream is not open!\n");
// Parsers are allowed to seek into the stream if they want in order to perform their task
// of gathering file information. Will return the byte-offset into the file where the
// data starts.
fileStream.Seek(0, AZ::IO::GenericStream::ST_SEEK_BEGIN);
// Begin parsing, start with the RIFF + WAVE tags...
AZ::u8* writePtr = reinterpret_cast<AZ::u8*>(&m_header);
size_t copySize = sizeof(m_header.riff) + sizeof(m_header.wave);
fileStream.Read(copySize, writePtr);
if (!ValidTag(m_header.riff.tag, WavFileParser::riff_tag))
{
AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Not a 'RIFF'!\n");
return 0;
}
if (!ValidTag(m_header.wave, WavFileParser::wave_tag))
{
AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Not a 'RIFF / WAVE'!\n");
return 0;
}
writePtr += copySize;
bool formatTagFound = false;
bool dataTagFound = false;
while (!dataTagFound)
{
// read the next tag, check what it is...
ChunkHeader header;
copySize = sizeof(header);
fileStream.Read(copySize, &header);
if (ValidTag(header.tag, WavFileParser::fmt__tag))
{
m_header.fmt.header = header;
writePtr = reinterpret_cast<AZ::u8*>(&m_header.fmt);
writePtr += sizeof(m_header.fmt.header); // skip forward because it was already read into the temp chunkheader.
copySize = sizeof(m_header.fmt) - sizeof(m_header.fmt.header);
fileStream.Read(copySize, writePtr);
formatTagFound = true;
}
else if (ValidTag(header.tag, WavFileParser::data_tag))
{
m_header.data = header;
dataTagFound = true;
}
else
{
// Unknown tag, skip by the size specified
// It is possible that we want to read certain tag data in the future.
// Tools/encoders may embed extra data in various sections.
fileStream.Seek(header.size, AZ::IO::GenericStream::ST_SEEK_CUR);
}
// Check for Eof (premature)...
if (fileStream.GetCurPos() == fileStream.GetLength())
{
AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Got to end of file and did not locate a 'data' chunk!\n");
return 0;
}
}
if (!ValidTag(m_header.fmt.header.tag, WavFileParser::fmt__tag))
{
AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Did not find a 'fmt' tag!\n");
}
if (!ValidTag(m_header.data.tag, WavFileParser::data_tag))
{
AZ_Error("WavFileParser", false, "WavFileParser::ParseHeader - Did not find a 'data' tag!\n");
}
#ifdef AZ_DEBUG_BUILD
if (formatTagFound)
{
AZ_TracePrintf("WavFileParser", "Format: %u\n", static_cast<AZ::u32>(GetSampleType()));
AZ_TracePrintf("WavFileParser", "Channels: %u\n", GetNumChannels());
AZ_TracePrintf("WavFileParser", "SampleRate: %u\n", GetSampleRate());
AZ_TracePrintf("WavFileParser", "ByteRate: %u\n", GetByteRate());
AZ_TracePrintf("WavFileParser", "BitsPerSample: %u\n", GetBitsPerSample());
AZ_TracePrintf("WavFileParser", "DataSize: %u\n", GetDataSize());
}
#endif // AZ_DEBUG_BUILD
if (dataTagFound && formatTagFound)
{
m_headerIsValid = true;
return fileStream.GetCurPos();
}
else
{
return 0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
AudioInputSampleType WavFileParser::GetSampleType() const
{
switch (m_header.fmt.audioFormat)
{
case 1:
return AudioInputSampleType::Int;
case 3:
return AudioInputSampleType::Float;
default:
return AudioInputSampleType::Unsupported;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// static
AZ_FORCE_INLINE bool WavFileParser::ValidTag(const AZ::u8 tag[4], const AZ::u8 name[4])
{
return (tag[0] == name[0] && tag[1] == name[1] && tag[2] == name[2] && tag[3] == name[3]);
}
} // namespace Audio
@@ -0,0 +1,131 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AudioInput/AudioInputFile.h>
namespace Audio
{
/**
* A RIFF format chunk header.
*/
struct ChunkHeader
{
AZ::u8 tag[4];
AZ::u32 size;
};
/**
* A WAVE format "fmt" chunk.
*/
struct FmtChunk
{
ChunkHeader header;
AZ::u16 audioFormat;
AZ::u16 numChannels;
AZ::u32 sampleRate;
AZ::u32 byteRate;
AZ::u16 blockAlign;
AZ::u16 bitsPerSample;
};
/**
* A WAVE format header.
*/
struct WavHeader
{
ChunkHeader riff;
AZ::u8 wave[4];
FmtChunk fmt;
ChunkHeader data;
static const size_t MinSize = 44;
};
static_assert(sizeof(WavHeader) == WavHeader::MinSize, "WavHeader struct size is not 44 bytes!");
/**
* Type of AudioFileParser for Wav File Format.
* Parses header information from Wav files and stores it for retrieval.
*/
class WavFileParser
: public AudioFileParser
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(WavFileParser)
WavFileParser();
~WavFileParser() override;
size_t ParseHeader(AZ::IO::FileIOStream& fileStream) override;
bool IsHeaderValid() const override;
AudioInputSampleType GetSampleType() const override;
AZ::u32 GetNumChannels() const override;
AZ::u32 GetSampleRate() const override;
AZ::u32 GetByteRate() const override;
AZ::u32 GetBitsPerSample() const override;
AZ::u32 GetDataSize() const override;
private:
static bool ValidTag(const AZ::u8 tag[4], const AZ::u8 name[4]);
WavHeader m_header;
bool m_headerIsValid = false;
static const AZ::u8 riff_tag[4];
static const AZ::u8 wave_tag[4];
static const AZ::u8 fmt__tag[4];
static const AZ::u8 data_tag[4];
};
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE bool WavFileParser::IsHeaderValid() const
{
return m_headerIsValid;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE AZ::u32 WavFileParser::GetNumChannels() const
{
return m_header.fmt.numChannels;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE AZ::u32 WavFileParser::GetSampleRate() const
{
return m_header.fmt.sampleRate;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE AZ::u32 WavFileParser::GetByteRate() const
{
return m_header.fmt.byteRate;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE AZ::u32 WavFileParser::GetBitsPerSample() const
{
return m_header.fmt.bitsPerSample;
}
///////////////////////////////////////////////////////////////////////////////////////////////
AZ_INLINE AZ::u32 WavFileParser::GetDataSize() const
{
return m_header.data.size;
}
} // namespace Audio