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,215 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <ATLEntityData.h>
#include <IAudioInterfacesCommonData.h>
#include <AudioAllocators.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/containers/vector.h>
#include <AK/SoundEngine/Common/AkTypes.h>
#include <AK/AkWwiseSDKVersion.h>
namespace Audio
{
using TAKUniqueIDVector = AZStd::vector<AkUniqueID, Audio::AudioImplStdAllocator>;
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLAudioObjectData_wwise
: public IATLAudioObjectData
{
// convert to ATLMapLookupType
using TEnvironmentImplMap = AZStd::map<AkAuxBusID, float, AZStd::less<AkAuxBusID>, Audio::AudioImplStdAllocator>;
SATLAudioObjectData_wwise(const AkGameObjectID nPassedAKID, const bool bPassedHasPosition)
: bNeedsToUpdateEnvironments(false)
, bHasPosition(bPassedHasPosition)
, nAKID(nPassedAKID)
{}
~SATLAudioObjectData_wwise() override {}
bool bNeedsToUpdateEnvironments;
const bool bHasPosition;
const AkGameObjectID nAKID;
TEnvironmentImplMap cEnvironmentImplAmounts;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLListenerData_wwise
: public IATLListenerData
{
explicit SATLListenerData_wwise(const AkGameObjectID passedObjectId)
: nAKListenerObjectId(passedObjectId)
{}
~SATLListenerData_wwise() override {}
const AkGameObjectID nAKListenerObjectId = AK_INVALID_GAME_OBJECT;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLTriggerImplData_wwise
: public IATLTriggerImplData
{
explicit SATLTriggerImplData_wwise(const AkUniqueID nPassedAKID)
: nAKID(nPassedAKID)
{}
~SATLTriggerImplData_wwise() override {}
const AkUniqueID nAKID;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLRtpcImplData_wwise
: public IATLRtpcImplData
{
SATLRtpcImplData_wwise(const AkRtpcID nPassedAKID, const float m_fPassedMult, const float m_fPassedShift)
: m_fMult(m_fPassedMult)
, m_fShift(m_fPassedShift)
, nAKID(nPassedAKID)
{}
~SATLRtpcImplData_wwise() override {}
const float m_fMult;
const float m_fShift;
const AkRtpcID nAKID;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
enum EWwiseSwitchType : TATLEnumFlagsType
{
eWST_NONE = 0,
eWST_SWITCH = 1,
eWST_STATE = 2,
eWST_RTPC = 3,
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLSwitchStateImplData_wwise
: public IATLSwitchStateImplData
{
SATLSwitchStateImplData_wwise(
const EWwiseSwitchType ePassedType,
const AkUInt32 nPassedAKSwitchID,
const AkUInt32 nPassedAKStateID,
const float fPassedRtpcValue = 0.0f)
: eType(ePassedType)
, nAKSwitchID(nPassedAKSwitchID)
, nAKStateID(nPassedAKStateID)
, fRtpcValue(fPassedRtpcValue)
{}
~SATLSwitchStateImplData_wwise() override {}
const EWwiseSwitchType eType;
const AkUInt32 nAKSwitchID;
const AkUInt32 nAKStateID;
const float fRtpcValue;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
enum EWwiseAudioEnvironmentType : TATLEnumFlagsType
{
eWAET_NONE = 0,
eWAET_AUX_BUS = 1,
eWAET_RTPC = 2,
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLEnvironmentImplData_wwise
: public IATLEnvironmentImplData
{
explicit SATLEnvironmentImplData_wwise(const EWwiseAudioEnvironmentType ePassedType)
: eType(ePassedType)
{}
SATLEnvironmentImplData_wwise(const EWwiseAudioEnvironmentType ePassedType, const AkAuxBusID nPassedAKBusID)
: eType(ePassedType)
, nAKBusID(nPassedAKBusID)
{
AZ_Assert(ePassedType == eWAET_AUX_BUS, "SATLEnvironmentImplData_wwise - type is incorrect, expected an Aux Bus!");
}
SATLEnvironmentImplData_wwise(
const EWwiseAudioEnvironmentType ePassedType,
const AkRtpcID nPassedAKRtpcID,
const float fPassedMult,
const float fPassedShift)
: eType(ePassedType)
, nAKRtpcID(nPassedAKRtpcID)
, fMult(fPassedMult)
, fShift(fPassedShift)
{
AZ_Assert(ePassedType == eWAET_RTPC, "SATLEnvironmentImplData_wwise - type is incorrect, expected an RTPC!");
}
~SATLEnvironmentImplData_wwise() override {}
const EWwiseAudioEnvironmentType eType;
union
{
// Aux Bus implementation
struct
{
AkAuxBusID nAKBusID;
};
// Rtpc implementation
struct
{
AkRtpcID nAKRtpcID;
float fMult;
float fShift;
};
};
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLEventData_wwise
: public IATLEventData
{
explicit SATLEventData_wwise(const TAudioEventID nPassedID)
: audioEventState(eAES_NONE)
, nAKID(AK_INVALID_UNIQUE_ID)
, nATLID(nPassedID)
, nSourceId(INVALID_AUDIO_SOURCE_ID)
{}
~SATLEventData_wwise() override {}
EAudioEventState audioEventState;
AkUniqueID nAKID;
const TAudioEventID nATLID;
TAudioSourceId nSourceId;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
struct SATLAudioFileEntryData_wwise
: public IATLAudioFileEntryData
{
SATLAudioFileEntryData_wwise()
: nAKBankID(AK_INVALID_BANK_ID)
{}
~SATLAudioFileEntryData_wwise() override {}
AkBankID nAKBankID;
};
} // namespace Audio
@@ -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
@@ -0,0 +1,375 @@
/*
* 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 <AudioSourceManager.h>
#include <AudioInput/AudioInputFile.h>
#include <AudioInput/AudioInputMicrophone.h>
#include <AudioInput/AudioInputStream.h>
#include <AzCore/std/parallel/lock.h>
#include <AK/AkWwiseSDKVersion.h>
#include <AK/Plugin/AkAudioInputPlugin.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////
// Audio Input Source
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioInputSource::IsFormatValid() const
{
// Audio Input Source has restrictions on the formats that are supported:
// 16-bit Integer samples, interleaved samples
// 32-bit Float samples, non-interleaved samples
// The Parser doesn't care about such restrictions and is only responsible for
// reading the header information and validating it.
bool valid = true;
if (m_config.m_sampleType == AudioInputSampleType::Int && m_config.m_bitsPerSample != 16)
{
valid = false;
}
if (m_config.m_sampleType == AudioInputSampleType::Float && m_config.m_bitsPerSample != 32)
{
valid = false;
}
if (m_config.m_sampleType == AudioInputSampleType::Unsupported)
{
valid = false;
}
if (!valid)
{
AZ_TracePrintf("AudioInputFile", "The file format is NOT supported! Only 16-bit integer or 32-bit float sample types are allowed!\n"
"Current Format: (%s / %d)\n", m_config.m_sampleType == AudioInputSampleType::Int ? "Int"
: (m_config.m_sampleType == AudioInputSampleType::Float ? "Float" : "Unknown"),
m_config.m_bitsPerSample);
}
return valid;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputSource::SetFormat(AkAudioFormat& format)
{
AkUInt32 speakerConfig = 0;
switch (m_config.m_numChannels)
{
case 1:
{
speakerConfig = AK_SPEAKER_SETUP_MONO;
break;
}
case 2:
{
speakerConfig = AK_SPEAKER_SETUP_STEREO;
break;
}
case 6:
{
speakerConfig = AK_SPEAKER_SETUP_5POINT1;
break;
}
default:
{
// TODO: Test more channels
return;
}
}
AkUInt32 sampleType = 0;
AkUInt32 sampleInterleaveType = 0;
switch (m_config.m_bitsPerSample)
{
case 16:
{
sampleType = AK_INT;
sampleInterleaveType = AK_INTERLEAVED;
break;
}
case 32:
{
sampleType = AK_FLOAT;
sampleInterleaveType = AK_NONINTERLEAVED;
break;
}
default:
{
// Anything else and Audio Input Source doesn't support it.
// But we've already checked the format when parsing the header, so we shouldn't get here.
break;
}
}
AkChannelConfig akChannelConfig(m_config.m_numChannels, speakerConfig);
format.SetAll(
m_config.m_sampleRate,
akChannelConfig,
m_config.m_bitsPerSample,
m_config.m_numChannels * m_config.m_bitsPerSample >> 3, // shift converts bits->bytes, this is the frame size
sampleType,
sampleInterleaveType
);
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioInputSource::SetSourceId(TAudioSourceId sourceId)
{
m_config.m_sourceId = sourceId;
}
///////////////////////////////////////////////////////////////////////////////////////////////
TAudioSourceId AudioInputSource::GetSourceId() const
{
return m_config.m_sourceId;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// Audio Input Source Manager
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
AudioSourceManager::AudioSourceManager()
{
}
///////////////////////////////////////////////////////////////////////////////////////////////
AudioSourceManager::~AudioSourceManager()
{
Shutdown();
}
///////////////////////////////////////////////////////////////////////////////////////////////
// static
AudioSourceManager& AudioSourceManager::Get()
{
static AudioSourceManager s_manager;
return s_manager;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// static
void AudioSourceManager::Initialize()
{
// Wwise Api call to setup the callbacks used by Audio Input Sources.
SetAudioInputCallbacks(AudioSourceManager::ExecuteCallback, AudioSourceManager::GetFormatCallback);
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioSourceManager::Shutdown()
{
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
m_activeAudioInputs.clear();
m_inactiveAudioInputs.clear();
}
///////////////////////////////////////////////////////////////////////////////////////////////
bool AudioSourceManager::CreateSource(const SAudioInputConfig& sourceConfig)
{
AZStd::unique_ptr<AudioInputSource> ptr = nullptr;
switch (sourceConfig.m_sourceType)
{
case AudioInputSourceType::PcmFile:
case AudioInputSourceType::WavFile:
//case AudioInputSourceType::OggFile:
//case AudioInputSourceType::OpusFile:
{
if (!sourceConfig.m_sourceFilename.empty())
{
ptr.reset(aznew AudioInputFile(sourceConfig));
}
break;
}
case AudioInputSourceType::Microphone:
{
ptr.reset(aznew AudioInputMicrophone(sourceConfig));
break;
}
case AudioInputSourceType::ExternalStream:
{
ptr.reset(aznew AudioInputStreaming(sourceConfig));
break;
}
case AudioInputSourceType::Synthesis: // Will need to allow setting a user-defined Generate callback.
default:
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::CreateSource - The type of AudioInputSource requested is not supported yet!\n");
return INVALID_AUDIO_SOURCE_ID;
}
}
if (!ptr || !ptr->IsOk())
{ // this check could change in the future as we add asynch loading.
return false;
}
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
ptr->SetSourceId(sourceConfig.m_sourceId);
m_inactiveAudioInputs.emplace(sourceConfig.m_sourceId, AZStd::move(ptr));
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioSourceManager::ActivateSource(TAudioSourceId sourceId, AkPlayingID playingId)
{
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
if (m_inactiveAudioInputs.find(sourceId) != m_inactiveAudioInputs.end())
{
if (m_activeAudioInputs.find(playingId) == m_activeAudioInputs.end())
{
m_inactiveAudioInputs[sourceId]->SetSourceId(sourceId);
m_activeAudioInputs[playingId] = AZStd::move(m_inactiveAudioInputs[sourceId]);
m_inactiveAudioInputs.erase(sourceId);
m_activeAudioInputs[playingId]->OnActivated();
}
else
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::ActivateSource - Active source with playing Id %u already exists!\n", playingId);
}
}
else
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::ActivateSource - Source with Id %u not found!\n", sourceId);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioSourceManager::DeactivateSource(AkPlayingID playingId)
{
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
if (m_activeAudioInputs.find(playingId) != m_activeAudioInputs.end())
{
TAudioSourceId sourceId = m_activeAudioInputs[playingId]->GetSourceId();
if (m_inactiveAudioInputs.find(sourceId) == m_inactiveAudioInputs.end())
{
m_inactiveAudioInputs[sourceId] = AZStd::move(m_activeAudioInputs[playingId]);
m_activeAudioInputs.erase(playingId);
// Signal to the audio input source that it was deactivated! It might unload it's resources.
m_inactiveAudioInputs[sourceId]->OnDeactivated();
if (!m_inactiveAudioInputs[sourceId]->IsOk())
{
m_inactiveAudioInputs.erase(sourceId);
}
}
else
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::DeactivateSource - Source with Id %u was already inactive!\n", sourceId);
}
}
else
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::DeactivateSource - Active source with playing Id %u not found!\n", playingId);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
void AudioSourceManager::DestroySource(TAudioSourceId sourceId)
{
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
if (m_inactiveAudioInputs.find(sourceId) != m_inactiveAudioInputs.end())
{
m_inactiveAudioInputs.erase(sourceId);
}
else
{
AZ_TracePrintf("AudioSourceManager", "AudioSourceManager::DestroySource - No source with Id %u was found!\nDid you call DeactivateSource first on the playingId??\n", sourceId);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
AkPlayingID AudioSourceManager::FindPlayingSource(TAudioSourceId sourceId)
{
AZStd::lock_guard<AZStd::mutex> lock(m_inputMutex);
for (auto& inputPair : m_activeAudioInputs)
{
if (inputPair.second->GetSourceId() == sourceId)
{
return inputPair.first;
}
}
return AK_INVALID_PLAYING_ID;
}
///////////////////////////////////////////////////////////////////////////////////////////////
// static
void AudioSourceManager::ExecuteCallback(AkPlayingID playingId, AkAudioBuffer* akBuffer)
{
if (!akBuffer->HasData())
{
akBuffer->eState = AK_Fail;
akBuffer->uValidFrames = 0;
return;
}
if (akBuffer->eState == AK_NoDataNeeded)
{
akBuffer->eState = AK_NoDataReady;
akBuffer->uValidFrames = 0;
return;
}
AZStd::lock_guard<AZStd::mutex> lock(Get().m_inputMutex);
auto inputIter = Get().m_activeAudioInputs.find(playingId);
if (inputIter != Get().m_activeAudioInputs.end())
{
auto& audioInput = inputIter->second;
if (audioInput)
{
// this will set the uValidFrames and eState for us.
audioInput->WriteOutput(akBuffer);
}
}
else
{
// signal that the audio input playback should end.
akBuffer->eState = AK_NoMoreData;
akBuffer->uValidFrames = 0;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
// static
void AudioSourceManager::GetFormatCallback(AkPlayingID playingId, AkAudioFormat& audioFormat)
{
AZStd::lock_guard<AZStd::mutex> lock(Get().m_inputMutex);
auto inputIter = Get().m_activeAudioInputs.find(playingId);
if (inputIter != Get().m_activeAudioInputs.end())
{
// Set the AkAudioFormat from the AudioInputSource's SAudioInputConfig
auto& audioInput = inputIter->second;
if (audioInput)
{
audioInput->SetFormat(audioFormat);
}
}
}
} // namespace Audio
@@ -0,0 +1,145 @@
/*
* 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 <AzCore/PlatformIncl.h> // This include is needed to include WinSock2.h before including Windows.h
// As AK/SoundEngine/Common/AkTypes.h eventually includes Windows.h
#include <IAudioInterfacesCommonData.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AzCore/IO/FileIO.h>
#include <AudioAllocators.h>
#include <AK/SoundEngine/Common/AkTypes.h>
#include <AK/SoundEngine/Common/IAkPlugin.h>
namespace Audio
{
/**
* Base class for Audio Input Source types.
* Represents an Audio Input Source, which has input/output routines and configuration information.
*/
class AudioInputSource
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(AudioInputSource)
AudioInputSource() = default;
virtual ~AudioInputSource() = default;
virtual void ReadInput(const AudioStreamData& data) = 0;
virtual void WriteOutput(AkAudioBuffer* akBuffer) = 0;
virtual bool IsOk() const = 0;
virtual bool IsFormatValid() const;
virtual void OnActivated() {}
virtual void OnDeactivated() {}
void SetFormat(AkAudioFormat& format);
void SetSourceId(TAudioSourceId sourceId);
TAudioSourceId GetSourceId() const;
protected:
SAudioInputConfig m_config; ///< Configuration information for the source type.
AkPlayingID m_playingId = AK_INVALID_PLAYING_ID; ///< Playing ID of the source.
};
/**
* Manager class for AudioInputSource.
* Manages lifetime of AudioInputSource objects as they are created, activated, deactivated, and destroyed.
* The lifetime of an Audio Input Source:
* CreateSource (loads resources)
* ActivateSource (once you obtain a playing Id)
* (Running, callbacks being received, also async loading input if enabled)
* DeactivateSource (once it's determined to be done playing)
* DestroySource (unloads resources)
*/
class AudioSourceManager
{
public:
AudioSourceManager();
~AudioSourceManager();
static AudioSourceManager& Get();
static void Initialize();
void Shutdown();
/**
* CreateSource a new AudioInputSource.
* Creates an AudioInputSource, based on the SAudioInputConfig and stores it in an inactive state.
* @param sourceConfig Configuration of the AudioInputSource.
* @return True if the source was created successfully, false otherwise.
*/
bool CreateSource(const SAudioInputConfig& sourceConfig);
/**
* Activates an AudioInputSource.
* Moves a source from the inactive state to an active state by assigning an AkPlayingID.
* @param sourceId ID of the source (returned by CreateSource).
* @param playingId A playing ID of the source that is now playing in Wwise.
*/
void ActivateSource(TAudioSourceId sourceId, AkPlayingID playingId);
/**
* Deactivates an AudioInputSource.
* Moves a source from the active state back to an inactive state, will happen when an end event callback is recieved.
* @param playingId Playing ID of the source that ended.
*/
void DeactivateSource(AkPlayingID playingId);
/**
* Destroy an AudioInputSource.
* Destroys an AudioInputSource from the manager when it is no longer needed.
* @param sourceId Source ID of the object to remove.
*/
void DestroySource(TAudioSourceId sourceId);
/**
* Find the Playing ID of a source.
* Given a Source ID, check if there are sources in the active state and if so, return their Playing ID.
* @param sourceId Source ID to look for in the active sources.
*/
AkPlayingID FindPlayingSource(TAudioSourceId sourceId);
private:
/**
* Wwise Audio Input Plugin "Execute" callback function.
* This will be called whenever a playing Audio Input Source needs to be fed.
* @param playingId The Playing ID of the source.
* @param audioBuffer The buffer to copy samples into.
*/
static void ExecuteCallback(AkPlayingID playingId, AkAudioBuffer* audioBuffer);
/**
* Wwise Audio Input Plugin "GetFormat" callback function.
* This will be called once whenever a new Audio Input Source is starting playback.
* @param playingId The Playing ID of the source.
* @param audioFormat The format structure that should be filled with format information.
*/
static void GetFormatCallback(AkPlayingID playingId, AkAudioFormat& audioFormat);
AZStd::mutex m_inputMutex; ///< Callbacks will come from the Wwise event processing thread.
template <typename KeyType, typename ValueType>
using AudioInputMap = AZStd::unordered_map<KeyType, AZStd::unique_ptr<ValueType>, AZStd::hash<KeyType>, AZStd::equal_to<KeyType>, Audio::AudioImplStdAllocator>;
AudioInputMap<TAudioSourceId, AudioInputSource> m_inactiveAudioInputs; ///< Sources that haven't started playing yet.
AudioInputMap<AkPlayingID, AudioInputSource> m_activeAudioInputs; ///< Sources that are currently playing.
};
}
@@ -0,0 +1,60 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <AudioSystemImplCVars.h>
#include <AudioEngineWwise_Traits_Platform.h>
namespace Audio::Wwise::Cvars
{
AZ_CVAR(AZ::u64, s_PrimaryMemorySize, AZ_TRAIT_AUDIOENGINEWWISE_PRIMARY_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of the primary memory pool used by the Wwise audio integration.\n"
"Usage: s_PrimaryMemorySize=" AZ_TRAIT_AUDIOENGINEWWISE_PRIMARY_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_SecondaryMemorySize, AZ_TRAIT_AUDIOENGINEWWISE_SECONDARY_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of the secondary memory pool. Most platforms do not use this.\n"
"Usage: s_SecondaryMemorySize=" AZ_TRAIT_AUDIOENGINEWWISE_PRIMARY_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_StreamDeviceMemorySize, AZ_TRAIT_AUDIOENGINEWWISE_STREAMER_DEVICE_MEMORY_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of the Wwise Stream Device.\n"
"Usage: s_StreamDeviceMemorySize=" AZ_TRAIT_AUDIOENGINEWWISE_STREAMER_DEVICE_MEMORY_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(AZ::u64, s_CommandQueueMemorySize, AZ_TRAIT_AUDIOENGINEWWISE_COMMAND_QUEUE_MEMORY_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of the Wwise Command Queue.\n"
"Usage: s_CommandQueueMemorySize=" AZ_TRAIT_AUDIOENGINEWWISE_COMMAND_QUEUE_MEMORY_POOL_SIZE_DEFAULT_TEXT "\n");
#if !defined(WWISE_RELEASE)
AZ_CVAR(AZ::u64, s_MonitorQueueMemorySize, AZ_TRAIT_AUDIOENGINEWWISE_MONITOR_QUEUE_MEMORY_POOL_SIZE,
nullptr, AZ::ConsoleFunctorFlags::Null,
"The size in KiB of the Wwise Monitor Queue.\n"
"Not available in Release build.\n"
"Usage: s_MonitorQueueMemorySize=" AZ_TRAIT_AUDIOENGINEWWISE_MONITOR_QUEUE_MEMORY_POOL_SIZE_DEFAULT_TEXT "\n");
AZ_CVAR(bool, s_EnableCommSystem, false,
nullptr, AZ::ConsoleFunctorFlags::Null,
"Enable initialization of the Wwise Comm system, which allows for remote profiling.\n"
"Not available in Release build.\n"
"Usage: s_EnableCommSystem=true (false)\n");
AZ_CVAR(bool, s_EnableOutputCapture, false,
nullptr, AZ::ConsoleFunctorFlags::Null,
"Capture the main audio output to a WAV file.\n"
"Not available in Release build.\n"
"Usage: s_EnableOutputCapture=true (false)\n");
#endif // !WWISE_RELEASE
} // namespace Audio::Wwise::Cvars
@@ -0,0 +1,31 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <AzCore/Console/IConsole.h>
namespace Audio::Wwise::Cvars
{
AZ_CVAR_EXTERNED(AZ::u64, s_PrimaryMemorySize);
AZ_CVAR_EXTERNED(AZ::u64, s_SecondaryMemorySize);
AZ_CVAR_EXTERNED(AZ::u64, s_StreamDeviceMemorySize);
AZ_CVAR_EXTERNED(AZ::u64, s_CommandQueueMemorySize);
#if !defined(WWISE_RELEASE)
AZ_CVAR_EXTERNED(AZ::u64, s_MonitorQueueMemorySize);
AZ_CVAR_EXTERNED(bool, s_EnableCommSystem);
AZ_CVAR_EXTERNED(bool, s_EnableOutputCapture);
#endif // !WWISE_RELEASE
} // namespace Audio::Wwise::Cvars
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,199 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <AudioAllocators.h>
#include <FileIOHandler_wwise.h>
#include <ATLEntities_wwise.h>
#include <IAudioSystemImplementation.h>
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////////
class CAudioSystemImpl_wwise
: public AudioSystemImplementation
{
public:
AUDIO_IMPL_CLASS_ALLOCATOR(CAudioSystemImpl_wwise)
explicit CAudioSystemImpl_wwise(const char* assetsPlatformName);
~CAudioSystemImpl_wwise() override;
// AudioSystemImplementationNotificationBus
void OnAudioSystemLoseFocus() override;
void OnAudioSystemGetFocus() override;
void OnAudioSystemMuteAll() override;
void OnAudioSystemUnmuteAll() override;
void OnAudioSystemRefresh() override;
// ~AudioSystemImplementationNotificationBus
// AudioSystemImplementationRequestBus
void Update(const float updateIntervalMS) override;
EAudioRequestStatus Initialize() override;
EAudioRequestStatus ShutDown() override;
EAudioRequestStatus Release() override;
EAudioRequestStatus StopAllSounds() override;
EAudioRequestStatus RegisterAudioObject(
IATLAudioObjectData* const audioObjectData,
const char* const objectName) override;
EAudioRequestStatus UnregisterAudioObject(IATLAudioObjectData* const audioObjectData) override;
EAudioRequestStatus ResetAudioObject(IATLAudioObjectData* const audioObjectData) override;
EAudioRequestStatus UpdateAudioObject(IATLAudioObjectData* const audioObjectData) override;
EAudioRequestStatus PrepareTriggerSync(
IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData) override;
EAudioRequestStatus UnprepareTriggerSync(
IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData) override;
EAudioRequestStatus PrepareTriggerAsync(
IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData,
IATLEventData* const eventData) override;
EAudioRequestStatus UnprepareTriggerAsync(
IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData,
IATLEventData* const eventData) override;
EAudioRequestStatus ActivateTrigger(
IATLAudioObjectData* const audioObjectData,
const IATLTriggerImplData* const triggerData,
IATLEventData* const eventData,
const SATLSourceData* const pSourceData) override;
EAudioRequestStatus StopEvent(
IATLAudioObjectData* const audioObjectData,
const IATLEventData* const eventData) override;
EAudioRequestStatus StopAllEvents(
IATLAudioObjectData* const audioObjectData) override;
EAudioRequestStatus SetPosition(
IATLAudioObjectData* const audioObjectData,
const SATLWorldPosition& worldPosition) override;
EAudioRequestStatus SetMultiplePositions(
IATLAudioObjectData* const audioObjectData,
const MultiPositionParams& multiPositionParams) override;
EAudioRequestStatus SetEnvironment(
IATLAudioObjectData* const audioObjectData,
const IATLEnvironmentImplData* const environmentData,
const float amount) override;
EAudioRequestStatus SetRtpc(
IATLAudioObjectData* const audioObjectData,
const IATLRtpcImplData* const rtpcData,
const float value) override;
EAudioRequestStatus SetSwitchState(
IATLAudioObjectData* const audioObjectData,
const IATLSwitchStateImplData* const switchStateData) override;
EAudioRequestStatus SetObstructionOcclusion(
IATLAudioObjectData* const audioObjectData,
const float obstruction,
const float occlusion) override;
EAudioRequestStatus SetListenerPosition(
IATLListenerData* const listenerData,
const SATLWorldPosition& newPosition) override;
EAudioRequestStatus ResetRtpc(
IATLAudioObjectData* const audioObjectData,
const IATLRtpcImplData* const rtpcData) override;
EAudioRequestStatus RegisterInMemoryFile(SATLAudioFileEntryInfo* const audioFileEntry) override;
EAudioRequestStatus UnregisterInMemoryFile(SATLAudioFileEntryInfo* const audioFileEntry) override;
EAudioRequestStatus ParseAudioFileEntry(const AZ::rapidxml::xml_node<char>* audioFileEntryNode, SATLAudioFileEntryInfo* const fileEntryInfo) override;
void DeleteAudioFileEntryData(IATLAudioFileEntryData* const oldAudioFileEntryData) override;
const char* const GetAudioFileLocation(SATLAudioFileEntryInfo* const fileEntryInfo) override;
IATLTriggerImplData* NewAudioTriggerImplData(const AZ::rapidxml::xml_node<char>* audioTriggerNode) override;
void DeleteAudioTriggerImplData(IATLTriggerImplData* const oldTriggerImplData) override;
IATLRtpcImplData* NewAudioRtpcImplData(const AZ::rapidxml::xml_node<char>* audioRtpcNode) override;
void DeleteAudioRtpcImplData(IATLRtpcImplData* const oldRtpcImplData) override;
IATLSwitchStateImplData* NewAudioSwitchStateImplData(const AZ::rapidxml::xml_node<char>* audioSwitchStateNode) override;
void DeleteAudioSwitchStateImplData(IATLSwitchStateImplData* const oldSwitchStateImplData) override;
IATLEnvironmentImplData* NewAudioEnvironmentImplData(const AZ::rapidxml::xml_node<char>* audioEnvironmentNode) override;
void DeleteAudioEnvironmentImplData(IATLEnvironmentImplData* const oldEnvironmentImplData) override;
SATLAudioObjectData_wwise* NewGlobalAudioObjectData(const TAudioObjectID objectId) override;
SATLAudioObjectData_wwise* NewAudioObjectData(const TAudioObjectID objectId) override;
void DeleteAudioObjectData(IATLAudioObjectData* const oldObjectData) override;
SATLListenerData_wwise* NewDefaultAudioListenerObjectData(const TATLIDType objectId) override;
SATLListenerData_wwise* NewAudioListenerObjectData(const TATLIDType objectId) override;
void DeleteAudioListenerObjectData(IATLListenerData* const oldListenerData) override;
SATLEventData_wwise* NewAudioEventData(const TAudioEventID eventId) override;
void DeleteAudioEventData(IATLEventData* const oldEventData) override;
void ResetAudioEventData(IATLEventData* const eventData) override;
const char* const GetImplSubPath() const override;
void SetLanguage(const char* const language) override;
// Functions below are only used when WWISE_RELEASE is not defined
const char* const GetImplementationNameString() const override;
void GetMemoryInfo(SAudioImplMemoryInfo& memoryInfo) const override;
AZStd::vector<AudioImplMemoryPoolInfo> GetMemoryPoolInfo() override;
bool CreateAudioSource(const SAudioInputConfig& sourceConfig) override;
void DestroyAudioSource(TAudioSourceId sourceId) override;
void SetPanningMode(PanningMode mode) override;
// ~AudioSystemImplementationRequestBus
protected:
void SetBankPaths();
AZStd::string m_soundbankFolder;
AZStd::string m_localizedSoundbankFolder;
AZStd::string m_assetsPlatform;
private:
static const char* const WwiseImplSubPath;
static const char* const WwiseGlobalAudioObjectName;
static const float ObstructionOcclusionMin;
static const float ObstructionOcclusionMax;
struct SEnvPairCompare
{
bool operator()(const AZStd::pair<const AkAuxBusID, float>& pair1, const AZStd::pair<const AkAuxBusID, float>& pair2) const;
};
SATLSwitchStateImplData_wwise* ParseWwiseSwitchOrState(const AZ::rapidxml::xml_node<char>* node, EWwiseSwitchType type);
SATLSwitchStateImplData_wwise* ParseWwiseRtpcSwitch(const AZ::rapidxml::xml_node<char>* node);
void ParseRtpcImpl(const AZ::rapidxml::xml_node<char>* node, AkRtpcID& akRtpcId, float& mult, float& shift);
EAudioRequestStatus PrepUnprepTriggerSync(
const IATLTriggerImplData* const triggerData,
bool prepare);
EAudioRequestStatus PrepUnprepTriggerAsync(
const IATLTriggerImplData* const triggerData,
IATLEventData* const eventData,
bool prepare);
EAudioRequestStatus PostEnvironmentAmounts(IATLAudioObjectData* const audioObjectData);
AkGameObjectID m_globalGameObjectID;
AkGameObjectID m_defaultListenerGameObjectID;
AkBankID m_initBankID;
CFileIOHandler_wwise m_fileIOHandler;
#if !defined(WWISE_RELEASE)
bool m_isCommSystemInitialized;
AZStd::vector<AudioImplMemoryPoolInfo> m_debugMemoryInfo;
AZStd::string m_fullImplString;
AZStd::string m_speakerConfigString;
#endif // !WWISE_RELEASE
};
} // namespace Audio
@@ -0,0 +1,14 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <Common_wwise.h>
@@ -0,0 +1,116 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <AK/SoundEngine/Common/AkMemoryMgr.h>
#include <AK/SoundEngine/Common/AkTypes.h>
#include <AK/AkWwiseSDKVersion.h>
#include <IAudioSystem.h>
#include <AudioEngineWwise_Traits_Platform.h>
#if AZ_TRAIT_AUDIOENGINEWWISE_PROVIDE_IMPL_SECONDARY_POOL
#include <platform.h>
#include <CryPool/PoolAlloc.h>
using TMemoryPoolReferenced = NCryPoolAlloc::CThreadSafe<NCryPoolAlloc::CBestFit<NCryPoolAlloc::CReferenced<NCryPoolAlloc::CMemoryDynamic, 4 * 1024, true>, NCryPoolAlloc::CListItemReference>>;
namespace Audio
{
extern TMemoryPoolReferenced g_audioImplMemoryPoolSecondary_wwise;
}
#endif // AZ_TRAIT_AUDIOENGINEWWISE_PROVIDE_IMPL_SECONDARY_POOL
#define WWISE_IMPL_VERSION_STRING "Wwise " AK_WWISESDK_VERSIONNAME
#define ASSERT_WWISE_OK(x) (AKASSERT((x) == AK_Success))
#define IS_WWISE_OK(x) ((x) == AK_Success)
namespace Audio
{
///////////////////////////////////////////////////////////////////////////////////////////////////
// Wwise Xml Element Names
namespace WwiseXmlTags
{
static constexpr const char* WwiseEventTag = "WwiseEvent";
static constexpr const char* WwiseRtpcTag = "WwiseRtpc";
static constexpr const char* WwiseSwitchTag = "WwiseSwitch";
static constexpr const char* WwiseStateTag = "WwiseState";
static constexpr const char* WwiseRtpcSwitchTag = "WwiseRtpc";
static constexpr const char* WwiseFileTag = "WwiseFile";
static constexpr const char* WwiseAuxBusTag = "WwiseAuxBus";
static constexpr const char* WwiseValueTag = "WwiseValue";
static constexpr const char* WwiseNameAttribute = "wwise_name";
static constexpr const char* WwiseValueAttribute = "wwise_value";
static constexpr const char* WwiseMutiplierAttribute = "atl_mult";
static constexpr const char* WwiseShiftAttribute = "atl_shift";
static constexpr const char* WwiseLocalizedAttribute = "wwise_localized";
namespace Legacy
{
static constexpr const char* WwiseLocalizedAttribute = "wwise_localised";
}
} // namespace WwiseXmlTags
///////////////////////////////////////////////////////////////////////////////////////////////////
// Wwise-specific helper functions
///////////////////////////////////////////////////////////////////////////////////////////////////
inline AkVector AZVec3ToAkVector(const AZ::Vector3& vec3)
{
// swizzle Y <--> Z
AkVector akVec;
akVec.X = vec3.GetX();
akVec.Y = vec3.GetZ();
akVec.Z = vec3.GetY();
return akVec;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
inline AkTransform AZVec3ToAkTransform(const AZ::Vector3& position)
{
AkTransform akTransform;
akTransform.SetOrientation(0.0, 0.0, 1.0, 0.0, 1.0, 0.0); // May add orientation support later.
akTransform.SetPosition(AZVec3ToAkVector(position));
return akTransform;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
inline void ATLTransformToAkTransform(const SATLWorldPosition& atlTransform, AkTransform& akTransform)
{
akTransform.Set(
AZVec3ToAkVector(atlTransform.GetPositionVec()),
AZVec3ToAkVector(atlTransform.GetForwardVec().GetNormalized()), // Wwise SDK requires that the Orientation vectors
AZVec3ToAkVector(atlTransform.GetUpVec().GetNormalized()) // are normalized prior to sending to the apis.
);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Wwise
{
// See AkMemoryMgr.h
inline static const char* MemoryManagerCategories[]
{
"Object", "Event", "Structure", "Media", "GameObject", "Processing", "ProcessingPlugin", "Streaming", "StreamingIO", "SpatialAudio",
"SpatialAudioGeometry", "SpatialAudioPaths", "GameSim", "MonitorQueue", "Profiler", "FilePackage", "SoundEngine"
};
static_assert(AZ_ARRAY_SIZE(MemoryManagerCategories) == AkMemID_NUM,
"Wwise memory categories have changed, the list of display names needs to be updated.");
} // namespace Wwise
} // namespace Audio
@@ -0,0 +1,110 @@
/*
* 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 <Config_wwise.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/FileFunc/FileFunc.h>
// For AZ_Printf statements...
#define WWISE_CONFIG_WINDOW "WwiseConfig"
namespace Audio::Wwise
{
static AZStd::string_view s_configuredBanksPath = DefaultBanksPath;
const AZStd::string_view GetBanksRootPath()
{
return s_configuredBanksPath;
}
void SetBanksRootPath(const AZStd::string_view path)
{
s_configuredBanksPath = path;
}
// static
void ConfigurationSettings::Reflect(AZ::ReflectContext* context)
{
if (auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<PlatformMapping>()
->Version(2)
->Field("assetPlatform", &PlatformMapping::m_assetPlatform)
->Field("altAssetPlatform", &PlatformMapping::m_altAssetPlatform)
->Field("enginePlatform", &PlatformMapping::m_enginePlatform)
->Field("wwisePlatform", &PlatformMapping::m_wwisePlatform)
->Field("bankSubPath", &PlatformMapping::m_bankSubPath)
;
serializeContext->Class<ConfigurationSettings>()
->Version(1)
->Field("platformMaps", &ConfigurationSettings::m_platformMappings)
;
}
}
bool ConfigurationSettings::Load(const AZStd::string& filePath)
{
AZ::IO::Path fileIoPath(filePath);
auto outcome = AzFramework::FileFunc::ReadJsonFile(fileIoPath);
if (!outcome)
{
AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: %s\n", outcome.GetError().c_str());
return false;
}
m_platformMappings.clear();
AZ::JsonDeserializerSettings deserializeSettings;
AZ::ComponentApplicationBus::BroadcastResult(deserializeSettings.m_serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
auto result = AZ::JsonSerialization::Load(*this, outcome.GetValue(), deserializeSettings);
if (result.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
{
AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: Deserializing Json file '%s'\n", filePath.c_str());
return false;
}
AZ_Printf(WWISE_CONFIG_WINDOW, "Loaded '%s' successfully.\n", filePath.c_str());
return true;
}
bool ConfigurationSettings::Save(const AZStd::string& filePath)
{
AZ::JsonSerializerSettings serializeSettings;
AZ::ComponentApplicationBus::BroadcastResult(serializeSettings.m_serializeContext, &AZ::ComponentApplicationBus::Events::GetSerializeContext);
rapidjson::Document jsonDoc;
auto result = AZ::JsonSerialization::Store(jsonDoc, jsonDoc.GetAllocator(), *this, serializeSettings);
if (result.GetProcessing() != AZ::JsonSerializationResult::Processing::Completed)
{
AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: Serializing Json file '%s'\n", filePath.c_str());
return false;
}
auto outcome = AzFramework::FileFunc::WriteJsonFile(jsonDoc, filePath);
if (!outcome)
{
AZ_Printf(WWISE_CONFIG_WINDOW, "ERROR: %s\n", outcome.GetError().c_str());
return false;
}
AZ_Printf(WWISE_CONFIG_WINDOW, "Saved '%s' successfully.\n", filePath.c_str());
return true;
}
} // namespace Audio::Wwise
@@ -0,0 +1,68 @@
/*
* 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 <AzCore/RTTI/ReflectContext.h>
#include <AzCore/std/string/string.h>
namespace Audio::Wwise
{
static constexpr const char DefaultBanksPath[] = "sounds/wwise/";
static constexpr const char ExternalSourcesPath[] = "external";
static constexpr const char ConfigFile[] = "wwise_config.json";
static constexpr const char BankExtension[] = ".bnk";
static constexpr const char MediaExtension[] = ".wem";
static constexpr const char InitBank[] = "init.bnk";
//! Banks path that's set after reading the configuration settings.
//! This might be different than the DefaultBanksPath.
const AZStd::string_view GetBanksRootPath();
void SetBanksRootPath(const AZStd::string_view path);
/**
* ConfigurationSettings
*/
struct ConfigurationSettings
{
AZ_TYPE_INFO(ConfigurationSettings, "{6BEEC05E-C5AE-4270-AAAD-08E27A6B5341}");
AZ_CLASS_ALLOCATOR(ConfigurationSettings, AZ::SystemAllocator, 0);
struct PlatformMapping
{
AZ_TYPE_INFO(PlatformMapping, "{9D444546-784B-4509-A8A5-8E174E345097}");
AZ_CLASS_ALLOCATOR(PlatformMapping, AZ::SystemAllocator, 0);
PlatformMapping() = default;
~PlatformMapping() = default;
// Serialized Data...
AZStd::string m_assetPlatform; // LY Asset Platform name (i.e. "pc", "osx_gl", "es3", ...)
AZStd::string m_altAssetPlatform; // Some platforms can be run using a different asset platform. Useful for builder worker.
AZStd::string m_enginePlatform; // LY Engine Platform name (i.e. "Windows", "Mac", "Android", ...)
AZStd::string m_wwisePlatform; // Wwise Platform name (i.e. "Windows", "Mac", "Android", ...)
AZStd::string m_bankSubPath; // Wwise Banks Sub-Path (i.e. "windows", "mac", "android", ...)
};
ConfigurationSettings() = default;
~ConfigurationSettings() = default;
static void Reflect(AZ::ReflectContext* context);
bool Load(const AZStd::string& filePath);
bool Save(const AZStd::string& filePath);
// Serialized Data...
AZStd::vector<PlatformMapping> m_platformMappings;
};
} // namespace Audio::Wwise
@@ -0,0 +1,474 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <AzCore/PlatformIncl.h>
#include <FileIOHandler_wwise.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/IO/IStreamer.h>
#include <IAudioInterfacesCommonData.h>
#include <AkPlatformFuncs_Platform.h>
#include <AudioEngineWwise_Traits_Platform.h>
#include <platform.h>
#include <ISystem.h>
#include <AzFramework/Archive/IArchive.h>
#define MAX_NUMBER_STRING_SIZE (10) // 4G
#define ID_TO_STRING_FORMAT_BANK AKTEXT("%u.bnk")
#define ID_TO_STRING_FORMAT_WEM AKTEXT("%u.wem")
#define MAX_EXTENSION_SIZE (4) // .xxx
#define MAX_FILETITLE_SIZE (MAX_NUMBER_STRING_SIZE + MAX_EXTENSION_SIZE + 1) // null-terminated
namespace Audio
{
// AkFileHandle must be able to store our AZ::IO::HandleType
static_assert(sizeof(AkFileHandle) >= sizeof(AZ::IO::HandleType), "AkFileHandle must be able to store at least the size of a AZ::IO::HandleType");
namespace Platform
{
AkFileHandle GetAkFileHandle(AZ::IO::HandleType realFileHandle);
AZ::IO::HandleType GetRealFileHandle(AkFileHandle akFileHandle);
void SetThreadProperties(AkThreadProperties& threadProperties);
}
AkFileHandle GetAkFileHandle(AZ::IO::HandleType realFileHandle)
{
if (realFileHandle == AZ::IO::InvalidHandle)
{
return InvalidAkFileHandle;
}
return Platform::GetAkFileHandle(realFileHandle);
}
AZ::IO::HandleType GetRealFileHandle(AkFileHandle akFileHandle)
{
if (akFileHandle == InvalidAkFileHandle)
{
return AZ::IO::InvalidHandle;
}
return Platform::GetRealFileHandle(akFileHandle);
}
CBlockingDevice_wwise::~CBlockingDevice_wwise()
{
Destroy();
}
bool CBlockingDevice_wwise::Init(size_t poolSize)
{
Destroy();
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings(deviceSettings);
deviceSettings.uIOMemorySize = poolSize;
deviceSettings.uSchedulerTypeFlags = AK_SCHEDULER_BLOCKING;
Platform::SetThreadProperties(deviceSettings.threadProperties);
m_deviceID = AK::StreamMgr::CreateDevice(deviceSettings, this);
return m_deviceID != AK_INVALID_DEVICE_ID;
}
void CBlockingDevice_wwise::Destroy()
{
if (m_deviceID != AK_INVALID_DEVICE_ID)
{
AK::StreamMgr::DestroyDevice(m_deviceID);
m_deviceID = AK_INVALID_DEVICE_ID;
}
}
bool CBlockingDevice_wwise::Open(const char* filename, AkOpenMode openMode, AkFileDesc& fileDesc)
{
const char* openModeString = nullptr;
switch (openMode)
{
case AK_OpenModeRead:
openModeString = "rbx";
break;
case AK_OpenModeWrite:
openModeString = "wbx";
break;
case AK_OpenModeWriteOvrwr:
openModeString = "w+bx";
break;
case AK_OpenModeReadWrite:
openModeString = "abx";
break;
default:
AZ_Assert(false, "Unknown Wwise file open mode.");
return false;
}
const size_t fileSize = gEnv->pCryPak->FGetSize(filename);
if (fileSize > 0)
{
AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen(filename, openModeString, AZ::IO::IArchive::FOPEN_HINT_DIRECT_OPERATION);
if (fileHandle != AZ::IO::InvalidHandle)
{
fileDesc.hFile = GetAkFileHandle(fileHandle);
fileDesc.iFileSize = static_cast<AkInt64>(fileSize);
fileDesc.uSector = 0;
fileDesc.deviceID = m_deviceID;
fileDesc.pCustomParam = nullptr;
fileDesc.uCustomParamSize = 0;
return true;
}
}
return false;
}
AKRESULT CBlockingDevice_wwise::Read(AkFileDesc& fileDesc, const AkIoHeuristics&, void* buffer, AkIOTransferInfo& transferInfo)
{
AZ_Assert(buffer, "Wwise didn't provide a valid buffer to write to.");
AZ::IO::HandleType fileHandle = GetRealFileHandle(fileDesc.hFile);
const uint64_t currentFileReadPos = gEnv->pCryPak->FTell(fileHandle);
const uint64_t wantedFileReadPos = static_cast<uint64_t>(transferInfo.uFilePosition);
if (currentFileReadPos != wantedFileReadPos)
{
gEnv->pCryPak->FSeek(fileHandle, wantedFileReadPos, SEEK_SET);
}
const size_t bytesRead = gEnv->pCryPak->FReadRaw(buffer, 1, transferInfo.uRequestedSize, fileHandle);
AZ_Assert(bytesRead == static_cast<size_t>(transferInfo.uRequestedSize),
"Number of bytes read (%zu) for Wwise request doesn't match the requested size (%u).", bytesRead, transferInfo.uRequestedSize);
return (bytesRead > 0) ? AK_Success : AK_Fail;
}
AKRESULT CBlockingDevice_wwise::Write(AkFileDesc& fileDesc, const AkIoHeuristics&, void* data, AkIOTransferInfo& transferInfo)
{
AZ_Assert(data, "Wwise didn't provide a valid buffer to read from.");
AZ::IO::HandleType fileHandle = GetRealFileHandle(fileDesc.hFile);
const uint64_t currentFileWritePos = gEnv->pCryPak->FTell(fileHandle);
const uint64_t wantedFileWritePos = static_cast<uint64_t>(transferInfo.uFilePosition);
if (currentFileWritePos != wantedFileWritePos)
{
gEnv->pCryPak->FSeek(fileHandle, wantedFileWritePos, SEEK_SET);
}
const size_t bytesWritten = gEnv->pCryPak->FWrite(data, 1, static_cast<size_t>(transferInfo.uRequestedSize), fileHandle);
if (bytesWritten != static_cast<size_t>(transferInfo.uRequestedSize))
{
AZ_Error("Wwise", false, "Number of bytes written (%zu) for Wwise request doesn't match the requested size (%u).",
bytesWritten, transferInfo.uRequestedSize);
return AK_Fail;
}
return AK_Success;
}
AKRESULT CBlockingDevice_wwise::Close(AkFileDesc& fileDesc)
{
return gEnv->pCryPak->FClose(GetRealFileHandle(fileDesc.hFile)) ? AK_Success : AK_Fail;
}
AkUInt32 CBlockingDevice_wwise::GetBlockSize([[maybe_unused]] AkFileDesc& fileDesc)
{
// No constraint on block size (file seeking).
return 1;
}
void CBlockingDevice_wwise::GetDeviceDesc(AkDeviceDesc& deviceDesc)
{
deviceDesc.bCanRead = true;
deviceDesc.bCanWrite = true;
deviceDesc.deviceID = m_deviceID;
AK_CHAR_TO_UTF16(deviceDesc.szDeviceName, "CryPak", AZ_ARRAY_SIZE(deviceDesc.szDeviceName));
deviceDesc.uStringSize = AKPLATFORM::AkUtf16StrLen(deviceDesc.szDeviceName);
}
AkUInt32 CBlockingDevice_wwise::GetDeviceData()
{
return 1;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
CStreamingDevice_wwise::~CStreamingDevice_wwise()
{
Destroy();
}
bool CStreamingDevice_wwise::Init(size_t poolSize)
{
Destroy();
AkDeviceSettings deviceSettings;
AK::StreamMgr::GetDefaultDeviceSettings(deviceSettings);
deviceSettings.uIOMemorySize = poolSize;
deviceSettings.uSchedulerTypeFlags = AK_SCHEDULER_DEFERRED_LINED_UP;
Platform::SetThreadProperties(deviceSettings.threadProperties);
m_deviceID = AK::StreamMgr::CreateDevice(deviceSettings, this);
return m_deviceID != AK_INVALID_DEVICE_ID;
}
void CStreamingDevice_wwise::Destroy()
{
if (m_deviceID != AK_INVALID_DEVICE_ID)
{
AK::StreamMgr::DestroyDevice(m_deviceID);
m_deviceID = AK_INVALID_DEVICE_ID;
}
}
bool CStreamingDevice_wwise::Open(const char* filename, [[maybe_unused]] AkOpenMode openMode, AkFileDesc& fileDesc)
{
AZ_Assert(openMode == AK_OpenModeRead, "Wwise Async File IO - Only supports opening files for reading.\n");
const size_t fileSize = gEnv->pCryPak->FGetSize(filename);
if (fileSize)
{
AZStd::string* filenameStore = azcreate(AZStd::string, (filename));
fileDesc.hFile = AkFileHandle();
fileDesc.iFileSize = static_cast<AkInt64>(fileSize);
fileDesc.uSector = 0;
fileDesc.deviceID = m_deviceID;
fileDesc.pCustomParam = filenameStore;
fileDesc.uCustomParamSize = sizeof(AZStd::string*);
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
streamer->QueueRequest(streamer->CreateDedicatedCache(*filenameStore));
return true;
}
return false;
}
AKRESULT CStreamingDevice_wwise::Read(AkFileDesc& fileDesc, const AkIoHeuristics& heuristics, AkAsyncIOTransferInfo& transferInfo)
{
AZ_Assert(fileDesc.pCustomParam, "Wwise Async File IO - Reading a file before it has been opened.\n");
auto callback = [&transferInfo](AZ::IO::FileRequestHandle request)
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Audio);
AZ::IO::IStreamerTypes::RequestStatus status = AZ::Interface<AZ::IO::IStreamer>::Get()->GetRequestStatus(request);
switch (status)
{
case AZ::IO::IStreamerTypes::RequestStatus::Completed:
transferInfo.pCallback(&transferInfo, AK_Success);
break;
case AZ::IO::IStreamerTypes::RequestStatus::Canceled:
transferInfo.pCallback(&transferInfo, AK_Cancelled);
break;
default:
transferInfo.pCallback(&transferInfo, AK_Fail);
break;
}
};
// The priorities for Wwise range from 0 (lowest priority) to 100 (highest priority). AZ::IO::Streamer has
// a similar range except between 0 (lowest) and 255 (highest) so remap from one to the other.
static_assert(AK_MIN_PRIORITY == 0, "The minimum priority for Wwise has changed, please update the conversion to AZ::IO::Streamers priority.");
static_assert(AK_DEFAULT_PRIORITY == 50, "The default priority for Wwise has changed, please update the conversion to AZ::IO::Streamers priority.");
static_assert(AK_MAX_PRIORITY == 100, "The maximum priority for Wwise has changed, please update the conversion to AZ::IO::Streamers priority.");
static_assert(AZ::IO::IStreamerTypes::s_priorityLowest == 0, "The priority range for AZ::IO::Streamer has changed, please update Wwise to match.");
static_assert(AZ::IO::IStreamerTypes::s_priorityHighest == 255, "The priority range for AZ::IO::Streamer has changed, please update Wwise to match.");
AZ::u16 wwisePriority = aznumeric_caster(heuristics.priority);
AZ::u8 priority = aznumeric_caster(
(wwisePriority << 1) // 100 -> 200
+ (wwisePriority >> 1) // 200 -> 250
+ (wwisePriority >> 4) // 250 -> 256
- (wwisePriority >> 6)); // 256 -> 255
auto filename = reinterpret_cast<AZStd::string*>(fileDesc.pCustomParam);
auto offset = aznumeric_cast<size_t>(transferInfo.uFilePosition);
auto readSize = aznumeric_cast<size_t>(transferInfo.uRequestedSize);
auto bufferSize = aznumeric_cast<size_t>(transferInfo.uBufferSize);
AZStd::chrono::microseconds deadline = AZStd::chrono::duration<float, AZStd::milli>(heuristics.fDeadline);
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
AZ::IO::FileRequestPtr request = streamer->Read(*filename, transferInfo.pBuffer, bufferSize, readSize, deadline, priority, offset);
streamer->SetRequestCompleteCallback(request, AZStd::move(callback));
streamer->QueueRequest(AZStd::move(request));
return AK_Success;
}
AKRESULT CStreamingDevice_wwise::Write(AkFileDesc&, const AkIoHeuristics&, AkAsyncIOTransferInfo&)
{
AZ_Assert(false, "Wwise Async File IO - Writing audio data is not supported for AZ::IO::Streamer based device.\n");
return AK_Fail;
}
AKRESULT CStreamingDevice_wwise::Close(AkFileDesc& fileDesc)
{
AZ_Assert(fileDesc.pCustomParam, "Wwise Async File IO - Closing a file before it has been opened.\n");
auto filename = reinterpret_cast<AZStd::string*>(fileDesc.pCustomParam);
auto streamer = AZ::Interface<AZ::IO::IStreamer>::Get();
streamer->QueueRequest(streamer->DestroyDedicatedCache(*filename));
azdestroy(filename);
return AK_Success;
}
AkUInt32 CStreamingDevice_wwise::GetBlockSize([[maybe_unused]] AkFileDesc& fileDesc)
{
// No constraint on block size (file seeking).
return 1;
}
void CStreamingDevice_wwise::GetDeviceDesc(AkDeviceDesc& deviceDesc)
{
deviceDesc.bCanRead = true;
deviceDesc.bCanWrite = false;
deviceDesc.deviceID = m_deviceID;
AK_CHAR_TO_UTF16(deviceDesc.szDeviceName, "Streamer", AZ_ARRAY_SIZE(deviceDesc.szDeviceName));
deviceDesc.uStringSize = AKPLATFORM::AkUtf16StrLen(deviceDesc.szDeviceName);
}
AkUInt32 CStreamingDevice_wwise::GetDeviceData()
{
return 2;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
CFileIOHandler_wwise::CFileIOHandler_wwise()
: m_useAsyncOpen(false)
{
::memset(m_bankPath, 0, AK_MAX_PATH * sizeof(AkOSChar));
::memset(m_languageFolder, 0, AK_MAX_PATH * sizeof(AkOSChar));
}
///////////////////////////////////////////////////////////////////////////////////////////////////
AKRESULT CFileIOHandler_wwise::Init(size_t poolSize)
{
// If the Stream Manager's File Location Resolver was not set yet, set this object as the
// File Location Resolver (this I/O hook is also able to resolve file location).
if (!AK::StreamMgr::GetFileLocationResolver())
{
AK::StreamMgr::SetFileLocationResolver(this);
}
if (!m_streamingDevice.Init(poolSize))
{
return AK_Fail;
}
if (!m_blockingDevice.Init(poolSize))
{
return AK_Fail;
}
return AK_Success;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void CFileIOHandler_wwise::ShutDown()
{
if (AK::StreamMgr::GetFileLocationResolver() == this)
{
AK::StreamMgr::SetFileLocationResolver(nullptr);
}
m_blockingDevice.Destroy();
m_streamingDevice.Destroy();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
AKRESULT CFileIOHandler_wwise::Open(const AkOSChar* fileName, AkOpenMode openMode, AkFileSystemFlags* flags, bool& syncOpen, AkFileDesc& fileDesc)
{
AKRESULT akResult = AK_Fail;
if (syncOpen || !m_useAsyncOpen)
{
syncOpen = true;
AkOSChar finalFilePath[AK_MAX_PATH] = { '\0' };
AKPLATFORM::SafeStrCat(finalFilePath, m_bankPath, AK_MAX_PATH);
if (flags && openMode == AK_OpenModeRead)
{
// Add language folder if the file is localized.
if (flags->uCompanyID == AKCOMPANYID_AUDIOKINETIC && flags->uCodecID == AKCODECID_BANK && flags->bIsLanguageSpecific)
{
AKPLATFORM::SafeStrCat(finalFilePath, m_languageFolder, AK_MAX_PATH);
}
}
AKPLATFORM::SafeStrCat(finalFilePath, fileName, AK_MAX_PATH);
char* tempStr = nullptr;
CONVERT_OSCHAR_TO_CHAR(finalFilePath, tempStr);
if (openMode == AK_OpenModeRead)
{
return m_streamingDevice.Open(tempStr, openMode, fileDesc) ? AK_Success : AK_Fail;
}
return m_blockingDevice.Open(tempStr, openMode, fileDesc) ? AK_Success : AK_Fail;
}
return akResult;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
AKRESULT CFileIOHandler_wwise::Open(AkFileID fileID, AkOpenMode openMode, AkFileSystemFlags* flags, bool& syncOpen, AkFileDesc& fileDesc)
{
AKRESULT akResult = AK_Fail;
if (flags && (syncOpen || !m_useAsyncOpen))
{
syncOpen = true;
AkOSChar finalFilePath[AK_MAX_PATH] = { '\0' };
AKPLATFORM::SafeStrCat(finalFilePath, m_bankPath, AK_MAX_PATH);
if (openMode == AK_OpenModeRead)
{
// Add language folder if the file is localized.
if (flags->uCompanyID == AKCOMPANYID_AUDIOKINETIC && flags->bIsLanguageSpecific)
{
AKPLATFORM::SafeStrCat(finalFilePath, m_languageFolder, AK_MAX_PATH);
}
}
AkOSChar fileName[MAX_FILETITLE_SIZE] = { '\0' };
const AkOSChar* const filenameFormat = (flags->uCodecID == AKCODECID_BANK ? ID_TO_STRING_FORMAT_BANK : ID_TO_STRING_FORMAT_WEM);
AK_OSPRINTF(fileName, MAX_FILETITLE_SIZE, filenameFormat, static_cast<int unsigned>(fileID));
AKPLATFORM::SafeStrCat(finalFilePath, fileName, AK_MAX_PATH);
char* filePath = nullptr;
CONVERT_OSCHAR_TO_CHAR(finalFilePath, filePath);
if (openMode == AK_OpenModeRead)
{
return m_streamingDevice.Open(filePath, openMode, fileDesc) ? AK_Success : AK_Fail;
}
return m_blockingDevice.Open(filePath, openMode, fileDesc) ? AK_Success : AK_Fail;
}
return akResult;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void CFileIOHandler_wwise::SetBankPath(const char* const bankPath)
{
const AkOSChar* akBankPath = nullptr;
CONVERT_CHAR_TO_OSCHAR(bankPath, akBankPath);
AKPLATFORM::SafeStrCpy(m_bankPath, akBankPath, AK_MAX_PATH);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
void CFileIOHandler_wwise::SetLanguageFolder(const char* const languageFolder)
{
const AkOSChar* akLanguageFolder = nullptr;
CONVERT_CHAR_TO_OSCHAR(languageFolder, akLanguageFolder);
AKPLATFORM::SafeStrCpy(m_languageFolder, akLanguageFolder, AK_MAX_PATH);
}
} // namespace Audio
@@ -0,0 +1,106 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <FileIOHandler_wwise_Platform.h>
#include <AK/SoundEngine/Common/AkTypes.h>
#include <AK/SoundEngine/Common/AkStreamMgrModule.h>
namespace Audio
{
//! Wwise file IO device that access the Lumberyard file system through standard blocking file IO calls. Wwise will still
//! run these in separate threads so it won't be blocking the audio playback, but it will interfere with the internal
//! file IO scheduling of Lumberyard. This class can also write, so it's intended use is for one-off file reads and
//! for tools to be able to write files.
class CBlockingDevice_wwise
: public AK::StreamMgr::IAkIOHookBlocking
{
public:
~CBlockingDevice_wwise() override;
bool Init(size_t poolSize);
void Destroy();
AkDeviceID GetDeviceID() const { return m_deviceID; }
bool Open(const char* filename, AkOpenMode openMode, AkFileDesc& fileDesc);
AKRESULT Read(AkFileDesc& fileDesc, const AkIoHeuristics& heuristics, void* buffer, AkIOTransferInfo& transferInfo) override;
AKRESULT Write(AkFileDesc& fileDesc, const AkIoHeuristics& heuristics, void* data, AkIOTransferInfo& transferInfo) override;
AKRESULT Close(AkFileDesc& fileDesc) override;
AkUInt32 GetBlockSize(AkFileDesc& fileDesc) override;
void GetDeviceDesc(AkDeviceDesc& deviceDesc) override;
AkUInt32 GetDeviceData() override;
protected:
AkDeviceID m_deviceID = AK_INVALID_DEVICE_ID;
};
//! Wwise file IO device that uses AZ::IO::Streamer to asynchronously handle file requests. By using AZ::IO::Streamer file requests
//! can be scheduled along side other file requests for optimal disk usage. This class can't write and is intended to be used
//! as part of a streaming system.
class CStreamingDevice_wwise
: public AK::StreamMgr::IAkIOHookDeferred
{
public:
~CStreamingDevice_wwise() override;
bool Init(size_t poolSize);
void Destroy();
AkDeviceID GetDeviceID() const { return m_deviceID; }
bool Open(const char* filename, AkOpenMode openMode, AkFileDesc& fileDesc);
AKRESULT Read(AkFileDesc& fileDesc, const AkIoHeuristics& heuristics, AkAsyncIOTransferInfo& transferInfo) override;
AKRESULT Write(AkFileDesc& fileDesc, const AkIoHeuristics& heuristics, AkAsyncIOTransferInfo& transferInfo) override;
void Cancel([[maybe_unused]] AkFileDesc& fileDesc, [[maybe_unused]] AkAsyncIOTransferInfo& transferInfo, [[maybe_unused]] bool& cancelAllTransfersForThisFile) override {}
AKRESULT Close(AkFileDesc& fileDesc) override;
AkUInt32 GetBlockSize(AkFileDesc& fileDesc) override;
void GetDeviceDesc(AkDeviceDesc& deviceDesc) override;
AkUInt32 GetDeviceData() override;
protected:
AkDeviceID m_deviceID = AK_INVALID_DEVICE_ID;
};
class CFileIOHandler_wwise
: public AK::StreamMgr::IAkFileLocationResolver
{
public:
CFileIOHandler_wwise();
~CFileIOHandler_wwise() override = default;
CFileIOHandler_wwise(const CFileIOHandler_wwise&) = delete;
CFileIOHandler_wwise& operator=(const CFileIOHandler_wwise&) = delete;
AKRESULT Init(size_t poolSize);
void ShutDown();
// IAkFileLocationResolver overrides.
AKRESULT Open(const AkOSChar* fileName, AkOpenMode openMode, AkFileSystemFlags* flags, bool& syncOpen, AkFileDesc& fileDesc) override;
AKRESULT Open(AkFileID fileID, AkOpenMode openMode, AkFileSystemFlags* flags, bool& syncOpen, AkFileDesc& fileDesc) override;
// ~IAkFileLocationResolver overrides.
void SetBankPath(const char* const bankPath);
void SetLanguageFolder(const char* const languageFolder);
private:
CStreamingDevice_wwise m_streamingDevice;
CBlockingDevice_wwise m_blockingDevice;
AkOSChar m_bankPath[AK_MAX_PATH];
AkOSChar m_languageFolder[AK_MAX_PATH];
bool m_useAsyncOpen;
};
} // namespace Audio
@@ -0,0 +1,29 @@
/*
* 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
//
// Use this plugin registration helpers header to auto-register plugin libraries.
// This will give a standard set of plugins, check <AK/Plugin/AllPluginFactories.h> for what it includes.
//
#include <AK/Plugin/AllPluginsRegistrationHelpers.h>
//
// Prior to finalization of a game, it is recommended that you include only the plugin headers used by the game.
// Third party plugins and/or plugins not included in <AK/Plugin/AllPluginFactories.h> should be added below.
//
// For example:
//
// #include <AK/Plugin/AkConvolutionReverbFXFactory.h>
// #include <AK/Plugin/AkReflectFXFactory.h>
// ...